How to Assert Multiple Arguments on Multiple Calls for Jest Mocks in javaScript
When testing in Jest, it's crucial to verify not only that a mock function was called, but what it was called with, especially when it's called multiple times. You might need to check the arguments for each specific call in order, or simply confirm that a set of calls with certain arguments occurred.
This guide will teach you the modern and effective methods for asserting arguments across multiple mock function calls. You will learn how to use toHaveBeenNthCalledWith for precise, ordered checks, toHaveBeenCalledWith for general existence checks, and how to inspect the mock.calls property for complex or partial assertions.
Method 1 (Most Specific): Checking Arguments for Each Call in Order
This is the most common and precise requirement: you need to verify that the mock was called a specific number of times and that the arguments for each call match an expected sequence. The best tool for this is the toHaveBeenNthCalledWith() matcher.
The logic:
- Use
toHaveBeenCalledTimes()to assert the total number of calls. - Use
toHaveBeenNthCalledWith(n, ...args)for each call, wherenis a 1-based index for the call number.
The test:
function processItems(items, callback) {
items.forEach(item => {
callback(item.id, item.value);
});
}
test('should call the mock with specific arguments in order', () => {
const myMock = jest.fn();
const items = [
{ id: 1, value: 'A' },
{ id: 2, value: 'B' },
];
processItems(items, myMock);
// 1. Assert the total number of calls
expect(myMock).toHaveBeenCalledTimes(2);
// 2. Assert the arguments for each specific call
expect(myMock).toHaveBeenNthCalledWith(1, 1, 'A'); // First call
expect(myMock).toHaveBeenNthCalledWith(2, 2, 'B'); // Second call
});
This is the most robust and readable way to test a sequence of calls. An alias for this matcher, nthCalledWith(), is also available.
Method 2 (Less Specific): Checking if Calls with Certain Arguments Were Made
Sometimes you don't care about the order of the calls, only that your mock was called at some point with a specific set of arguments. The toHaveBeenCalledWith() matcher is perfect for this.
The Logic:
- Use
toHaveBeenCalledWith(...args)for each set of arguments you expect to have been used in a call, regardless of the order or total number of calls.
Example:
test('should have been called with the expected arguments, regardless of order', () => {
const myMock = jest.fn();
// Calls are made in a different order than we will test
myMock('first call', 1);
myMock('second call', 2);
// Assert that the mock was called with these arguments at some point
expect(myMock).toHaveBeenCalledWith('second call', 2);
expect(myMock).toHaveBeenCalledWith('first call', 1);
// This will fail, as there was no call with these arguments
// expect(myMock).toHaveBeenCalledWith('third call', 3);
});
This method is useful when the exact sequence of operations is not guaranteed but the operations themselves are important.
Method 3 (Most Flexible): Directly Inspecting the mock.calls Property
For the most complex assertions—such as checking only a subset of arguments, or when you need to inspect the calls programmatically—you can access the mock.calls property directly. This property is an array of arrays, where each inner array contains the arguments for one call.
The mock.calls Structure
const myMock = jest.fn();
myMock('a', 1);
myMock('b', 2);
console.log(myMock.mock.calls);
Output:
[
['a', 1], // Arguments from the first call
['b', 2] // Arguments from the second call
]
The Test
You can use standard array access and matchers to assert anything you need.
test('should have the correct arguments in the mock.calls array', () => {
const myMock = jest.fn();
myMock('first', { value: 100 });
myMock('second', { value: 200 });
// Assert the entire calls structure
expect(myMock.mock.calls).toEqual([
['first', { value: 100 }],
['second', { value: 200 }],
]);
// Assert a specific argument from a specific call
expect(myMock.mock.calls[0][1].value).toBe(100); // 1st call, 2nd arg, .value property
expect(myMock.mock.calls[1][0]).toBe('second'); // 2nd call, 1st arg
});
This method provides the ultimate flexibility but is also the most verbose. It is best reserved for situations where the standard Jest matchers are not sufficient.
Conclusion
Jest provides a powerful and flexible toolkit for asserting mock function calls. Choosing the right tool makes your tests cleaner and more expressive.
- Use
toHaveBeenNthCalledWith()for strict, ordered assertions. This is the most common and specific test you will write. - Use
toHaveBeenCalledWith()when you only need to confirm that a call with specific arguments happened at some point, regardless of order. - Use the
mock.callsproperty directly for complex or partial assertions where standard matchers are too restrictive.