Jest setup, configuration, test runner, assertions, lifecycle hooks, coverage. Activates when user mentions "Jest config", "setup Jest", "Jest configuration", "test coverage", "Jest hooks", "beforeEach", "afterEach", "describe blocks", or wants to configure Jest for JavaScript/TypeScript projects.
Configures Jest testing framework with setup, assertions, lifecycle hooks, and coverage for JavaScript and TypeScript projects.
npx claudepluginhub karchtho/my-claude-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Master Jest configuration, test structure, assertions, and lifecycle hooks for JavaScript and TypeScript projects.
Create jest.config.js or jest.config.ts at project root:
// jest.config.js
module.exports = {
preset: 'ts-jest', // Use ts-jest for TypeScript
testEnvironment: 'node', // 'node' for backend, 'jsdom' for frontend
roots: ['<rootDir>/src'],
testMatch: [
'**/__tests__/**/*.ts',
'**/?(*.)+(spec|test).ts'
],
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/**/index.ts'
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
},
setupFilesAfterEnv: ['<rootDir>/src/test/setup.ts'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1' // Path alias support
},
clearMocks: true,
restoreMocks: true
};
For TypeScript projects, ensure tsconfig.json includes:
{
"compilerOptions": {
"types": ["jest", "node"],
"esModuleInterop": true
}
}
Create src/test/setup.ts for global test configuration:
// src/test/setup.ts
import { jest } from '@jest/globals';
// Extend Jest matchers
expect.extend({
toBeWithinRange(received, floor, ceiling) {
const pass = received >= floor && received <= ceiling;
return {
message: () =>
`expected ${received} ${pass ? 'not ' : ''}to be within range ${floor} - ${ceiling}`,
pass
};
}
});
// Global timeout for async tests
jest.setTimeout(10000);
// Clean up after each test
afterEach(() => {
jest.clearAllMocks();
});
describe('ComponentName', () => {
// Group related tests
describe('methodName', () => {
it('should do expected behavior when given valid input', () => {
// Arrange
const input = 'test';
// Act
const result = methodName(input);
// Assert
expect(result).toBe('expected');
});
it('should throw error when given invalid input', () => {
expect(() => methodName(null)).toThrow('Invalid input');
});
});
});
Structure every test with clear phases:
it('should calculate total with discount', () => {
// Arrange - Set up test data and conditions
const cart = new ShoppingCart();
cart.addItem({ name: 'Widget', price: 100 });
const discount = 0.1;
// Act - Execute the behavior being tested
const total = cart.calculateTotal(discount);
// Assert - Verify the expected outcome
expect(total).toBe(90);
});
describe('Database operations', () => {
let connection;
let testData;
// Runs once before all tests in this describe block
beforeAll(async () => {
connection = await createTestConnection();
});
// Runs before each test
beforeEach(async () => {
testData = await seedTestData(connection);
});
// Runs after each test
afterEach(async () => {
await clearTestData(connection);
jest.clearAllMocks();
});
// Runs once after all tests
afterAll(async () => {
await connection.close();
});
it('should query data', async () => {
const result = await connection.query('SELECT * FROM users');
expect(result.length).toBeGreaterThan(0);
});
});
// Equality
expect(value).toBe(expected); // Strict equality (===)
expect(value).toEqual(expected); // Deep equality for objects/arrays
expect(value).toStrictEqual(expected); // Deep equality + undefined checks
// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();
// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3);
expect(value).toBeLessThan(5);
expect(value).toBeCloseTo(0.3, 5); // Floating point comparison
// Strings
expect(str).toMatch(/pattern/);
expect(str).toContain('substring');
expect(str).toHaveLength(5);
// Arrays
expect(array).toContain(item);
expect(array).toContainEqual({ id: 1 });
expect(array).toHaveLength(3);
// Objects
expect(obj).toHaveProperty('key');
expect(obj).toHaveProperty('nested.key', 'value');
expect(obj).toMatchObject({ partial: 'match' });
// Sync errors
expect(() => throwingFunction()).toThrow();
expect(() => throwingFunction()).toThrow('specific message');
expect(() => throwingFunction()).toThrow(CustomError);
// Async errors
await expect(asyncFunction()).rejects.toThrow('error message');
await expect(asyncFunction()).rejects.toBeInstanceOf(CustomError);
const mockFn = jest.fn();
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
expect(mockFn).toHaveBeenLastCalledWith('lastArg');
expect(mockFn).toHaveBeenNthCalledWith(1, 'firstCallArg');
expect(mockFn).toHaveReturnedWith('value');
// Resolves
it('should resolve with data', async () => {
await expect(fetchData()).resolves.toEqual({ id: 1 });
});
// Rejects
it('should reject with error', async () => {
await expect(fetchInvalidData()).rejects.toThrow('Not found');
});
// Async/await
it('should fetch user data', async () => {
const user = await fetchUser(1);
expect(user.name).toBe('John');
});
describe('Timer functions', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
it('should call callback after delay', () => {
const callback = jest.fn();
setTimeout(callback, 1000);
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalledTimes(1);
});
it('should run all pending timers', () => {
const callback = jest.fn();
setTimeout(callback, 1000);
setTimeout(callback, 2000);
jest.runAllTimers();
expect(callback).toHaveBeenCalledTimes(2);
});
});
# Generate coverage report
npm test -- --coverage
# Watch mode with coverage
npm test -- --coverage --watchAll
# Coverage for specific files
npm test -- --coverage --collectCoverageFrom='src/utils/**/*.ts'
Enforce minimum coverage in jest.config.js:
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
},
'./src/critical/': {
branches: 100,
functions: 100,
lines: 100
}
}
# Run all tests
npm test
# Watch mode
npm test -- --watch
# Run specific file
npm test -- path/to/test.ts
# Run tests matching pattern
npm test -- --testNamePattern="should calculate"
# Run tests in specific directory
npm test -- --testPathPattern="src/utils"
# Verbose output
npm test -- --verbose
# Update snapshots
npm test -- --updateSnapshot