
Jest Testing
- 2 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
jest-testing is a Claude Code skill that provides Jest configuration, mocking, snapshot and React Testing Library expertise for JavaScript and TypeScript apps.
About
jest-testing is a Claude Code skill providing Jest expertise for testing React, Node.js and JavaScript or TypeScript applications. A developer uses it for Jest configuration, matchers, mocking strategies, snapshot testing, code coverage and React Testing Library setup. It activates on Jest config or test files and also applies to Vitest due to API compatibility.
- Jest configuration, matchers, mocks and snapshot testing expertise
- React Testing Library setup and query-priority guidance
- Also applies to Vitest due to API compatibility
Jest Testing by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,693 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
jest-testing capabilities & compatibility
- Capabilities
- jest configuration · mocking strategies · snapshot testing · code coverage · react testing library · async testing
- Use cases
- testing
What jest-testing says it does
You are an expert in Jest testing framework with deep knowledge of its configuration, matchers, mocks, and best practices for testing JavaScript and TypeScript applications.
Also applies to Vitest due to API compatibility.
npx skills add https://github.com/aiskillstore/marketplace --skill jest-testingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Write and configure Jest tests for React, Node.js and JavaScript apps.
Who is it for?
Configuring and writing Jest tests for JS/TS apps and React components
Skip if: General test-quality analysis (use analyzing-test-quality)
When should I use this skill?
Working with Jest tests, jest.config, matchers, mocks, or *.test.* files
What you get
- Jest test files
- jest.config
- React Testing Library setup
By the numbers
- 9 declared capabilities
- coverageThreshold example set to 80% branches/functions/lines/statements
Files
Jest Testing Expertise
You are an expert in Jest testing framework with deep knowledge of its configuration, matchers, mocks, and best practices for testing JavaScript and TypeScript applications.
Your Capabilities
1. Jest Configuration: Setup, configuration files, environments, and presets 2. Matchers & Assertions: Built-in and custom matchers, asymmetric matchers 3. Mocking: Mock functions, modules, timers, and external dependencies 4. Snapshot Testing: Inline and external snapshots, snapshot updates 5. Code Coverage: Coverage configuration, thresholds, and reports 6. Test Organization: Describe blocks, hooks, test filtering 7. React Testing: Testing React components with Jest DOM and RTL
When to Use This Skill
Claude should automatically invoke this skill when:
- The user mentions Jest, jest.config, or Jest-specific features
- Files matching
*.test.js,*.test.ts,*.test.jsx,*.test.tsxare encountered - The user asks about mocking, snapshots, or Jest matchers
- The conversation involves testing React, Node.js, or JavaScript apps
- Jest configuration or setup is discussed
How to Use This Skill
Accessing Resources
Use {baseDir} to reference files in this skill directory:
- Scripts:
{baseDir}/scripts/ - Documentation:
{baseDir}/references/ - Templates:
{baseDir}/assets/
Progressive Discovery
1. Start with core Jest expertise 2. Reference specific documentation as needed 3. Provide code examples from templates
Available Resources
This skill includes ready-to-use resources in {baseDir}:
- references/jest-cheatsheet.md - Quick reference for matchers, mocks, async patterns, and CLI commands
- assets/test-file.template.ts - Complete test templates for unit tests, async tests, class tests, mock tests, React components, and hooks
- scripts/check-jest-setup.sh - Validates Jest configuration and dependencies
Jest Best Practices
Test Structure
describe('ComponentName', () => {
beforeEach(() => {
// Setup
});
afterEach(() => {
// Cleanup
});
describe('method or behavior', () => {
it('should do expected thing when condition', () => {
// Arrange
// Act
// Assert
});
});
});Mocking Patterns
Mock Functions
const mockFn = jest.fn();
mockFn.mockReturnValue('value');
mockFn.mockResolvedValue('async value');
mockFn.mockImplementation((arg) => arg * 2);Mock Modules
jest.mock('./module', () => ({
func: jest.fn().mockReturnValue('mocked'),
}));Mock Timers
jest.useFakeTimers();
jest.advanceTimersByTime(1000);
jest.runAllTimers();Common Matchers
expect(value).toBe(expected); // Strict equality
expect(value).toEqual(expected); // Deep equality
expect(value).toBeTruthy(); // Truthy
expect(value).toContain(item); // Array/string contains
expect(fn).toHaveBeenCalledWith(args); // Function called with
expect(value).toMatchSnapshot(); // Snapshot
expect(fn).toThrow(error); // ThrowsAsync Testing
// Promises
it('async test', async () => {
await expect(asyncFn()).resolves.toBe('value');
});
// Callbacks
it('callback test', (done) => {
callbackFn((result) => {
expect(result).toBe('value');
done();
});
});Jest Configuration
Basic Configuration
// jest.config.js
module.exports = {
testEnvironment: 'node', // or 'jsdom'
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.ts', '**/*.test.ts'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};React Testing Library
Setup with Custom Render
// test-utils.tsx
import { render, RenderOptions } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';
const AllProviders = ({ children }: { children: React.ReactNode }) => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return (
<QueryClientProvider client={queryClient}>
<BrowserRouter>
{children}
</BrowserRouter>
</QueryClientProvider>
);
};
export const renderWithProviders = (
ui: React.ReactElement,
options?: RenderOptions
) => render(ui, { wrapper: AllProviders, ...options });
export * from '@testing-library/react';Query Priority (Best to Worst)
// 1. Accessible queries (best)
screen.getByRole('button', { name: 'Submit' });
screen.getByLabelText('Email');
screen.getByPlaceholderText('Enter email');
screen.getByText('Welcome');
// 2. Semantic queries
screen.getByAltText('Profile picture');
screen.getByTitle('Close');
// 3. Test IDs (last resort)
screen.getByTestId('submit-button');User Interactions
import userEvent from '@testing-library/user-event';
test('form submission', async () => {
const user = userEvent.setup();
render(<LoginForm />);
// Type in inputs
await user.type(screen.getByLabelText('Email'), 'test@example.com');
await user.type(screen.getByLabelText('Password'), 'password123');
// Click button
await user.click(screen.getByRole('button', { name: 'Sign in' }));
// Check result
await waitFor(() => {
expect(screen.getByText('Welcome!')).toBeInTheDocument();
});
});
test('keyboard navigation', async () => {
const user = userEvent.setup();
render(<Form />);
await user.tab(); // Focus first element
await user.keyboard('{Enter}'); // Press enter
await user.keyboard('[ShiftLeft>][Tab][/ShiftLeft]'); // Shift+Tab
});Testing Hooks
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';
test('useCounter increments', () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
// With wrapper for context
test('hook with context', () => {
const wrapper = ({ children }) => (
<ThemeProvider theme="dark">{children}</ThemeProvider>
);
const { result } = renderHook(() => useTheme(), { wrapper });
expect(result.current.theme).toBe('dark');
});Async Assertions
import { waitFor, waitForElementToBeRemoved } from '@testing-library/react';
test('async loading', async () => {
render(<DataFetcher />);
// Wait for loading to disappear
await waitForElementToBeRemoved(() => screen.queryByText('Loading...'));
// Wait for content
await waitFor(() => {
expect(screen.getByText('Data loaded')).toBeInTheDocument();
});
// With timeout
await waitFor(
() => expect(screen.getByText('Slow content')).toBeInTheDocument(),
{ timeout: 5000 }
);
});Network Mocking with MSW
Setup
// src/mocks/handlers.ts
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' },
]);
}),
http.post('/api/users', async ({ request }) => {
const body = await request.json();
return HttpResponse.json({ id: 3, ...body }, { status: 201 });
}),
http.delete('/api/users/:id', ({ params }) => {
return HttpResponse.json({ deleted: params.id });
}),
];
// src/mocks/server.ts
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
export const server = setupServer(...handlers);Jest Setup
// jest.setup.ts
import { server } from './src/mocks/server';
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());Test-Specific Handlers
import { server } from '../mocks/server';
import { http, HttpResponse } from 'msw';
test('handles error response', async () => {
// Override for this test only
server.use(
http.get('/api/users', () => {
return HttpResponse.json(
{ error: 'Server error' },
{ status: 500 }
);
})
);
render(<UserList />);
await waitFor(() => {
expect(screen.getByText('Failed to load users')).toBeInTheDocument();
});
});
test('handles network error', async () => {
server.use(
http.get('/api/users', () => {
return HttpResponse.error();
})
);
render(<UserList />);
await waitFor(() => {
expect(screen.getByText('Network error')).toBeInTheDocument();
});
});Request Assertions
test('sends correct request', async () => {
let capturedRequest: Request | null = null;
server.use(
http.post('/api/users', async ({ request }) => {
capturedRequest = request.clone();
return HttpResponse.json({ id: 1 });
})
);
render(<CreateUserForm />);
await userEvent.type(screen.getByLabelText('Name'), 'John');
await userEvent.click(screen.getByRole('button', { name: 'Create' }));
await waitFor(() => {
expect(capturedRequest).not.toBeNull();
});
const body = await capturedRequest!.json();
expect(body).toEqual({ name: 'John' });
});Custom Matchers
Creating Custom Matchers
// jest.setup.ts
expect.extend({
toBeWithinRange(received: number, floor: number, ceiling: number) {
const pass = received >= floor && received <= ceiling;
return {
pass,
message: () =>
pass
? `expected ${received} not to be within range ${floor} - ${ceiling}`
: `expected ${received} to be within range ${floor} - ${ceiling}`,
};
},
toHaveBeenCalledOnceWith(received: jest.Mock, ...args: unknown[]) {
const pass =
received.mock.calls.length === 1 &&
JSON.stringify(received.mock.calls[0]) === JSON.stringify(args);
return {
pass,
message: () =>
pass
? `expected not to be called once with ${args}`
: `expected to be called once with ${args}, but was called ${received.mock.calls.length} times`,
};
},
});
// Type declarations
declare global {
namespace jest {
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
toHaveBeenCalledOnceWith(...args: unknown[]): R;
}
}
}Asymmetric Matchers
test('asymmetric matchers', () => {
const data = {
id: 123,
name: 'Test',
createdAt: new Date().toISOString(),
};
expect(data).toEqual({
id: expect.any(Number),
name: expect.stringContaining('Test'),
createdAt: expect.stringMatching(/^\d{4}-\d{2}-\d{2}/),
});
expect(['a', 'b', 'c']).toEqual(
expect.arrayContaining(['a', 'c'])
);
expect({ a: 1, b: 2, c: 3 }).toEqual(
expect.objectContaining({ a: 1, b: 2 })
);
});Debugging Jest Tests
Debug Output
import { screen } from '@testing-library/react';
test('debugging', () => {
render(<MyComponent />);
// Print DOM
screen.debug();
// Print specific element
screen.debug(screen.getByRole('button'));
// Get readable DOM
console.log(prettyDOM(container));
});Finding Slow Tests
# Run with verbose timing
jest --verbose
# Detect open handles
jest --detectOpenHandles
# Run tests serially to find interactions
jest --runInBandCommon Debug Patterns
// Check what's in the DOM
test('debug queries', () => {
render(<MyComponent />);
// Log all available roles
screen.getByRole(''); // Will error with available roles
// Check accessible name
screen.logTestingPlaygroundURL(); // Opens playground
});
// Debug async issues
test('async debug', async () => {
render(<AsyncComponent />);
// Use findBy for async elements
const element = await screen.findByText('Loaded');
// Log state at each step
screen.debug();
});CI/CD Integration
GitHub Actions Workflow
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test -- --coverage --ci
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.infoJest CI Configuration
// jest.config.js
module.exports = {
// ... other config
// CI-specific settings
...(process.env.CI && {
maxWorkers: 2,
ci: true,
coverageReporters: ['lcov', 'text-summary'],
}),
// Coverage thresholds
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};Caching Dependencies
# In GitHub Actions
- name: Cache Jest
uses: actions/cache@v3
with:
path: |
node_modules/.cache/jest
key: jest-${{ runner.os }}-${{ hashFiles('**/jest.config.js') }}Common Issues & Solutions
Issue: Tests are slow
- Use
jest.mock()for expensive modules - Run tests in parallel with
--maxWorkers - Use
beforeAllfor expensive setup - Mock network requests with MSW
Issue: Flaky tests
- Mock timers for timing-dependent code
- Use
waitForfor async state changes - Avoid shared mutable state
- Use
findByqueries for async elements
Issue: Mock not working
- Ensure mock is before import
- Use
jest.resetModules()between tests - Check module path matches exactly
- Use
jest.doMock()for dynamic mocks
Issue: Memory leaks
- Clean up in
afterEach - Mock timers with
jest.useFakeTimers() - Use
--detectLeaksflag - Check for unresolved promises
Examples
Example 1: Testing a React Component
When testing React components: 1. Check for React Testing Library usage 2. Verify proper queries (getByRole, getByLabelText) 3. Test user interactions with userEvent 4. Assert on accessible elements
Example 2: Testing API Calls
When testing code that makes API calls: 1. Mock fetch or axios at module level 2. Test success and error scenarios 3. Verify request parameters 4. Test loading states
Version Compatibility
The patterns in this skill require the following minimum versions:
| Package | Minimum Version | Features Used |
|---|---|---|
| Jest | 29.0+ | Modern mock APIs, ESM support |
| @testing-library/react | 14.0+ | renderHook in main package |
| @testing-library/user-event | 14.0+ | userEvent.setup() API |
| msw | 2.0+ | http, HttpResponse (v1 used rest, ctx) |
| @testing-library/jest-dom | 6.0+ | Modern matchers |
Migration Notes
MSW v1 → v2:
// v1 (deprecated)
import { rest } from 'msw';
rest.get('/api', (req, res, ctx) => res(ctx.json(data)));
// v2 (current)
import { http, HttpResponse } from 'msw';
http.get('/api', () => HttpResponse.json(data));user-event v13 → v14:
// v13 (deprecated)
userEvent.click(button);
// v14 (current)
const user = userEvent.setup();
await user.click(button);Important Notes
- Jest is automatically invoked by Claude when relevant
- Always check for jest.config.js/ts for project-specific settings
- Use
{baseDir}variable to reference skill resources - Prefer Testing Library queries over direct DOM access for React
/**
* Jest Test File Template
*
* Usage:
* 1. Copy this file to your __tests__ directory or next to your source file
* 2. Rename to match your file (e.g., myModule.test.ts)
* 3. Update imports and test cases
*/
// === UNIT TEST TEMPLATE ===
import { functionToTest, ClassToTest } from '../myModule';
describe('functionToTest', () => {
// Setup/teardown
beforeEach(() => {
// Reset state before each test
});
afterEach(() => {
// Cleanup after each test
jest.clearAllMocks();
});
describe('happy path', () => {
it('should return expected result for valid input', () => {
// Arrange
const input = { key: 'value' };
const expected = { result: 'expected' };
// Act
const result = functionToTest(input);
// Assert
expect(result).toEqual(expected);
});
it('should handle multiple inputs correctly', () => {
// Arrange
const inputs = [1, 2, 3];
// Act
const results = inputs.map(functionToTest);
// Assert
expect(results).toHaveLength(3);
results.forEach(result => {
expect(result).toBeDefined();
});
});
});
describe('error handling', () => {
it('should throw error for invalid input', () => {
// Arrange
const invalidInput = null;
// Act & Assert
expect(() => functionToTest(invalidInput)).toThrow('Invalid input');
});
it('should throw specific error type', () => {
// Arrange
const invalidInput = {};
// Act & Assert
expect(() => functionToTest(invalidInput)).toThrow(ValidationError);
});
});
describe('edge cases', () => {
it('should handle empty input', () => {
expect(functionToTest([])).toEqual([]);
expect(functionToTest('')).toBe('');
expect(functionToTest({})).toEqual({});
});
it('should handle boundary values', () => {
expect(functionToTest(Number.MAX_SAFE_INTEGER)).toBeDefined();
expect(functionToTest(0)).toBeDefined();
expect(functionToTest(-1)).toBeDefined();
});
});
});
// === ASYNC TEST TEMPLATE ===
describe('asyncFunction', () => {
it('should resolve with data', async () => {
// Arrange
const input = 'test';
// Act
const result = await asyncFunction(input);
// Assert
expect(result).toEqual({ data: 'test' });
});
it('should reject with error', async () => {
// Arrange
const invalidInput = null;
// Act & Assert
await expect(asyncFunction(invalidInput)).rejects.toThrow('Error');
});
it('should handle timeout', async () => {
jest.useFakeTimers();
const promise = asyncFunctionWithTimeout();
jest.advanceTimersByTime(5000);
await expect(promise).rejects.toThrow('Timeout');
jest.useRealTimers();
});
});
// === CLASS TEST TEMPLATE ===
describe('ClassToTest', () => {
let instance: ClassToTest;
beforeEach(() => {
instance = new ClassToTest();
});
describe('constructor', () => {
it('should initialize with default values', () => {
expect(instance.property).toBe('default');
});
it('should accept configuration', () => {
const configured = new ClassToTest({ option: 'value' });
expect(configured.option).toBe('value');
});
});
describe('method', () => {
it('should update state', () => {
instance.method('new value');
expect(instance.property).toBe('new value');
});
});
});
// === MOCK TEST TEMPLATE ===
// Mock external dependency
jest.mock('../externalService');
import { externalService } from '../externalService';
const mockExternalService = externalService as jest.Mocked<typeof externalService>;
describe('functionWithDependency', () => {
beforeEach(() => {
mockExternalService.fetch.mockReset();
});
it('should call external service', async () => {
// Arrange
mockExternalService.fetch.mockResolvedValue({ data: 'mocked' });
// Act
const result = await functionWithDependency('input');
// Assert
expect(mockExternalService.fetch).toHaveBeenCalledWith('input');
expect(result).toEqual({ data: 'mocked' });
});
it('should handle service error', async () => {
// Arrange
mockExternalService.fetch.mockRejectedValue(new Error('Service error'));
// Act & Assert
await expect(functionWithDependency('input')).rejects.toThrow('Service error');
});
});
// === REACT COMPONENT TEST TEMPLATE ===
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MyComponent } from '../MyComponent';
describe('MyComponent', () => {
it('should render correctly', () => {
render(<MyComponent />);
expect(screen.getByRole('heading')).toHaveTextContent('Title');
expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
});
it('should handle user interaction', async () => {
const user = userEvent.setup();
const onSubmit = jest.fn();
render(<MyComponent onSubmit={onSubmit} />);
await user.type(screen.getByLabelText('Name'), 'John');
await user.click(screen.getByRole('button', { name: 'Submit' }));
expect(onSubmit).toHaveBeenCalledWith({ name: 'John' });
});
it('should display loading state', async () => {
render(<MyComponent />);
expect(screen.getByText('Loading...')).toBeInTheDocument();
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
});
expect(screen.getByText('Content')).toBeInTheDocument();
});
it('should display error state', async () => {
// Mock error response
server.use(
http.get('/api/data', () => {
return HttpResponse.json({ error: 'Failed' }, { status: 500 });
})
);
render(<MyComponent />);
await waitFor(() => {
expect(screen.getByRole('alert')).toHaveTextContent('Error');
});
});
});
// === HOOK TEST TEMPLATE ===
import { renderHook, act } from '@testing-library/react';
import { useCustomHook } from '../useCustomHook';
describe('useCustomHook', () => {
it('should return initial state', () => {
const { result } = renderHook(() => useCustomHook());
expect(result.current.value).toBe(0);
expect(result.current.isLoading).toBe(false);
});
it('should update state', () => {
const { result } = renderHook(() => useCustomHook());
act(() => {
result.current.increment();
});
expect(result.current.value).toBe(1);
});
it('should handle async operations', async () => {
const { result } = renderHook(() => useCustomHook());
await act(async () => {
await result.current.fetchData();
});
expect(result.current.data).toBeDefined();
});
});
Jest Quick Reference
Common Matchers
Equality
expect(value).toBe(expected); // Strict equality (===)
expect(value).toEqual(expected); // Deep equality
expect(value).toStrictEqual(expected); // Deep + type equalityTruthiness
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).toBeLessThanOrEqual(5);
expect(value).toBeCloseTo(0.3, 5); // Floating pointStrings
expect(string).toMatch(/regex/);
expect(string).toContain('substring');
expect(string).toHaveLength(5);Arrays/Iterables
expect(array).toContain(item);
expect(array).toContainEqual(item); // Deep equality
expect(array).toHaveLength(3);
expect(array).toEqual(expect.arrayContaining([1, 2]));Objects
expect(object).toHaveProperty('key');
expect(object).toHaveProperty('key', value);
expect(object).toMatchObject({ key: value });
expect(object).toEqual(expect.objectContaining({ key: value }));Functions/Errors
expect(fn).toThrow();
expect(fn).toThrow(Error);
expect(fn).toThrow('error message');
expect(fn).toThrow(/regex/);---
Mock Functions
Creating Mocks
const mockFn = jest.fn();
const mockFn = jest.fn(() => 'default');
const mockFn = jest.fn().mockReturnValue('value');
const mockFn = jest.fn().mockResolvedValue('async');
const mockFn = jest.fn().mockRejectedValue(new Error());Mock Implementations
mockFn.mockImplementation(fn);
mockFn.mockImplementationOnce(fn);
mockFn.mockReturnValue(value);
mockFn.mockReturnValueOnce(value);
mockFn.mockResolvedValue(value);
mockFn.mockResolvedValueOnce(value);Mock Assertions
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith(arg1, arg2);
expect(mockFn).toHaveBeenLastCalledWith(arg);
expect(mockFn).toHaveBeenNthCalledWith(1, arg);
expect(mockFn).toHaveReturnedWith(value);Mock Properties
mockFn.mock.calls; // [[arg1, arg2], [arg3]]
mockFn.mock.results; // [{ type: 'return', value: 1 }]
mockFn.mock.instances; // [mockInstance]Clearing Mocks
mockFn.mockClear(); // Clear calls/results
mockFn.mockReset(); // Clear + remove implementation
mockFn.mockRestore(); // Restore original (spies only)
jest.clearAllMocks();
jest.resetAllMocks();---
Module Mocking
Basic Module Mock
jest.mock('./module');
jest.mock('./module', () => ({
fn: jest.fn(),
value: 'mocked',
}));Partial Mock
jest.mock('./module', () => ({
...jest.requireActual('./module'),
specificFn: jest.fn(),
}));Manual Mocks
__mocks__/
moduleName.ts // Auto-used when jest.mock('moduleName')Mocking Node Modules
jest.mock('axios');
import axios from 'axios';
const mockedAxios = axios as jest.Mocked<typeof axios>;---
Timer Mocks
jest.useFakeTimers();
jest.useRealTimers();
jest.advanceTimersByTime(1000);
jest.runAllTimers();
jest.runOnlyPendingTimers();
jest.advanceTimersToNextTimer();
jest.setSystemTime(new Date('2024-01-01'));
jest.getRealSystemTime();---
Async Testing
Promises
// Return promise
test('async', () => {
return promise.then(data => expect(data).toBe('value'));
});
// Async/await
test('async', async () => {
const data = await asyncFn();
expect(data).toBe('value');
});
// Resolves/rejects
test('async', async () => {
await expect(asyncFn()).resolves.toBe('value');
await expect(asyncFn()).rejects.toThrow();
});Callbacks
test('callback', done => {
asyncFn(data => {
expect(data).toBe('value');
done();
});
});---
Test Lifecycle
beforeAll(() => {}); // Once before all tests
afterAll(() => {}); // Once after all tests
beforeEach(() => {}); // Before each test
afterEach(() => {}); // After each test---
Test Organization
describe('group', () => {
describe('nested', () => {
test('test', () => {});
it('alias for test', () => {});
});
});
test.only('run only this', () => {});
test.skip('skip this', () => {});
test.todo('implement later');
test.each([
[1, 2, 3],
[2, 3, 5],
])('add(%i, %i) = %i', (a, b, expected) => {
expect(a + b).toBe(expected);
});---
CLI Commands
# Run tests
jest
jest --watch # Watch mode
jest --watchAll # Watch all files
jest path/to/test # Specific test
jest --testNamePattern="pattern"
# Debug
jest --verbose
jest --detectOpenHandles
jest --runInBand # Sequential
jest --debug
# Coverage
jest --coverage
jest --coverageThreshold='{"global":{"lines":80}}'
jest --collectCoverageFrom='src/**/*.ts'
# Other
jest --clearCache
jest --listTests
jest --showConfig---
Configuration (jest.config.js)
module.exports = {
// Test environment
testEnvironment: 'node', // or 'jsdom'
// Test files
testMatch: ['**/*.test.ts'],
testPathIgnorePatterns: ['/node_modules/'],
// Transform
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
// Modules
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
// Setup
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
// Coverage
collectCoverageFrom: ['src/**/*.ts'],
coverageThreshold: {
global: { branches: 80, functions: 80, lines: 80 },
},
};---
React Testing Library
Queries
// Single element (throws if not found)
getByRole, getByLabelText, getByText, getByTestId
// Single element (returns null)
queryByRole, queryByLabelText, queryByText
// Async (waits for element)
findByRole, findByLabelText, findByText
// Multiple elements
getAllByRole, queryAllByRole, findAllByRoleUser Events
import userEvent from '@testing-library/user-event';
const user = userEvent.setup();
await user.click(element);
await user.type(input, 'text');
await user.clear(input);
await user.selectOptions(select, 'value');
await user.tab();Async Utilities
await waitFor(() => expect(element).toBeVisible());
await waitForElementToBeRemoved(element);#!/bin/bash
# Jest Project Setup Checker
# Validates that a project has Jest properly configured
set -e
echo "🃏 Jest Setup Checker"
echo "====================="
echo ""
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
ERRORS=0
WARNINGS=0
# Check for package.json
if [ ! -f "package.json" ]; then
echo -e "${RED}❌ package.json not found${NC}"
exit 1
fi
echo "📦 Checking dependencies..."
# Check for Jest
if grep -q '"jest"' package.json || grep -q '"@jest/core"' package.json; then
VERSION=$(grep -o '"jest": *"[^"]*"' package.json | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "installed")
echo -e "${GREEN}✅ Jest installed: $VERSION${NC}"
else
echo -e "${RED}❌ Jest not found${NC}"
echo " Run: npm install -D jest"
((ERRORS++))
fi
# Check for TypeScript support
if grep -q '"ts-jest"' package.json; then
echo -e "${GREEN}✅ ts-jest installed${NC}"
elif grep -q '"@swc/jest"' package.json; then
echo -e "${GREEN}✅ @swc/jest installed${NC}"
elif grep -q '"babel-jest"' package.json; then
echo -e "${GREEN}✅ babel-jest installed${NC}"
else
if grep -q '"typescript"' package.json; then
echo -e "${YELLOW}⚠ TypeScript found but no Jest transformer${NC}"
echo " Run: npm install -D ts-jest"
((WARNINGS++))
fi
fi
# Check for Testing Library
if grep -q '"@testing-library/react"' package.json; then
echo -e "${GREEN}✅ @testing-library/react installed${NC}"
if grep -q '"@testing-library/jest-dom"' package.json; then
echo -e "${GREEN} ✓ jest-dom matchers available${NC}"
else
echo -e "${YELLOW} ⚠ Consider adding @testing-library/jest-dom${NC}"
((WARNINGS++))
fi
if grep -q '"@testing-library/user-event"' package.json; then
echo -e "${GREEN} ✓ user-event installed${NC}"
else
echo -e "${YELLOW} ⚠ Consider adding @testing-library/user-event${NC}"
((WARNINGS++))
fi
fi
# Check for MSW
if grep -q '"msw"' package.json; then
echo -e "${GREEN}✅ MSW installed for network mocking${NC}"
fi
echo ""
echo "⚙️ Checking configuration..."
# Check for Jest config
if [ -f "jest.config.ts" ] || [ -f "jest.config.js" ] || [ -f "jest.config.json" ]; then
CONFIG_FILE=$(ls jest.config.* 2>/dev/null | head -1)
echo -e "${GREEN}✅ Config file found: $CONFIG_FILE${NC}"
# Check config contents
if grep -q "testEnvironment" "$CONFIG_FILE"; then
echo -e "${GREEN} ✓ testEnvironment configured${NC}"
fi
if grep -q "setupFilesAfterEnv" "$CONFIG_FILE"; then
echo -e "${GREEN} ✓ Setup files configured${NC}"
else
echo -e "${YELLOW} ⚠ No setupFilesAfterEnv (for jest-dom, MSW, etc.)${NC}"
((WARNINGS++))
fi
if grep -q "coverageThreshold" "$CONFIG_FILE"; then
echo -e "${GREEN} ✓ Coverage thresholds set${NC}"
else
echo -e "${YELLOW} ⚠ No coverage thresholds configured${NC}"
((WARNINGS++))
fi
if grep -q "moduleNameMapper" "$CONFIG_FILE"; then
echo -e "${GREEN} ✓ Module aliases configured${NC}"
fi
elif grep -q '"jest"' package.json && grep -A 100 '"jest"' package.json | grep -q '"testEnvironment"'; then
echo -e "${GREEN}✅ Jest configured in package.json${NC}"
else
echo -e "${RED}❌ No Jest configuration found${NC}"
echo " Create jest.config.ts or add jest section to package.json"
((ERRORS++))
fi
# Check for setup file
if [ -f "jest.setup.ts" ] || [ -f "jest.setup.js" ] || [ -f "setupTests.ts" ]; then
SETUP_FILE=$(ls jest.setup.* setupTests.* 2>/dev/null | head -1)
echo -e "${GREEN}✅ Setup file found: $SETUP_FILE${NC}"
fi
echo ""
echo "🧪 Checking test files..."
# Count test files
TEST_COUNT=$(find . -name "*.test.ts" -o -name "*.test.tsx" -o -name "*.test.js" -o -name "*.spec.ts" 2>/dev/null | grep -v node_modules | wc -l)
if [ "$TEST_COUNT" -gt 0 ]; then
echo -e "${GREEN}✅ Found $TEST_COUNT test file(s)${NC}"
else
echo -e "${YELLOW}⚠ No test files found${NC}"
((WARNINGS++))
fi
# Check __mocks__ directory
if [ -d "__mocks__" ] || find . -name "__mocks__" -type d 2>/dev/null | grep -q .; then
echo -e "${GREEN}✅ Manual mocks directory found${NC}"
fi
echo ""
echo "📜 Checking npm scripts..."
# Check for test script
if grep -q '"test"' package.json; then
TEST_SCRIPT=$(grep '"test"' package.json | head -1)
if echo "$TEST_SCRIPT" | grep -q "jest"; then
echo -e "${GREEN}✅ Test script uses Jest${NC}"
fi
if grep -q '"test:watch"' package.json; then
echo -e "${GREEN} ✓ Watch mode script available${NC}"
fi
if grep -q '"test:coverage"' package.json; then
echo -e "${GREEN} ✓ Coverage script available${NC}"
fi
fi
# Check for CI configuration
echo ""
echo "🔄 Checking CI/CD..."
if [ -f ".github/workflows/test.yml" ] || grep -q "jest" .github/workflows/*.yml 2>/dev/null; then
echo -e "${GREEN}✅ GitHub Actions test workflow found${NC}"
else
echo -e "${YELLOW}⚠ No CI test configuration found${NC}"
((WARNINGS++))
fi
# Summary
echo ""
echo "====================="
echo "📊 Summary"
echo "====================="
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
echo -e "${GREEN}✅ All checks passed!${NC}"
exit 0
elif [ $ERRORS -eq 0 ]; then
echo -e "${YELLOW}⚠ $WARNINGS warning(s) found${NC}"
exit 0
else
echo -e "${RED}❌ $ERRORS error(s), $WARNINGS warning(s)${NC}"
exit 1
fi
{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-01-16T20:35:14.670Z",
"slug": "c0ntr0lledcha0s-jest-testing",
"source_url": "https://github.com/C0ntr0lledCha0s/claude-code-plugin-automations/tree/main/testing-expert/skills/jest-testing",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "2b9153f943f5c44c1395cfa87fb40d03b965dc1909961d38196826de9a6183e5",
"tree_hash": "72a7afc4c79913e57e04f8d25cc3e31f88b6a727bd56d99d8664e572186aee67"
},
"skill": {
"name": "jest-testing",
"description": "Automatically activated when user works with Jest tests, mentions Jest configuration, asks about Jest matchers/mocks, or has files matching *.test.js, *.test.ts, jest.config.*. Provides Jest-specific expertise for testing React, Node.js, and JavaScript applications. Also applies to Vitest due to API compatibility. Does NOT handle general quality analysis - use analyzing-test-quality for that.",
"summary": "Automatically activated when user works with Jest tests, mentions Jest configuration, asks about Jes...",
"icon": "🃏",
"version": "1.1.0",
"author": "C0ntr0lledCha0s",
"license": "MIT",
"category": "coding",
"tags": [
"testing",
"jest",
"javascript",
"typescript",
"react"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"network",
"filesystem",
"external_commands",
"env_access"
]
},
"security_audit": {
"risk_level": "safe",
"is_blocked": false,
"safe_to_publish": true,
"summary": "This is a documentation-only skill containing Jest testing guides, code examples, and a read-only validation script. All static findings are false positives: network patterns are MSW library references for test mocking, external_commands are CLI examples in markdown, path traversal is TypeScript import syntax, and 'weak cryptographic algorithm' patterns match unrelated code. The check-jest-setup.sh script only reads files to validate configuration without modification. No malicious intent or dangerous patterns exist.",
"risk_factor_evidence": [
{
"factor": "network",
"evidence": [
{
"file": "assets/test-file.template.ts",
"line_start": 224,
"line_end": 224
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 139,
"line_end": 139
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 140,
"line_end": 140
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 140,
"line_end": 140
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 141,
"line_end": 141
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 141,
"line_end": 141
},
{
"file": "skill-report.json",
"line_start": 6,
"line_end": 6
},
{
"file": "SKILL.md",
"line_start": 301,
"line_end": 301
},
{
"file": "SKILL.md",
"line_start": 343,
"line_end": 343
},
{
"file": "SKILL.md",
"line_start": 360,
"line_end": 360
},
{
"file": "SKILL.md",
"line_start": 657,
"line_end": 657
},
{
"file": "SKILL.md",
"line_start": 630,
"line_end": 630
}
]
},
{
"factor": "filesystem",
"evidence": [
{
"file": "assets/test-file.template.ts",
"line_start": 12,
"line_end": 12
},
{
"file": "assets/test-file.template.ts",
"line_start": 152,
"line_end": 152
},
{
"file": "assets/test-file.template.ts",
"line_start": 153,
"line_end": 153
},
{
"file": "assets/test-file.template.ts",
"line_start": 187,
"line_end": 187
},
{
"file": "assets/test-file.template.ts",
"line_start": 240,
"line_end": 240
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 82,
"line_end": 82
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 117,
"line_end": 117
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 125,
"line_end": 125
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 135,
"line_end": 135
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 162,
"line_end": 162
},
{
"file": "SKILL.md",
"line_start": 337,
"line_end": 337
},
{
"file": "SKILL.md",
"line_start": 589,
"line_end": 589
}
]
},
{
"factor": "external_commands",
"evidence": [
{
"file": "references/jest-cheatsheet.md",
"line_start": 6,
"line_end": 10
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 10,
"line_end": 13
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 13,
"line_end": 19
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 19,
"line_end": 22
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 22,
"line_end": 28
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 28,
"line_end": 31
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 31,
"line_end": 35
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 35,
"line_end": 38
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 38,
"line_end": 43
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 43,
"line_end": 46
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 46,
"line_end": 51
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 51,
"line_end": 54
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 54,
"line_end": 59
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 59,
"line_end": 66
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 66,
"line_end": 72
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 72,
"line_end": 75
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 75,
"line_end": 82
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 82,
"line_end": 85
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 85,
"line_end": 92
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 92,
"line_end": 95
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 95,
"line_end": 99
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 99,
"line_end": 102
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 102,
"line_end": 108
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 108,
"line_end": 115
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 115,
"line_end": 121
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 121,
"line_end": 124
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 124,
"line_end": 129
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 129,
"line_end": 132
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 132,
"line_end": 135
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 135,
"line_end": 138
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 138,
"line_end": 142
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 142,
"line_end": 148
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 148,
"line_end": 159
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 159,
"line_end": 166
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 166,
"line_end": 183
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 183,
"line_end": 186
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 186,
"line_end": 193
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 193,
"line_end": 199
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 199,
"line_end": 204
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 204,
"line_end": 210
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 210,
"line_end": 228
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 228,
"line_end": 234
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 234,
"line_end": 257
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 257,
"line_end": 263
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 263,
"line_end": 291
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 291,
"line_end": 298
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 298,
"line_end": 310
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 310,
"line_end": 313
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 313,
"line_end": 322
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 322,
"line_end": 325
},
{
"file": "references/jest-cheatsheet.md",
"line_start": 325,
"line_end": 328
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 30,
"line_end": 30
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 82,
"line_end": 82
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 117,
"line_end": 117
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 125,
"line_end": 125
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 144,
"line_end": 144
},
{
"file": "scripts/check-jest-setup.sh",
"line_start": 1,
"line_end": 1
},
{
"file": "SKILL.md",
"line_start": 36,
"line_end": 36
},
{
"file": "SKILL.md",
"line_start": 36,
"line_end": 36
},
{
"file": "SKILL.md",
"line_start": 36,
"line_end": 36
},
{
"file": "SKILL.md",
"line_start": 36,
"line_end": 36
},
{
"file": "SKILL.md",
"line_start": 45,
"line_end": 45
},
{
"file": "SKILL.md",
"line_start": 46,
"line_end": 46
},
{
"file": "SKILL.md",
"line_start": 47,
"line_end": 47
},
{
"file": "SKILL.md",
"line_start": 48,
"line_end": 48
},
{
"file": "SKILL.md",
"line_start": 58,
"line_end": 58
},
{
"file": "SKILL.md",
"line_start": 67,
"line_end": 85
},
{
"file": "SKILL.md",
"line_start": 85,
"line_end": 90
},
{
"file": "SKILL.md",
"line_start": 90,
"line_end": 95
},
{
"file": "SKILL.md",
"line_start": 95,
"line_end": 98
},
{
"file": "SKILL.md",
"line_start": 98,
"line_end": 102
},
{
"file": "SKILL.md",
"line_start": 102,
"line_end": 105
},
{
"file": "SKILL.md",
"line_start": 105,
"line_end": 109
},
{
"file": "SKILL.md",
"line_start": 109,
"line_end": 112
},
{
"file": "SKILL.md",
"line_start": 112,
"line_end": 120
},
{
"file": "SKILL.md",
"line_start": 120,
"line_end": 123
},
{
"file": "SKILL.md",
"line_start": 123,
"line_end": 136
},
{
"file": "SKILL.md",
"line_start": 136,
"line_end": 141
},
{
"file": "SKILL.md",
"line_start": 141,
"line_end": 162
},
{
"file": "SKILL.md",
"line_start": 162,
"line_end": 167
},
{
"file": "SKILL.md",
"line_start": 167,
"line_end": 193
},
{
"file": "SKILL.md",
"line_start": 193,
"line_end": 196
},
{
"file": "SKILL.md",
"line_start": 196,
"line_end": 209
},
{
"file": "SKILL.md",
"line_start": 209,
"line_end": 212
},
{
"file": "SKILL.md",
"line_start": 212,
"line_end": 240
},
{
"file": "SKILL.md",
"line_start": 240,
"line_end": 243
},
{
"file": "SKILL.md",
"line_start": 243,
"line_end": 268
},
{
"file": "SKILL.md",
"line_start": 268,
"line_end": 271
},
{
"file": "SKILL.md",
"line_start": 271,
"line_end": 291
},
{
"file": "SKILL.md",
"line_start": 291,
"line_end": 296
},
{
"file": "SKILL.md",
"line_start": 296,
"line_end": 323
},
{
"file": "SKILL.md",
"line_start": 323,
"line_end": 326
},
{
"file": "SKILL.md",
"line_start": 326,
"line_end": 333
},
{
"file": "SKILL.md",
"line_start": 333,
"line_end": 336
},
{
"file": "SKILL.md",
"line_start": 336,
"line_end": 371
},
{
"file": "SKILL.md",
"line_start": 371,
"line_end": 374
},
{
"file": "SKILL.md",
"line_start": 374,
"line_end": 397
},
{
"file": "SKILL.md",
"line_start": 397,
"line_end": 402
},
{
"file": "SKILL.md",
"line_start": 402,
"line_end": 411
},
{
"file": "SKILL.md",
"line_start": 411,
"line_end": 412
},
{
"file": "SKILL.md",
"line_start": 412,
"line_end": 424
},
{
"file": "SKILL.md",
"line_start": 424,
"line_end": 425
},
{
"file": "SKILL.md",
"line_start": 425,
"line_end": 439
},
{
"file": "SKILL.md",
"line_start": 439,
"line_end": 442
},
{
"file": "SKILL.md",
"line_start": 442,
"line_end": 464
},
{
"file": "SKILL.md",
"line_start": 464,
"line_end": 469
},
{
"file": "SKILL.md",
"line_start": 469,
"line_end": 484
},
{
"file": "SKILL.md",
"line_start": 484,
"line_end": 487
},
{
"file": "SKILL.md",
"line_start": 487,
"line_end": 496
},
{
"file": "SKILL.md",
"line_start": 496,
"line_end": 499
},
{
"file": "SKILL.md",
"line_start": 499,
"line_end": 521
},
{
"file": "SKILL.md",
"line_start": 521,
"line_end": 526
},
{
"file": "SKILL.md",
"line_start": 526,
"line_end": 555
},
{
"file": "SKILL.md",
"line_start": 555,
"line_end": 558
},
{
"file": "SKILL.md",
"line_start": 558,
"line_end": 580
},
{
"file": "SKILL.md",
"line_start": 580,
"line_end": 583
},
{
"file": "SKILL.md",
"line_start": 583,
"line_end": 591
},
{
"file": "SKILL.md",
"line_start": 591,
"line_end": 596
},
{
"file": "SKILL.md",
"line_start": 596,
"line_end": 597
},
{
"file": "SKILL.md",
"line_start": 597,
"line_end": 598
},
{
"file": "SKILL.md",
"line_start": 598,
"line_end": 603
},
{
"file": "SKILL.md",
"line_start": 603,
"line_end": 605
},
{
"file": "SKILL.md",
"line_start": 605,
"line_end": 609
},
{
"file": "SKILL.md",
"line_start": 609,
"line_end": 611
},
{
"file": "SKILL.md",
"line_start": 611,
"line_end": 614
},
{
"file": "SKILL.md",
"line_start": 614,
"line_end": 615
},
{
"file": "SKILL.md",
"line_start": 615,
"line_end": 616
},
{
"file": "SKILL.md",
"line_start": 616,
"line_end": 650
},
{
"file": "SKILL.md",
"line_start": 650,
"line_end": 658
},
{
"file": "SKILL.md",
"line_start": 658,
"line_end": 661
},
{
"file": "SKILL.md",
"line_start": 661,
"line_end": 668
},
{
"file": "SKILL.md",
"line_start": 668,
"line_end": 674
}
]
},
{
"factor": "env_access",
"evidence": [
{
"file": "SKILL.md",
"line_start": 564,
"line_end": 564
},
{
"file": "SKILL.md",
"line_start": 564,
"line_end": 564
}
]
}
],
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [],
"dangerous_patterns": [],
"files_scanned": 5,
"total_lines": 1675,
"audit_model": "claude",
"audited_at": "2026-01-16T20:35:14.670Z"
},
"content": {
"user_title": "Write Jest tests for JavaScript apps",
"value_statement": "Users need guidance writing effective Jest tests for JavaScript and TypeScript applications. This skill provides comprehensive Jest expertise including configuration, matchers, mocking strategies, and React Testing Library patterns to write reliable, maintainable tests.",
"seo_keywords": [
"jest testing",
"jest framework",
"claude code",
"javascript testing",
"typescript testing",
"react testing library",
"jest mocks",
"test coverage",
"claude",
"codex"
],
"actual_capabilities": [
"Configure Jest for JavaScript and TypeScript projects",
"Write matchers and assertions including custom matchers",
"Implement mock functions, modules, and timers",
"Test React components with React Testing Library",
"Handle async testing patterns and callbacks",
"Set up MSW for network request mocking"
],
"limitations": [
"Does not install or modify project dependencies",
"Does not execute tests or report results",
"Does not analyze test quality or coverage metrics",
"Limited to Jest and compatible frameworks (Vitest)"
],
"use_cases": [
{
"target_user": "Frontend developers",
"title": "Test React components",
"description": "Write component tests using React Testing Library with proper query prioritization and user event simulation"
},
{
"target_user": "Backend developers",
"title": "Test Node.js services",
"description": "Create unit and integration tests for API endpoints, database operations, and async business logic"
},
{
"target_user": "Full-stack engineers",
"title": "Mock external APIs",
"description": "Configure MSW handlers to simulate API responses and test error scenarios without real network calls"
}
],
"prompt_templates": [
{
"title": "Basic test setup",
"scenario": "Write a simple unit test",
"prompt": "Write a unit test for my function that calculates the sum of two numbers. Use proper arrange-act-assert structure."
},
{
"title": "Mock external service",
"scenario": "Test with mocked dependencies",
"prompt": "Help me write a test that mocks an external API call using jest.mock. The function fetches user data from /api/user/:id."
},
{
"title": "Test React component",
"scenario": "Test component interactions",
"prompt": "Write a test for my LoginForm component. It has email and password fields. Test that clicking submit calls the onSubmit prop with the form data."
},
{
"title": "Async error handling",
"scenario": "Test async error paths",
"prompt": "Help me test an async function that should throw an error when the API returns a 500 status. Use MSW to mock the error response."
}
],
"output_examples": [
{
"input": "Write a test for a function that fetches user data",
"output": [
"Import the function and mock the API module",
"Set up mockResolvedValue for the happy path",
"Assert the function calls the API with correct parameters",
"Assert the returned data matches expected structure",
"Add a separate test for error handling with mockRejectedValue"
]
},
{
"input": "How do I test if a component shows an error message",
"output": [
"Render the component with MSW handler returning 500 error",
"Use waitFor to wait for the error element to appear",
"Assert screen.getByRole('alert') has the expected error text",
"Test that the error state is properly managed"
]
},
{
"input": "Set up Jest for my TypeScript project",
"output": [
"Install jest, ts-jest, @types/jest, and jest-dom",
"Create jest.config.ts with testEnvironment: 'node'",
"Add transform for TypeScript files using ts-jest",
"Configure testMatch pattern for *.test.ts files",
"Add jest.setup.ts for importing jest-dom matchers"
]
}
],
"best_practices": [
"Use meaningful test descriptions that explain what is being tested and expected outcome",
"Follow the arrange-act-assert pattern for clear test structure",
"Mock external dependencies and network calls to keep tests fast and reliable",
"Use beforeEach and afterEach hooks to reset state between tests"
],
"anti_patterns": [
"Avoid testing implementation details; focus on observable behavior and outputs",
"Do not make real network calls in tests; always mock external APIs",
"Avoid brittle tests that break on minor refactoring; use flexible matchers like toMatchObject"
],
"faq": [
{
"question": "What versions of Jest are supported?",
"answer": "Jest 29.0+ is recommended for modern mock APIs and ESM support. Older versions work but some features may be unavailable."
},
{
"question": "Can I use this skill with Vitest?",
"answer": "Yes. Vitest shares a similar API with Jest and most patterns translate directly. The skill notes Vitest compatibility."
},
{
"question": "Does this skill run tests for me?",
"answer": "No. This skill provides guidance and examples for writing tests. To run tests, use the jest CLI directly."
},
{
"question": "Is my test data safe?",
"answer": "Yes. The skill only reads files and provides guidance. It never sends data externally or modifies your codebase."
},
{
"question": "Why are my tests failing randomly?",
"answer": "Common causes include shared mutable state, timing issues with async code, or missing cleanup in afterEach hooks."
},
{
"question": "How is this different from analyzing-test-quality?",
"answer": "jest-testing helps you write tests. analyzing-test-quality reviews existing tests for coverage and best practices."
}
]
},
"file_structure": [
{
"name": "assets",
"type": "dir",
"path": "assets",
"children": [
{
"name": "test-file.template.ts",
"type": "file",
"path": "assets/test-file.template.ts",
"lines": 270
}
]
},
{
"name": "references",
"type": "dir",
"path": "references",
"children": [
{
"name": "jest-cheatsheet.md",
"type": "file",
"path": "references/jest-cheatsheet.md",
"lines": 329
}
]
},
{
"name": "scripts",
"type": "dir",
"path": "scripts",
"children": [
{
"name": "check-jest-setup.sh",
"type": "file",
"path": "scripts/check-jest-setup.sh",
"lines": 185
}
]
},
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 676
}
]
}
Related skills
FAQ
Does this skill work with Vitest?
Yes. The skill states it also applies to Vitest due to API compatibility.
When does the skill activate?
It activates when you work with Jest, mention jest.config, ask about matchers or mocks, or have files matching *.test.js/ts/jsx/tsx or jest.config.*.