Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
7.6 KiB
phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 07-mobile-test-harness | 02 | test-harness |
|
|
|
|
|
|
Phase 07 Plan 02: globalSetup Readiness Gate + DB Seed Summary
One-liner: Playwright globalSetup with 60s /health readiness poll and deterministic TRUNCATE+INSERT seed onto calendar_id=10 and user_id=1 lists — idempotent run-over-run.
What Was Built
-
apps/pwa/e2e/global-setup.ts— full implementation replacing the Plan 01 stub:- Step 1 (D-08): polls
${PLAYWRIGHT_BASE_URL}/healthwith a 60-second deadline; swallows ECONNREFUSED; breaks on firstres.ok; throws with a clear diagnostic message if the deadline passes - Step 2 (D-06/D-07): direct mysql2 connection using exact env-var names from
apps/api/src/db/client.ts;SET FOREIGN_KEY_CHECKS=0→ TRUNCATE list_items/list_shares/lists/calendar_events →SET FOREIGN_KEY_CHECKS=1→ INSERT IGNORE calendars guard (id=10) → one timed calendar_event → E2E Grocery List (owner_id=1, is_shared=true) + list_shares row + Milk/Eggs items - No
@playwright/testimports — plain Node.js (Pitfall 2 compliant)
- Step 1 (D-08): polls
-
apps/pwa/e2e/README.md— operator reference documenting:- Prerequisites: dev stack (API + PWA + MariaDB + Redis) with DEV_AUTH_BYPASS=true
- Run commands:
pnpm --filter @familysync/pwa test:e2e, single profile, headed, UI mode - Env var contract: PLAYWRIGHT_BASE_URL, DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME — credentials env-only, never hardcoded (T-07-05)
- Security guardrail: DEV_AUTH_BYPASS is dev-only, NODE_ENV !== 'production' hard guard, production compose MUST NOT set it (T-07-04)
- No storageState (D-01 — designed out)
- CI scope note: Phase 8 brings up the stack; harness handles its own readiness gate
-
apps/pwa/package.json— mysql2@3.22.4 added as devDependency (same version as apps/api; pnpm linked without downloading)
Verification Evidence
grep "^import mysql from 'mysql2/promise'" apps/pwa/e2e/global-setup.ts— foundgrep "from '@playwright/test'" apps/pwa/e2e/global-setup.ts— absent (Pitfall 2 pass)grep "TRUNCATE TABLE" apps/pwa/e2e/global-setup.ts— 4 tables (list_items, list_shares, lists, calendar_events)grep "INSERT IGNORE INTO calendars" apps/pwa/e2e/global-setup.ts— found with VALUES (10, 1, ...)grep "list_shares\|Milk\|Eggs" apps/pwa/e2e/global-setup.ts— all presentgrep -c 'DEV_AUTH_BYPASS|NODE_ENV|storageState|PLAYWRIGHT_BASE_URL|test:e2e' apps/pwa/e2e/README.md→ 15 (acceptance criteria: non-zero count)tsc --noEmit --project tsconfig.e2e.json(apps/pwa) → 0 errorstsc --noEmit(apps/pwa src) → 0 errors
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] mysql2 not available in apps/pwa
- Found during: Task 1 TypeScript check —
tsc --noEmit --project tsconfig.e2e.jsonemittedTS2307: Cannot find module 'mysql2/promise' - Issue: mysql2 is in
apps/api/dependenciesbut not linked toapps/pwa. The global-setup importsmysql2/promisewhich requires the package to be a direct or devDependency of apps/pwa for TypeScript resolution. - Fix: Added
"mysql2": "3.22.4"toapps/pwa/devDependencies(same version as apps/api to stay in sync).pnpm installlinked it from the pnpm store in 4s with zero downloads — the binary was already present from apps/api. - Files modified:
apps/pwa/package.json,pnpm-lock.yaml - Commit:
53498e3
2. [Rule 2 - Missing Critical] Explicit deadline-exceeded throw after poll loop
- Found during: Task 1 implementation review — the research pattern's while loop exits via
breakon success OR whenDate.now() >= deadline. After the loop, without an explicit check, code would silently proceed to the DB seed on a timed-out poll, causing confusing mysql2 errors rather than a clear "stack is not up" message. - Fix: Added
if (Date.now() >= deadline) { throw new Error(...) }immediately after the while loop so timeout is distinguishable from success. - Files modified:
apps/pwa/e2e/global-setup.ts - Commit:
53498e3
3. [Rule 2 - Missing Critical] DTEND in minimal VCALENDAR seed string
- Found during: Task 1 implementation — minimal VCALENDAR without DTEND may fail CalDAV/ical.js parsing in some spec paths. Plan said "minimal VCALENDAR/VEVENT" but no explicit DTEND.
- Fix: Added DTEND line (futureStart + 1 hour) to the VCALENDAR seed string for spec compatibility. Does not affect seed idempotency.
- Files modified:
apps/pwa/e2e/global-setup.ts - Commit:
53498e3
Known Stubs
None — the Plan 01 stub in global-setup.ts is fully replaced with the real implementation.
Threat Surface Scan
No new network endpoints, auth paths, or schema changes. All changes are test-infrastructure files only.
Threat mitigations from plan threat model:
- T-07-04 (Elevation of Privilege / DEV_AUTH_BYPASS): README explicitly documents that DEV_AUTH_BYPASS is dev-only, that the API guards on
NODE_ENV !== 'production', and that the production compose MUST NOT set it. global-setup does not set the env var (it cannot — it runs after the API is already up). - T-07-05 (Information Disclosure / DB credentials): global-setup reads DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME from env exclusively, mirroring
apps/api/src/db/client.ts. No credential is hardcoded. README states this explicitly. - T-07-06 (Information Disclosure / OIDC session state): No storageState.json is written by the harness. README states this. Designed out per D-01.
Self-Check: PASSED
apps/pwa/e2e/global-setup.ts— existsapps/pwa/e2e/README.md— exists- Task 1 commit
53498e3— exists - Task 2 commit
535ba11— exists