diff --git a/testing/README.md b/testing/README.md new file mode 100644 index 0000000..04be637 --- /dev/null +++ b/testing/README.md @@ -0,0 +1,40 @@ +# Test harness (handbook §10.3 two-tier testing) + +One environment-agnostic suite, two targets. + +## Tier 1 — local Docker (every PR) + +```sh +make tier1-up # build + start: gitea(seeded) + backend + web(nginx) + mailpit +make e2e # run Playwright against http://localhost:8080 +make fe-unit # run Vitest frontend unit tests +make tier1-down # stop + wipe volumes +``` + +- App (SPA + API): http://localhost:8080 +- Mailpit UI / API: http://localhost:8025 +- Gitea (disposable): http://localhost:3001 + +The stack is hermetic and disposable — fresh SQLite + fresh seeded Gitea each +`tier1-up`. e2e signs in via the email OTC flow, reading the code back from +Mailpit, so no real OAuth provider is needed. + +**CI note:** the backend enforces a per-IP OTC request limiter (5 requests / +300s, `backend/app/ratelimit.py`). A single `make e2e` run uses exactly one OTC +request, so the normal "fresh `tier1-up` then one `e2e`" flow is well clear of +it. Do not retry `make e2e` more than ~4 times in a 5-minute window against the +same running stack, or the 6th OTC request will 429. Restarting the backend +container (or `tier1-down`/`tier1-up`) resets the in-process limiter. + +## Tier 2 — PPE (deploy gate) + +The SAME suite, pointed at the PPE instance (once `rfc-app-ppe.` is stood +up via flotilla — see the engineering handbook §10.1/§10.3): + +```sh +cd e2e && BASE_URL=https://rfc-app-ppe. MAILSINK_URL= npm run e2e +``` + +PPE provides the real nginx/systemd/SQLite topology + its own isolated Gitea + +always-pass Turnstile keys. Standing up the PPE VM is an operator task, not part +of this repo.