fix(e2e): pin Playwright baseURL to localhost regardless of PUBLIC_APP_URL

Root cause of the recurring "just test-all shows 27/16, playwright alone
shows 43/0" split:

  Justfile loads .env with dotenv-load, which sets PUBLIC_APP_URL to the
  LAN IP from the phone-preview config. playwright.config.ts was reading
  that env and using it as baseURL. The resulting LAN-IP OAuth round-trip
  (browser → GoTrue → Keycloak → browser) adds ~hundreds of ms of
  loopback routing per hop and pushes the $currentCollective hydration
  past Playwright's first synthetic keystroke, producing a silent early
  return in handleAdd (name typed but Enter never triggers a write).

  Running playwright directly skipped dotenv-load, baseURL fell back to
  localhost, and everything passed. Same code, same machine, different
  wrapper.

Fix
  apps/web/playwright.config.ts: baseURL hardcoded to 'http://localhost:5173'.
    The LAN IP stays in PUBLIC_APP_URL for on-device phone previews (step
    2/3 of the mobile-testing recipe in CLAUDE.md), but e2e always hits
    the loopback so the timing profile is deterministic.
  apps/web/tests/fixtures/login.ts: origin-check hardcoded to localhost
    to match.

Verification
  just test-all → exit 0, 228 tests green (34 pgTAP + 140 Vitest
    integration + 11 Vitest unit + 43 Playwright), 4 skipped (upstream
    Realtime presence + WebKit-only touch gestures).
  just test-e2e alone → 43 passed.
  pnpm exec playwright test alone → 43 passed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 00:48:10 +02:00
parent 4532c24e1a
commit a86b296ecd
2 changed files with 10 additions and 9 deletions

View File

@@ -18,12 +18,11 @@ export async function loginAs(page: Page, user: (typeof USERS)[keyof typeof USER
await page.fill('#password', user.password);
await page.click('#kc-login');
// Wait until we're redirected OFF the callback page. Origin depends on the
// PUBLIC_APP_URL the stack is configured with (localhost for plain dev; LAN
// IP like http://192.168.1.167:5173 when phones are in the loop).
const appOrigin = new URL(process.env.PUBLIC_APP_URL ?? 'http://localhost:5173').origin;
// We pin Playwright's baseURL to http://localhost:5173 (see playwright.config.ts)
// regardless of whether PUBLIC_APP_URL is the LAN IP for device previews, so
// the post-login origin is always localhost.
await page.waitForURL(
(url) => url.origin === appOrigin && !url.pathname.startsWith('/auth/callback'),
(url) => url.origin === 'http://localhost:5173' && !url.pathname.startsWith('/auth/callback'),
{ timeout: 20_000 }
);
await page.waitForFunction(