Skip to content

Jest Module Mocking

Sometimes you need to replace an entire imported module, not just one function. This lesson covers jest.mock(), how it hoists to the top of the file, and how to provide a custom factory for the mock's implementation.

Replacing a Module with jest.mock()

jest.mock('./modulePath') tells Jest to replace every import of that module (within the current test file) with a mock version. Without a factory function, Jest auto-mocks the module, replacing every exported function with an empty jest.fn().

Jest hoists jest.mock() calls to the top of the file automatically (using Babel), so the mock is in place before any import/require statements run — this is why jest.mock() calls work even when written after your imports.

// emailClient.js
module.exports = {
  send: (to, subject) => { /* calls a real email API */ },
};

// notifications.test.js
jest.mock('./emailClient');
const emailClient = require('./emailClient');
const { notifyUser } = require('./notifications');

test('calls emailClient.send with the right arguments', () => {
  notifyUser({ email: 'ada@example.com' });
  expect(emailClient.send).toHaveBeenCalledWith('ada@example.com', expect.any(String));
});

emailClient.send is automatically replaced with a jest.fn(), so no real email is sent during the test.

Providing a Custom Mock Factory

jest.mock('./emailClient', () => ({
  send: jest.fn().mockResolvedValue({ delivered: true }),
}));
  • The second argument to jest.mock() is a factory function returning the mock module's shape.
  • Use a factory when you need specific default behavior, not just empty mock functions.
  • The factory runs once and its return value becomes the module every import receives.
  • Factories cannot reference out-of-scope variables directly due to Jest's hoisting (use jest.requireActual() or define values inside the factory).

Module Mocking Cheat Sheet

Common jest.mock() usage patterns.

Pattern Example
Auto-mock a module jest.mock('./emailClient')
Custom mock factory jest.mock('./emailClient', () => ({ send: jest.fn() }))
Partial mock (keep some real exports) jest.requireActual('./module') inside factory
Mock a default export jest.mock('./api', () => ({ default: jest.fn() }))
Unmock for one test file jest.unmock('./module')
Reset module registry jest.resetModules()

Partial Mocks: Keeping Some Real Exports

Sometimes you want to mock only part of a module while keeping the rest of its real behavior. jest.requireActual() inside a factory retrieves the real module so you can spread its exports and override just what you need.

jest.mock('./mathUtils', () => {
  const actual = jest.requireActual('./mathUtils');
  return {
    ...actual,
    random: jest.fn().mockReturnValue(0.5), // only randomness is mocked
  };
});

add, subtract, and every other real export from mathUtils keep working normally; only random is replaced.

Understanding jest.mock() Hoisting

Because Babel hoists jest.mock() calls above imports, referencing an outer-scope variable inside the factory (one not prefixed with mock) throws an "out-of-scope variable" error. Jest allows variable names starting with mock as an exception to this rule.

const mockSend = jest.fn(); // OK: starts with "mock"

jest.mock('./emailClient', () => ({
  send: mockSend,
}));

Naming mock-related variables with a mock prefix avoids Jest's out-of-scope variable restriction.

Common Mistakes

  • Referencing a non-mock-prefixed outer variable inside a jest.mock() factory and hitting a hoisting error.
  • Forgetting that auto-mocking replaces every exported function with an empty mock returning undefined.
  • Mocking an entire module when only a partial mock (via jest.requireActual()) was actually needed.
  • Not calling jest.resetModules() when a test needs a completely fresh module instance.

Key Takeaways

  • jest.mock('./path') replaces every import of a module within the test file.
  • A factory function as the second argument customizes exactly what the mock module exports.
  • jest.requireActual() inside a factory enables partial mocking of a module.
  • Jest hoists jest.mock() calls above imports; only mock-prefixed variables can be referenced inside factories.

Pro Tip

When a jest.mock() factory needs a shared mock function across multiple tests, declare it with a mock prefix (e.g. mockSend) at the top of the file — it satisfies Jest's hoisting rule and stays easy to reconfigure per test.