# Tdd

> Test-driven development with red-green-refactor loop. Use when writing tests, creating new features, or fixing bugs. Includes planning phase, tracer bullets, async leak detection, deep module design, and condition-based waiting.

- Skill: `redpanda-data/tdd` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add redpanda-data/tdd`
- Raw SKILL.md: https://api.skillmd.com/api/skills/redpanda-data/tdd/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: redpanda-data (https://skillmd.com/u/redpanda-data)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/redpanda-data/tdd

---


# Test-Driven Development

## Iron Law

**No prod code without failing test first.** No exceptions.

## Anti-Pattern: Horizontal Slices

**DO NOT write all tests first, then all impl.** Bulk tests test *imagined* behavior, not *actual*.

**Correct**: Vertical slices -- one test -> one impl -> repeat.

    WRONG:  RED: test1,test2,test3  ->  GREEN: impl1,impl2,impl3
    RIGHT:  RED->GREEN: test1->impl1  ->  RED->GREEN: test2->impl2

## State Machine

Full state diagram: [REFERENCE.md#state-machine](REFERENCE.md#state-machine).

## Workflow

### 0. PLAN -- Coverage gap analysis

- Use project's domain glossary for test/interface names; respect ADRs in the area
- Run `vitest run --coverage.enabled --coverage.reporter=text`
- Find uncovered lines/branches/functions in changed files -> test targets
- Confirm behaviors w/ user (prioritize gaps over covered)
- Find [deep module](deep-modules.md) chance (small interface, deep impl)
- Design interfaces for [testability](interface-design.md); test behaviour through public interface, not impl ([tests.md](tests.md))

### 1. RED -- Failing test (tracer bullet)

- ONE test, ONE behavior, clear name
- Real code, no mocks (unless unavoidable -- see [mocking.md](mocking.md))
- Verify fails for RIGHT reason

### 2. GREEN -- Minimal code to pass

- Only enough to pass | no premature optimization
- Run test | see green

### 3. REFACTOR -- Clean up while green

- Kill duplication | fix naming | deepen modules
- Tests after every change -- stay green
- **Never refactor while RED.** Get GREEN first.
- Flag unit tests >500ms, integration >2s
- Avoid per-keystroke sim (slow, flaky) -> bulk input
- Commit when clean

### Reactive TDD with Monitor

`Monitor: vitest --watch` -- stream pass/fail as edit. Edit->fail->fix->pass->refactor->repeat.

### 4. REPEAT -- Next behavior

RED->GREEN->REFACTOR per behavior. One at a time.

### Per-Cycle Checklist

- [ ] Test describe behavior, not impl
- [ ] Test use public interface only
- [ ] Test survive internal refactor
- [ ] Code minimal for this test
- [ ] No speculative features

## Test Classification

| Suffix | Purpose | DOM? |
|--------|---------|------|
| `.test.ts` | Unit -- pure logic | No |
| `.test.tsx` / `.integration.tsx` | Integration -- render components | Yes |
| `e2e/*.spec.ts` | E2E -- Playwright browser | Browser |

## Visual Regression Tests (Route Files)

New TanStack Router routes need `*.browser.test.tsx` sibling -- only if project use vitest browser mode (existing `*.browser.test.*` files or `@vitest/browser` dep). Skip layout/redirect-only routes. See [REFERENCE.md](REFERENCE.md).

## When Done

- [ ] All pass (`vitest run`)
- [ ] **Zero warnings** -- green run w/ `DeprecationWarning` / React `act()` / unhandled rejection / `@ts-ignore` is NOT done. `test-warning-check` hook surfaces; fix at source. Escape: `// allow: test-warning` w/ reason.
- [ ] No async leaks (`vitest run --detectAsyncLeaks`) -- Stop hook run auto
- [ ] No `setTimeout` hacks -- condition-based wait
- [ ] Coverage gaps closed -- re-run coverage, verify changed files
- [ ] Selector priority: `getByRole` > `getByText` > `getByTestId` > `querySelector`
- [ ] Portal tests: `defaultOpen` for content tests | `waitFor` for close assertions
- [ ] Tests verify behavior, not impl | `expect.soft()` for multi-assertion state tests
- [ ] CI green AND `ci-warning-audit` clean -- `gh run view <id> --log | grep -E 'Warning|Deprecation'` returns nothing

See [REFERENCE.md](REFERENCE.md) for element selectors, portal testing, mock patterns, diagnostics, Vitest config.
