You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(e2e): establish a deterministic WelcomePortal entry precondition (#533)
* fix(e2e): establish a deterministic WelcomePortal entry precondition
export.spec.ts's beforeEach assumed waitForSpaReady() always resolves via
WelcomePortal and clicked "Start a New Project" unconditionally, but that
helper's Promise.race also succeeds when the app boots straight into an
already-mounted main shell. This caused all 3 retries to fail identically
on a post-merge main run, distinct from the (already-fixed) #527 portal-
activation auto-seed race.
Adds ensureWelcomePortalEntry() (tests/e2e/helpers.ts), which recovers via
the real Settings -> Data & Backups -> Factory Reset flow when the portal
isn't already showing -- no storage/React internals touched, only supported
app behavior. Regression-tested from both startup shapes in a new spec.
See issue #532 for the full evidence trail and the still-open root-cause
question of how a persisted project reached IndexedDB before the test's
own actions ran.
* fix(e2e): address review findings on the WelcomePortal precondition fix
- Add the required QNBS-v3 marker to ensureWelcomePortalEntry
(CodeRabbit).
- Harden the persisted-main-shell regression case: wait for the real
debounced autosave to land (observable "All changes saved" signal in
Header.tsx) before reloading, and explicitly assert the reload landed
back in the main shell with "Start a New Project" absent -- otherwise
the scenario could pass via a fresh WelcomePortal without ever
exercising ensureWelcomePortalEntry()'s Factory Reset fallback
(chatgpt-codex-connector).
* fix(e2e): normalize to English before the locale-dependent recovery flow
ensureWelcomePortalEntry()'s Factory Reset fallback matches Settings/
Data & Backups/Factory Reset button text in English or German only. If
a non-EN/DE language were persisted when the fallback is entered, it
would hang instead of establishing the promised precondition. Force
worldscript-language to 'en' via the same localStorage key the app's
own language switcher writes, then reload, before navigating.
* fix(e2e): fix strict-mode violation in the persisted-main-shell regression test
The new post-reload main-shell assertion used locator('#sidebar').or(
locator('[data-tour="nav-mobile"]')).toBeVisible(), which fails with a
Playwright strict-mode violation: both elements exist in the DOM at
once (only one is CSS-visible per viewport via Tailwind's responsive
classes), so .or() resolves to 2 elements instead of 1. This caused
the CI E2E job on the prior push to fail on all projects (chromium,
Mobile Chrome).
Export the existing waitForMainChrome() helper (already correct via
Promise.race of two independent visibility waits, the same pattern
ensureBlankProject()/waitForSpaReady() already use) and reuse it
instead of duplicating the buggy pattern.
* fix(e2e): make WelcomePortal readiness detection locale-independent
waitForSpaReady() detected the welcome portal via the English-only
"Start a New Project" button label. If the app booted into a
non-English WelcomePortal, none of the race's three conditions would
ever match, so the whole helper (and anything built on it, including
ensureWelcomePortalEntry()'s own language-normalization step, which
only runs after waitForSpaReady() resolves) would time out before ever
getting a chance to fix the locale.
Adds a stable data-testid="welcome-portal" to WelcomePortal's root and
uses it in the readiness race instead of the translated button text.
* fix(e2e): make ensureWelcomePortalEntry's own portal check locale-independent
The stable-selector fix in 878c1e7 only updated waitForSpaReady()'s
race. ensureWelcomePortalEntry()'s own early-return check still used
the English-only button text, so a non-English WelcomePortal would
incorrectly fall through into the main-chrome-only Settings recovery
flow (which itself would then fail, since clickNavItem needs main-
chrome nav that doesn't exist on WelcomePortal). Switch this check to
the same welcome-portal testid.
Adds a regression case seeding a non-English (Spanish) language before
boot, per CodeRabbit's suggestion, proving the whole helper survives a
non-English WelcomePortal end to end.
* fix(e2e): collapse a two-line comment into the required single-line QNBS-v3 form
* fix(e2e): handle the fallback's own internal reload racing autosave
ensureWelcomePortalEntry()'s Settings/Factory Reset fallback forces
English then reloads before waiting for main chrome rigidly. If that
reload happens before a still-pending debounced autosave (~1s) lands,
the reload discards the unpersisted project and lands back in
WelcomePortal instead of main chrome -- exactly what was observed on
CI (E2E Tests failed on 7513e37, 13m timeout in waitForMainChrome).
Re-check both states after the internal reload instead of assuming
main chrome: if the portal is already visible, the target state was
reached via the race and no Settings navigation is needed.
Also fixes the helper's contract to be explicit: it guarantees the
portal is reached, locale-independently, not that it is English.
Aligns both existing regression tests (which incorrectly asserted the
English button after a locale-independent portal check) and adds a new
regression proving the helper is deterministic when its own internal
reload can land in either shape.
* fix(e2e): replace export.spec.ts's fragile EN-button click with a locale seed
ensureWelcomePortalEntry()'s contract is locale-independent (portal
reached, not necessarily English), which makes it newly possible for
export.spec.ts to actually return from a non-English WelcomePortal --
previously that state just timed out entirely, so this dead code path
was never exercised.
The existing "click the EN button" logic is unreliable there: the
custom LanguageSelector's closed-state trigger is a listbox opener,
not a direct language switch, and its accessible name comes from an
aria-label that can itself contain "en" as a substring in another
locale (Spanish's translation of the group label contains "bienvenida"
-- "bienvenida" matches /en/i). Clicking it would just open the
dropdown instead of selecting English.
Seed worldscript-language to 'en' via page.addInitScript() before the
first navigation instead, matching the existing setFeatureFlags()
idiom -- deterministic, and removes the need for any in-page language
switching in this test entirely.
{/* QNBS-v3: shell is now scrollable (overflow-y-auto) with min-h-full centering — content
371
374
taller than the viewport (e.g. the feature grid on mobile) scrolls instead of being
372
375
clipped by the old fixed `flex items-center` shell. Fixes Mobile-Chrome E2E click
373
376
timeouts where the bottom action buttons were unreachable. */}
377
+
{/* QNBS-v3: stable, locale-independent selector for E2E readiness checks — the primary action button's label is translated, but this attribute is not. */}
374
378
{/* LanguageSelector now imported from ui/LanguageSelector.tsx with search functionality */}
// QNBS-v3: seeds English before boot — ensureWelcomePortalEntry's contract is locale-independent, and the LanguageSelector trigger's accessible name isn't a reliable /EN/i click target (its aria-label can itself contain "en" as a substring in other locales, e.g. Spanish "bienvenida").
// QNBS-v3: this reload can itself race a pending debounced autosave and land back in WelcomePortal instead of main chrome — accept either state again rather than assuming main chrome.
// QNBS-v3: proves ensureWelcomePortalEntry's contract (portal reached, locale-independent) holds from every startup shape waitForSpaReady() accepts, including its own internal-reload race.
test('reaches the entry point from an already-mounted main shell with a persisted project',async({
30
+
page,
31
+
})=>{
32
+
awaitpage.goto('/');
33
+
awaitensureBlankProject(page);
34
+
// QNBS-v3: waits for the debounced autosave to land so this scenario specifically exercises the full Settings/Factory Reset fallback, which does normalize to English as an implementation detail.
test('reaches the entry point when its own internal reload can race a pending autosave',async({
47
+
page,
48
+
})=>{
49
+
// QNBS-v3: deliberately does not wait for "All changes saved" — the helper's own English-normalization reload can race the pending debounced save either way, and it must end in the portal regardless.
0 commit comments