9

I searched for a very long time how to mock any module with jest (like rewire does). I finally manage to do it this way, and it work like a charm :

jest.mock('common/js/browser-utils', () => ({
    openBrowser: jest.fn()
}));
const { openBrowser: openBrowserSpy } = jest.requireMock(
    'common/js/browser-utils'
);

But i wonder if there is another fast way to do so ? I saw the genMockFromModule method but i never makes it work (maybe it's not for that usage.)

What i want is simple : mocking a module by a jest.fn() (or any auto mechanism), then being able to access this jest.fn() in my tests (here: openBrowserSpy) to expect(assertions) on it

oopinou
  • 143
  • 1
  • 1
  • 9

1 Answers1

14

You can just auto-mock the module using jest.mock:

jest.mock('common/js/browser-utils');

The docs could probably be improved with a better description of what "auto-mocked version" means, but what happens is that Jest keeps the API surface of the module the same while replacing the implementation with empty mock functions.

Complete example

browser-utils.js

export const openBrowser = () => { /* do something */ };

code.js

import { openBrowser } from './browser-utils';

export const func = () => {
  /* do stuff */
  openBrowser();
  /* do other stuff */
}

code.test.js

jest.mock('./browser-utils');  // create an auto-mock of the module

import { openBrowser } from './browser-utils';  // openBrowser is already an empty mock function
import { func } from './code';

test('func', () => {
  func();
  expect(openBrowser).toHaveBeenCalled();  // Success!
});

Bonus: Mock single function

To mock a single function you can use jest.spyOn like this:

import * as browserUtils from './browser-utils';
import { func } from './code';

test('func', () => {
  const spy = jest.spyOn(browserUtils, 'openBrowser');
  spy.mockImplementation();  // replace implementation with empty mock function (optional)
  func();
  expect(spy).toHaveBeenCalled();  // Success!
});
Brian Adams
  • 43,011
  • 9
  • 113
  • 111
  • Thank you very much, that was exactly what i searched for. What blows my mind was to do a `jest.mock` BEFORE any `import`. – oopinou Mar 17 '19 at 12:09
  • 6
    @oopinou you're welcome! ...and actually in this case it doesn't matter if `jest.mock` comes first or not since [`babel-jest` hoists calls to `jest.mock` to the top of the code block](https://jestjs.io/docs/en/jest-object.html#jestdomockmodulename-factory-options) so any `jest.mock` calls *always* happen first. – Brian Adams Mar 17 '19 at 20:41
  • Actually i'm not using babel but typescript, which has the same kind of behaviour i suppose – oopinou Apr 24 '19 at 08:19
  • Can anyone speak to the difference between using `jest.mock` and `jest.requireMock`? – mac Dec 15 '22 at 01:46