Testing Guide
How we test Unphish v2 — frameworks, parity matrix, UAT, and release gates.
This guide covers how we test Unphish v2 end to end. It is for QA engineers, release managers, Unphish staff doing UAT, and engineers who need to know what counts as "tested" before a change ships.
The four layers of testing
Unphish v2 is tested at four layers:
- Test types — Unit, integration, route smoke, e2e, and the local-parity smoke harness. What runs, where, and against what data.
- V1 parity matrix — The 20-epic, 102-row truth table tracking every v1 capability and its v2 disposition (retained / replaced / merged / retired).
- Staff UAT — The 1,540-case user-acceptance test corpus harvested from staff workbooks, mapped onto the parity matrix.
- Release gates — What must be green before a deployment promotes to staging or production.
Three principles before you write a test
1. Real cookies, not bypasses
P0 parity rows must be exercised through a real-browser role flow with a real session cookie. DEV_AUTH_BYPASS is for ad-hoc developer debugging, not for signoff. A test that bypasses auth does not exercise the parts of the system that fail in production: route guards, capability checks, audit, source labelling.
2. Source-state assertions are mandatory
Every P0 row must assert the data source state is correct: live, imported, demo, fixture, or unavailable. A test that "passes" because the page rendered fixture data while a customer should be seeing live data is a failed test, not a passing one. Source labelling is the contract; a test that ignores it does not protect the contract.
3. Audit assertions for sensitive flows
Sensitive workflows (impersonation, team delete, provider secret writes, whitelist uploads, scan config changes, enforcement submissions, client approvals) require an audit log assertion. The audit entry is part of the feature; a test that does not check it is incomplete.
What "tested" means in v2
A change is tested when:
- Unit tests cover its logic in isolation.
- Integration / route / e2e tests cover the user-visible behavior with real auth and real data.
- The relevant parity row(s) are green with a real-browser flow, an API assertion, a seeded-data assertion, and a source-state assertion.
- Audit assertions exist for sensitive flows.
- Dark mode and responsive QA pass for surfaces that need it (dashboard, threat feed, case detail, client review, partner queue, watchlist, whitelist, scan centre).
Anything less is partial coverage. Partial coverage is fine for in-progress work; it is not fine for promotion to production.
Where to find each thing
| What | Where |
|---|---|
| Unit tests | tests/*.test.mjs, lib/**/*.test.mjs, workers/**/*.test.mjs |
| Route smoke | pnpm smoke:routes → scripts/smoke-routes.js |
| Local parity smoke | pnpm test:local-parity-smoke → scripts/local-v1-parity-smoke.mjs |
| Playwright e2e | pnpm test:e2e → e2e/ |
| Migration tests | pnpm test:migration → scripts/audit-v1-dump.test.js |
| Worker tests | pnpm test:worker-config |
| Workbench tests | pnpm test:workbench |
| V1 parity matrix | docs/qa/v1-parity-matrix.md |
| Staff UAT review | docs/qa/staff-uat-functional-spec-gap-review-2026-05-03.md |
| Local QA runbook | docs/production-readiness-runbook.md |
| Frontend QA checklist | docs/frontend-hub-team-qa-checklist.md |