Skip to content

fix(e2e): ensureWelcomePortalEntry's Factory-Reset recovery path doesn't reliably force English for non-EN/DE locales #589

Description

@qnbs

What happened

tests/e2e/helpers.ts's ensureWelcomePortalEntry() failed 3 times in a row on 2026-09-02/03 (PR #587's own run, and twice on main post-merge at commit c1a728bf), always the same test: onboarding-entry-precondition.spec.ts:18 ("reaches the entry point when a non-English language is already persisted", Mobile Chrome), always the same locator timeout on [data-tour="nav-mobile"] >> role=button[name=/More/i].

None of the failing commits touched any app or test source (PR #587 was a pnpm-workspace.yaml/pnpm-lock.yaml/AUDIT.md-only dependency-floor bump), which ruled out a code regression from that PR specifically.

Actual root cause (from the Playwright error-context accessibility snapshot)

The test persists worldscript-language: 'es' before navigating. The helper's contract (per its own comment) is meant to be locale-independent, but its fallback path is not:

// helpers.ts:188-213 (ensureWelcomePortalEntry)
if (await portal.isVisible({ timeout: 3000 }).catch(() => false)) return;
// force English before the locale-dependent recovery flow below...
await page.evaluate(() => localStorage.setItem('worldscript-language', 'en'));
await page.reload();
await waitForSpaReady(page);
if (await portal.isVisible({ timeout: 3000 }).catch(() => false)) return;
await waitForMainChrome(page);
await clickNavItem(page, /Settings/i);          // <- fails here
await page.getByRole('button', { name: /Data & Backups|Daten & Backups/i })...
await page.getByRole('button', { name: /Factory Reset|Werkseinstellungen/i })...
await page.getByRole('button', { name: /Delete everything & restart|Alles löschen & neu starten/i })...

The recovery branch (used when a pre-existing/leftover project causes the app to land in the main shell instead of the WelcomePortal — the helper's own comment calls this "its own internal-reload race", i.e. a known, accepted, low-probability contingency) tries to force English via localStorage.setItem + page.reload(), then drives Factory Reset through English/German-only button-name regexes. The captured accessibility snapshot at the failure point shows the UI still fully rendered in Spanish ("Panel", "Manuscrito", "Más", ...) — the forced-English reload did not actually take effect before clickNavItem ran, so it searches for /More/i against a button labeled "Más" and never finds it. This will deterministically fail for any persisted locale other than English/German, every time the rare internal-reload race triggers.

This is pre-existing test-infrastructure debt, not something introduced by #587. It manifested 3x on 2026-09-02/03 specifically, plausibly because this session ran an unusually high number of back-to-back full-suite CI runs that day (heavier runner load can increase the probability of the debounced-autosave-vs-reload race the comment already documents), but the underlying bug is real and deterministic once the race triggers, independent of load.

Fix needed

Either:

  1. Make the forced-English step actually reliable before the Factory-Reset recovery path runs (e.g. wait for the language change to actually apply — check a stable indicator, not just page.reload() timing — before proceeding), or
  2. Make the Factory-Reset recovery path itself locale-independent (match by stable data-testid/aria-label keys rather than translated button text, consistent with how the rest of this same test file already treats welcome-portal as the stable, locale-independent success signal).

Non-goals

  • Do not weaken the test's actual coverage (it should still prove a fresh WelcomePortal is reached regardless of persisted locale).
  • Do not just increase timeouts as a workaround — the button is never going to say "More" in Spanish no matter how long you wait.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions