Files
familysync/.planning/phases/07-mobile-test-harness/07-02-SUMMARY.md
T

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
playwright
e2e
global-setup
db-seed
mysql2
readiness-gate
requires provides affects
apps/pwa/playwright.config.ts (07-01) — globalSetup path reference
apps/api dev MariaDB :3306 — seed target
apps/api DEV_AUTH_BYPASS=true — required in API process before harness runs
global-setup.ts — /health readiness poll + deterministic reset-and-seed
e2e/README.md — run instructions and security guardrails
mysql2@3.22.4 devDependency in apps/pwa
Phase 07 plans 03-04 (specs depend on this seed for populated-state assertions)
Phase 08 CI (globalSetup runs unchanged in the CI runner)
added patterns
mysql2@3.22.4 devDependency in apps/pwa — enables mysql2/promise in global-setup.ts
TRUNCATE + INSERT (not INSERT IGNORE) for seed rows — D-06 deterministic reset
INSERT IGNORE INTO calendars guard — ensures calendar_id=10 FK satisfied on fresh CI DB (Pitfall 4)
SET FOREIGN_KEY_CHECKS=0/1 around TRUNCATE — FK-safe truncate ordering
fetch() for /health poll — native Node.js 22, no @playwright/test import (Pitfall 2)
created modified
apps/pwa/e2e/README.md
apps/pwa/e2e/global-setup.ts
apps/pwa/package.json
pnpm-lock.yaml
D-07-02-mysql2-in-pwa: Added mysql2@3.22.4 as devDependency to apps/pwa — global-setup.ts needs mysql2/promise for TypeScript types; the package was already in the monorepo (apps/api), so pnpm install just linked it without downloading
D-07-02-deadline-check: Added explicit deadline check after the health poll loop to distinguish 'loop exited via break (success)' from 'loop exited via deadline expiry' — ensures throw fires correctly on timeout
D-07-02-dtend-in-vevent: Added DTEND line to the minimal VCALENDAR seed string for spec compatibility — some CalDAV parsers reject VEVENTs without DTEND
duration_seconds completed_date tasks_completed files_changed
196 2026-06-11 2 4

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}/health with a 60-second deadline; swallows ECONNREFUSED; breaks on first res.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/test imports — plain Node.js (Pitfall 2 compliant)
  • 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.jsonmysql2@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 — found
  • grep "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 present
  • grep -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 errors
  • tsc --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.json emitted TS2307: Cannot find module 'mysql2/promise'
  • Issue: mysql2 is in apps/api/dependencies but not linked to apps/pwa. The global-setup imports mysql2/promise which requires the package to be a direct or devDependency of apps/pwa for TypeScript resolution.
  • Fix: Added "mysql2": "3.22.4" to apps/pwa/devDependencies (same version as apps/api to stay in sync). pnpm install linked 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 break on success OR when Date.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 — exists
  • apps/pwa/e2e/README.md — exists
  • Task 1 commit 53498e3 — exists
  • Task 2 commit 535ba11 — exists