I am currently encountering an issue while spying on a function using vitest and attempting to assert that it is called with specific arguments. The function I am testing internally calls another function four times, each time with a different argument. I have defined an array expectedArgs
containing the expected arguments for these function calls.
Here is a simplified representation of the code structure:
const expectedArgs = [1, 2, 3, 4];
// Function under test
function myFunction() {
// ...
mySpiedFunc(1);
mySpiedFunc(2);
mySpiedFunc(3);
mySpiedFunc(4);
// ...
}
// Spy on mySpiedFunc
const mySpiedFunc = vi.spyOn(objectContainingMyFunction, 'mySpiedFunc');
// Test case
it('should call mySpiedFunc with expected arguments', () => {
myFunction();
expect(mySpiedFunc).toBeCalledWith(1);
expect(mySpiedFunc).toBeCalledWith(2);
expect(mySpiedFunc).toBeCalledWith(3);
expect(mySpiedFunc).toBeCalledWith(4);
});
In an ideal scenario where all instances of mySpiedFunc
are called with the expected arguments (1, 2, 3, and 4), the test passes without any issues.
However, I have observed that if, for instance, the third call to mySpiedFunc
mistakenly uses 5
instead of 3
, then, instead of only the third assertion failing, all subsequent assertions also fail, displaying a diff-like output:
1st spy call return:
- 1
+ 5
2nd spy call return:
- 2
+ 5
...
I would anticipate that only the assertion for the incorrect argument (3) would fail, while the other assertions for 1, 2, and 4 would pass.
I am using vitest for mocking and spying in my testing framework. I would greatly appreciate any insights, explanations, or potential workarounds for this.
I found an answer for this. The problem was that I was expecting toBeCalledWith
to check each call in order (first toBeCalledWith
for 1, second for 2, etc.).
toBeCalledWith
will check every mock call. If there was no match, it will show an error message for each check made.
If you want to check each mock call in order then you can use toHaveBeenNthCalledWith or toHaveNthReturnedWith, depending on your use case.
Changing the initial code like this:
it('should call mySpiedFunc with expected arguments', () => {
myFunction();
// toHaveBeenNthCalledWith(<index-starting-from-1>, <value-to-be-called-with>)
expect(mySpiedFunc).toHaveBeenNthCalledWith(1, 1);
expect(mySpiedFunc).toHaveBeenNthCalledWith(2, 2);
expect(mySpiedFunc).toHaveBeenNthCalledWith(3, 3);
expect(mySpiedFunc).toHaveBeenNthCalledWith(4, 4);
});
will provide the expected behavior (fail on first unexpected value).