You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When asserting multiple calls to the same mock function using objects as parameters to the mock function, Jest will not record the values of the object as they were at the moment of the call, but only the reference to the object.
When tested code mutates the object after the call, it will also mutate the recorded calls within Jest, resulting in failing tests, that should be green.
To Reproduce
Using Jest 26.2.2, consider this test:
let doingSomething = jest.fn();
function myFunction() {
let myParam = { myField: 'testValue' };
doingSomething(myParam);
myParam.myField = 'differentValue';
doingSomething(myParam);
}
describe('something', () => {
test('should work', () => {
myFunction();
expect(doingSomething).toBeCalledTimes(2);
// this assert will fail, because myField == 'differentValue', even though it shouldn't:
expect(doingSomething).toHaveBeenNthCalledWith(1, { myField: 'testValue' });
// this is okay:
expect(doingSomething).toHaveBeenNthCalledWith(2, { myField: 'differentValue' });
});
});
Expected behavior
Both expects should be green, since the object parameter was correct at the time of the first call.
The text was updated successfully, but these errors were encountered:
letdoingSomething=jest.fn();functionmyFunction(){letmyParam={myField: "testValue"};doingSomething(myParam);myParam.myField="differentValue";doingSomething(myParam);}describe("something",()=>{beforeEach(()=>{doingSomething.mockReset();});test("should realy work",()=>{letcalledTimes=0;doingSomething.mockImplementation((myParam)=>{calledTimes++;switch(calledTimes){case1:
expect(myParam).toEqual({myField: "testValue"});break;case2:
expect(myParam).toEqual({myField: "differentValue"});break;default:
break;}});myFunction();expect(doingSomething).toBeCalledTimes(2);});test("should NOT work",()=>{myFunction();expect(doingSomething).toBeCalledTimes(2);// this assert will fail, because myField == 'differentValue', even though it shouldn't:expect(doingSomething).toHaveBeenNthCalledWith(1,{myField: "testValue"});// this is okay:expect(doingSomething).toHaveBeenNthCalledWith(2,{myField: "differentValue"});});});
To better understand this problem you can imagine what is happening in similar pure js example:
// VERY simple ala jest.fnfunctionmakeMockFn(){constcallHistory=[]constmockedFn=(...args)=>{callHistory.push(args)}// helper to get function call historymockedFn.getCallHistory=()=>callHistoryreturnmockedFn}// creating ala jest.fn()constfn=makeMockFn()// create params to pass to fnconstmyParams={a: 1,b: 2}// running fnfn(myParams)fn('string')fn(123456)// check what we have in call historyconsole.log(fn.getCallHistory())// lets mutate myParamsmyParams.a='CHANGED a key'// try to run fnfn(myParams)// check what happen with first and last position of history arrayconsole.log(fn.getCallHistory())
There are earlier reference to the same underlying issue in #434 and #429.
A simple approach would be to support cloning the parameters for specific calls where this is a known issue due to the implementation (called out here: #434 (comment))
Some other comments have said that its not good practice to mutate the objects in the code, however, I think a testing framework shouldn't be pushing a particular coding practice.
An overall better approach IMHO is that of sinon where the mock is set to expect certain values, or support for conditional mocking could be used also.
#10373 馃悰 Bug Report
When asserting multiple calls to the same mock function using objects as parameters to the mock function, Jest will not record the values of the object as they were at the moment of the call, but only the reference to the object.
When tested code mutates the object after the call, it will also mutate the recorded calls within Jest, resulting in failing tests, that should be green.
To Reproduce
Using Jest 26.2.2, consider this test:
Expected behavior
Both expects should be green, since the object parameter was correct at the time of the first call.
The text was updated successfully, but these errors were encountered: