Skip to content
Development
Skill

/tdd

Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.

From plugin
gaia-react-gaia
2320 skills10 agents14 commands
Install
$ npx -y skills add gaia-react/gaia --skill tdd --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/tdd

Context preview

The summary Claude sees to decide when to auto-load this skill.

Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.

SKILL.md

tdd.SKILL.md
name: tdd
description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.

Test-Driven Development

Selecting a Stack Reference

Before writing the first red test, consult the reference for your stack:

  • **React / Vitest / MSW / Storybook** → [references/tests-react.md](references/tests-react.md)

Add a new `references/tests-{stack}.md` when adopting a new stack. The stack reference covers concrete patterns, test layers, mocking rules, and good/bad examples specific to that environment.

Philosophy

**Core principle**: tests verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.

**Good tests** are integration-style, they exercise real code paths through public APIs and describe _what_ the system does, not _how_. A good test reads like a specification: "user submits a valid form and sees a success toast" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.

**Bad tests** are coupled to implementation. They mock internal collaborators, spy on state setters, or assert on internal call signatures. The warning sign: your test breaks when you refactor, but behavior hasn't changed.

Anti-Pattern: Horizontal Slices

**DO NOT write all tests first, then all implementation.** This is "horizontal slicing", treating RED as "write all tests" and GREEN as "write all code."

Tests written in bulk test _imagined_ behavior, not _actual_ behavior. You outrun your headlights, committing to structure before understanding the implementation, producing tests insensitive to real changes.

**Correct approach**: vertical slices via tracer bullets. One test → one implementation → repeat.

WRONG (horizontal):
  RED:   test1, test2, test3, test4, test5
  GREEN: impl1, impl2, impl3, impl4, impl5

RIGHT (vertical):
  RED→GREEN: test1→impl1
  RED→GREEN: test2→impl2
  RED→GREEN: test3→impl3
  ...

Workflow

1. Planning

Before writing any code:

  • [ ] Confirm which layer owns this test (see stack reference for layer breakdown)
  • [ ] Confirm which behaviors to test (prioritize)
  • [ ] Identify opportunities for [deep modules](deep-modules.md), small interface, deep implementation
  • [ ] Design interfaces for [testability](interface-design.md)
  • [ ] List the behaviors to test (not implementation steps)
  • [ ] Get user approval on the plan

Ask: "What should the public interface look like? Which behaviors are most important to test?"

**You can't test everything.** Focus on critical paths and complex logic, not every edge case.

2. Tracer Bullet

Write ONE test that confirms ONE thing end-to-end for this layer. `RED → GREEN`. The tracer bullet confirms the testing infrastructure wires up before adding real coverage.

3. Incremental Loop

For each remaining behavior: `RED → GREEN`. One test at a time. Only enough code to pass the current test. Don't anticipate future tests.

**Bound the green chase.** If a test won't pass after a few focused attempts, stop and reassess instead of thrashing the implementation: the test, the interface, or an assumption may be wrong. Surface the blocker rather than looping indefinitely to force green.

Authoring an honest RED on the deterministic surface

The deterministic surface (pure utils, service parsers, spec-derivable hooks) is RED-gated: a new test there commits only after a genuine failing-first run is observed at its current body.

**Author the test against the not-yet-written or stub implementation symbol.** Write the test for the behavior you are about to build, pointing at a symbol that does not exist yet (or exists only as a stub that returns the wrong value). Run it; it fails because the implementation is missing or incomplete. That failure is the honest RED: a real missing-implementation failure, not a manufactured one. Then write the implementation that turns it green.

RIGHT:  test names parseAmount() → run → fails (parseAmount undefined / stub) → implement → green
WRONG:  implement parseAmount() → write the test → break parseAmount() to force red → restore it → green

**Never break working production code to force a red, then restore it.** That pattern relocates the theater into the implementation file: it is mechanically identical to the green-only theater the RED gate condemns. The content signal covers the test's comment-free content, so rewording a comment leaves a captured RED intact, while editing what the test itself executes invalidates it. The signal never covers the implementation, so this is a pattern the gate cannot catch: it is an authoring obligation, not an enforced one. The honest path is always to author the test against the absent or stub symbol, so the red comes for free from the missing implementation.

**Single-pass-author exemption.** When the implementation already exists in the same change with no prior failing observation (a single-pass author landing impl and test together), do NOT manufacture a red by breaking and restoring the impl. Author the test honestly against the existing behavior and route it to the worthiness audit, exactly as an emergent test is routed. A test that lands alongside its implementation with no prior failing observation is detectable, and a missed RED on it is caught late by the advisory audit, never by forcing theater up front.

4. Refactor

After all tests pass, look for [refactor candidates](refactoring.md):

  • [ ] Extract duplication
  • [ ] Deepen modules (move complexity behind simple interfaces)
  • [ ] Apply SOLID principles where natural
  • [ ] Consider what new code reveals about existing code
  • [ ] Run tests after each refactor step

**Never refactor while RED.** Get to GREEN first.

5. Determinism Roll-up

After green, classify every touched source file and report the verdict. C

Read more
Ships withgaia-react-gaia

Claude is raw power. GAIA is order and focus. The foundation that keeps Claude-shipped code production-grade as your team scales. The React frontend is handled. You build the rest of your app on top. Every convention enforced in code.

Get the whole plugin

Other skills on gaia-react-gaia.