fix(playwright): stop notoast leaking into shared storage state - #3747
fix(playwright): stop notoast leaking into shared storage state#3747EmilyRagan wants to merge 4 commits into
Conversation
Enterprise runs re-save storageState.json after a mid-run Keycloak re-login, which captured the fixture's own notoast=true and disabled alert toasts for every later context - notifications.s.spec.ts failed 9 tests because its disableToasts: false only skipped the init script instead of clearing the inherited value. Always write the toast preference in the init script, and filter UI preference keys out of the saved auth state. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3747 +/- ##
==========================================
- Coverage 80.00% 79.12% -0.88%
==========================================
Files 885 894 +9
Lines 65382 66857 +1475
Branches 2543 2543
==========================================
+ Hits 52309 52903 +594
- Misses 12411 13293 +882
+ Partials 662 661 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| ) | ||
| } | ||
| await writeFile(path, JSON.stringify(state)) | ||
| } |
There was a problem hiding this comment.
Would this whole thing be better as a white list instead of a black list? Like we should probably only be saving just the auth info.
Denylisting notoast/toastPosition only covers the two keys that already caused a failure. The app writes several other keys through the same path (notificationStreamOffset, lastReadNotification, ackedAlerts, per-tool settings), each able to change behavior for every later context. Keep session + scope keys instead, so a leak has to be opted into. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Enterprise workflow with notification tests passing. One flaky, next commit pushed in an attempt to address that or at least make the problem more diagnosable in the future |
In Enterprise every page load bounces through Keycloak, so page.reload() spends ~4s on redirect, token exchange and app boot before the message stream resubscribes and replays - all of it inside the 20s toast assertion, which made "un-acked alerts survive a page reload" flaky. Wait for the app bar after reloading, give the replay assertion 30s, and raise the two reload tests past the 60s default so an overrun still names the failing assertion. Also retain traces for any failed attempt: on-first-retry only keeps the passing run's trace. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|



Problem
Enterprise Playwright CI (run 32272124083) failed 9 tests in
notifications.s.spec.ts— every assertion waiting on[data-test=toast]timed out. The two tests that assert no toast passed vacuously.That run's trace artifact shows the context's
storageStateforhttp://localhost:2900contains:Notifications.vue:316reads it asshowToast = false, so the gate atNotifications.vue:524never queues a toast. Menu population is outside the gate, which is why the notifications badge still counted the alert.Why it only happens under Enterprise:
fixture.tssetsnotoast=truefor every spec (disableToasts: true), and — inside theENTERPRISE === '1'branch only — re-saves the whole context tostorageState.jsonafter a mid-run Keycloak re-login, baking that flag in. Every later context is created from that file, andnotifications.s.spec.ts'sdisableToasts: falseonly skips the init script, so it could not clear an inherited value.Unrelated to the cosmos
web-socket-api-refactormerge: core CI passes the same spec on the same commit.Fix
The init script always writes the toast preference (
setItemwhen disabling,removeItemwhen a spec opts out), so opting out defeats an inherited value.saveAuthStateallowlists what gets written tostorageState.json/adminStorageState.json, keeping only session and scope keys:openc3Token,openc3RefreshToken,openc3OfflineToken,openc3LoginMode,keycloakUrl,keycloakRealm,keycloakClientId,openc3Scope. Everything else is dropped — UI preferences (notoast,toastPosition), notification read state (notificationStreamOffset,lastReadNotification,ackedAlerts),kc-callback-*redirect leftovers.Allowlist rather than denylist because the leak is the bug: any test-injected key that reaches that file silently changes behavior for the rest of the run, and the notification read-state keys would do it in the same way
notoastdid. A key missing from the allowlist fails every spec loudly instead, which is the better failure mode — but it does mean the list needs updating if auth-relevant keys are added.Removed a dead commented-out
setSetting(..., 'show-alerts', ...)block in the spec.Hardened the two reload tests, which flaked once the toasts started working: in Enterprise every page load bounces through Keycloak, so
page.reload()spends ~4s on redirect, token exchange and app boot before the message stream resubscribes and replays — all of it previously inside the 20s toast assertion. They now wait for the app bar after reloading, give the replay assertion 30s, and raise their own timeout past the 60s default so an overrun still names the failing assertion.trace: 'retain-on-failure'in CI. Withon-first-retry, a test that fails then passes leaves a trace of the passing run — the one that needs no diagnosing.Verification
Enterprise run 32395585458, which did check out this branch: the 9 toast failures are gone (serial batch 47 passed). Two remaining issues, both now understood:
un-acked alerts survive a page reloadflaked — the reload/replay timing above, addressed by the last commit and not yet re-run in CI.table-manager.s.spec.ts:259 downloads binary, definition, reportfailed on a download timeout. Pre-existing and unrelated; it was already flaky before this branch.Locally, against an Enterprise stack with a deliberately poisoned
storageState.json(live operator session plusnotoastandnotificationStreamOffset):pnpm lint --max-warnings 0cleanFollow-ups (not in this PR)
setQuietinnotifications.s.spec.tsbuilds a raw context fromstorageState.jsonand cannot log in. Global setup saves the operator session then logs out of it to log in as admin, so that file only works because the fixture refreshes it mid-run — the same write that was poisoning it.metrics_helper.rb:187) andToast.vueshows 3 toasts at a time withduration: Infinity, so stuck system-health alerts could still starve a spec's toast on a loaded runner.🤖 Generated with Claude Code