I am writing a Jest/RTL test for a React component that invokes another component. I want to mock that second component so I can have it do things like invoking callbacks that the first component passes to it.
But there is nothing specific to React about this requirement: it comes up for non-React modules, too. I have an approach that I have shown to work using trivial modules and I want to document it here for myself and anyone else who finds it useful.
The module being tested is src/experiment/MyModule.js
, and it reads as follows in its entirety:
import nameToGreet from './subdir/SubModule'; export default function greet() { return `Hello, ${nameToGreet()}` };
The second module that it includes, and which I want to mock, is of course src/experiment/subdir/SubModule.js
, and it reads:
export default function nameToGreet() { return 'Mike' };
Clearly calling greet()
returns “Hello, Mike” — I have verified this. But from within my test-script I can mock the second module to change the greeting as follows (in src/experiment/MyModule.test.js
):
import greet from './MyModule'; import nameToGreet from './subdir/SubModule'; jest.mock('./subdir/SubModule'); nameToGreet.mockImplementation(() => 'Fiona'); test('Greets Fiona instead of Mike', () => { expect(greet()).toBe('Hello, Fiona'); });
Obviously the second stanza (import
/jest.mock
/mockImplementation
) is the clever part here. First you import the particular part of the included module that your tested module is going to use — in this case the default export but it works fine with named exports, too. Then you use jest.mock
to replace the module’s exports with mockable stubs. Finally you use mockImplementation
to specify how that function should behave in the context of tests.
And, yes, as you would expect: this works when the tested thing and/or the included module’s export is a React component rather than a regular function. I just showed the regular-function here because it’s easier to understand what’s going on.
jest.mock(‘./subdir/SubModulenameToGreet.mockImplementation(() => ‘Fiona’);
Is this a typo?
I don’t think so?