⏳
Loading cheatsheet...
Test structure, matchers, mocking, snapshots, async testing, coverage, configuration, and React Testing Library.
// ── Common Matchers ──
describe('Common Matchers', () => {
test('equality', () => {
expect(2 + 2).toBe(4);
expect({ a: 1 }).toEqual({ a: 1 }); // deep equality
expect(null).toBeNull();
expect(undefined).toBeUndefined();
expect(7).toBeDefined();
expect(true).toBeTruthy();
expect(false).toBeFalsy();
expect(0).toBeFalsy();
expect('').toBeFalsy();
expect('hello').toBeTruthy();
});
test('numbers', () => {
expect(10).toBeGreaterThan(5);
expect(10).toBeGreaterThanOrEqual(10);
expect(5).toBeLessThan(10);
expect(5).toBeLessThanOrEqual(5);
expect(0.1 + 0.2).toBeCloseTo(0.3, 5);
expect(NaN).toBeNaN();
expect(Infinity).toBeFinite();
});
test('strings', () => {
expect('hello world').toMatch(/world/);
expect('hello world').toContain('hello');
expect('hello').toHaveLength(5);
expect('').toHaveLength(0);
});
test('arrays', () => {
expect([1, 2, 3]).toContain(2);
expect([1, 2, 3]).toEqual(expect.arrayContaining([2, 3]));
expect([{ id: 1 }]).toContainEqual({ id: 1 });
expect([1, 2, 3]).toHaveLength(3);
});
test('objects', () => {
const obj = { name: 'John', age: 30, address: { city: 'NYC' } };
expect(obj).toHaveProperty('name');
expect(obj).toHaveProperty('address.city');
expect(obj).toMatchObject({ name: 'John', age: 30 });
});
test('exceptions', () => {
const throwError = () => { throw new Error('something went wrong'); };
expect(throwError).toThrow();
expect(throwError).toThrow('something went wrong');
expect(throwError).toThrow(/wrong/);
});
test('function calls', () => {
const mockFn = jest.fn();
mockFn('hello', 'world');
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledWith('hello', 'world');
expect(mockFn).toHaveBeenLastCalledWith('hello', 'world');
});
});| Matcher | Negated | Description |
|---|---|---|
| .not.toBe() | expect(x).not.toBe(y) | Inequality check |
| .not.toContain() | expect(arr).not.toContain(x) | Does not include |
| .not.toHaveProperty() | expect(obj).not.toHaveProperty(k) | No property |
| .not.toThrow() | expect(fn).not.toThrow() | Does not throw |
| Matcher | Description |
|---|---|
| .resolves.toBe() | Awaited promise equals value |
| .resolves.toHaveLength() | Resolved array has length |
| .rejects.toThrow() | Promise rejects with error |
| .rejects.toEqual() | Rejected with specific value |
// ── Mock Functions ──
describe('Mock Functions', () => {
test('mock implementation', () => {
const mockFn = jest.fn((x: number) => x * 2);
expect(mockFn(5)).toBe(10);
expect(mockFn).toHaveBeenCalledWith(5);
expect(mockFn.mock.calls).toEqual([[5]]);
expect(mockFn.mock.results[0].value).toBe(10);
});
test('mock return values', () => {
const fn = jest.fn()
.mockReturnValueOnce('first')
.mockReturnValueOnce('second')
.mockReturnValue('default');
expect(fn()).toBe('first');
expect(fn()).toBe('second');
expect(fn()).toBe('default');
expect(fn()).toBe('default');
});
test('mock resolved values', async () => {
const fn = jest.fn().mockResolvedValue({ id: 1, name: 'Test' });
const result = await fn();
expect(result).toEqual({ id: 1, name: 'Test' });
});
test('mock rejected values', async () => {
const fn = jest.fn().mockRejectedValue(new Error('API Error'));
await expect(fn()).rejects.toThrow('API Error');
});
// ── Spying on Object Methods ──
test('spy on object method', () => {
const user = {
getName: () => 'John',
getAge: () => 30,
};
const spy = jest.spyOn(user, 'getName').mockReturnValue('Jane');
expect(user.getName()).toBe('Jane');
expect(spy).toHaveBeenCalled();
spy.mockRestore();
});
// ── Mocking Modules ──
test('mock axios module', async () => {
const axios = require('axios');
axios.get = jest.fn().mockResolvedValue({ data: { users: [] } });
// ... test code that calls axios.get
expect(axios.get).toHaveBeenCalledWith('/api/users');
});
});// ── Module Mocking ──
// __mocks__/axios.ts (auto-mocked by Jest)
const axios = {
get: jest.fn(() => Promise.resolve({ data: {} })),
post: jest.fn(() => Promise.resolve({ data: {} })),
put: jest.fn(() => Promise.resolve({ data: {} })),
delete: jest.fn(() => Promise.resolve({ data: {} })),
create: jest.fn(() => axios),
default: jest.fn(() => axios),
};
export default axios;
// ── Partial Mocking ──
// In your test file:
jest.mock('axios');
import axios from 'axios';
test('partial mock', async () => {
axios.get.mockResolvedValueOnce({ data: { id: 1 } });
axios.get.mockResolvedValueOnce({ data: { id: 2 } });
const r1 = await axios.get('/users/1');
const r2 = await axios.get('/users/2');
expect(r1.data.id).toBe(1);
expect(r2.data.id).toBe(2);
});jest.clearAllMocks() in beforeEach to ensure clean state between tests. Use jest.restoreAllMocks() to restore original implementations. Prefer jest.spyOn over full mocks when you only need to spy on specific methods.// ── Snapshot Testing ──
import React from 'react';
import { render } from '@testing-library/react';
import UserProfile from './UserProfile';
describe('UserProfile Snapshot', () => {
it('matches snapshot', () => {
const { container } = render(
<UserProfile name="John" email="john@example.com" />
);
expect(container).toMatchSnapshot();
});
it('inline snapshot', () => {
const user = { id: 1, name: 'John', role: 'admin' };
expect(user).toMatchInlineSnapshot(`
Object {
"id": 1,
"name": "John",
"role": "admin",
}
`);
});
// Property matchers for dynamic values
it('property matcher snapshot', () => {
expect({ date: new Date(), id: expect.any(Number) }).toMatchSnapshot({
date: expect.any(Date),
});
});
});
// ── Async Testing ──
describe('Async Tests', () => {
it('works with promises', async () => {
const data = await fetchUser(1);
expect(data.name).toBe('John');
});
it('works with async/await error', async () => {
await expect(fetchUser(999)).rejects.toThrow('User not found');
});
it('works with callbacks', (done) => {
function callback(data: string) {
try {
expect(data).toBe('result');
done();
} catch (err) {
done(err);
}
}
fetchData(callback);
});
it('resolves within timeout', async () => {
await expect(
new Promise(resolve => setTimeout(() => resolve('done'), 100))
).resolves.toBe('done');
}, 5000); // custom timeout
});
// ── Setup & Teardown ──
describe('Setup & Teardown', () => {
let db: any;
beforeAll(async () => {
db = await connectDatabase();
});
afterAll(async () => {
await db.disconnect();
});
beforeEach(() => {
db.clear();
});
afterEach(() => {
jest.clearAllMocks();
});
test('uses fresh database for each test', () => {
db.insert({ name: 'Test' });
expect(db.findAll()).toHaveLength(1);
});
});| Option | Description | Example |
|---|---|---|
| testEnvironment | Test environment | jsdom, node |
| transform | Module transform | babel-jest, ts-jest |
| moduleNameMapper | Path aliases | @/./src/ |
| setupFilesAfterSetup | Setup before tests | jest.setup.ts |
| coverageDirectory | Coverage output | ./coverage |
| collectCoverageFrom | Files to cover | src/**/*.{ts,tsx} |
| testPathIgnorePatterns | Exclude paths | /node_modules/ |
| coverageThreshold | Min coverage % | { global: { branches: 80 } } |
| Command | Purpose |
|---|---|
| jest | Run all tests |
| jest --watch | Watch mode |
| jest --coverage | With coverage report |
| jest --updateSnapshot | Update snapshots |
| jest -t "pattern" | Run matching tests |
| jest --verbose | Show individual test results |
| jest --detectOpenHandles | Detect async issues |
| jest --forceExit | Force exit after tests |
toBe checks for strict equality (same as ===), comparing object references.toEqual performs deep equality comparison, recursively checking all properties of objects and arrays. Use toBe for primitives and toEqual for objects and arrays.
jest.fn() creates a completely new mock function from scratch. Use it when passing mock callbacks or replacing dependencies entirely. jest.spyOn() wraps an existing object method with a spy, preserving the original implementation while tracking calls. Use it when you want to observe calls without changing behavior, or temporarily replace specific methods while keeping the rest intact.