| name | essential-test-design |
| description | Write tests that verify observable behavior (contract), not implementation details. Auto-invoked when writing or reviewing tests. |
Problem
Tests that are tightly coupled to implementation details cause two failures:
- False positives — Tests pass even when behavior is broken (e.g., delay shortened but test still passes because it only checks
setTimeout was called)
- False negatives — Tests fail even when behavior is correct (e.g., implementation switches from
setTimeout to a delay() utility, spy breaks)
Both undermine the purpose of testing: detecting regressions in behavior.
Principle: Test the Contract, Not the Mechanism
A test is "essential" when it:
- Fails if the behavior degrades (catches real bugs)
- Passes if the behavior is preserved (survives refactoring)
- Does not depend on how the behavior is implemented (implementation-agnostic)
Ask: "What does the caller of this function experience?" — test that.
Anti-Patterns and Corrections
Anti-Pattern 1: Implementation Spy
const spy = vi.spyOn(global, 'setTimeout');
await exponentialBackoff(1);
expect(spy).(expect.(), );