# Tdd Workflow

> Complete Test-Driven Development workflow with red-green-refactor cycle Use when this capability is needed.

- Skill: `tomevault-io/tdd-workflow-18` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/tdd-workflow-18`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/tdd-workflow-18/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/tdd-workflow-18

---


# TDD Workflow Skill

Use this skill when implementing features using Test-Driven Development methodology.

## When to Use

- Implementing new features or functions
- Adding new API endpoints
- Creating utility functions
- Building components with complex logic
- When high test coverage is required

## TDD Cycle

```
┌──────────────────────────────────────────────────────────┐
│                                                          │
│   🔴 RED      →    🟢 GREEN    →    🔵 REFACTOR         │
│   Write test       Make pass        Improve code         │
│   that fails       (minimal)        (keep green)         │
│                                                          │
│                    ↺ Repeat                              │
└──────────────────────────────────────────────────────────┘
```

## Step-by-Step Process

### Phase 1: RED - Write Failing Test

1. **Understand the requirement**
   - What is the input?
   - What is the expected output?
   - What are the edge cases?

2. **Write the simplest test case first**
   ```typescript
   describe('calculateDiscount', () => {
     it('should return 0 for orders under $50', () => {
       expect(calculateDiscount(30)).toBe(0);
     });
   });
   ```

3. **Run the test - it MUST fail**
   ```bash
   npm test -- calculateDiscount
   ```

### Phase 2: GREEN - Make It Pass

1. **Write the minimal code to pass**
   ```typescript
   function calculateDiscount(orderTotal: number): number {
     return 0;
   }
   ```

2. **Run the test - it MUST pass**
   ```bash
   npm test -- calculateDiscount
   ```

3. **Don't over-engineer** - Only write enough code to pass the current test

### Phase 3: REFACTOR - Improve the Code

1. **Only refactor when tests are green**
2. **Keep tests passing throughout**
3. **Improve code quality:**
   - Extract constants
   - Rename for clarity
   - Remove duplication
   - Simplify logic

### Phase 4: Repeat

Add the next test case and repeat the cycle:

```typescript
it('should return 10% for orders $50-$100', () => {
  expect(calculateDiscount(75)).toBe(7.5);
});
```

## Test Structure

### Arrange-Act-Assert Pattern

```typescript
it('should apply discount to premium users', () => {
  // Arrange
  const user = createUser({ isPremium: true });
  const order = createOrder({ total: 100 });

  // Act
  const result = applyDiscount(user, order);

  // Assert
  expect(result.total).toBe(90);
  expect(result.discountApplied).toBe(10);
});
```

### Test Naming Convention

```typescript
// Format: should_[expected behavior]_when_[condition]
it('should return empty array when no items match filter', () => {});
it('should throw ValidationError when email is invalid', () => {});
it('should retry 3 times when API returns 503', () => {});
```

## Complete Example

### Requirement
Create a password validator that checks:
- Minimum 8 characters
- At least one uppercase letter
- At least one number

### TDD Implementation

```typescript
// Step 1: RED - First test
describe('validatePassword', () => {
  it('should reject passwords shorter than 8 characters', () => {
    expect(validatePassword('Short1')).toEqual({
      valid: false,
      errors: ['Password must be at least 8 characters'],
    });
  });
});

// Step 2: GREEN - Minimal implementation
function validatePassword(password: string) {
  const errors: string[] = [];
  
  if (password.length < 8) {
    errors.push('Password must be at least 8 characters');
  }
  
  return { valid: errors.length === 0, errors };
}

// Step 3: RED - Next test
it('should reject passwords without uppercase', () => {
  expect(validatePassword('lowercase1')).toEqual({
    valid: false,
    errors: ['Password must contain an uppercase letter'],
  });
});

// Step 4: GREEN - Add uppercase check
function validatePassword(password: string) {
  const errors: string[] = [];
  
  if (password.length < 8) {
    errors.push('Password must be at least 8 characters');
  }
  if (!/[A-Z]/.test(password)) {
    errors.push('Password must contain an uppercase letter');
  }
  
  return { valid: errors.length === 0, errors };
}

// Step 5: RED - Test for number requirement
it('should reject passwords without numbers', () => {
  expect(validatePassword('NoNumbers')).toEqual({
    valid: false,
    errors: ['Password must contain a number'],
  });
});

// Step 6: GREEN - Add number check
function validatePassword(password: string) {
  const errors: string[] = [];
  
  if (password.length < 8) {
    errors.push('Password must be at least 8 characters');
  }
  if (!/[A-Z]/.test(password)) {
    errors.push('Password must contain an uppercase letter');
  }
  if (!/[0-9]/.test(password)) {
    errors.push('Password must contain a number');
  }
  
  return { valid: errors.length === 0, errors };
}

// Step 7: REFACTOR - Clean up
const PASSWORD_RULES = [
  { test: (p: string) => p.length >= 8, message: 'Password must be at least 8 characters' },
  { test: (p: string) => /[A-Z]/.test(p), message: 'Password must contain an uppercase letter' },
  { test: (p: string) => /[0-9]/.test(p), message: 'Password must contain a number' },
];

function validatePassword(password: string) {
  const errors = PASSWORD_RULES
    .filter(rule => !rule.test(password))
    .map(rule => rule.message);
  
  return { valid: errors.length === 0, errors };
}

// Step 8: RED - Happy path test
it('should accept valid passwords', () => {
  expect(validatePassword('ValidPass1')).toEqual({
    valid: true,
    errors: [],
  });
});
// Already passes! ✅
```

## Best Practices

### Do
- Write one test at a time
- Run tests after every change
- Test behavior, not implementation
- Keep tests independent
- Use descriptive test names

### Don't
- Write tests after code
- Skip the RED phase
- Write multiple tests before implementing
- Test private methods directly
- Couple tests to implementation details

## Commands

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

# Run specific test file
npm test -- validatePassword

# Run with coverage
npm test -- --coverage

# Run and update snapshots
npm test -- --updateSnapshot
```

## When TDD Might Not Fit

- Exploratory/prototype code
- UI layout (visual testing better)
- Third-party integration spikes
- Performance optimization (profile first)

In these cases, write tests after, but still write them.

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/speedoa1) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-12 -->

