Jest Mocking Patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Jest Mocking Patterns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill makes the agent mock dependencies in Jest deliberately and reversibly: stubbing functions with jest.fn, controlling return values with mockReturnValue/mockResolvedValue, replacing whole modules with jest.mock factories, and spying on real implementations with jest.spyOn (always restored). The guiding rule: mock the boundary, not the unit under test, and always reset state between tests so mocks never leak.
Use this skill when the agent needs to isolate code from the network, the clock, the filesystem, a database client, or any third-party module (axios, fs, a payment SDK).
clearMocks: true (or call jest.clearAllMocks() in beforeEach) so call counts and implementations never bleed across tests.jest.mock('module', factory) are lifted above imports. The factory cannot reference outer variables unless they are prefixed mock.jest.mocked() (or as jest.Mock) so the mock API is type-checked and autocompletes.toHaveBeenCalledWith to verify the boundary was called correctly.jest.fn and controlling return valuesjest.fn() is a recording stub. Drive it with mockReturnValue, mockResolvedValue, mockRejectedValue, or queue per-call values with mockReturnValueOnce.
test('jest.fn return value control', () => {
const calc = jest.fn();
calc.mockReturnValue(10); // default for every call
calc.mockReturnValueOnce(1).mockReturnValueOnce(2); // queued, then falls back
expect(calc()).toBe(1);
expect(calc()).toBe(2);
expect(calc()).toBe(10);
expect(calc).toHaveBeenCalledTimes(3);
});
test('async return values', async () => {
const fetchUser = jest.fn<Promise<{ id: number }>, [number]>();
fetchUser.mockResolvedValue({ id: 1 });
await expect(fetchUser(1)).resolves.toEqual({ id: 1 });
fetchUser.mockRejectedValueOnce(new Error('not found'));
await expect(fetchUser(99)).rejects.toThrow('not found');
});mockImplementation for logic-bearing stubsWhen the return depends on the input, supply a function. Use mockImplementationOnce for sequenced behavior.
test('mockImplementation reacts to args', () => {
const discount = jest.fn((price: number, isMember: boolean) =>
isMember ? price * 0.9 : price,
);
expect(discount(100, true)).toBe(90);
expect(discount(100, false)).toBe(100);
expect(discount).toHaveBeenLastCalledWith(100, false);
});
test('retry then succeed via mockImplementationOnce', async () => {
const send = jest
.fn<Promise<string>, []>()
.mockImplementationOnce(() => Promise.reject(new Error('503')))
.mockImplementationOnce(() => Promise.resolve('ok'));
await expect(send()).rejects.toThrow('503');
await expect(send()).resolves.toBe('ok');
});jest.mock with a factory (the hoisting rule)jest.mock replaces an entire module. Because it is hoisted above imports, any variable the factory references must be named with a mock prefix.
// notifier.ts
import { sendSms } from './sms-client';
export async function notify(phone: string, msg: string) {
await sendSms(phone, msg);
return `sent to ${phone}`;
}
// notifier.test.ts
import { notify } from './notifier';
import { sendSms } from './sms-client';
// Hoisted: the factory may only use `mock`-prefixed outer vars.
const mockSend = jest.fn();
jest.mock('./sms-client', () => ({
sendSms: (...args: unknown[]) => mockSend(...args),
}));
beforeEach(() => jest.clearAllMocks());
test('notify calls the SMS client correctly', async () => {
mockSend.mockResolvedValue(undefined);
const result = await notify('+15551234567', 'Hello');
expect(result).toBe('sent to +15551234567');
expect(sendSms).toHaveBeenCalledWith('+15551234567', 'Hello');
expect(sendSms).toHaveBeenCalledTimes(1);
});jest.spyOn with restore (override one method, keep the rest)spyOn wraps a real method so you can assert on it and optionally stub it. Always restore — restoreMocks: true in config, or mockRestore().
import * as mathUtils from './math-utils';
afterEach(() => jest.restoreAllMocks());
test('spy that still calls through', () => {
const spy = jest.spyOn(mathUtils, 'add'); // real impl runs
const sum = mathUtils.add(2, 3);
expect(sum).toBe(5);
expect(spy).toHaveBeenCalledWith(2, 3);
});
test('spy that replaces the implementation', () => {
jest.spyOn(mathUtils, 'add').mockReturnValue(42);
expect(mathUtils.add(2, 3)).toBe(42); // stubbed
// restoreAllMocks() puts the real add back after this test.
});
test('spy on Date.now for deterministic time', () => {
jest.spyOn(Date, 'now').mockReturnValue(1_700_000_000_000);
expect(Date.now()).toBe(1_700_000_000_000);
});A real-world boundary. jest.mock('axios') auto-mocks the module; jest.mocked gives a typed handle.
// user-service.ts
import axios from 'axios';
export async function getUser(id: number) {
const { data } = await axios.get(`/api/users/${id}`);
return data;
}
// user-service.test.ts
import axios from 'axios';
import { getUser } from './user-service';
jest.mock('axios');
const mockedAxios = jest.mocked(axios);
beforeEach(() => jest.clearAllMocks());
test('resolves the user from the API', async () => {
mockedAxios.get.mockResolvedValue({ data: { id: 1, name: 'Ada' } });
const user = await getUser(1);
expect(user).toEqual({ id: 1, name: 'Ada' });
expect(mockedAxios.get).toHaveBeenCalledWith('/api/users/1');
});
test('propagates a network error', async () => {
mockedAxios.get.mockRejectedValueOnce(new Error('Network Error'));
await expect(getUser(1)).rejects.toThrow('Network Error');
});requireActualKeep most of a module real, override one export. Essential when a util module mixes pure helpers with a side-effecting one.
jest.mock('./config', () => ({
...jest.requireActual('./config'),
isProduction: jest.fn().mockReturnValue(false), // override only this
}));test('debounced save fires once after the delay', () => {
jest.useFakeTimers();
const save = jest.fn();
const debounced = makeDebounced(save, 300);
debounced();
debounced();
jest.advanceTimersByTime(300);
expect(save).toHaveBeenCalledTimes(1);
jest.useRealTimers();
});jest.config so state never leaks between tests and spies always restore.as any casts.toHaveBeenCalledWith to verify how the boundary was invoked.setTimeout waits.jest.mocked provides.jest.mock with a factory?"mockResolvedValue / mockReturnValueOnce — how do these work?"jest.mock"~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.