From typescript-dev
TypeScript testing patterns with Jest/Vitest including unit tests, integration tests, mocking strategies, and coverage. Use when writing TypeScript tests.
How this skill is triggered — by the user, by Claude, or both
Slash command
/typescript-dev:typescript-testingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are a testing specialist for TypeScript projects.
You are a testing specialist for TypeScript projects.
jest.config.* or "jest" in package.json → Jestvitest.config.* or "vitest" in package.json → Vitestcypress.config.* → Cypress (E2E)playwright.config.* → Playwright (E2E)Examples below use Jest APIs. For Vitest, replace jest with vi and import helpers from vitest.
describe('UserService', () => {
let sut: UserService;
let mockRepository: jest.Mocked<IUserRepository>;
beforeEach(() => {
mockRepository = {
findById: jest.fn(),
save: jest.fn(),
};
sut = new UserService(mockRepository);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('getUser', () => {
it('should return user when found', async () => {
// Arrange
const expectedUser = { id: '1', name: 'Test' };
mockRepository.findById.mockResolvedValue(expectedUser);
// Act
const result = await sut.getUser('1');
// Assert
expect(result).toEqual(expectedUser);
expect(mockRepository.findById).toHaveBeenCalledWith('1');
});
it('should return null when user not found', async () => {
// Arrange
mockRepository.findById.mockResolvedValue(null);
// Act
const result = await sut.getUser('unknown');
// Assert
expect(result).toBeNull();
});
});
});
// Mock modules
jest.mock('./database', () => ({
getConnection: jest.fn().mockResolvedValue(mockConnection),
}));
// Mock implementations (include standard Response properties)
const mockData = { id: '1', name: 'Test' };
const mockFetch = jest.fn().mockImplementation((url: string) =>
Promise.resolve({ ok: true, status: 200, json: () => Promise.resolve(mockData) })
);
// Spy on methods
const spy = jest.spyOn(service, 'validate');
expect(spy).toHaveBeenCalledTimes(1);
describe('API Integration', () => {
let app: Express;
beforeAll(async () => {
app = await createApp({ database: testDb });
});
afterAll(async () => {
await testDb.close();
});
it('should create and retrieve user', async () => {
const createResponse = await request(app)
.post('/users')
.send({ name: 'Test', email: '[email protected]' })
.expect(201);
const getResponse = await request(app)
.get(`/users/${createResponse.body.id}`)
.expect(200);
expect(getResponse.body.name).toBe('Test');
});
});
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
describe('Button', () => {
it('should call onClick when clicked', async () => {
const user = userEvent.setup();
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
await user.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('should be disabled when loading', () => {
render(<Button isLoading>Submit</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});
// Testing async functions
it('should handle async errors', async () => {
mockApi.get.mockRejectedValue(new NetworkError('timeout'));
await expect(service.fetchData('url')).rejects.toThrow(NetworkError);
});
// Testing timers (clean up in afterEach to prevent leaks on failure)
describe('debounce', () => {
beforeEach(() => jest.useFakeTimers());
afterEach(() => jest.useRealTimers());
it('should debounce input', () => {
const callback = jest.fn();
debounce(callback, 300)('test');
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(300);
expect(callback).toHaveBeenCalledWith('test');
});
});
If using Vitest instead of Jest, the API is nearly identical:
| Jest | Vitest |
|---|---|
jest.fn() | vi.fn() |
jest.mock() | vi.mock() |
jest.spyOn() | vi.spyOn() |
jest.clearAllMocks() | vi.clearAllMocks() |
jest.useFakeTimers() | vi.useFakeTimers() |
jest.Mocked<T> | Mocked<T> (from vitest) |
.env files or API keys in testsnpx claudepluginhub dmitriyyukhanov/claude-plugins --plugin typescript-devGuides Vitest testing for TypeScript/JavaScript projects: installation, config, running tests with watch/UI/coverage, assertions, and mocking.
Provides Vitest testing patterns with MSW for API mocking and typed mocks for dependency injection. Includes snapshot testing and spy utilities for TypeScript projects.
Writes and configures Vitest tests for Vite projects: test suites with describe/it, mocking with vi.fn/vi.mock, code coverage, parallel execution, and type testing.