unit-testing

Unit Testing & TDD Expert - Vitest/Jest

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "unit-testing" with this command: npx skills add anton-abyzov/specweave/anton-abyzov-specweave-unit-testing

Unit Testing & TDD Expert - Vitest/Jest

Test-Driven Development (TDD)

Red-Green-Refactor Cycle

// 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

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

const mockFn = vi.fn(); mockFn.mockReturnValue(42); expect(mockFn()).toBe(42); expect(mockFn).toHaveBeenCalledTimes(1);

  1. Mock Modules

vi.mock('./database', () => ({ query: vi.fn().mockResolvedValue([{ id: 1 }]) }));

import { query } from './database';

  1. ESM Mocking with vi.hoisted()

CRITICAL for ESM modules:

// ✅ Define mocks in hoisted context FIRST const { mockFn } = vi.hoisted(() => ({ mockFn: vi.fn() }));

vi.mock('./module', () => ({ myFunc: mockFn }));

import { myFunc } from './module';

  1. Dependency Injection

class UserService { constructor(private db: Database) {} }

// Test with mock const mockDb = { query: vi.fn().mockResolvedValue({ id: '123' }) }; const service = new UserService(mockDb);

Test Patterns

AAA Pattern (Arrange-Act-Assert)

it('should calculate total', () => { // Arrange const cart = new ShoppingCart(); cart.addItem({ price: 10, quantity: 2 });

// Act const total = cart.getTotal();

// Assert expect(total).toBe(20); });

Parametric Testing

describe.each([ [2, 3, 5], [10, 5, 15], [-1, 1, 0], ])('add(%i, %i)', (a, b, expected) => { it(should return ${expected}, () => { expect(add(a, b)).toBe(expected); }); });

Coverage Analysis

// vitest.config.ts export default { test: { coverage: { provider: 'v8', reporter: ['text', 'html', 'lcov'], lines: 80, functions: 80, branches: 80, } } };

Async Testing

it('should fetch user', async () => { const user = await api.fetchUser('123'); expect(user).toEqual({ id: '123', name: 'John' }); });

it('should handle API errors', async () => { await expect(api.fetchUser('invalid')).rejects.toThrow('Not found'); });

VSCode Debug Mode Fix

When tests spawn child processes, use clean environment:

function getCleanEnv(): NodeJS.ProcessEnv { const cleanEnv = { ...process.env }; delete cleanEnv.NODE_OPTIONS; delete cleanEnv.NODE_INSPECT; delete cleanEnv.VSCODE_INSPECTOR_OPTIONS; return cleanEnv; }

// Usage execSync('node cli.js', { env: getCleanEnv() });

Isolated Temp Directories

import * as os from 'os';

const TEST_ROOT = path.join(os.tmpdir(), test-${Date.now()});

beforeEach(() => fs.mkdir(TEST_ROOT, { recursive: true })); afterEach(() => fs.rm(TEST_ROOT, { recursive: true, force: true }));

Best Practices

  • Test behavior, not implementation

  • One assertion per test (when possible)

  • Independent tests (no shared state)

  • Fast tests (<100ms each)

  • Clear test names (should...)

  • Mock external dependencies only

Quick Reference

Assertions

expect(value).toBe(expected); // === expect(value).toEqual(expected); // Deep equality expect(array).toContain(item); // Array includes expect(string).toMatch(/pattern/); // Regex expect(fn).toThrow(Error); // Throws expect(obj).toHaveProperty('key'); // Has property

Mock Utilities

vi.fn() // Create mock vi.fn().mockReturnValue(x) // Return value vi.fn().mockResolvedValue(x) // Async return vi.mock('./module') // Mock module vi.spyOn(obj, 'method') // Spy on method vi.clearAllMocks() // Clear history

Related Skills

  • qa-engineer

  • Overall test strategy

  • e2e-testing

  • E2E and visual tests

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

technical-writing

No summary provided by upstream source.

Repository SourceNeeds Review
General

spec-driven-brainstorming

No summary provided by upstream source.

Repository SourceNeeds Review
General

kafka-architecture

No summary provided by upstream source.

Repository SourceNeeds Review