# Test-first — Claude Code rules ## Philosophy - Write the test before the change when fixing a regression. Reproduce the bug, watch it fail, then make it pass. - For new features, write the smallest end-to-end test that demonstrates the feature works. Iterate inward from there. ## Layering - **Unit** tests cover pure functions / single classes. No I/O, no clock, no network. Fast (<10ms). - **Integration** tests cover the seam between code we own and code we don't (DB, queue, HTTP). - **End-to-end** tests cover real user flows. Few of them, but they run against the real stack. ## Test names - Describe behaviour, not implementation. `it("rejects expired tokens")` ✅ not `it("calls verifyJwt")` ❌. - One assertion per behaviour. Multiple assertions are OK only when they describe the **same** behaviour. ## What not to mock - Don't mock code we own. If a function is hard to test without mocking, restructure it. - Don't mock the database for integration tests — use a real test database (docker compose, transactional rollback per test). ## Snapshots - Snapshots are for stable, semantic outputs (rendered components, SQL). Don't snapshot deep JSON with timestamps / IDs. - Review snapshot diffs in PR — never blindly accept. ## Coverage - Coverage is a smell detector, not a goal. 100% coverage with bad assertions ships bugs.