neiya
neiya

Reputation: 3142

Mock only part of the return of a mocked function with jest

Using jest and typescript, I wonder if that's possible to mock only a part of the return of a function. My goal is to pass a spy for the mocked part, and to receive the original function output for the unmocked part.

Given the following function, that I want to mock part of the return:

// util.ts

export interface OutputMyFunction {
  function: void;
  anotherFunction: void;
}

export function myFunction(): OutputMyFunction {
  return {
    function: () => console.log('function!'); // ⬅️ I want to mock this function
    anotherFunction: () => console.log('another function!'); // I don't want to alter this function
  }
}

Is there a way I can mock function without altering what anotherFunction would have returned, without the mock?

// myModule.test.ts

import {myFunction, OutputMyFunction} from '../util';

jest.mock('../util', () => ({
  myFunction: jest.fn(),
}));

const myFunctionMock: jest.Mock<() => OutputMyFunction> =
  jest.requireMock('../util').myFunction;

describe('myModule', () => {
  describe('when doing this', () => {
    it('should call `function`' () => {
      const functionSpy = jest.fn();

      // When mocking the return value of `function` using mockReturnValue, I should pass a mock for all other properties
      // Is there a way I can get the original value that myFunction would have returned, for all the other properties?
      myFunctionMock.mockReturnValue({
        function: functionSpy,
      });
    }) 
  }
});

The reason why other returned properties should have their real implementation, is that it would make it clearer what is the test case testing for.

Also in case the function is returning a complex object or has complex logic, it can be complicated to mock all properties in a way that matches what the original implementation would have returned.

Another approach would be to create two functions in the util file, with each one returning a different output so that it can be mocked separately. But I wonder if there is another approach that would work without having to refactor that file.

Upvotes: 1

Views: 2165

Answers (1)

Junlong Wang
Junlong Wang

Reputation: 456

Have you tried using requireActual like this?

jest.mock('../util', () => {
  const original = jest.requireActual('../utils').myFunciton;

  return
  {
    myFunction: {...original(),function:jest.fn()}
  }
});

Upvotes: -1

Related Questions