'Sinon.js combining calledWith number of times

I know with sinon.js you can test that a spy was called a certain number of times:

sinon.assert.calledTwice(mySpy.someMethod);

And you can test that a spy was called with certain arguments:

sinon.assert.calledWith(mySpy.someMethod, 1, 2);

But how to you combine them to test that a method was called a specific number of times with specific arguments? Something, theoretically, like this:

sinon.assert.calledTwiceWith(mySpy.someMethod, 1, 2);


Solution 1:[1]

A spy provides access to the calls made to it using getCall() and getCalls(). Each Spy call can be tested using methods like calledWithExactly():

import * as sinon from 'sinon';

test('spy', () => {

  const spy = sinon.spy();
  spy(1, 2);
  spy(3, 4);
  expect(spy.callCount).toBe(2);
  expect(spy.getCall(0).calledWithExactly(1, 2)).toBe(true);
  expect(spy.getCall(1).calledWithExactly(3, 4)).toBe(true);

});

Solution 2:[2]

Unfortunately, Sinon doesn't have a function that checks what you're looking for, especially if you don't know or care about the order of calls ahead of time. However, it does let you inspect each time that a function was called individually. As a result, although it's a bit inelegant, you can count the number of times the function was called with the expected arguments yourself.

Use spy.getCalls() to get an array of the spy's calls, which are instances of spy call objects. Each call lets you access an array of the arguments passed to the spy with call.args (not call.args()).

test('spy', () => {
  const spy = sinon.spy();
  spy(1, 2);
  spy(1, 2);
  spy(3, 4);

  const wantedCalls = spy.getCalls().filter(
    (call) => call.args.length === 2 && call.args[0] === 1 && call.args[1] === 2
  );

  expect(wantedCalls.length).toEqual(2);
});

A bit more cleanly, as Brian Adams points out, you can call call.calledWithExactly() to check the arguments a specific call received:

test('spy', () => {
  const spy = sinon.spy();
  spy(1, 2);
  spy(1, 2);
  spy(3, 4);

  const wantedCalls = spy.getCalls().filter(
    (call) => call.calledWithExactly(1, 2)
  );

  expect(wantedCalls.length).toEqual(2);
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Brian Adams
Solution 2 Kevin