--- name: tdd description: > Test-driven development workflow. Enforces red/green/refactor discipline: write failing tests first, implement the minimum code to pass, then clean up. Use when the user invokes /tdd with a feature to implement (e.g., "/tdd implement the vocab export endpoint", "/tdd add useMyHook"). Never skips ahead to implementation before confirming tests fail. --- # TDD Workflow ## Overview Phases run in strict order. **Never proceed to the next phase without running tests and confirming the expected outcome.** 1. **Understand** — read existing code, tests, and project structure before writing anything 2. **Red** — write failing test(s); confirm they fail for the right reason 3. **Green** — write the minimum implementation to make tests pass 4. **Refactor** — clean up; confirm tests still pass 5. **Report** — summarize what's covered and what's missing --- ## Phase 1 — Understand Before writing any code: ### 1a — Read the feature spec The argument passed to `/tdd` is the feature to implement. Parse it to identify: - What behaviour needs to exist - What layer it lives in (API, business logic, UI component, hook, utility) - What the expected inputs and outputs are ### 1b — Discover the project structure Do not assume paths. Explore the actual codebase: - Find the test runner config: look for `pytest.ini`, `pyproject.toml` (pytest section), `vitest.config.*`, `jest.config.*` - Find existing test directories: search for directories matching `**/tests/` and `**/__tests__/`, and files matching `**/*.test.*` and `**/*.spec.*` - Find the nearest existing code in the relevant layer and read it - Find existing tests for similar features — identify patterns to follow (naming, fixture usage, assertion style) ### 1c — Identify the test layer Based on what you find, determine: | Feature type | Typical test layer | Notes | |---|---|---| | Pure function / utility | Unit test | Fastest, no I/O | | API endpoint / DB interaction | Integration test | Needs DB fixture | | React hook | Frontend unit (renderHook) | Mock network with MSW or similar | | React component | Frontend unit | Render + assert | | Full user flow | E2E | Manual or Playwright | Confirm which test runner and commands apply to this project before proceeding. ### 1d — Find reusable test utilities Before writing anything, check for: - Backend: conftest.py files with fixtures (sessions, clients, factories, users) - Frontend: test utility wrappers, MSW handlers, mock servers Note what's available — do not reinvent what already exists. --- ## Phase 2 — Red (write failing tests) **Rules:** - Write tests before any implementation - Tests must exercise behaviour that does not exist yet — this is intentional - Run tests; confirm the failure is caused by that absent behaviour, not by a broken test - If tests pass immediately, the feature already exists — stop and report that to the user Write the tests in the appropriate location following the project's existing conventions for test file placement and naming. **After writing tests — run them and confirm RED:** Show the failure output. A correct red takes either shape: - **Something that does not exist yet** — the name, the attribute, or the *signature* you are calling has nothing behind it: `ImportError`, `ModuleNotFoundError`, `Cannot find module`, `AttributeError`, a `TypeError` naming an argument the function does not accept yet, or a `NotImplementedError` raised by a stub. These are the common shapes, not a closed set: what makes a red correct is that the *behaviour* is absent, not which exception carries the news. Adding a parameter to an existing function reds as a `TypeError`, and that is a legitimate red — not a broken test to be repaired. - **New behaviour on an API that already exists** — a **failing assertion**: the call runs and returns the old answer. This is the usual red when extending existing code, and it is a valid red, not a broken test. Either one means proceed to Phase 3. If it fails for any other reason (syntax error, wrong import path, fixture or setup error), fix the test first — the test must be correct before the implementation begins. --- ## Phase 3 — Green (minimum implementation) Write the **minimum** code to make the failing tests pass: - No extra features, no future-proofing - No refactoring of adjacent code - Follow existing patterns in the same file/module (naming, error handling, async style) **After implementing — run tests and confirm GREEN:** All tests in the new file must pass. No previously passing tests may regress. Run the full test suite (or at minimum the affected layer) to confirm no regressions. If tests still fail, fix the implementation — do not modify the tests to make them pass. --- ## Phase 4 — Refactor (optional) If the implementation has obvious duplication, poor naming, or violates project conventions: - Clean it up - Run tests again to confirm they still pass - Do not add new behaviour during refactor If nothing needs cleanup, skip this phase. --- ## Phase 5 — Report After tests are green, summarize: ``` ## TDD Summary: **Tests written:** tests in **Test layer:** **Test command:** **All passing:** yes / no **What's covered:** - - **Known gaps (not covered by these tests):** - ``` --- ## Important constraints - Do not skip running tests between phases — the red→green transition is the whole point - Do not add `eslint-disable`, `# noqa`, or test-specific conditionals in production code to make tests pass - Do not modify tests to make them pass — fix the implementation instead - Use existing test utilities and fixtures — do not duplicate infrastructure that already exists - Follow the project's `CLAUDE.md` / `AGENTS.md` conventions (whichever exists) throughout