Unit testing and TDD expert for Vitest/Jest. Red-green-refactor workflow, mocking strategies, coverage analysis, and ESM mocking patterns. Use for writing tests, implementing TDD, or setting up test coverage.
View on GitHubanton-abyzov/specweave
sw-testing
February 4, 2026
Select agents to install to:
npx add-skill https://github.com/anton-abyzov/specweave/blob/main/plugins/specweave-testing/skills/unit-testing/SKILL.md -a claude-code --skill unit-testingInstallation paths:
.claude/skills/unit-testing/# Unit Testing & TDD Expert - Vitest/Jest
## Test-Driven Development (TDD)
### Red-Green-Refactor Cycle
```typescript
// 1. RED: Write failing test
describe('Calculator', () => {
it('should add two numbers', () => {
const calc = new Calculator();
expect(calc.add(2, 3)).toBe(5); // FAILS - doesn't exist
});
});
// 2. GREEN: Minimal implementation
class Calculator {
add(a: number, b: number): number {
return a + b;
}
}
// 3. REFACTOR: Improve design
class Calculator {
add(...numbers: number[]): number {
return numbers.reduce((sum, n) => sum + n, 0);
}
}
```
### TDD Checklist
- [ ] RED: Test fails for the RIGHT reason
- [ ] GREEN: Simplest code that passes
- [ ] REFACTOR: All tests still green
## Basic Test Structure
```typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
describe('UserService', () => {
let service: UserService;
beforeEach(() => {
service = new UserService();
vi.clearAllMocks();
});
it('should create user', () => {
const user = service.create({ name: 'John', email: 'john@test.com' });
expect(user).toMatchObject({
id: expect.any(String),
name: 'John',
email: 'john@test.com'
});
});
it('should throw for invalid email', () => {
expect(() => service.create({ email: 'invalid' })).toThrow('Invalid email');
});
});
```
## Mocking Strategies
### 1. Mock Functions
```typescript
const mockFn = vi.fn();
mockFn.mockReturnValue(42);
expect(mockFn()).toBe(42);
expect(mockFn).toHaveBeenCalledTimes(1);
```
### 2. Mock Modules
```typescript
vi.mock('./database', () => ({
query: vi.fn().mockResolvedValue([{ id: 1 }])
}));
import { query } from './database';
```
### 3. ESM Mocking with vi.hoisted()
**CRITICAL for ESM modules**:
```typescript
// ✅ Define mocks in hoisted context FIRST
const { mockFn } = vi.hoisted(() => ({
mockFn: vi.fn()
}));
vi.mock('./module', () => ({
myFunc: mockFn
}));
import { myFunc } from './module';
`