Milkncookiez
Milkncookiez

Reputation: 7407

Jest mock a module to produce different results on function calls

I have a module:

// foo.js
module.exports = async () => {
  ...
}

This module is called in another module, which behaviour I'm testing:

// bar.js
const one = await foo();
const two = await foo();

I want to mock foo with Jest, so that multiple calls on it return different results. More precisely, the first call to be successful, the second one to return an error.

This is my mocking mechanism:

const fooMock = jest.mock('../src/foo')
fooMock
  .mockImplementationOnce(() => Promise.resolve({ id: 'asdf' }))
  .mockImplementationOnce(() => Promise.reject(new Error('some error')))

The problem is that mockImplementationOnce is not a function of jest.mock(). It's only a function of jest.fn(). The jest.mock() object only has mockImplementation which will mock and seal the return result of the mocked function and doesn't allow for different results on multiple calls.

How can I mock the module to return different results on 1st and on 2nd call?

Inspiration taken from the jest docs here.

UPDATE:

I also tried this approach:

  jest.mock('../src/foo', () => jest.fn()
      .mockImplementationOnce(() => Promise.resolve({ _id: 'asdf' }))
      .mockImplementationOnce(() => Promise.reject('some error'))
  )

But now no mocking is happening at all.

Upvotes: 2

Views: 5508

Answers (1)

Lin Du
Lin Du

Reputation: 102597

You should use mockFn.mockReturnValueOnce(value):

Accepts a value that will be returned for one call to the mock function. Can be chained so that successive calls to the mock function return different values

After calling jest.mock('./src/foo'), you should import the ./src/foo module and it will be a mocked version instead of using the return value.

const fooMock = require('./src/foo');

jest.mock('./src/foo');

test('should pass', () => {
  fooMock.mockReturnValue('default')
         .mockReturnValueOnce('first call')
         .mockReturnValueOnce('second call')

  // 'first call', 'second call', 'default', 'default'
  console.log(fooMock(), fooMock(), fooMock(), fooMock());
})

Upvotes: 5

Related Questions