# ADR-022: Playwright Is the E2E Test Framework — One Spec File Per PWA

## Status

Accepted, 2026-06-25.

## Status History

```yaml
status_history:
  - date: 2026-06-25
    status: Proposed
    changed_by: hkl
    reason: Formalising test framework choice already in use across all PWAs
    changed_via: adr-kit (360lm)
  - date: 2026-06-25
    status: Accepted
    changed_by: hkl
    reason: Playwright test suite live with 58+ tests; framework stable
    changed_via: adr-kit (360lm)
```

## Context

360lm needs automated testing to catch regressions before deployment, especially given the pace of PWA development and the lack of a dedicated QA engineer. Tests must cover: DOM rendering, JavaScript state, hub registry checks (PostgREST query), and SW cache version verification. The tests run on the VPS directly against the live dev URL. The dev stack (single HTML files, no bundler, no component framework) means unit tests of isolated components are not practical — the smallest meaningful test unit is the PWA loaded in a real browser.

## Decision

Playwright is the E2E testing framework for all 360lm PWAs. One `tests/<pwa>.spec.js` file per PWA. All new PWAs MUST have a spec file created at the same time as the PWA itself, using `tests/_template.spec.js` as the base. Tests run against the **dev domain** (`dev.srv1111289.hstgr.cloud`). Playwright tests MUST pass before any merge to master / deployment to prod (see ADR-015).

Tests for each PWA cover at minimum:
- PWA loads and renders core screen elements
- SW cache version is at or above minimum (`CACHE_VER` check)
- Hub registry row exists (`hub.pwa_registry` check via dev PostgREST)
- Core JS state (page.evaluate) behaves correctly
- Key user interactions (form fields, buttons, navigation)

**Decision Maker:** hkl

## Alternatives Considered

- **Cypress.** Rejected: at the time of adoption, Cypress had limitations with cross-origin iframes and service worker testing; slower test execution than Playwright; Playwright's `page.evaluate()` for JS state inspection is cleaner for single-HTML-file PWA testing.
- **Jest + jsdom.** Rejected: jsdom is not a real browser — service worker, IndexedDB, localStorage, and GPS APIs are not available or are mocked; tests would not catch the class of bugs that actually occur (SW caching issues, DOM rendering, PostgREST auth).
- **Selenium / WebDriver.** Rejected: verbose API; slower than Playwright; requires separate browser driver management; Playwright is the modern successor for the same use case.
- **Manual testing only.** Rejected: with 20 PWAs and frequent changes, manual regression testing before each deployment is impractical; automated tests catch SW version misses and hub registry gaps that are easy to forget.
- **Vitest + browser mode.** Rejected: newer tool, less mature for full PWA E2E at time of adoption; Playwright is well-established with strong async/await support.

## Consequences

**Positive:**
- Real browser execution catches SW, IDB, and DOM bugs that jsdom misses.
- `page.evaluate()` can inspect JS `state` objects directly — no need to instrument the app.
- JSON reporter (`--reporter=json`) writes structured output to `test_reports/` for CI-style review.
- `_template.spec.js` ensures new PWA tests cover the minimum baseline immediately.

**Negative / Trade-offs:**
- Tests run against the live dev URL — they require the dev stack to be running.
- Playwright tests are slower than unit tests (~8–10 min for full suite of 58 tests).
- Spec files must be updated whenever new screens or form fields are added to a PWA — easy to let them drift.

**Risks and mitigations:**
- Test hits prod URL accidentally: mitigated by hardcoding `BASE_URL = 'https://dev.srv1111289.hstgr.cloud/<pwa>/'` in every spec file; prod URL is never referenced in tests.
- Flaky tests due to network timing: mitigated by `await page.waitForSelector()` and `await expect(locator).toBeVisible()` rather than fixed `sleep()` calls.
- New PWA shipped without tests: mitigated by CLAUDE.md rule "always create spec file using _template.spec.js when building a new PWA".

## Related Decisions

- ADR-015 (dev/prod two stacks) — tests run on dev domain; passing tests = prerequisite for promoting to prod.
- ADR-016 (hub PWA registry) — hub registry check is a standard test in every spec file.
- ADR-005 (SW CACHE_VER) — CACHE_VER minimum version check is a standard test in every spec file.

## References

- `playwright.config.js` — Playwright config (browsers, base URL, timeouts)
- `tests/_template.spec.js` — base template for new PWA spec files
- `tests/tour_pg.spec.js` — reference spec (58 tests, all patterns used)
- `CLAUDE.md` — "Always fire Playwright AFTER self-test, in background"
