Testing Strategy Guide
Philosophy
Risk-Based Testing: Priority = Business Impact (1–5) × Probability of failure (1–5).
| Priority |
Decision |
Example |
| ≥ 15 |
MUST test |
RBAC logic, job state machine, audit logger |
| 9–14 |
SHOULD test |
Translation pipeline, TTS routing |
| ≤ 8 |
SKIP (manual sufficient) |
Email template rendering, UI cosmetics |
Write tests for business logic, not for framework behaviour. Never test that FastAPI routes a request — test that YOUR business logic in the handler produces the correct outcome.
Current Coverage (as of 2026-04-29 audit)
| Layer |
Files |
Files with tests |
Risk-weighted coverage |
| Backend |
118 |
8 (7%) |
~3% |
| Frontend |
98 |
~12 (12%) |
— |
| E2E |
— |
3 spec files |
Effectively 0 (most tests skipped) |
Critical gap: All Celery tasks (10 files) and 19 service files have zero test coverage. See full audit at /tmp/audit/test-audit.md.
Test Pyramid
| Level |
Framework |
Location |
Current count |
| Unit (backend) |
pytest + AsyncMock |
backend/tests/unit/ |
8 files, ~338 assertions |
| Unit (frontend) |
Vitest + RTL |
frontend/src/**/__tests__/ |
9 files, ~218 assertions |
| Integration (backend) |
pytest + FastAPI TestClient |
backend/tests/integration/ |
Does not exist yet |
| E2E |
Playwright |
frontend/tests/e2e/ |
3 files, mostly skipped |
Test Commands
| Command |
What it runs |
cd backend && poetry run pytest |
All backend unit tests |
cd backend && poetry run pytest -v tests/unit/test_security.py |
Single test file |
cd frontend && npm run test |
All frontend unit tests (Vitest) |
cd frontend && npm run test:e2e |
Playwright E2E tests |
cd frontend && npm run test:coverage |
Unit tests with coverage report |
docker compose exec backend python -m pytest |
Tests inside Docker (for integration tests) |
What Exists and Is High-Value
| Test file |
Value |
What it tests |
backend/tests/unit/test_security.py |
HIGH |
JWT encode/decode, expiry, type fields, password hashing |
backend/tests/unit/test_vtt.py |
HIGH |
VTT parsing (26 tests) |
backend/tests/unit/test_vtt_retimer.py |
HIGH |
VTT timing logic (27 tests) |
frontend/src/lib/__tests__/auth.test.ts |
HIGH |
JWT in-memory store, refresh flow |
frontend/src/components/Auth/__tests__/RequireAuth.test.tsx |
HIGH |
Auth guard redirect |
Priority Gaps to Fill
The following are MUST-fill based on Priority ≥15:
| Priority |
Module |
Gap |
| 25 |
tasks/ingest_and_ai.py |
Job state machine — zero tests |
| 20 |
core/authz.py |
RBAC permission checks — zero tests |
| 20 |
services/audit_logger.py |
Audit trail correctness — zero tests |
| 20 |
services/glossary_service.py |
Hybrid retrieval — zero tests |
| 16 |
services/language_qc.py |
QC state transitions — zero tests |
| 16 |
tasks/translate_and_synthesize.py |
Translation pipeline — zero tests |
Full test plan at /tmp/audit/test-plan.md.
Anti-Patterns to Avoid
| Anti-pattern |
Why |
Fix |
Hardcoded job IDs like test-job-123 |
Non-existent in test DB |
Use factories to create real test data |
with patch(...) as mock: in every test method |
Setup duplication |
Move to @pytest.fixture(autouse=True) |
MagicMock() on async functions |
Silently returns a mock, not a coroutine |
Use AsyncMock() |
| Testing that a library function was called |
Tests library, not our logic |
Test the business outcome |
E2E tests that are .skip |
They provide no coverage |
Implement auth fixture and un-skip |
Infrastructure Required Before Writing Integration/E2E Tests
| Blocker |
What's needed |
Backend conftest.py |
Shared MockSettings, mock_db, test_user_factory, test_job_factory |
| Celery test mode |
task_always_eager=True fixture for synchronous task execution |
| Playwright auth fixture |
Wire tests/helpers/auth.ts into beforeEach in all spec files |
| Playwright seed fixture |
tests/fixtures/seed.ts to create test jobs, glossary, linguists |
| Mock AI responses |
tests/mocks/gemini-responses/*.json fixtures |
Maintenance
Update triggers: New test file added, coverage target changes, new testing tool added.
Verification: All commands in the Commands table execute without error. Priority gap table matches the current test-audit report.