Agent skill
Vitest Unit Testing
Write fast unit tests with Vitest, coverage reporting, mocking, and snapshots. Apply when testing utilities, components, services, or building test coverage.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/examples-thamjiahe-claude-prompt-engine-12
SKILL.md
Vitest Unit Testing
Systematic unit testing with Vitest for fast, reliable test feedback.
Overview
This Skill enforces:
- Test-driven development (TDD) with Vitest
- Component testing with React
- Mocking and spying
- Snapshot testing
- Code coverage reporting
- Watch mode for development
- Parallel test execution
Apply when writing unit tests, testing components, or building test coverage.
Setup Vitest
Install Dependencies
npm install -D vitest @vitest/ui
npm install -D @testing-library/react @testing-library/jest-dom
npm install -D jsdom # For DOM testing
Configure vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./vitest.setup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'dist/',
'**/*.test.ts',
'**/*.spec.ts'
]
}
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
});
Setup File
// vitest.setup.ts
import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import '@testing-library/jest-dom';
// Cleanup after each test
afterEach(() => {
cleanup();
});
Package.json Scripts
{
"scripts": {
"test": "vitest",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui",
"test:coverage": "vitest --coverage"
}
}
Writing Unit Tests
Basic Test Structure
// src/utils/helpers.test.ts
import { describe, it, expect } from 'vitest';
import { add, multiply } from './helpers';
describe('Math Helpers', () => {
describe('add', () => {
it('should add two numbers correctly', () => {
expect(add(2, 3)).toBe(5);
});
it('should handle negative numbers', () => {
expect(add(-5, 3)).toBe(-2);
});
it('should handle zero', () => {
expect(add(0, 5)).toBe(5);
});
});
describe('multiply', () => {
it('should multiply two numbers correctly', () => {
expect(multiply(3, 4)).toBe(12);
});
it('should return 0 when multiplying by 0', () => {
expect(multiply(5, 0)).toBe(0);
});
});
});
Component Testing
// src/components/Button.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';
describe('Button Component', () => {
it('renders button with text', () => {
render(<Button>Click me</Button>);
expect(screen.getByRole('button')).toHaveTextContent('Click me');
});
it('calls onClick handler when clicked', async () => {
const handleClick = vi.fn();
const user = userEvent.setup();
render(<Button onClick={handleClick}>Click</Button>);
const button = screen.getByRole('button');
await user.click(button);
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('renders disabled button', () => {
render(<Button disabled>Disabled</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});
Mocking
Mocking Functions
import { describe, it, expect, vi, beforeEach } from 'vitest';
describe('User Service', () => {
let mockFetch: any;
beforeEach(() => {
mockFetch = vi.fn();
});
it('fetches user data', async () => {
mockFetch.mockResolvedValue({
json: async () => ({ id: 1, name: 'Alice' })
});
// Use mockFetch in your function
const response = await mockFetch();
const data = await response.json();
expect(data).toEqual({ id: 1, name: 'Alice' });
expect(mockFetch).toHaveBeenCalledTimes(1);
});
it('handles fetch error', async () => {
mockFetch.mockRejectedValue(new Error('Network error'));
await expect(mockFetch()).rejects.toThrow('Network error');
});
});
Mocking Modules
// src/services/api.test.ts
import { describe, it, expect, vi } from 'vitest';
import { fetchUsers } from './api';
// Mock the entire module
vi.mock('../lib/http', () => ({
get: vi.fn(() => Promise.resolve([{ id: 1, name: 'Alice' }]))
}));
describe('API Service', () => {
it('fetches users', async () => {
const users = await fetchUsers();
expect(users).toHaveLength(1);
expect(users[0].name).toBe('Alice');
});
});
Partial Mocking
import { describe, it, expect, vi } from 'vitest';
vi.mock('../utils', async () => {
const actual = await vi.importActual('../utils');
return {
...actual,
dateUtil: {
now: () => new Date('2025-01-01')
}
};
});
Spying
import { describe, it, expect, vi, spyOn } from 'vitest';
import { logger } from './logger';
describe('Spy on function', () => {
it('spies on console.log', () => {
const consoleSpy = spyOn(console, 'log');
console.log('test message');
expect(consoleSpy).toHaveBeenCalledWith('test message');
expect(consoleSpy).toHaveBeenCalledTimes(1);
consoleSpy.mockRestore();
});
});
Async Testing
import { describe, it, expect, vi } from 'vitest';
describe('Async Operations', () => {
it('waits for promise to resolve', async () => {
const fetchData = () =>
new Promise(resolve =>
setTimeout(() => resolve('data'), 100)
);
const data = await fetchData();
expect(data).toBe('data');
});
it('handles async errors', async () => {
const failingFetch = () =>
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Network error')), 100)
);
await expect(failingFetch()).rejects.toThrow('Network error');
});
});
Snapshot Testing
import { describe, it, expect } from 'vitest';
import { render } from '@testing-library/react';
import { Card } from './Card';
describe('Card Snapshot', () => {
it('matches snapshot', () => {
const { container } = render(
<Card title="Test">Content</Card>
);
expect(container).toMatchSnapshot();
});
});
Code Coverage
Run Coverage
npm run test:coverage
Coverage Configuration
// vitest.config.ts
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html', 'lcov'],
lines: 80, // Minimum line coverage
functions: 80,
branches: 75,
statements: 80,
exclude: [
'node_modules/',
'dist/',
'**/*.d.ts',
'**/*.test.ts'
]
}
}
});
Vitest UI
npm run test:ui
# Opens interactive UI at http://localhost:51204/__vitest__/
Performance Benefits
Framework | Time (500 tests)
----------|----------------
Jest | ~8 seconds
Vitest | ~3 seconds
Mocha | ~6 seconds
Vitest is ~2.7x faster than Jest!
Anti-Patterns
// ❌ BAD: Slow synchronous operations
it('slow test', () => {
for (let i = 0; i < 1000000; i++) {
// Pointless loop
}
});
// ❌ BAD: Global state pollution
let counter = 0;
it('increments counter', () => {
counter++;
expect(counter).toBe(1);
});
it('another test', () => {
expect(counter).toBe(1); // Depends on previous test!
});
// ✅ GOOD: Use beforeEach for setup
let counter: number;
beforeEach(() => {
counter = 0;
});
// ❌ BAD: Testing implementation details
vi.spyOn(obj, 'privateMethod');
// ✅ GOOD: Test behavior, not implementation
expect(result).toBe(expectedValue);
// ❌ BAD: Snapshot without understanding
expect(largeObject).toMatchSnapshot();
// Snapshot bloat, hard to review
// ✅ GOOD: Targeted snapshots
expect({ name, email }).toMatchSnapshot();
Verification Before Production
- Unit test coverage >= 80%
- No console warnings in tests
- Async tests properly handled
- Mocks cleaned up (mockRestore)
- No flaky tests (random failures)
- Tests isolated (no dependencies)
- Snapshot tests reviewed
- Coverage report passing
Integration with Project Standards
Enforces T-1 through T-10:
- Colocated tests (same directory as source)
- Pure logic tested separately
- Edge cases covered
- Fast feedback (RED-GREEN-REFACTOR)
Resources
- Vitest Docs: https://vitest.dev
- Testing Library: https://testing-library.com
- Vitest Examples: https://github.com/vitest-dev/vitest/tree/main/examples
Last Updated: January 24, 2026 Compatibility: Claude Opus 4.5, Claude Code v2.x Status: Production Ready
January 2026 Update: This skill is compatible with Claude Opus 4.5 and Claude Code v2.x. For complex tasks, use the
effort: highparameter for thorough analysis.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?