diff --git a/e2e/specs/08-browser-chaos/storage-purge.spec.ts b/e2e/specs/08-browser-chaos/storage-purge.spec.ts index cb52152..074d4af 100644 --- a/e2e/specs/08-browser-chaos/storage-purge.spec.ts +++ b/e2e/specs/08-browser-chaos/storage-purge.spec.ts @@ -81,7 +81,16 @@ test.describe('Browser chaos — storage purge', () => { await clearAllStorage(page); - await page.goto('/admin'); + // The `goto` is deliberately allowed to REJECT. What is under test is a race the app wins: + // the admin layout redirects to /admin/login the moment it sees no JWT, and a redirect that + // lands first makes this navigation either "interrupted by another navigation" or + // ERR_ABORTED. Both mean the app did exactly the right thing, quickly — so failing on them + // made the test red precisely when the behaviour was correct, roughly one run in three, and + // it read as a regression in whatever change happened to be in flight. (`waitUntil: 'commit'` + // narrows the window but does not close it; an abort can beat commit too.) + // + // `waitForURL` below is the assertion, and it is unaffected by how the navigation ended. + await page.goto('/admin').catch(() => {}); // The admin layout should bounce them to /admin/login when the JWT is gone. await page.waitForURL(/admin\/login|join/, { timeout: 5_000 }); }); @@ -94,6 +103,12 @@ test.describe('Browser chaos — storage purge', () => { const g = await guest('PurgePin'); await signIn(page, g); await page.goto('/account'); + // Let the page finish settling before touching its execution context. `goto` resolves at + // `load`, but the layout's boot hydration is still in flight and any navigation it triggers + // destroys the context out from under the `page.evaluate` below — which surfaced as an + // intermittent "Execution context was destroyed" that has nothing to do with what this test + // asserts. + await page.waitForLoadState('networkidle'); // Simulate clearAuth() — clears JWT + user_id but keeps PIN so the user can recover. await page.evaluate(() => {