From ef4116bc385ccc21cf9281bcb09397f0492ad392 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Tue, 8 Sep 2026 10:32:49 +0100 Subject: [PATCH] test(alerts): distinguish staged recovery edits from saved intent The real-backend persistence check covered only the saved path. Assert that reload discards an unsaved recovery edit before saving it, so browser-only state cannot be mistaken for persisted operator intent. Retain reload and real startup checks after Save. Change-source: pulse-maintainer --- scripts/incident-browser-checks.md | 3 ++- .../tests/97-alert-config-persistence.spec.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/incident-browser-checks.md b/scripts/incident-browser-checks.md index 37f53e53e..3cf470fd2 100644 --- a/scripts/incident-browser-checks.md +++ b/scripts/incident-browser-checks.md @@ -94,7 +94,8 @@ pulse-heavy-run -- env PULSE_E2E_USE_LOCAL_BACKEND=1 PULSE_MOCK_MODE=false \ This opt-in test requires the managed, disposable backend. It activates that instance through the real configuration API, changes Recovery notifications through the production Schedule UI, verifies the staged value has not reached -the server, and clicks Save Changes. It checks the real PUT result, subsequent +the server, reloads to prove the unsaved edit is discarded, then edits again +and clicks Save Changes. It checks the real PUT result, subsequent GETs and rendered control after both page reload and managed backend restart with preserved data. It does not intercept HTTP or WebSocket responses and must not be run against a shared installation. The attachment contains only diff --git a/tests/integration/tests/97-alert-config-persistence.spec.ts b/tests/integration/tests/97-alert-config-persistence.spec.ts index 704bf12ef..637d7d7cb 100644 --- a/tests/integration/tests/97-alert-config-persistence.spec.ts +++ b/tests/integration/tests/97-alert-config-persistence.spec.ts @@ -70,8 +70,15 @@ test('saves recovery intent through the UI and preserves it across reload and re const initial = true; await expect(recovery).toHaveAttribute('aria-pressed', String(initial)); await recovery.click(); + await expect(recovery).toHaveAttribute('aria-pressed', String(!initial)); // A staged edit must not already have altered the server. expect((await readConfig()).schedule.notifyOnResolve).toBe(initial); + // Reload must discard the unsaved edit rather than restore browser-only state. + await page.reload({ waitUntil: 'domcontentloaded' }); + await expect(recovery).toHaveAttribute('aria-pressed', String(initial)); + expect((await readConfig()).schedule.notifyOnResolve).toBe(initial); + await recovery.click(); + await expect(recovery).toHaveAttribute('aria-pressed', String(!initial)); const saved = page.waitForResponse(response => new URL(response.url()).pathname === '/api/alerts/config' && response.request().method() === 'PUT'); await page.getByRole('button', { name: 'Save Changes', exact: true }).click(); @@ -87,7 +94,8 @@ test('saves recovery intent through the UI and preserves it across reload and re await expect(recovery).toHaveAttribute('aria-pressed', String(!initial)); expect(await readConfig()).toMatchObject(expected); await testInfo.attach('saved-intent-proof.json', { - body: Buffer.from(JSON.stringify({ expected, reload: true, backendRestart: true, + body: Buffer.from(JSON.stringify({ expected, unsavedEditDiscardedOnReload: true, + reload: true, backendRestart: true, mockedAlertEndpoints: false, destinationReceiptProven: false })), contentType: 'application/json', });