A guide to module mocking with Jest
Tags: react, jest
Published: 2020-01-23 20:32:09

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`:

```jsx
// 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`:
```jsx
// 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
```jsx
// 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`:
```jsx
// 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:

```jsx
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:

```jsx
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`:

```jsx
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:

```jsx
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:
```jsx
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`:

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

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

## Chaining mocks

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

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