If an ES6 module directly exports two functions (not within a class, object, etc., just directly exports the functions like in the question) and one directly calls the other, then that call cannot be mocked.
In this case, funcB
cannot be mocked within funcA
the way the code is currently written.
A mock replaces the module export for funcB
, but funcA
doesn't call the module export for funcB
, it just calls funcB
directly.
Mocking funcB
within funcA
requires that funcA
call the module export for funcB
.
That can be done in one of two ways:
Move funcB
to its own module
funcB.js
export const funcB = () => {
return 'original';
};
helper.js
import { funcB } from './funcB';
export const funcA = () => {
return funcB();
};
helper.spec.js
import * as funcBModule from './funcB';
import { funcA } from './helper';
describe('helper', () => {
test('test funcB', () => {
expect(funcBModule.funcB()).toBe('original'); // Success!
});
test('test funcA', () => {
const spy = jest.spyOn(funcBModule, 'funcB');
spy.mockReturnValue('mocked');
expect(funcA()).toBe('mocked'); // Success!
spy.mockRestore();
});
});
Import the module into itself
"ES6 modules support cyclic dependencies automatically" so it is perfectly valid to import
a module into itself so that functions within the module can call the module export for other functions in the module:
helper.js
import * as helper from './helper';
export const funcA = () => {
return helper.funcB();
};
export const funcB = () => {
return 'original';
};
helper.spec.js
import * as helper from './helper';
describe('helper', () => {
test('test funcB', () => {
expect(helper.funcB()).toBe('original'); // Success!
});
test('test funcA', () => {
const spy = jest.spyOn(helper, 'funcB');
spy.mockReturnValue('mocked');
expect(helper.funcA()).toBe('mocked'); // Success!
spy.mockRestore();
});
});