From jest-testing-bundle
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.
How this skill is triggered — by the user, by Claude, or both
Slash command
/jest-testing-bundle:jest-fundamentalsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Master Jest configuration, test structure, assertions, and lifecycle hooks for JavaScript and TypeScript projects.
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
npx claudepluginhub karchtho/my-claude-marketplace --plugin jest-testing-bundleConfigures Jest for JavaScript and TypeScript projects including setup files, module resolution, coverage thresholds, transform rules, and project organization for optimal testing.
Generates Jest unit tests for JavaScript/TypeScript modules and React components with mocking, coverage, spies, and snapshots. Use for test creation, missing coverage, or improper mocking.
Guides Vitest testing for TypeScript/JavaScript projects: installation, config, running tests with watch/UI/coverage, assertions, and mocking.