The Red-Green-Refactor Cycle
The Defining Order: Test First
TDD isn't "has tests" — it's a specific ORDER: write the test before the implementation. That ordering is what makes it test-DRIVEN, not just tested.
// RED — write the test, confirm it fails (for the right reason)
test('adds two numbers', () => {
expect(add(2, 3)).toBe(5);
});
// fails: add is not defined — good, that's the expected failure
// GREEN — minimal code to pass, nothing more
function add(a, b) { return a + b; }
// REFACTOR — now safe to clean up, the passing test is the safety net
// (nothing to refactor yet in this trivial example)Confirming RED (not just writing the test) catches a subtle bug: a test that passes even before any implementation exists is testing nothing meaningful. GREEN's "minimal code" discipline resists building ahead of what's currently tested — future tests drive future functionality, not speculation.
Refactor Needs the Safety Net
With a passing test already in place, restructuring the code (removing duplication, renaming, reorganizing) is safe — the test immediately signals if behavior actually changed, not just structure. This is the same "refactoring requires tests" principle from general refactoring practice, but built incrementally, one small piece at a time.
Fast Unit Tests, Not Slow E2E
TDD's tight cycle (many times per hour) needs near-instant feedback — this is why TDD discussions center on fast unit tests, not slower integration/end-to-end tests that don't fit the rapid cadence.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free