xiaohongshu
xiaohongshu
jest
Tests JavaScript and TypeScript applications with Jest test runner including mocking, snapshot testing, and code coverage. Use when setting up testing, writing unit tests, or when user mentions Jest, test runner, or JavaScript testing.
Full skill instructions
Delightful JavaScript testing framework with zero configuration and rich mocking capabilities.
# Install
npm install -D jest @types/jest
# With TypeScript
npm install -D jest ts-jest @types/jest
npx ts-jest config:init
# Or with Babel
npm install -D jest @babel/preset-env @babel/preset-typescript
import type { Config } from 'jest';
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: ['<rootDir>/src'],
testMatch: ['**/__tests__/**/*.ts', '**/*.test.ts', '**/*.spec.ts'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/**/__tests__/**',
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
clearMocks: true,
verbose: true,
};
export default config;
import type { Config } from 'jest';
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
transform: {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.jest.json' }],
},
};
export default config;
import '@testing-library/jest-dom';
// Global mocks
global.fetch = jest.fn();
// Extend expect
expect.extend({
toBeWithinRange(received: number, floor: number, ceiling: number) {
const pass = received >= floor && received <= ceiling;
return {
pass,
message: () =>
`expected ${received} ${pass ? 'not ' : ''}to be within range ${floor} - ${ceiling}`,
};
},
});
declare global {
namespace jest {
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
}
}
}
import { describe, it, expect, test, beforeEach, afterEach } from '@jest/globals';
describe('Calculator', () => {
let calculator: Calculator;
beforeEach(() => {
calculator = new Calculator();
});
afterEach(() => {
// Cleanup
});
describe('add', () => {
it('should add two positive numbers', () => {
expect(calculator.add(1, 2)).toBe(3);
});
it('should handle negative numbers', () => {
expect(calculator.add(-1, -2)).toBe(-3);
});
test.each([
[1, 2, 3],
[0, 0, 0],
[-1, 1, 0],
[100, 200, 300],
])('add(%i, %i) should return %i', (a, b, expected) => {
expect(calculator.add(a, b)).toBe(expected);
});
});
describe('divide', () => {
it('should throw when dividing by zero', () => {
expect(() => calculator.divide(10, 0)).toThrow('Division by zero');
});
});
});
// Equality
expect(value).toBe(expected); // ===
expect(value).toEqual(expected); // Deep equality
expect(value).toStrictEqual(expected); // Deep + undefined props
// Truthiness
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();
expect(value).toBeTruthy();
expect(value).toBeFalsy();
// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3);
expect(value).toBeLessThan(5);
expect(value).toBeCloseTo(0.3, 5); // Floating point
// Strings
expect(string).toMatch(/pattern/);
expect(string).toContain('substring');
expect(string).toHaveLength(5);
// Arrays
expect(array).toContain(item);
expect(array).toContainEqual(object);
expect(array).toHaveLength(3);
// Objects
expect(object).toHaveProperty('key');
expect(object).toHaveProperty('nested.key', value);
expect(object).toMatchObject({ key: value });
// Exceptions
expect(() => fn()).toThrow();
expect(() => fn()).toThrow('message');
expect(() => fn()).toThrow(ErrorType);
// Negation
expect(value).not.toBe(other);
// Asymmetric matchers
expect(value).toEqual(expect.any(Number));
expect(value).toEqual(expect.stringContaining('sub'));
expect(value).toEqual(expect.arrayContaining([1, 2]));
expect(value).toEqual(expect.objectContaining({ key: value }));
// Return promise
test('fetches user data', () => {
return fetchUser(1).then((user) => {
expect(user.name).toBe('Alice');
});
});
// Async/await
test('fetches user data', async () => {
const user = await fetchUser(1);
expect(user.name).toBe('Alice');
});
// Resolves/rejects
test('resolves to user', async () => {
await expect(fetchUser(1)).resolves.toEqual({ name: 'Alice' });
});
test('rejects with error', async () => {
await expect(fetchUser(-1)).rejects.toThrow('User not found');
});
test('callback with done', (done) => {
fetchDataWithCallback((error, data) => {
try {
expect(error).toBeNull();
expect(data).toEqual({ success: true });
done();
} catch (e) {
done(e);
}
});
});
jest.useFakeTimers();
test('delays execution', () => {
const callback = jest.fn();
delayedCall(callback, 1000);
expect(callback).not.toHaveBeenCalled();
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalledTimes(1);
});
test('with modern timers', () => {
jest.useFakeTimers({ advanceTimers: true });
const callback = jest.fn();
setTimeout(callback, 1000);
jest.runAllTimers();
expect(callback).toHaveBeenCalled();
});
afterEach(() => {
jest.useRealTimers();
});
// Create mock function
const mockFn = jest.fn();
// With implementation
const mockAdd = jest.fn((a, b) => a + b);
// Mock return values
mockFn.mockReturnValue(42);
mockFn.mockReturnValueOnce(1).mockReturnValueOnce(2);
mockFn.mockResolvedValue({ data: 'value' });
mockFn.mockRejectedValue(new Error('Failed'));
// Assertions
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
expect(mockFn).toHaveBeenLastCalledWith('lastArg');
expect(mockFn).toHaveBeenNthCalledWith(1, 'firstCallArg');
expect(mockFn).toHaveReturnedWith(42);
// __mocks__/axios.ts
const axios = {
get: jest.fn(),
post: jest.fn(),
create: jest.fn(() => axios),
};
export default axios;
// In test file
jest.mock('axios');
import axios from 'axios';
const mockedAxios = axios as jest.Mocked<typeof axios>;
test('fetches data', async () => {
mockedAxios.get.mockResolvedValue({ data: { users: [] } });
const result = await fetchUsers();
expect(mockedAxios.get).toHaveBeenCalledWith('/api/users');
expect(result).toEqual({ users: [] });
});
// Mock specific exports
jest.mock('./utils', () => ({
...jest.requireActual('./utils'),
expensiveOperation: jest.fn(),
}));
// Mock with factory
jest.mock('./database', () => {
return {
connect: jest.fn().mockResolvedValue(true),
query: jest.fn(),
};
});
const video = {
play() {
return true;
},
};
test('plays video', () => {
const spy = jest.spyOn(video, 'play');
video.play();
expect(spy).toHaveBeenCalled();
spy.mockRestore();
});
// Spy on prototype
jest.spyOn(Date.prototype, 'toISOString').mockReturnValue('2024-01-01');
// __mocks__/fs.ts
const fs = jest.createMockFromModule('fs') as typeof import('fs');
let mockFiles: Record<string, string> = {};
fs.readFileSync = jest.fn((path: string) => {
if (path in mockFiles) {
return mockFiles[path];
}
throw new Error(`ENOENT: ${path}`);
});
(fs as any).__setMockFiles = (files: Record<string, string>) => {
mockFiles = files;
};
export default fs;
// Basic snapshot
test('renders correctly', () => {
const tree = renderer.create(<Button label="Click me" />).toJSON();
expect(tree).toMatchSnapshot();
});
// Inline snapshot
test('formats date', () => {
expect(formatDate(new Date('2024-01-15'))).toMatchInlineSnapshot(
`"January 15, 2024"`
);
});
// Property matchers for dynamic values
test('creates user', () => {
const user = createUser('Alice');
expect(user).toMatchSnapshot({
id: expect.any(String),
createdAt: expect.any(Date),
});
});
// Update snapshots: jest --updateSnapshot
# Run with coverage
jest --coverage
# Coverage report options
jest --coverage --coverageReporters="text" --coverageReporters="html"
// jest.config.ts coverage options
{
collectCoverage: true,
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/index.ts',
],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
'./src/utils/': {
branches: 100,
statements: 100,
},
},
}
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('submits form with user data', async () => {
const handleSubmit = jest.fn();
const user = userEvent.setup();
render(<LoginForm onSubmit={handleSubmit} />);
await user.type(screen.getByLabelText(/email/i), '[email protected]');
await user.type(screen.getByLabelText(/password/i), 'password123');
await user.click(screen.getByRole('button', { name: /submit/i }));
expect(handleSubmit).toHaveBeenCalledWith({
email: '[email protected]',
password: 'password123',
});
});
test('shows error on invalid input', async () => {
render(<LoginForm />);
fireEvent.click(screen.getByRole('button', { name: /submit/i }));
await waitFor(() => {
expect(screen.getByText(/email is required/i)).toBeInTheDocument();
});
});
test('fetches and displays users', async () => {
const mockUsers = [{ id: 1, name: 'Alice' }];
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockUsers),
});
render(<UserList />);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByText('Alice')).toBeInTheDocument();
});
});
# Run all tests
jest
# Watch mode
jest --watch
# Run specific file
jest path/to/test.spec.ts
# Run tests matching pattern
jest --testNamePattern="should add"
# Run only changed files
jest --onlyChanged
# Parallel execution
jest --maxWorkers=4
# Debug mode
node --inspect-brk node_modules/.bin/jest --runInBand
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience