Explicit project requirement: lots of tests. Testing is not optional and not left "for later": it is part of the definition of done.
╱╲
╱E2E╲ Few. Critical end-to-end flows (Playwright).
╱──────╲
╱ Integr. ╲ Some. Service + its real dependencies (DB, MinIO).
╱────────────╲
╱ Unit ╲ Many. Pure domain logic, fast.
╱──────────────────╲
Lower = more of them, faster, cheaper. We invest in the base first.
| Type | What it tests | Tool | Where it lives |
|---|---|---|---|
| Unit | Domain logic, no frameworks or network | Vitest (TS) · pytest (Py) | each service's src/ |
| Integration | Service with real DB/MinIO/NATS (Testcontainers) | Vitest/pytest + Testcontainers | tests/integration/ per service |
| Contract | APIs honor their OpenAPI; client and server agree | Schemathesis / contract tests | per service |
| E2E | Full flows in a browser | Playwright | tests/e2e/ |
| Load | Performance under stress | k6 | tests/load/ |
| Security | Authorization, isolation, hashing | Vitest/pytest + dedicated cases | per service + tests/ |
These are non-negotiable and block the merge:
- Cross-tenant isolation: a user from organization A cannot read, list, or modify organization B's resources (tested directly via API, not through the UI).
- Resource authorization: a
viewercannot edit; someone without permission cannot access. - No plaintext passwords: the DB hash is Argon2id; logs contain no credentials.
org_idis never trusted from the client: forcing anotherorg_idin the body/headers is rejected.
| Layer | Minimum coverage |
|---|---|
Domain (domain/, application/) |
90% — it's the critical logic |
| Full services | 80% |
| Authorization/security cases | 100% of the defined paths |
Coverage is a signal, not the goal. 80% with meaningful tests > 95% with trivial ones.
- Testcontainers for real Postgres/MinIO/NATS in CI → faithful integration, no brittle infra mocks.
- Factories (not giant fixtures) to generate test entities.
- Reproducible seeds per tenant for E2E.
PR opened
└─ Turborepo detects what changed
└─ runs ONLY the affected tests (fast)
└─ lint + typecheck
└─ security/isolation tests (always)
merge to main
└─ full suite (unit + integration + E2E)
release (tag)
└─ + load tests against staging
A feature is done when:
- It has unit tests for its domain logic.
- It has integration tests if it touches DB/storage/events.
- If it affects data access: it has a cross-tenant isolation test.
- It passes lint, typecheck, and security scans.
- It updates the service doc if the contract changed.
- It exposes metrics/health if it's a new service.
- F0: the testing harness exists before the first feature. Testcontainers configured. The cross-tenant isolation test is written alongside Atlas.
- F1+: each app is born with its suite. E2E covers each app's main happy path.
- F6: serious load testing, external pentest, DR tests (restoring backups).