- CLAUDE.md: remove Redis constraint, ioredis library row, Redis architecture sentence, update compose comment - README.md: remove Redis from prereqs, quick-start command, compose description, tech-stack live-sync row - docs/ARCHITECTURE.md: delete Redis infrastructure table row - docs/CONFIGURATION.md: remove Redis localhost:6379 mention from dev section - docs/deployment.md: delete redis services table row - docs/DEVELOPMENT.md: remove prereq mention, heading, two up commands, expose bullet, stack comment - docs/GETTING-STARTED.md: prereq row, up command, prose mention - docs/TESTING.md: 'API and MariaDB' (was API, MariaDB, and Redis) - apps/pwa/e2e/README.md: delete Redis on :6379 bullet - apps/pwa/playwright.config.ts: two comments updated (API+MariaDB, not API+MariaDB+Redis)
118 lines
6.1 KiB
Markdown
118 lines
6.1 KiB
Markdown
# E2E Test Harness
|
||
|
||
Playwright test harness for the FamilySync PWA — mobile-emulated (iPhone 14/WebKit + Pixel 7/Chromium) and Desktop Chrome (1280×720), authenticated via `DEV_AUTH_BYPASS`, deterministically seeded, runs headlessly in CI.
|
||
|
||
---
|
||
|
||
## Prerequisites
|
||
|
||
**You bring up the dev stack first (D-09).** The harness waits for it — it does not start it.
|
||
|
||
See `docs/deployment.md` under "Running locally (host-side, no Docker)" for the canonical bring-up command.
|
||
|
||
The stack must include:
|
||
|
||
- API on `:3000` started with `DEV_AUTH_BYPASS=true` (see Security Guardrail below)
|
||
- PWA dev server on `:5173` (`pnpm --filter @familysync/pwa dev`)
|
||
- Dev MariaDB on `:3306` (exposed via `docker-compose.dev.yml`)
|
||
|
||
**`DEV_AUTH_BYPASS=true` MUST be set in the API's environment BEFORE the API process starts.** The harness cannot inject it at runtime — the API reads the env var once at startup. If the API is running without it, all `/api/*` requests return an auth redirect and every spec fails.
|
||
|
||
---
|
||
|
||
## Run Commands
|
||
|
||
`global-setup.ts` is **fail-closed**: it refuses to run (throws before any DB write) unless
|
||
`DEV_AUTH_BYPASS=true` **and** `NODE_ENV !== 'production'` — the same handshake the API uses
|
||
(see Security Guardrail). So `DEV_AUTH_BYPASS=true` must be exported in the **test process**
|
||
environment (not only the API's). Source the DB credentials from the repo-root `.env` and point
|
||
`DB_HOST` at the host-side MariaDB:
|
||
|
||
```bash
|
||
# Load DB creds, then run. DEV_AUTH_BYPASS=true is required by the global-setup guard.
|
||
set -a; source .env; set +a
|
||
export DEV_AUTH_BYPASS=true DB_HOST=127.0.0.1 DB_PORT=3306
|
||
|
||
# Full suite — iPhone (WebKit), Pixel (Chromium), Desktop Chrome profiles
|
||
pnpm --filter @familysync/pwa test:e2e
|
||
|
||
# Single profile (faster local iteration)
|
||
pnpm --filter @familysync/pwa exec playwright test --project=pixel
|
||
pnpm --filter @familysync/pwa exec playwright test --project=desktop
|
||
|
||
# Headed (local debug — shows the browser)
|
||
pnpm --filter @familysync/pwa exec playwright test --headed
|
||
|
||
# UI mode (interactive test explorer)
|
||
pnpm --filter @familysync/pwa test:e2e:ui
|
||
```
|
||
|
||
---
|
||
|
||
## Env Vars
|
||
|
||
The harness reads these from the environment. DB credentials are env-only — never hardcoded in seed scripts or specs.
|
||
|
||
| Var | Default | Purpose |
|
||
| --------------------- | ----------------------- | --------------------------------------------------------------- |
|
||
| `PLAYWRIGHT_BASE_URL` | `http://localhost:5173` | Base URL for all spec navigation and the /health readiness poll |
|
||
| `DB_HOST` | `127.0.0.1` | MariaDB host for the global-setup seed script |
|
||
| `DB_PORT` | `3306` | MariaDB port |
|
||
| `DB_USER` | `familysync` | MariaDB user |
|
||
| `DB_PASSWORD` | _(empty)_ | MariaDB password — set in environment or `.env` |
|
||
| `DB_NAME` | `familysync` | MariaDB database name |
|
||
|
||
Set `DB_PASSWORD` (and other non-default values) via the shell or the repo root `.env` file before running. The `.env` file is gitignored — never commit credentials.
|
||
|
||
---
|
||
|
||
## Security Guardrail — DEV_AUTH_BYPASS
|
||
|
||
`DEV_AUTH_BYPASS=true` is a **development-only bypass** that resolves all API requests to Dev User id 1 without OIDC authentication.
|
||
|
||
The API enforces this via `apps/api/src/auth/devBypass.ts`:
|
||
|
||
```text
|
||
if (process.env.NODE_ENV === 'production') → bypass is a no-op (always)
|
||
if (process.env.DEV_AUTH_BYPASS !== 'true') → bypass is a no-op
|
||
```
|
||
|
||
**The production Docker Compose (`docker-compose.yml`) MUST NOT set `DEV_AUTH_BYPASS`.** Setting it in production is an Elevation of Privilege vulnerability — any request would be resolved as the dev user with no authentication.
|
||
|
||
The `docker-compose.dev.yml` override sets it for local dev and CI. Review it before any production deployment to confirm `DEV_AUTH_BYPASS` is absent from the production compose file.
|
||
|
||
---
|
||
|
||
## No Session State File
|
||
|
||
This harness uses **no `storageState` file** (D-01). There is no checked-in session cookie, no expiring auth artifact, and no per-run login flow. `DEV_AUTH_BYPASS=true` makes the API respond as user 1 unconditionally — the tests run repeatably day-over-day without re-authentication. See PITFALLS.md §Pitfall 14 for why `storageState` is excluded.
|
||
|
||
---
|
||
|
||
## What globalSetup Does
|
||
|
||
Before any spec runs, `global-setup.ts`:
|
||
|
||
0. **Fail-closed guard:** throws immediately if `NODE_ENV === 'production'` or `DEV_AUTH_BYPASS !== 'true'`, before opening any DB connection — so the TRUNCATE/seed can never run against a production (or unconfirmed) database.
|
||
1. **Polls `PLAYWRIGHT_BASE_URL/health`** until 200 OK (60s timeout, then fails fast with a clear error).
|
||
2. **Truncates** `list_items`, `list_shares`, `lists`, `calendar_events` (FK checks disabled around TRUNCATE).
|
||
3. **Seeds** deterministic fixtures for Dev User 1:
|
||
- One timed calendar event (`'Seeded Test Event'`) on calendar_id=10
|
||
- One shared list (`'E2E Grocery List'`) owned by user 1, with a `list_shares` row and two items (`'Milk'`, `'Eggs'`)
|
||
|
||
This seeding is idempotent — two consecutive runs leave the same row counts, no stale rows, no duplicate-key errors.
|
||
|
||
---
|
||
|
||
## CI (Phase 8)
|
||
|
||
Phase 8 (Gitea CI) runs these specs unchanged as a PR UI-regression step. The CI workflow owns:
|
||
|
||
- Bringing up the dev stack (compose) with `DEV_AUTH_BYPASS=true`
|
||
- Waiting for the MariaDB health check before starting the API
|
||
- Setting `PLAYWRIGHT_BASE_URL`, `DB_*`, and `DEV_AUTH_BYPASS=true` env vars in the runner environment (the global-setup guard requires `DEV_AUTH_BYPASS=true` in the Playwright process, not only the API's)
|
||
|
||
The harness handles its own readiness gate (`/health` poll) once the runner sets things up. No changes to spec files are needed for CI — the harness is stack-agnostic via env vars.
|
||
|
||
CI Dockerfile must use `playwright install --with-deps webkit chromium` to install WebKit system deps (see RESEARCH.md §Pitfall 6).
|