fix(e2e): dismiss the first-login welcome modal deterministically in devBypassAuth#1812
Conversation
…devBypassAuth The admin shell opens the welcome modal whenever its currentUser query resolves with isFirstLogin — on a cold workerd start that can be seconds after the sidebar renders, past dismissOnboardingModal()'s 2s visibility window, so the modal survives and swallows the test's clicks (actions run 28678460523, E2E Cloudflare shard 3/8). devBypassAuth now lands the bypass on the shell-free auth/me endpoint, clears the welcomeDismissed flag over HTTP, and only then loads the admin shell, so the first currentUser fetch already reports isFirstLogin: false and the modal can never mount on the standard auth path. The UI-side dismissal stays as a fallback for flows that authenticate outside the bypass.
|
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
This is the right fix for the right problem: the E2E auth fixture was racing the shell's first-login modal, and clearing the flag server-side before the shell loads eliminates the race instead of just widening the timeout.
I checked the changed fixture against the relevant server code:
POST /_emdash/api/auth/mewithaction: "dismissWelcome"is the same endpoint the admin UI uses; it persistswelcomeDismissedin the DB and returns{ success: true }on success.- The auth middleware requires
X-EmDash-Request: 1for cookie-authenticated state-changing API requests; the fixture supplies it. - The setup/dev-bypass redirect to
/_emdash/api/auth/meis a safe local path (isSafeRedirectaccepts it), andwaitForURLmatching on pathname avoids matching the redirect query string while the meta-refresh page is still loaded. page.requestshares the browser context's cookies, so the session established by the bypass is present for the POST.- The existing
dismissOnboardingModal()fallback inwaitForShell()is preserved for non-bypass flows.
The change is test-only, touches no published package, and needs no changeset. No AGENTS.md convention violations found. The PR is clean.
What does this PR do?
Removes a timing race in the E2E auth fixture that intermittently fails unrelated PRs on the Cloudflare suite.
The admin shell opens the first-login "Welcome to EmDash" modal whenever its
currentUserquery resolves withisFirstLogin— on a cold workerd start that can be several seconds after the sidebar renders.AdminPage.waitForShell()only dismisses the modal if it is visible within a 2-second window, so when the query resolves late the modal survives and swallows the test's clicks/assertions.Observed in the wild on actions run 28678460523, E2E Cloudflare (3/8) (failing #1810, whose diff touches only the menus resolver):
content-types.spec.ts › displays seeded collections in a tablefailed withelement(s) not foundfor the table links, and the Playwright error context shows the page covered bydialog "Welcome to EmDash, Dev!". The equivalent SQLite shard and the other seven Cloudflare shards passed.The fix makes the standard auth path deterministic instead of retiming the race:
devBypassAuth()now lands the bypass redirect on the shell-free/_emdash/api/auth/meJSON endpoint, clears the flag server-side (POST /_emdash/api/auth/mewithaction: "dismissWelcome", viapage.requestso the session cookie and CSRF header are supplied), and only then loads the admin shell — so the shell's firstcurrentUserfetch already reportsisFirstLogin: falseand the modal can never mount.dismissOnboardingModal()fallback inwaitForShell()is left in place for flows that authenticate outside the bypass (e.g. the setup-wizard spec's real first-run path).No product code changes; the fixture ends in the same post-condition as before (authenticated, dashboard loaded, shell hydrated).
Issue: none filed — happy to open one instead if you prefer tracking flakes that way.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
pnpm exec playwright test e2e/tests/content-types.spec.ts e2e/tests/setup-wizard.spec.ts→ 17 passed (42.0s)EMDASH_E2E_TARGET=cloudflare pnpm exec playwright test e2e/tests/content-types.spec.ts e2e/tests/setup-wizard.spec.ts→ 17 passed (52.7s)pnpm lint:json | jq '.diagnostics | length'→0pnpm format→ ran