Why Mock Entire Modules?
A unit test should exercise the logic in the file under test, not the behavior of everything it imports. When a module reaches out to the filesystem, hits a real database, or calls a third-party API, jest.mock('./path/to/module') replaces every import of that module in the current test file with a fake version, cutting the dependency entirely. This is a different tool than jest.fn() alone: instead of stubbing one function you control directly, jest.mock() intercepts the module resolution system itself so any file importing that module gets the fake automatically.
Cricket analogy: Replacing a live stadium pitch with a practice net during training, so a batsman like Rohit Sharma can drill technique without match-day variables, mirrors jest.mock() swapping a real module for a controlled fake.
Automatic vs Manual Mocks
Calling jest.mock('./userService') with no second argument triggers automatic mocking: Jest inspects the module's shape and replaces every exported function with a jest.fn() that returns undefined by default, while non-function exports are kept as-is. For more control, you create a manual mock — a file with the same name placed inside a __mocks__ folder next to the real module (or at the project root for node_modules packages) — that Jest will use automatically once jest.mock() is called, giving you a hand-written fake implementation reused across every test file that mocks it.
Cricket analogy: Using a bowling machine's default settings (automatic mock) versus programming a custom line-and-length routine (manual mock in __mocks__) mirrors jest.mock()'s automatic mocking versus a manual mock file.
// __mocks__/axios.js
export default {
get: jest.fn(() => Promise.resolve({ data: { id: 1 } })),
};
// user.test.js
jest.mock('axios');
import axios from 'axios';
import { fetchUser } from './user';
test('fetches user data', async () => {
axios.get.mockResolvedValueOnce({ data: { id: 1, name: 'Ada' } });
const user = await fetchUser(1);
expect(user.name).toBe('Ada');
expect(axios.get).toHaveBeenCalledWith('/users/1');
});Mocking Node Modules and Factory Functions
For third-party npm packages, jest.mock('module-name', factory) lets you supply a factory function inline that returns the fake module shape, which is especially handy for a package like axios where you only need get, post, and defaults stubbed rather than the entire API surface. This inline factory approach avoids creating a __mocks__ file when the fake behavior is specific to a single test file, and it runs before any import statement executes because Babel hoists jest.mock() calls to the top of the module.
Cricket analogy: Telling a scoring app to always report DRS as 'not out' via a scripted factory response resembles jest.mock('module', factory) supplying a custom fake implementation for an entire package.
Jest hoists jest.mock() calls to the top of the file (above imports) via babel-plugin-jest-hoist, so you can safely write jest.mock('./api') before the import statement — but this also means you cannot reference out-of-scope variables inside the factory unless the variable name is prefixed with 'mock'.
Partial Mocking with jest.requireActual
Sometimes you want most of a module's real behavior but need to override just one export — for example, keeping a real formatCurrency helper while faking a network-dependent fetchExchangeRate. jest.requireActual('./module') retrieves the genuine, unmocked module regardless of any active jest.mock() call, so inside a factory you can spread the real module's exports and override only the specific property you need faked, preserving real logic everywhere else.
Cricket analogy: Keeping a fielder's real throwing arm but scripting only the run-out decision, like requireActual keeping most exports real while overriding one, is jest.requireActual mixed with selective mocking.
jest.mock() calls are hoisted above imports by Babel, so referencing a local variable inside the factory function throws an 'out-of-scope variable' reference error unless the variable name starts with 'mock' (e.g., mockAxios).
- jest.mock('./path') swaps an entire module with an automatic or manual mock for every import in that test file.
- Automatic mocks replace every exported function with a jest.fn() that returns undefined by default.
- Manual mocks live in a __mocks__ folder adjacent to the real module (or at the root for node_modules) and give full control over fake behavior.
- jest.mock('module', factory) lets you supply a custom factory function returning the fake implementation inline in the test file.
- jest.requireActual('./module') retrieves the real, unmocked module so you can keep most exports genuine while overriding just one.
- jest.mock() calls are hoisted above import statements by Babel, which affects what variables the factory function can reference.
- Mocking entire modules is the right tool when a dependency touches the filesystem, network, or database — not for controlling a single function's return value.
Practice what you learned
1. Where should a manual mock for ./userService.js live?
2. What happens with automatic mocking when you call jest.mock('./api') with no factory?
3. Why are jest.mock() calls hoisted above import statements?
4. How do you keep most of a module real but override a single export?
5. What variable name prefix must out-of-scope variables have to be safely referenced inside a jest.mock() factory?
Was this page helpful?
You May Also Like
Mock Functions with jest.fn()
Learn how to create, configure, and inspect Jest mock functions to isolate units under test and verify how dependencies are called.
Spying on Functions with jest.spyOn()
Learn how jest.spyOn() wraps real methods to track and optionally override their behavior, and how it differs from a plain jest.fn() mock.
Mocking HTTP Requests
Learn how to mock network calls in Jest tests using axios/fetch stubs, interceptor libraries like nock and msw, and how to simulate error and timeout scenarios.