Claude
Skills
Sign in
Back

typescript-unit-testing

Included with Lifetime
$97 forever

Unit testing for TypeScript/NestJS projects using Jest, @golevelup/ts-jest (DeepMocked/createMock), and in-memory databases, with AAA structure. Use whenever the user is working on `.spec.ts` files or asks to set up Jest, write/add tests for a service/usecase/controller/guard/interceptor/pipe/filter, mock dependencies, review test quality or coverage, run unit tests, debug failing or flaky tests, or optimize test performance and open handles.

Code Review

What this skill does


# Unit Testing Skill

Unit testing validates individual functions, methods, and classes in isolation by mocking all external dependencies.

---

## Workflows

For guided, step-by-step execution of unit testing tasks, use the appropriate workflow:

| Workflow | Purpose | When to Use |
|----------|---------|-------------|
| [Setup](workflows/setup/workflow.md) | Initialize test infrastructure | New project or missing test setup |
| [Writing](workflows/writing/workflow.md) | Write new unit tests | Creating tests for components |
| [Reviewing](workflows/reviewing/workflow.md) | Review existing tests | Code review, quality audit |
| [Running](workflows/running/workflow.md) | Execute tests | Running tests, analyzing results |
| [Debugging](workflows/debugging/workflow.md) | Fix failing tests | Tests failing, need diagnosis |
| [Optimizing](workflows/optimizing/workflow.md) | Improve test performance | Slow tests, maintainability |

## Workflow Selection Guide

**IMPORTANT**: Before starting any testing task, identify the user's intent and load the appropriate workflow.

### Detect User Intent → Select Workflow

| User Says / Wants | Workflow to Load | File |
|-------------------|------------------|------|
| "Set up tests", "configure Jest", "add testing to project", "install test dependencies" | **Setup** | `workflows/setup/workflow.md` |
| "Write tests", "add tests", "create tests", "test this service/controller" | **Writing** | `workflows/writing/workflow.md` |
| "Review tests", "check test quality", "audit tests", "are these tests good?" | **Reviewing** | `workflows/reviewing/workflow.md` |
| "Run tests", "execute tests", "check if tests pass", "show test results" | **Running** | `workflows/running/workflow.md` |
| "Fix tests", "debug tests", "tests are failing", "why is this test broken?" | **Debugging** | `workflows/debugging/workflow.md` |
| "Speed up tests", "optimize tests", "tests are slow", "fix open handles" | **Optimizing** | `workflows/optimizing/workflow.md` |

### Workflow Execution Protocol

1. **ALWAYS load the workflow file first** - Read the full workflow before taking action
2. **Follow each step in order** - Complete checkpoints before proceeding
3. **Load knowledge files as directed** - Each workflow specifies which `references/` files to read
4. **Verify compliance after completion** - Re-read relevant reference files to ensure quality

---

## Knowledge Base Structure

```
references/
├── common/              # Core testing fundamentals
│   ├── knowledge.md     # Testing philosophy and test pyramid
│   ├── rules.md         # Mandatory testing rules (AAA, naming, coverage)
│   ├── assertions.md    # Assertion patterns and matchers
│   ├── examples.md      # Comprehensive examples by category
│   ├── detect-open-handles.md   # Open handle detection and cleanup
│   └── performance-optimization.md  # Jest runtime optimization
│
├── nestjs/              # NestJS component testing
│   ├── services.md      # Service/usecase testing patterns
│   ├── controllers.md   # Controller testing patterns
│   ├── guards.md        # Guard testing patterns
│   ├── interceptors.md  # Interceptor testing patterns
│   └── pipes-filters.md # Pipe and filter testing
│
├── mocking/             # Mock patterns and strategies
│   ├── deep-mocked.md   # @golevelup/ts-jest patterns
│   ├── jest-native.md   # Jest.fn, spyOn, mock patterns
│   └── factories.md     # Test data factory patterns
│
├── repository/          # Repository testing
│   ├── mongodb.md       # mongodb-memory-server patterns
│   └── postgres.md      # pg-mem patterns
│
├── kafka/               # NestJS Kafka microservices testing
│   └── kafka.md         # ClientKafka, @MessagePattern, @EventPattern handlers
│
└── redis/               # Redis cache testing
    └── redis.md         # Cache operations, health checks, graceful degradation
```

## Quick Reference by Task

### Write Unit Tests
1. **MANDATORY**: Read `references/common/rules.md` - AAA pattern, naming, coverage
2. Read `references/common/assertions.md` - Assertion best practices
3. Read component-specific files:
   - **Services**: `references/nestjs/services.md`
   - **Controllers**: `references/nestjs/controllers.md`
   - **Guards**: `references/nestjs/guards.md`
   - **Interceptors**: `references/nestjs/interceptors.md`
   - **Pipes/Filters**: `references/nestjs/pipes-filters.md`

### Setup Mocking
1. Read `references/mocking/deep-mocked.md` - DeepMocked patterns
2. Read `references/mocking/jest-native.md` - Native Jest patterns
3. Read `references/mocking/factories.md` - Test data factories

### Test Repositories
1. **MongoDB**: `references/repository/mongodb.md`
2. **PostgreSQL**: `references/repository/postgres.md`

### Test Kafka (NestJS Microservices)
- Read `references/kafka/kafka.md` - ClientKafka mocking, @MessagePattern/@EventPattern handlers, emit/send testing

### Test Redis
- Read `references/redis/redis.md` - Cache operations, health checks, graceful degradation

### Examples
- Read `references/common/examples.md` for comprehensive patterns

### Optimize Test Performance
1. Read `references/common/performance-optimization.md` - Worker config, caching, CI optimization
2. Read `references/common/detect-open-handles.md` - Fix open handles preventing clean exit

### Debug Open Handles
- Read `references/common/detect-open-handles.md` - Detection commands, common handle types, cleanup patterns

---

## Core Principles

### 0. Context Efficiency (Temp File Output)
**ALWAYS redirect unit test output to temp files, NOT console**. Test output can be verbose and bloats agent context.

**IMPORTANT**: Use unique session ID in filenames to prevent conflicts when multiple agents run.

```bash
# Initialize session (once at start of testing session)
export UT_SESSION=$(date +%s)-$$

# Standard pattern - redirect output to temp file (NO console output)
npm test > /tmp/ut-${UT_SESSION}-output.log 2>&1

# Read summary only (last 50 lines)
tail -50 /tmp/ut-${UT_SESSION}-output.log

# Get failure details
grep -B 2 -A 15 "FAIL\|✕" /tmp/ut-${UT_SESSION}-output.log

# Cleanup when done
rm -f /tmp/ut-${UT_SESSION}-*.log /tmp/ut-${UT_SESSION}-*.md
```

**Temp Files** (with `${UT_SESSION}` unique per agent):
- `/tmp/ut-${UT_SESSION}-output.log` - Full test output
- `/tmp/ut-${UT_SESSION}-failures.md` - Tracking file for one-by-one fixing
- `/tmp/ut-${UT_SESSION}-debug.log` - Debug runs
- `/tmp/ut-${UT_SESSION}-verify.log` - Verification runs
- `/tmp/ut-${UT_SESSION}-coverage.log` - Coverage output

### 1. AAA Pattern (Mandatory)
ALL unit tests MUST follow Arrange-Act-Assert:
```typescript
it('should return user when found', async () => {
  // Arrange
  const userId = 'user-123';
  mockRepository.findById.mockResolvedValue({
    id: userId,
    email: '[email protected]',
    name: 'Test User',
  });

  // Act
  const result = await target.getUser(userId);

  // Assert
  expect(result).toEqual({
    id: userId,
    email: '[email protected]',
    name: 'Test User',
  });
  expect(mockRepository.findById).toHaveBeenCalledWith(userId);
});
```

### 2. Use `target` for SUT
Always name the system under test as `target`:
```typescript
let target: UserService;
let mockRepository: DeepMocked<UserRepository>;
```

### 3. DeepMocked Pattern
Use `@golevelup/ts-jest` for type-safe mocks:
```typescript
import { createMock, DeepMocked } from '@golevelup/ts-jest';

let mockService: DeepMocked<UserService>;

beforeEach(() => {
  mockService = createMock<UserService>();
});
```

### 4. Specific Assertions
Assert exact values, not just existence:
```typescript
// WRONG
expect(result).toBeDefined();
expect(result.id).toBeDefined();

// CORRECT
expect(result).toEqual({
  id: 'user-123',
  email: '[email protected]',
  name: 'Test User',
});
```

### 5. Mock All Dependencies
Mock external services, never real databases for unit tests:
```typescript
// Unit Test: Mock repository
{ provide: UserRepository, useValue: mockRepository }

// Repository Test: Use in-memory
Files: 81
Size: 331.8 KB
Complexity: 69/100
Category: Code Review

Related in Code Review