# Quickest Way to Mock Module Dependencies with Jest

[Rodolfo Gobbi](https://www.strv.com/blog/authors/rodgobbi)  
Frontend Engineer

---

Jest offers many features out of the box. One that is very powerful and commonly used in unit tests is the auto mock feature, which is when Jest automatically mocks everything exported by a module that is imported as a dependency by any module we are testing. Due to Jest’s extensive list of features, the auto mock feature can be easily missed—especially because the documentation doesn’t explicitly focus on it (it’s mentioned in the [The Jest Object](https://jestjs.io/docs/en/jest-object?ref=strv.ghost.io#jestmockmodulename-factory-options), [Mock Function](https://jestjs.io/docs/en/mock-functions?ref=strv.ghost.io#mocking-modules), and [ES6 Class Mocks](https://jestjs.io/docs/en/es6-class-mocks?ref=strv.ghost.io#automatic-mock) sections).

In this article, we’ll cover the simplest and quickest way of mocking any dependency—external or internal—with Jest just by calling `jest.mock`, without changing the implementation of the modules.

## MOCKING AN EXTERNAL DEPENDENCY

Suppose we have these extracted API calls using [axios](https://github.com/axios/axios?ref=strv.ghost.io):

```js
// api/users.js
import axios from 'axios';

export const getUsers = async () => {
  const { data } = await axios.get('/api/users');
  return data;
};

export const getUserData = async (id) => {
  const { data } = await axios.get(`/api/user/${id}`);
  return data;
};
```

If we want to unit test this simple function and don't want to call the API every time the test runs, we can solve this by simply calling `jest.mock`:

```js
// __tests__/api/users.js
import axios from 'axios';
import { getUsers, getUserData } from '../../api/users';

jest.mock('axios');

const axiosGet = axios.get;

beforeEach(() => {
  axiosGet.mockReset();
});

describe('getUsers', () => {
  it('should call the API and return the data', async () => {
    const usersData = [
      { id: 51, name: 'Allan' },
      { id: 120, name: 'George' },
    ];

    axiosGet.mockResolvedValue({ data: usersData });

    // also could be mockImplementation
    // or anything that mock functions can do

    const returnedUsersData = await getUsers();

    expect(returnedUsersData).toEqual(usersData);
    expect(axiosGet).toHaveBeenCalledTimes(1);
    expect(axiosGet).toHaveBeenCalledWith('/api/users');
  });

  it('should get user data with correct ID', async () => {
    const userId = 51;
    const userData = { id: userId, name: 'Allan' };

    axiosGet.mockResolvedValue({ data: userData });

    const returnedUserData = await getUserData(userId);

    expect(returnedUserData).toEqual(userData);
    expect(axiosGet).toHaveBeenCalledWith(`/api/user/${userId}`);
  });
});
```

We can call `jest.mock('axios')` after importing axios because Jest will [hoist](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting?ref=strv.ghost.io) all `jest.mock` calls to the top of the file. ([Reference](https://jestjs.io/docs/en/es6-class-mocks?ref=strv.ghost.io#calling-jestmockdocsenjest-objectjestmockmodulename-factory-options-with-the-module-factory-parameter))

When we call `jest.mock('axios')`, both the `axios` module imported in the test and the module imported by `users.js` will be the mocked version and the same one imported in this test.

We need to reset the `axios.get` mock before each test because all tests in the file share the same mock function. (In this case, we could achieve the same with [mockClear](https://jestjs.io/docs/en/mock-function-api?ref=strv.ghost.io#mockfnmockclear), but [mockReset](https://jestjs.io/docs/en/mock-function-api?ref=strv.ghost.io#mockfnmockreset) is safer.)

If using TypeScript, for autocomplete safety, you could write:

```js
const axiosGet = axios.get as jest.Mock;
```

You need to type cast the function because without it, TS wouldn't recognize that `axios.get` was mocked.

## MOCKING AN INTERNAL DEPENDENCY

Suppose we have a module that does more complex data processing:

```js
// utils/getSortedUserData.js
import { getUserData } from '../api/users';

const getSortedUserData = async (id) => {
  const userData = await getUserData(id);
  const contactsSortedByName = [...userData.contacts]
    .sort((a, b) => {
      // implementation details are not relevant to this article
    });
  // other processing...

  return {
    user: userData,
    contactsSortedByName,
    contactsSortedByAge,
  };
};

export default getSortedUserData;
```

...and suppose we want to test if we are processing the data correctly. In this case, we could use `jest.mock` for either `axios` or `getUserData`, but for an example of mocking internal modules, we'll mock `users.js`:

```js
// __tests__/utils/getSortedUserData.js
import { getUserData } from '../../api/users';
import getSortedUserData from '../../utils/getSortedUserData';

// the path of the mocked module should be relative to the test file
jest.mock('../../api/users');

describe('getSortedUserData', () => {
  it('should get user data and sort the contacts', async () => {
    const userId = 123; // example id
    const userData = {
      id: userId,
      name: 'Allan',
      // detailed data not relevant here
      contacts: [...],
    };
    const expectedSortedUserData = {
      contactsSortedByName: [...],
      contactsSortedByAge: [...],
    };
    getUserData.mockResolvedValue(userData);

    const sortedUserData = await getSortedUserData(userId);

    expect(sortedUserData).toEqual(expectedSortedUserData);
    expect(getUserData).toHaveBeenCalledTimes(1);
    expect(getUserData).toHaveBeenCalledWith(userId);
  });
});
```

When we mock an internal module, we use the path relative to the test file where we call `jest.mock`, not the path used inside the modules being tested.

Also, we import anything exported by the mocked module exactly as it was exported, whether named exports or default.

## CONCLUSION

A simple `jest.mock` call allows us to intercept any dependency of the modules we are testing, without changing their implementation. Jest exposes everything exported by the mocked module as mock functions, which we can manipulate and assert in our tests. It also enables us to verify that modules being tested are using dependencies properly.

## FURTHER READING

`jest.mock` accepts two more arguments: a [module factory](https://jestjs.io/docs/en/es6-class-mocks?ref=strv.ghost.io#calling-jestmockdocsenjest-objectjestmockmodulename-factory-options-with-the-module-factory-parameter), which returns the mock implementation, and an [object](https://jestjs.io/docs/en/jest-object?ref=strv.ghost.io#jestmockmodulename-factory-options) for creating virtual mocks—modules that don't exist in the system.

Using the module factory usually involves more work because of differences between CommonJS and ES6 modules. These differences should be considered.

The second argument can be needed for cases like:

- Jest cannot auto-mock an external module (e.g., a minified build version).
- Mocking part of a module while keeping original implementation for some properties.

For an in-depth guide on mocking modules with Jest, including the use of the second argument, see [Jest Full and Partial Mock/Spy of CommonJS and ES6 Module Imports](https://codewithhugo.com/jest-mock-spy-module-import/?ref=strv.ghost.io).

<em>Article originally published on </em><a href="https://rodgobbi.com/?ref=strv.ghost.io"><em>https://rodgobbi.com/</em></a><em>.</em>

---

Don't miss anything