Skip to main content
ClaudeWave
Skill171 repo starsupdated 1mo ago

Testing Strategy

Apply TDD with RED-GREEN-REFACTOR cycles, separate unit tests from integration tests, ensure comprehensive coverage. Apply when writing tests, evaluating test coverage, testing databases, or testing admin flows.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/ThamJiaHe/claude-code-handbook /tmp/testing-strategy && cp -r /tmp/testing-strategy/skills/examples/testing- ~/.claude/skills/testing-strategy
Then start a new Claude Code session; the skill loads automatically.

testing-skill.md

# Testing Strategy

Systematic TDD workflow ensuring comprehensive test coverage following RED-GREEN-REFACTOR cycles.

## Overview

This Skill enforces:
- RED-GREEN-REFACTOR cycles (TDD)
- Atomic test coverage
- Separation of logic from database tests (T-3)
- E2E testing for critical admin flows (T-7)
- Edge case coverage (T-8)

Apply when writing tests, designing test suites, or evaluating coverage.

## RED-GREEN-REFACTOR Workflow

**Every feature follows this cycle**:

### RED Phase: Write Failing Test

Write test BEFORE implementation:

```ts
import { describe, test, expect } from 'vitest';
import { validateEmail } from './email';

describe('validateEmail', () => {
  test('returns true for valid email', () => {
    expect(validateEmail('user@example.com')).toBe(true);
  });

  test('returns false for missing @', () => {
    expect(validateEmail('userexample.com')).toBe(false);
  });

  test('returns false for empty string', () => {
    expect(validateEmail('')).toBe(false);
  });
});
```

Run: `pnpm test validateEmail` → **FAILS** (RED)

### GREEN Phase: Make Test Pass

Write minimal code to pass:

```ts
export function validateEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
```

Run: `pnpm test validateEmail` → **PASSES** (GREEN)

### REFACTOR Phase: Improve Code

Improve without changing behavior:

```ts
// Extract pattern for readability
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

export function validateEmail(email: string): boolean {
  return EMAIL_PATTERN.test(email);
}
```

Run: `pnpm test validateEmail` → **STILL PASSES** (verify before claiming done)

## Test Organization

### T-1 (MUST): Colocate Tests with Source

```
src/utils/validators.ts
src/utils/validators.spec.ts      ← Same directory
```

### T-3 (MUST): Separate Logic from Database Tests

**Unit Tests** (pure logic, no database):

```ts
// src/utils/helpers.spec.ts
describe('calculateTotal', () => {
  test('sums array correctly', () => {
    const result = calculateTotal([10, 20, 30]);
    expect(result).toBe(60);
  });

  test('handles empty array', () => {
    expect(calculateTotal([])).toBe(0);
  });
});
```

**Integration Tests** (with database):

```ts
// server/tests/user-api.test.ts
describe('User API', () => {
  beforeEach(async () => {
    await db.clear('users');
  });

  test('creates user in database', async () => {
    const user = await createUser({
      email: 'test@example.com',
      name: 'Test User'
    });

    const retrieved = await db.users.findById(user.id);
    expect(retrieved).toEqual(user);
  });
});
```

### Anti-Pattern: Mixed Tests

```ts
// ❌ BAD: Mixes logic and database
describe('calculateTotal', () => {
  test('calculates and saves', async () => {
    const result = calculateTotal([10, 20, 30]);
    await db.totals.save(result);  // Don't mix!
    expect(result).toBe(60);
  });
});
```

## Test Coverage Requirements

**By Feature Type**:

- **Utilities** (formatting, validation): 80%+ coverage
- **Business Logic** (algorithms, rules): 90%+ coverage
- **Admin Flows** (user management): 100% coverage (T-7)
- **Public APIs** (REST endpoints): 90%+ coverage

Check coverage:

```bash
pnpm test --coverage
```

## Unit Test Patterns

### Pattern 1: Simple Function

```ts
// ✅ GOOD: Complete test
test('returns true for valid email format', () => {
  expect(validateEmail('user@example.com')).toBe(true);
});

// ❌ BAD: Unclear what's being tested
test('validates email', () => {
  expect(validateEmail('user@example.com')).toBe(true);
});
```

### Pattern 2: Edge Cases (T-8)

```ts
// ✅ GOOD: Covers boundaries
describe('calculateDiscount', () => {
  test('returns 0% for purchases under $100', () => {
    expect(calculateDiscount(99.99)).toBe(0);
  });

  test('returns 10% for purchases >= $100', () => {
    expect(calculateDiscount(100)).toBe(10);
    expect(calculateDiscount(100.01)).toBe(10.001);
  });

  test('handles edge cases', () => {
    expect(calculateDiscount(0)).toBe(0);      // Zero
    expect(calculateDiscount(-50)).toBe(0);    // Negative
    expect(calculateDiscount(999999)).toBe(99999.9);  // Large
  });
});
```

### Pattern 3: Parameterized Tests

```ts
// ✅ GOOD: No magic literals
test.each([
  ['user@example.com', true],
  ['invalid.email', false],
  ['', false],
  ['user@domain.co.uk', true]
])('validateEmail("%s") returns %p', (email, expected) => {
  expect(validateEmail(email)).toBe(expected);
});
```

### Pattern 4: Entire Structure Assertion

**T-1 (MUST)**: Compare entire result, not individual fields:

```ts
// ✅ GOOD: Complete structure
const result = createUser({ name: 'Alice', email: 'alice@example.com' });
expect(result).toEqual({
  id: expect.any(String),
  name: 'Alice',
  email: 'alice@example.com',
  createdAt: expect.any(Date)
});

// ❌ BAD: Separate assertions
expect(result).toHaveProperty('id');
expect(result.name).toBe('Alice');
expect(result.email).toBe('alice@example.com');
```

## Anti-Patterns

Avoid these:

```ts
// ❌ Testing implementation details
test('caches value internally', () => {
  const cache = getInternalCache();
  expect(cache).toContain('value');
});

// ❌ Trivial assertions
test('2 equals 2', () => {
  expect(2).toBe(2);
});

// ❌ Magic numbers
test('total calculation', () => {
  expect(calculateTotal([10, 20, 30])).toBe(60);
  // What do 10, 20, 30 represent?
});

// ❌ Testing type checker conditions
test('rejects null', () => {
  // @ts-expect-error - Testing invalid input
  expect(validateEmail(null)).toBe(false);
});

// ❌ Mixing async and sync confusingly
test('async function', () => {
  const result = fetchUser('123');
  expect(result).toBe(user);  // Wrong! result is Promise
});
```

## Integration Test Patterns

### Testing APIs

```ts
describe('POST /api/users', () => {
  test('creates user with valid input', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'Alice', email: 'alice@example.com' })
      .expect(201);

    expect(re
API DevelopmentSkill

Build REST APIs with proper error handling, status codes, request validation, response formatting, and rate limiting. Apply when creating API routes, handling errors, validating input, or designing API responses.

API Security HardeningSkill

Harden REST and GraphQL APIs against common attack vectors. Apply when building API endpoints, implementing authentication, handling file uploads, or exposing APIs to external consumers.

AWS Cloud InfrastructureSkill

Deploy Node.js applications on AWS using EC2, RDS, and managed services with security best practices. Apply when setting up AWS infrastructure, configuring databases, managing security, or optimizing costs.

Build Error ResolverSkill

Rapidly fix build failures, type errors, and lint issues with minimal diffs. Apply when builds fail, TypeScript reports errors, or CI/CD pipelines break. Focuses on getting the build green fast.

Cybersecurity Threat ModelingSkill

STRIDE-based threat modeling for application architecture. Apply when designing new systems, reviewing architecture, or assessing security posture of existing applications.

Docker ContainerizationSkill

Production-ready Docker patterns for multi-stage builds, security hardening, and orchestration. Apply when creating Dockerfiles, docker-compose configs, or deploying containerized applications.

Git WorkflowSkill

Enforces Conventional Commits, PR standards, merge conflict resolution, and branch management. Apply when committing code, opening PRs, resolving conflicts, managing branches, or handling Git operations.

Google Cloud Platform & APIsSkill

Deploy Node.js applications on Google Cloud with Cloud Run, Cloud Firestore, and Google APIs. Implement OAuth2 authentication and manage service accounts. Apply when building serverless applications, integrating Google services, or deploying to GCP.