DEV Community

Cover image for A guide to module mocking with Jest
Emma Goto πŸ™
Emma Goto πŸ™

Posted on • Edited on • Originally published at emgoto.com

A guide to module mocking with Jest

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',
}));
Enter fullscreen mode Exit fullscreen mode

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
}));
Enter fullscreen mode Exit fullscreen mode

Mocking a default import

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

// test.js
jest.mock('./time', () => () => 'Monday');
Enter fullscreen mode Exit fullscreen mode

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',
}));
Enter fullscreen mode Exit fullscreen mode

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');
    //...
});
Enter fullscreen mode Exit fullscreen mode

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
});
Enter fullscreen mode Exit fullscreen mode

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
});
Enter fullscreen mode Exit fullscreen mode

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
});
Enter fullscreen mode Exit fullscreen mode

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
});
Enter fullscreen mode Exit fullscreen mode

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', () => {
    // ...
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
zeke profile image
Zeke Hernandez

this has been by far the most helpful guide to module mocking I have ever come across, thanks for writing!

Collapse
 
emma profile image
Emma Goto πŸ™

You're welcome!

Collapse
 
skarnl profile image
Oskar van Velden

Thanks for this article. Found it while looking how to mock functions with named imports and your article (on your own blog) really made it all clear to me.

Collapse
 
emma profile image
Emma Goto πŸ™

Awesome! Glad I could help