How to check multiple arguments on multiple calls for jest spies?
Solution 1
I was able mock multiple calls and check the arguments this way:
expect(mockFn.mock.calls).toEqual([
[arg1, arg2, ...], // First call
[arg1, arg2, ...] // Second call
]);
where mockFn
is your mocked function name.
Solution 2
Since jest 23.0 there is .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)
https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-
Also under the alias: .nthCalledWith(nthCall, arg1, arg2, ...)
If you have a mock function, you can use
.toHaveBeenNthCalledWith
to test what arguments it was nth called with. For example, let's say you have adrinkEach(drink, Array<flavor>)
function that appliesf
to a bunch of flavors, and you want to ensure that when you call it, the first flavor it operates on is'lemon'
and the second one is'octopus'
. You can write:
test('drinkEach drinks each drink', () => {
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenNthCalledWith(1, 'lemon');
expect(drink).toHaveBeenNthCalledWith(2, 'octopus');
});
Note: the nth argument must be positive integer starting from 1.
Solution 3
You can also test toHaveBeenCalledWith
and test multiple times for each expected parameter combination.
One example is Google Analytics plugin api uses the same function call with different parameter combinations.
function requireGoogleAnalyticsPlugins() {
...
ga('create', 'UA-XXXXX-Y', 'auto');
ga('require', 'localHitSender', {path: '/log', debug: true});
ga('send', 'pageview');
}
To test this the below example tests that ga
has been called three times with the various parameter combinations.
describe("requireGoogleAnalyticsPlugins", () => {
it("requires plugins", () => {
requireGoogleAnalyticsPlugins();
expect(GoogleAnalytics.ga.toHaveBeenCalledTimes(3);
expect(GoogleAnalytics.ga).toHaveBeenCalledWith('create', 'UA-XXXXX-Y', 'auto');
expect(GoogleAnalytics.ga).toHaveBeenCalledWith('require', 'localHitSender', {path: '/log', debug: true});
expect(GoogleAnalytics.ga).toHaveBeenCalledWith('send', 'pageview');
});
});
In OP case you could test this with
expect(formData.append).toHaveBeenCalledWith('mimeType', 'someMimeType');
expect(formData.append).toHaveBeenCalledWith('fileName', 'someFileName');
Solution 4
The signature is .toHaveBeenCalledWith(arg1, arg2, ...)
, where arg1, arg2, ...
means in a single call (see).
If you want to test multiple calls, just expect
it multiple times.
Unfortunately, I have not yet found a method to test the order of multiple calls.
Solution 5
You can also create an array of the expected arguments per call and loop over it:
const expectedArgs = ['a', 'b', 'c', 'd']
expectedArgs.forEach((arg, index) =>
expect(myFunc).toHaveBeenNthCalledWith(index + 1, arg))
This solution considers the order of the calls. If you do not care about the order, you can use toHaveBeenCalledWith
without the index instead.
Related videos on Youtube
Andreas Köberle
Updated on January 13, 2022Comments
-
Andreas Köberle over 2 years
I have the following function in a React component:
onUploadStart(file, xhr, formData) { formData.append('filename', file.name); formData.append('mimeType', file.type); }
This is my test that at least gets the spy to be called:
const formData = { append: jest.fn() }; const file = { name: 'someFileName', type: 'someMimeType' }; eventHandlers.onUploadStart(file, null, formData); expect(formData.append).toHaveBeenCalledWith( ['mimeType', 'someMimeType'], ['fileName', 'someFileName'] );
However, the assertion is not working:
Expected mock function to have been called with: [["mimeType", "someMimeType"], ["fileName", "someFileName"]] But it was called with: ["mimeType", "someMimeType"], ["filename", "someFileName"]
What is the right way to use
toHaveBeenCalledWith
? -
Andi over 6 yearsI believe I've addressed how to use a single
expect
(see my answer below). -
Toni Feistauer about 6 yearsthis should be the "best answer"
-
WhatsThePoint almost 6 yearsWhile this link may assist in your answer to the question, you can improve this answer by taking vital parts of the link and putting it into your answer, this makes sure your answer is still an answer if the link gets changed or removed :)
-
rubmz almost 6 yearsThis method does not work/supported - unfortunately!
-
quirimmo over 5 yearsEven if not provided an example in the answer, this point is really valid! up to yoU!
-
Andi over 5 years@IlyaSaunkin <3
-
Jacob Raihle almost 4 yearsThis checks the order of the calls, not just that they have all happened (which may or may not be desired). But toHaveBeenNthCalledWith wants
1
if it is checking the first call, not0
, so the index is off by one. -
Kim Kern almost 4 years@JacobRaihle Thanks for pointing that out. :) I have updated the answer according to your comment.
-
Hew Wolff over 3 yearsAlso, note that if you don't know exactly what the parameters should be, you can use things like
expect.objectContaining
.