Jest: the second argument of jest.mock must be a function

Created on 3 Oct 2017  路  7Comments  路  Source: facebook/jest

What is the current behavior?

jest.mock(moduleName, func) throws the error, the second argument of jest.mock must be a function if func is defined as:

function func() {
   return 'Hello';
}

...but works if the func is defined inline as an arrow function:
jest.mock(moduleName, () => 'Hello')

In both cases moduleName is a string like 'fs'

What is the expected behavior?

Either of:

  • Change error message to say the second argument of jest.mock must be an arrow function
  • Make jest.mock accept a function that's not an arrow function

This is in a bare-bones Node app that doesn't use Babel and has index.js that prints a message to console.

good first issue

Most helpful comment

Yes, because your mock may be required before references are fully initialized. It's easier to see jest.mock calls as fully isolated, and the function as an isolated module scope.

Consider a module Banana that depends on Kiwi, which is mocked:

import Banana from './Banana';
jest.mock('Kiwi', () => name);
const name = ''I am a pear';

When Banana requires Kiwi, we know Kiwi is mocked. We run the function and then it throws saying name does not exist/is not initialized, simply because it is sequentially executed:

  • require Banana
  • Banana requires Kiwi
  • Kiwi is mocked, and runs the mock function.
  • The mock function would like to return name.
  • name isn't initialized yet

This is why you cannot reference anything from the outer scope. Hope that makes sense.

All 7 comments

It accepts functions, it just doesn't accept references. If you'd like, you could send a PR to babel-plugin-jest-hoist to adjust the error message to say must be an inline function. What do you think?

@cpojer is there a good reason why mock it doesn't accept function reference?

Yes, because your mock may be required before references are fully initialized. It's easier to see jest.mock calls as fully isolated, and the function as an isolated module scope.

Consider a module Banana that depends on Kiwi, which is mocked:

import Banana from './Banana';
jest.mock('Kiwi', () => name);
const name = ''I am a pear';

When Banana requires Kiwi, we know Kiwi is mocked. We run the function and then it throws saying name does not exist/is not initialized, simply because it is sequentially executed:

  • require Banana
  • Banana requires Kiwi
  • Kiwi is mocked, and runs the mock function.
  • The mock function would like to return name.
  • name isn't initialized yet

This is why you cannot reference anything from the outer scope. Hope that makes sense.

Hi, is there a way to automatically call mock on every test suite? I ran into this (now updated) error message when trying to create a mock module for i18n and call it as jest.mock('react-i18next', fn);.

I know this function will be required in multiple modules so I am trying to avoid writing this fix in every test.

jest.mock('react-i18next', () => ({
  // this mock makes sure any components using the translate HoC receive the t function as a prop
  translate: () => Component => props => <Component t={() => ''} {...props} />,
}));

@lmenus add your mock to a file called react-i18next in __mocks__. See https://facebook.github.io/jest/docs/en/manual-mocks.html

@SimenB Ah, missed that, thank you! This certainly reduces it to a mere jest.mock('react-i18next'); now!

Was this page helpful?
0 / 5 - 0 ratings