I have one file called helper.js that consist of two functions
export const funcA = (key) => {
return funcB(key)
};
export const funcB = (key,prop) => {
return someObj;
};
I have my helper.spec.js to test the helper.js file functions.
import {funcA,funcB} from 'helper';
describe('helper', () => {
test('testFuncB', () => {
}
test('testFuncA', () => {
}
}
The test for funcB is pretty simple i just call it and expect someObj
The problem is to test funcA, in order to test it i want to mock the response of funcB.
I want testFuncB call the actual funcB and testFuncA call mocked funcB
How can i achieve funcB to be mocked and original in my two tests?
This is not a duplicate. It is a different case: they mock inner called functions only, if I remove the testFuncB then it will be the same but I must perform test on testFuncB too.
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();
});
});
Late answer but this should work. Also you should test funcB in its own file and not inside the 'helper' tests.
import { funcB } from './funcB';
import { funcA } from './helper';
jest.mock('./funcB');
describe('helper', () => {
test('test funcA', () => {
const funcBSpy = jest.fn();
funcB.mockImplementation(() => funcBSpy());
expect(funcBSpy).toHaveBeenCalledTimes(1);
});
});
import * as helper from 'helper';
describe('helper', () => {
it('should test testFuncA', () => {
const mockTestFuncB = jest.mock();
// spy on calls to testFuncB and respond with a mock function
mockTestFuncB.spyOn(helper, 'testFuncB').mockReturnValue(/*your expected return value*/);
// test logic
// Restore helper.testFuncB to it's original function
helper.testFuncB.mockRestore();
}
}
I create a kind of nameSpace to handle this issue:
let helper = {}
const funcA = (key) => {
return helper.funcB(key)
};
const funcB = (key,prop) => {
return someObj;
};
helper = { funcA, funcB }
module.exports = helper
and then mocking is obvious with jest.fn
You can do the following trick when you test the funcA
:
1.Mock the funcB
:
helper.funcB = jest.fn().mockImplementationOnce(() => <your data>);
2.Change the funcB(key)
to this.funcB(key)
I had the same problem and worked! Full Code:
export const funcA = (key) => {
return this.funcB(key)
};
export const funcB = (key,prop) => {
return someObj;
};
Test Code:
import helper from 'helper';
describe('helper', () => {
test('testFuncB', () => {
...
}
test('testFuncA', () => {
helper.funcB = jest.fn().mockImplementationOnce(() => <your data>);
}
}
You can use babel-plugin-rewire provided __set__
function to mock internal function.
Assuming you have set up babel-plugin-rewire.
helper.spec.js
import {funcA, __set__} as helper from './helper';
describe('helper', () => {
test('test funcA', () => {
__set__('funcB', () => {
return 'funcB return value'
})
expect(funcA()).toBe('funcB return value');
});
});
One advantage of this solution is you don't need to change any original code
I was able to get this working. I separated my helper and my main logic into two files like other solutions. In the test file, I had to mock the entire helper file.
const { doAdd } = require('./addHelper');
function add(a, b) {
return doAdd(a, b);
}
jest.mock('./addHelper');
// ...
it('should call doAdd', () => {
// hook into doAdd helper method and intercept its return value
jest.spyOn(helperModule, 'doAdd').mockReturnValue(11);
expect(addModule.add()).toEqual(11);
expect(helperModule.doAdd).toBeCalled();
});
Here is my solution:
I think this might work
import * as helper from 'helper';
describe('helper', () => {
test('testFuncB', () => {
}
test('testFuncA', () => {
const mockTestFuncB = jest.mock();
// spy on calls to testFuncB and respond with a mock function
jest.spyOn(helper, 'testFuncB').mockImplementationOnce(mockTestFuncB);
// Do the testing ...
// Restore helper.testFuncB to it's original function
helper.testFuncB.mockRestore();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.