Mock Only One Function From Module With Jest

// Comment on DEV

Mocking functions in Jest can be a powerful tool for testing your code, but sometimes you just want to mock one function from a module while leaving the others intact. Here's how to do it.

Let's say you're working on a project where you're making REST API requests to a third-party service to retrieve user data. You have a module called userService that contains functions for these requests, such as getUserById or listUsers. Internally, these functions use the request function from the rest-api-request module to execute the REST API query.

However, the API is rate-limited, and you want to avoid exceeding the rate limit during your tests. Therefore, you decide to mock the request function to return a fake user object, but leave the rest of the implementation unchanged to avoid side effects.

import userService from './userService'; import { request } from 'rest-api-request'; jest.mock('rest-api-request', () => { const original = jest.requireActual('rest-api-request'); return { ...original, request: jest.fn(() => ({ id: 1, name: 'John Doe', email: 'john.doe@example.com', })), }; });

In this example, we use the jest.mock() function to create a mock for rest-api-request. Then we use the jest.requireActual() function to get the original implementation of rest-api-request. The original module is spread to a new object and the request function is overwritten with a mock implementation using jest.fn(). In this case, the mock implementation returns only a dummy user object.

Next, this is how we would test our userService:

describe('userService', () => { test('Should call the REST API and return a user object', async () => { const id = 1; const params = { endpoint: `/users/${id}`, method: 'GET', }; const expectedUser = { id, name: 'John Doe', email: 'john.doe@example.com', }; const user = await userService.getUserById(id); // test user object was returned from mock function expect(user).toEqual(expectedUser); // test mock function was called once with correct parameters expect(request).toHaveBeenCalledTimes(1); expect(request).toHaveBeenCalledWith(params) }); });

In this test, we set up the objects that the mock function should receive and return. Then we call getUserById with an ID, which would normally trigger a call to request to execute the REST API query, but will stop at our mock function. Finally, we use Jest's toHaveBeenCalledTimes() and toHaveBeenCalledWith() matchers to check that request was called once and with the correct parameters.

Overall, this approach allows us to test the functionality of our user service module while ensuring that it uses the request function correctly. Using this technique, we can selectively mock functions in dependent modules without affecting the functionality of the module itself.