Mocking & Advanced
jest.fn() — Mock Functions
const mockFn = jest.fn();
// Set return value
mockFn.mockReturnValue(42);
mockFn.mockReturnValueOnce(10).mockReturnValueOnce(20);
// Async
mockFn.mockResolvedValue({ id: 1, name: 'Alice' });
mockFn.mockRejectedValue(new Error('Failed'));
// Implementation
mockFn.mockImplementation((x: number) => x * 2);
mockFn.mockImplementationOnce(() => 'first call');
// Assertions on mock
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledTimes(3);
expect(mockFn).toHaveBeenCalledWith('arg1', 42);
expect(mockFn).toHaveBeenLastCalledWith('last-arg');
expect(mockFn).toHaveBeenNthCalledWith(2, 'second-call-arg');
// Access calls
console.log(mockFn.mock.calls); // [[arg1, arg2], [arg3], ...]
console.log(mockFn.mock.results); // [{type: 'return', value: 42}, ...]
console.log(mockFn.mock.instances); // if called as constructor
// Reset / clear
mockFn.mockClear(); // clear calls, instances, results (keep implementation)
mockFn.mockReset(); // clear + remove return values/implementations
mockFn.mockRestore(); // restore original (only for jest.spyOn)jest.mock() — Module Mocking
// Auto-mock entire module
jest.mock('../services/emailService');
import { sendEmail } from '../services/emailService';
const mockedSendEmail = sendEmail as jest.MockedFunction<typeof sendEmail>;
mockedSendEmail.mockResolvedValue(undefined);
// Manual mock with factory
jest.mock('../db', () => ({
findUser: jest.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
createUser: jest.fn().mockResolvedValue({ id: 2 }),
}));
// Partial mock — keep real implementations for some exports
jest.mock('../utils', () => ({
...jest.requireActual('../utils'), // keep real implementations
generateId: jest.fn().mockReturnValue('test-id'),
}));
// Mock default export
jest.mock('../config', () => ({
default: { apiUrl: 'http://test-api', timeout: 1000 },
}));
// ES module default export
jest.mock('../logger', () => ({
__esModule: true,
default: {
info: jest.fn(),
error: jest.fn(),
},
}));jest.spyOn() — Spy on Methods
// Spy on existing method (can still call original)
const spy = jest.spyOn(userService, 'findById');
spy.mockResolvedValue({ id: 1, name: 'Alice' });
expect(spy).toHaveBeenCalledWith(1);
spy.mockRestore(); // restore original implementation
// Spy without changing behavior
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
// Spy on property
jest.spyOn(Date, 'now').mockReturnValue(1700000000000);
// Mock timers
jest.useFakeTimers();
jest.setSystemTime(new Date('2024-01-01'));
setTimeout(() => callback(), 1000);
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
jest.useRealTimers();Testing React Components
// @testing-library/react
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { UserCard } from './UserCard';
describe('UserCard', () => {
it('renders user name', () => {
render(<UserCard user={{ id: 1, name: 'Alice', email: 'a@b.com' }} />);
expect(screen.getByText('Alice')).toBeInTheDocument();
expect(screen.getByRole('heading', { name: 'Alice' })).toBeInTheDocument();
});
it('calls onDelete when button clicked', async () => {
const onDelete = jest.fn();
const user = userEvent.setup();
render(<UserCard user={{ id: 1, name: 'Alice' }} onDelete={onDelete} />);
await user.click(screen.getByRole('button', { name: /delete/i }));
expect(onDelete).toHaveBeenCalledWith(1);
});
it('shows loading state', async () => {
render(<UserCard userId={1} />);
expect(screen.getByRole('progressbar')).toBeInTheDocument();
await waitFor(() => expect(screen.getByText('Alice')).toBeInTheDocument());
});
// Prefer queries: getBy (throws), queryBy (null), findBy (async)
// getByRole > getByLabelText > getByText > getByTestId (last resort)
});Snapshot Testing
// Snapshot — save rendered output, fail when it changes
it('matches snapshot', () => {
const { container } = render(<Button label="Click me" />);
expect(container).toMatchSnapshot();
});
// Inline snapshot
expect(user).toMatchInlineSnapshot(`
Object {
"email": "alice@example.com",
"id": 1,
"name": "Alice",
}
`);
// Update snapshots: jest --updateSnapshot (or jest -u)
// Use sparingly — snapshots of large components are brittleKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free