Reputation: 1590
Consider code -
// utils.js
export const foo = async (a, b) => {
// do something
bar(a)
}
export const bar = async (a) => {
// do something
}
// utils.spec.js
const utils = require('./utils');
const barSpy = jest.spyOn(utils, 'bar');
const result = await utils.foo('a', 'b');
expect(barSpy).toHaveBeenCalledTimes(1);
The test is failing -
Error: expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
I read https://medium.com/@DavideRama/mock-spy-exported-functions-within-a-single-module-in-jest-cdf2b61af642 and https://github.com/facebook/jest/issues/936 but could not solve this with multiple permutations.
Do you see any issue with this?
Upvotes: 4
Views: 6660
Reputation: 1429
As @bhargav-shah said, when you spy on a module function with jest you are actually spying on its exported function values, not in the internal function itself.
This happens because of how commonJS modules work. With an ES modules environment you could actually be able to achieve what you are trying to do here without modifying your code, as the exports would be bindings. A more in depth explanation can be found here.
At the moment Jest doesn't support ES modules, so the only way you could make your code work would be calling the actual exported function from your foo
function:
// utils.js
export const foo = async (a, b) => {
// do something
// Call the actual exported function
exports.bar(a)
}
export const bar = async (a) => {
// do something
}
// utils.spec.js
const utils = require('./utils');
const barSpy = jest.spyOn(utils, 'bar');
const result = await utils.foo('a', 'b');
expect(barSpy).toHaveBeenCalledTimes(1);
Upvotes: 3
Reputation: 865
As explained in the article that you shared, in your utils.js
file you are exporting an object that has foo
and bar
. Your utils.spec.js
actually imports exports.foo
and exports.bar
. Consequently, you mock exports.bar
By changing the utils.js
as below, when you mock bar you will be mocking the actual bar that foo uses.
utils.js
const bar = async () => {};
const foo = async () => {
exportFunctions.bar();
};
const exportFunctions = {
foo,
bar
};
module.exports = exportFunctions;
See this in action in this codesandbox. You can open a new terminal (bottom right) and run npm test
right in the browser
Upvotes: 3