TDD is about design quality, not coverage metrics. The red-green-refactor cycle forces you to think about behavior before implementation, producing cleaner interfaces and more testable code. **Principle:** If you can describe the behavior as `expect(fn(input)).toBe(output)` before writing `fn`, TDD improves the result. ## When TDD Improves Quality **TDD candidates (add `tdd="true"`, include ``):** - Business logic with defined inputs/outputs - API endpoints with request/response contracts - Data transformations, parsing, formatting - Validation rules and constraints - Algorithms with testable behavior - State machines and workflows - Utility functions with clear specifications **Skip TDD (standard `type="auto"`):** - UI layout, styling, visual components - Configuration changes - Glue code connecting existing components - One-off scripts and migrations - Simple CRUD with no business logic - Exploratory prototyping **Heuristic:** Can you write `expect(fn(input)).toBe(output)` before writing `fn`? → Yes: TDD will help → No: Implement first, add tests after if needed ## Red-Green-Refactor Cycle **RED - Write failing test:** 1. Create test file following project conventions 2. Write test describing expected behavior (from `` element) 3. Run test - it MUST fail 4. If test passes: feature exists or test is wrong. Investigate. 5. Commit: `test: add failing test for [feature]` **GREEN - Implement to pass:** 1. Write minimal code to make test pass 2. No cleverness, no optimization - just make it work 3. Run test - it MUST pass 4. Commit: `feat: implement [feature]` **REFACTOR (if needed):** 1. Clean up implementation if obvious improvements exist 2. Run tests - MUST still pass 3. Only commit if changes made: `refactor: clean up [feature]` **Atomic commits:** Each TDD task produces 2-3 commits following this pattern. ## Good Tests vs Bad Tests **Test behavior, not implementation:** - Good: "returns formatted date string" - Bad: "calls formatDate helper with correct params" - Tests should survive refactors **One concept per test:** - Good: Separate tests for valid input, empty input, malformed input - Bad: Single test checking all edge cases with multiple assertions **Descriptive names:** - Good: "should reject empty email", "returns null for invalid ID" - Bad: "test1", "handles error", "works correctly" **No implementation details:** - Good: Test public API, observable behavior - Bad: Mock internals, test private methods, assert on internal state ## Test Framework Setup (If None Exists) When a TDD task exists but no test framework is configured: **1. Detect project type:** ```bash # JavaScript/TypeScript if [ -f package.json ]; then echo "node"; fi # Python if [ -f requirements.txt ] || [ -f pyproject.toml ]; then echo "python"; fi # Go if [ -f go.mod ]; then echo "go"; fi # Rust if [ -f Cargo.toml ]; then echo "rust"; fi ``` **2. Install minimal framework:** | Project | Framework | Install | |---------|-----------|---------| | Node.js | Jest | `npm install -D jest @types/jest ts-jest` | | Node.js (Vite) | Vitest | `npm install -D vitest` | | Python | pytest | `pip install pytest` | | Go | testing | Built-in | | Rust | cargo test | Built-in | **3. Create config if needed:** - Jest: `jest.config.js` with ts-jest preset - Vitest: `vitest.config.ts` with test globals - pytest: `pytest.ini` or `pyproject.toml` section **4. Verify setup:** ```bash # Run empty test suite - should pass with 0 tests npm test # Node pytest # Python go test ./... # Go cargo test # Rust ``` **5. Create first test file:** Follow project conventions for test location: - `*.test.ts` / `*.spec.ts` next to source - `__tests__/` directory - `tests/` directory at root ## Error Handling **Test doesn't fail in RED phase:** - Feature may already exist - investigate - Test may be wrong (not testing what you think) - Fix before proceeding **Test doesn't pass in GREEN phase:** - Debug implementation - Don't skip to next task - Keep iterating until green **Tests fail in REFACTOR phase:** - Undo refactor - Commit was premature - Refactor in smaller steps **Unrelated tests break:** - Stop and investigate - May indicate coupling issue - Fix before proceeding ## Commit Pattern for TDD Tasks Each TDD task produces atomic commits: ``` test: add failing test for email validation feat: implement email validation refactor: extract regex to constant (optional) ``` This pattern: - Creates clean git history - Each commit is independently revertable - Shows TDD discipline in commit log