Patrick Desjardins Blog
Patrick Desjardins picture from a conference

TypeScript and Jest to Mock a Module Function

Posted on: 2024-03-08

Mocking with Jest a Module Function using Jest.Mock

The use case is this one: you have a function that live directly into a TypeScript (.ts) file. The function returns an array using a service. The service does an HTTP request and use crypto hashing function from an old library not compatible with Jest. In any case, you do not want to perform the HTTP query, nor having to handle the crypto function. However, you have unit tests to do that call that function. What you need is to mock this problematic function. Not only it will be faster to avoid making HTTP calls, it will remove Jest to import the problematic import and the test is tailor toward the real tested function and not the functions that this one uses. Finally, mocking help consistency as we control the exact output of the dependency.

The first step is to mock the direct dependency, the one that perform the HTTP request.

jest.mock('../../service/entities', () => ({
  getEntities: jest.fn().mockReturnValue([]),
}));

This command can be at the top of your test.ts file. For every invocation to the getEntities function in the service/entities file the function will return an empty array. However, this file has a dependency on the problematic library. While, this might not be the case of yo and you can skip this step, for others it requires an additional mock. The solution is to mock the import that the service/entities file has to the other dependency file.

jest.mock('../otherpath/otherfile', () => ({
  functionThatCallCryptoLibrary: jest.fn().mockReturnValue({}),
}));

In that case, the getEntities was using the functionThatCallCryptoLibrary from ../otherpath/otherfile.ts which was using the old unsupported file with old import syntax.

A small detail before moving forward, the jest.mock does not specify the extension of the file.

How to make mockReturnValue Returns Different values

At the moment, the mockReturnValue returns for every invocation []. An intuitive but wrong idea might be to call the mocking return value function into a describe that describe a different scenario. For example:

describe('when the server as many entities', () => {
    (getEntities as jest.Mock).mockReturnValue([{},{},{}]);

    it("returns three entities", ()=>{
        // Test here
    });
});

The issue is that the value will be set once and will remain set for every other tests in the test file. The clean and right way is to invoke the mockReturnValue using the beforeEach.

describe('when the server as many entities', () => {
    beforeEach(() => {
        (getEntities as jest.Mock).mockReturnValue([{},{},{}]);
    });

    it("returns three entities", ()=>{
        // Test here
    });
});

In that case, every new test (it) will perform the mock. Thus, having several beforeEach in the file that return different output does not conflict or share values.

Conclusion