writing-meaningful-testslisted
Install: claude install-skill yuchi-chang/no-cape
# Writing Meaningful Tests
A test is meaningful when it fails for exactly one reason: the behavior it names is broken. Tests that verify mocks, implementation details, or timing luck are coverage theater.
## Behavior, not implementation
- One behavior per test; the name states it ("retries failed operations 3 times", not "test1" or "retry works").
- Assert on outcomes a caller can observe, not on internal call sequences. A refactor that preserves behavior should not break the test.
## Mock discipline
- **Never assert on the mock.** `expect(mockFn).toHaveBeenCalledTimes(3)` verifies wiring, not behavior. If the assertion targets the mock, unmock it or assert on real output.
- **Understand side effects before mocking.** If the test depends on a side effect of the mocked method (a config write, a cache fill), mock one level lower — at the genuinely slow or external operation.
- **Mock the complete structure.** A partial mock response containing only the fields you remembered passes the test and fails the integration. Mirror the real schema.
- **No test-only methods on production classes.** Cleanup helpers belong in test utilities.
- Mock setup longer than the test logic → consider an integration test with real components instead.
## No sleeps — wait for conditions
Arbitrary delays (`sleep(500)`, `setTimeout(r, 50)`) are the top source of flaky tests: they pass on a fast machine and fail in CI under load.
```typescript
// ❌ guess at timing
await new Promise(r => setTimeou