Skip to content

leimon.io

Mocking modules with Jest

2 min read

Jest is a great tool for adding confidence in our codebase, primarily by unit testing our implementation. It provides a wide range of functionality to simplify the tests we write.

A common case when unit testing our modules, is mocking external dependencies of tested modules. This is where jest.mock(...) comes in the scene by doing exactly that. This is great for globally mocking these dependencies in our testing file.

Something that is not really straight forward is how to manually mock module dependencies for each separate test.

To better illustrate this, imagine having a module A.js depending on another module B.js as follows:

There are different approaches to mocking module dependencies. Let's see some of them based on the example above and when each of these is the best option. But first lets start with the case when we don't mock any external dependency.


No mock


When we don't apply any mock for the someFunctionB function, the actual function is getting triggered. That way, our test depends on the result of the actual implementation of that function. We don't really want to keep this behaviour for unit testing our module. This would be a good practice in case we wanted to test the result of integrating those two modules.


Global mock (default)


By using jest.mock for the dependencies of the tested module, Jest will enable auto-mocking for the dependency module. In that case, the module implementation is replaced by default mocks. In this specific example someFunctionB from auto-mocked module B.js will be replaced with a jest.fn() which returns an undefined value. You can find more information about auto-mocking Jest feature here.


Global mock (explicit implementation)


There are cases when Jest auto-mocking feature is not enough, and we need to explicitly mock the implementation of the module. The above approach is good enough as far as the mocked implementation covers all our test cases. But what happens when we need an explicit mocked implementation for each of our tests?


Explicit mock


To explicitly test our module based on specific module dependency results, we need to:

  1. auto-mock the module imported

  2. import the function we need to mock from that module

  3. in each of the depending tests

    3.1. mock the function with an explicit mocked implementation

    3.2. clear the mock for not affecting next tests

To add a mock function implementation for each of our tests we are using mockImplementation. We explicitly define the dependent module implementation and its return value. This will also affect the result of the actual tested module. As result, we can test our module based on all the possible result combinations of its dependencies. You can learn more about mockImplementation here.

A common pitfall is that our mocks need to be in a clean state after each test is run. As a result, we need to clear these mocks at the end of each test, so as our tests are not affected from one another.

As we can see there is not a silver bullet of mocking a dependency of a module while unit testing it. Each mocking strategy above covers a different test case. We should be aware of what we want our tests to achieve and select the best option based on these needs.