A guide to module mocking with Jest

Updated 29 September 2021
·
jest
react

When writing Jest unit tests, I always struggle to remember the syntax for mocking modules. So this post is intended as a part-guide, part-cheatsheet to refresh your memory when you need to do some mocking.

Mocking a named import

If you wanted to mock a imported named function, say getTime:

// Usage
import { getTime } from './time';

// test.js
jest.mock('./time', () => ({
    getTime: () => '1:11PM',
}));

Mocking only the named import (and leaving other imports unmocked)

If there are multiple functions in a module, and you only want to mock one, you can use requireActual:

// Usage
import { getTime, isMorning } from './time';

// test.js
jest.mock('./time', () => ({
    ...jest.requireActual('./time'), 
    getTime: () => '1:11PM',
    // isMorning will return its true value
}));

Mocking a default import

// Usage
import getDayOfWeek from './time';

// test.js
jest.mock('./time', () => () => 'Monday');

Mocking default and named imports

If you want to mock default and named imports, you’ll need to remember to use __esModule: true:

// Usage
import getDayOfWeek, { getTime } from './time';

// test.js
jest.mock('./time', () => ({
    __esModule: true,
    default: () => 'Thursday'
    getTime: () => '1:11PM',
}));

Changing what the mock returns per test

Using mockReturnValue

If you wanted to have getDayOfWeek to return a different value per test, you can use mockReturnValue in each of your tests:

import getDayOfWeek from './time';

jest.mock('./time', () => jest.fn());

test('App renders Monday', () => {
    getDayOfWeek.mockReturnValue('Monday');
    //...
});

test('App renders Tuesday', () => {
    getDayOfWeek.mockReturnValue('Tuesday');
    //...
});

If you only wanted to change what the mocked function returned for just one test, beware you don’t do something like this, as it won’t work:

jest.mock('./time', () => jest.fn(() => 'Tuesday'));

test('App renders Tuesday', () => {
    // Passes
});

test('App renders Monday', () => {
    getDayOfWeek.mockReturnValue('Monday');
    // Passes
});

test('App renders Tuesday, again', () => {
    // Fails
});

This is because calling mockReturnValue inside a test still changes the mock for all other tests after it.

Using mockReturnValueOnce

To get around the above scenario, you could use mockReturnValueOnce:

jest.mock('./time', () => jest.fn(() => 'Tuesday'));

test('App renders Monday', () => {
    getDayOfWeek.mockReturnValueOnce('Monday');
    // Passes
});

test('App renders Tuesday', () => {
    // Passes
});

mockReturnValueOnce will return a Monday once, and then resume returning Tuesday for all other tests.

Defining the mocks in beforeEach

Alternatively you can define the mock before each test, and then call mockReturnValue inside the Monday test to override the mock just for that test:

jest.mock('./time', () => jest.fn());

beforeEach(() => {
    getDayOfWeek.mockReturnValue('Tuesday');
});

test('App renders Tuesday', () => {
    // Passes
});

test('App renders Monday', () => {
    getDayOfWeek.mockReturnValue('Monday');
    // Passes
});

test('App renders Tuesday, again', () => {
    // Passes
});

Personally I’d prefer this approach over using mockReturnValueOnce as I think it’s less likely to cause confusion or end up in a scenario where your mocks are in a weird state.

Clearing mocks between tests with clearAllMocks

If we declare the mock once, its call count doesn’t reset between tests. So the second test here would fail:

jest.mock('./time', () => jest.fn(() => 'Tuesday'));

test('Calls getDayOfWeek function once', () => {
    render(<App />);
    expect(getDayOfWeek).toBeCalledTimes(1);
});

test('Calls getDayOfWeek function once, again', () => {
    render(<App />);
    expect(getDayOfWeek).toBeCalledTimes(1); // getDayOfWeek has been called twice
});

We would need to make sure we clear the call count between each test by calling clearAllMocks:

beforeEach(() => {
    jest.clearAllMocks();
});

test('Calls getDayOfWeek function once', () => {
    // ...

Chaining mocks

As one final tip, when mocking multiple modules you can chain them like so:

jest
    .mock('./time', () => jest.fn())
    .mock('./space', () => jest.fn());

Comments