Skip to main content

Overview

The tdd-guide agent is a Test-Driven Development specialist who ensures all code is developed test-first with comprehensive coverage (80%+ required).
name
string
default:"tdd-guide"
Agent identifier
model
string
default:"sonnet"
Uses Claude Sonnet for efficient test generation
tools
array
Available tools: Read, Write, Edit, Bash, Grep

When to Use

Writing new features
Fixing bugs
Refactoring existing code
Ensuring test coverage meets 80%+ threshold
The tdd-guide agent activates PROACTIVELY when writing new features, fixing bugs, or refactoring code.

Core Responsibilities

  • Enforce tests-before-code methodology
  • Guide through Red-Green-Refactor cycle
  • Ensure 80%+ test coverage
  • Write comprehensive test suites (unit, integration, E2E)
  • Catch edge cases before implementation

TDD Workflow

The agent follows the classic Red-Green-Refactor cycle:

1. Write Test First (RED)

Write a failing test that describes the expected behavior.
// Write the test BEFORE implementation
test('calculateTotal should sum item prices', () => {
  const items = [{ price: 10 }, { price: 20 }];
  expect(calculateTotal(items)).toBe(30);
});

2. Run Test — Verify it FAILS

npm test
# Test should FAIL because calculateTotal doesn't exist yet
If the test passes immediately, you haven’t written a proper test!

3. Write Minimal Implementation (GREEN)

Only enough code to make the test pass.
function calculateTotal(items: Array<{ price: number }>): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

4. Run Test — Verify it PASSES

npm test
# Test should now PASS

5. Refactor (IMPROVE)

Remove duplication, improve names, optimize — tests must stay green.

6. Verify Coverage

npm run test:coverage
# Required: 80%+ branches, functions, lines, statements
Coverage must be at least 80% for all metrics

Test Types Required

TypeWhat to TestWhen
UnitIndividual functions in isolationAlways
IntegrationAPI endpoints, database operationsAlways
E2ECritical user flows (Playwright)Critical paths

Unit Tests

Test individual functions without external dependencies:
import { describe, it, expect } from 'vitest';
import { formatCurrency } from './utils';

describe('formatCurrency', () => {
  it('formats USD correctly', () => {
    expect(formatCurrency(1234.56, 'USD')).toBe('$1,234.56');
  });

  it('handles zero', () => {
    expect(formatCurrency(0, 'USD')).toBe('$0.00');
  });

  it('handles negative amounts', () => {
    expect(formatCurrency(-50, 'USD')).toBe('-$50.00');
  });
});

Integration Tests

Test API endpoints and database operations:
import { describe, it, expect, beforeEach } from 'vitest';
import { createUser, getUser } from './api/users';

describe('User API', () => {
  beforeEach(async () => {
    // Clear database before each test
    await db.users.deleteAll();
  });

  it('creates and retrieves user', async () => {
    const user = await createUser({ email: '[email protected]' });
    const retrieved = await getUser(user.id);
    expect(retrieved.email).toBe('[email protected]');
  });
});

E2E Tests

Test critical user journeys:
import { test, expect } from '@playwright/test';

test('user can sign up and log in', async ({ page }) => {
  await page.goto('/signup');
  await page.fill('[data-testid="email"]', '[email protected]');
  await page.fill('[data-testid="password"]', 'secure123');
  await page.click('[data-testid="submit"]');
  
  await expect(page).toHaveURL('/dashboard');
  await expect(page.locator('[data-testid="welcome"]')).toBeVisible();
});

Edge Cases You MUST Test

Never skip edge case testing!
  1. Null/Undefined input
  2. Empty arrays/strings
  3. Invalid types passed
  4. Boundary values (min/max)
  5. Error paths (network failures, DB errors)
  6. Race conditions (concurrent operations)
  7. Large data (performance with 10k+ items)
  8. Special characters (Unicode, emojis, SQL chars)
describe('validateEmail edge cases', () => {
  it('rejects null', () => {
    expect(validateEmail(null)).toBe(false);
  });

  it('rejects empty string', () => {
    expect(validateEmail('')).toBe(false);
  });

  it('rejects invalid format', () => {
    expect(validateEmail('notanemail')).toBe(false);
  });

  it('handles unicode characters', () => {
    expect(validateEmail('user@例え.jp')).toBe(true);
  });
});

Test Anti-Patterns to Avoid

Common mistakes that reduce test value:
Anti-PatternProblemSolution
Testing implementation detailsTests break on refactorTest behavior, not internals
Tests depending on each otherShared state causes failuresIndependent tests
Asserting too littlePassing tests that don’t verify anythingSpecific assertions
Not mocking external dependenciesFlaky tests, slow testsMock Supabase, Redis, OpenAI, etc.
Using real timersNon-deterministic testsUse vi.useFakeTimers()

Bad: Testing Implementation Details

// BAD: Testing internal state
test('counter increments internal value', () => {
  const counter = new Counter();
  counter.increment();
  expect(counter._value).toBe(1); // Testing private property
});

Good: Testing Behavior

// GOOD: Testing observable behavior
test('counter increments', () => {
  const counter = new Counter();
  counter.increment();
  expect(counter.getValue()).toBe(1); // Testing public API
});

Mocking External Dependencies

Always mock external services to keep tests fast and deterministic:
import { vi } from 'vitest';
import { supabase } from './lib/supabase';

// Mock Supabase
vi.mock('./lib/supabase', () => ({
  supabase: {
    from: vi.fn(() => ({
      select: vi.fn().mockResolvedValue({
        data: [{ id: 1, name: 'Test' }],
        error: null,
      }),
    })),
  },
}));

Quality Checklist

  • All public functions have unit tests
  • All API endpoints have integration tests
  • Critical user flows have E2E tests
  • Coverage is 80%+ (branches, functions, lines, statements)
  • Null/undefined inputs tested
  • Empty arrays/strings tested
  • Invalid type inputs tested
  • Boundary values tested
  • Error paths tested (not just happy path)
  • External dependencies mocked
  • Tests are independent (no shared state)
  • Assertions are specific and meaningful
  • Test names clearly describe behavior
  • Tests run fast (<100ms per unit test)

Running Tests

# Run all tests
npm test

# Run tests in watch mode
npm test -- --watch

# Run with coverage report
npm run test:coverage

# Run specific test file
npm test -- src/utils.test.ts

# Run tests matching pattern
npm test -- --grep="calculateTotal"

Usage Example

# Invoke tdd-guide directly
ask tdd-guide "Write tests for user authentication flow"

# Or let it activate automatically
ask "Implement password reset functionality"
# → tdd-guide activates and writes tests FIRST

Success Criteria

Tests written before implementation
All tests pass
Coverage meets 80%+ threshold
Edge cases covered
External dependencies mocked
Tests are independent and fast
For detailed mocking patterns and framework-specific examples, use the tdd-workflow skill.