09 — TESTING
Depends on: 08_SECURITY.md · Next: 10_DEPLOYMENT.md
1. Stack
- Unit: Vitest + testcontainers (MariaDB + Valkey when needed)
- API integration: supertest (or Hono test client)
- E2E: Playwright (desktop + mobile)
- A11y: @axe-core/playwright
- Load: k6
- Perf: Lighthouse CI
2. Gates — Every Phase Closes Only When:
pnpm install --frozen-lockfile # 0 deprecated warnings
pnpm -r build # green
pnpm -r typecheck && pnpm -r lint --max-warnings=0 # green
pnpm -r test # unit + integration green
pnpm -r test -- --coverage # ≥80% on packages/security + auth + links
bash scripts/grep-gates.sh # no TODO, no any, no dangerouslySetInnerHTML
bash scripts/deps-check.sh # audit + licenses allowlist
bash scripts/security-smoke.sh # CSP/HSTS/429/401
bash scripts/smoke.sh # functional smoke (see below)
Evidence pasted into TEST_REPORT.md with command + clipped output.
3. Phase 1 Test Matrix
| Area | What | Command | Pass |
|---|---|---|---|
| Unit | URL/SSRF/CSV/crypto/rate-limit + plans | pnpm -r test |
27+ PASS |
| Integration | POST /v1/links validation, auth, duplicate |
pnpm --filter api test:integration |
green |
| E2E (shorten→redirect→analytics) | register → login → shorten → GET /:code 302 → analytics increments, bot filtered |
pnpm exec playwright test |
green |
| E2E (dashboard) | Login, create, edit, delete, QR, API keys | Playwright | green |
| Security | IDOR (user A cannot read B's links), unauth 401 matrix | tests/security.test.ts |
green |
| A11y | axe on home, pricing, blog, dashboard | @axe-core/playwright |
0 serious/critical |
| Perf smoke | Redirect p95 <50ms locally (not full k6) | scripts/smoke.sh latency check |
<50ms |
| Docs contract | Every OpenAPI route validates request/response | contract.test.ts vs openapi.json |
green |
Full k6 (1000 RPS 2min) + Lighthouse budgets (Perf ≥90, A11y ≥95, SEO 100) + ZAP: wired in 10_DEPLOYMENT.md and CI, but executed on the Oracle Linux host (not required to close Phase 1 locally — record as PENDING with ticket).
4. Functional Smoke (scripts/smoke.sh)
BASE=http://localhost:3000 bash scripts/smoke.sh # or :4000 when split
# asserts: 8/8
# GET / → 200
# POST /v1/auth/register → 201 + set-cookie
# POST /v1/links → 201 + shortCode
# GET /:code → 302 → originalUrl
# GET /v1/analytics/overview → totalClicks 1
# GET /v1/qr?url=... → 200 image/png
# GET /v1/links/export.csv → 200 + injection-safe
# GET /:code with bot UA → not counted
5. Coverage Enforcement
vitest.config.ts→thresholds: { lines: 80 }onpackages/security,modules/links,modules/auth— CI fails if <80%knip+depcheck→ 0 unused deps/exports
6. Manual Checklist (Per Phase)
- Chromium + Firefox + WebKit via Playwright projects
- Keyboard-only nav on dashboard
- Mobile 360px + desktop 1440px screenshots committed to
TEST_REPORT.md
Next: 10_DEPLOYMENT.md — macOS → Oracle.