32 lines | 1.3 KB

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.