2

Sinon mocks have a method withExactArgs, which asserts the number of arguments passed to the method in question. Is there a way to have this behaviour using stubs?

Right now they seem to work like this:

const methodStub = stub();
methodStub.withArgs().returns(1);
console.log(methodStub()); // prints 1
console.log(methodStub({})); // also prints 1

I would like to have an exact argument match. I have looked into adding a custom behaviour to sinon, which didn't work out. I don't really know what to try next.

I am aware that I can check the arguments after the calls have been made, but I feel like the cleanliness of the test written that way does not fare.

Also, this reasonably well-received post on SO has me very confused: Can sinon stub withArgs match some but not all arguments. Quote:

if I use method.get.withArgs(25).calls... then it does not match either, because withArgs() matches all arguments

I seem to be observing the complete opposite with Sinon v6, exactly the behaviour that the OP was looking for...

Avius
  • 5,504
  • 5
  • 20
  • 42

1 Answers1

1

This statement from the linked question is incorrect:

withArgs() matches all arguments

withArgs does not match all arguments. I've added an answer with details.


withExactArgs for a stub has been discussed but never implemented.


So yes, checking the arguments after the calls have been made, using callsFake with a custom function, adding custom behavior, or using a mock instead of a stub are the current options in sinon for asserting that a method was called with exact args.


As an example, the stub from the question looks like it should only return 1 if it is called with no arguments which can be done using callsFake:

test('stub exact args', () => {
  const stub = sinon.stub();
  stub.callsFake((...args) => {
    if (args.length === 0) {
      return 1;
    }
    return 'default response';
  });

  expect(stub()).toBe(1);  // SUCCESS
  expect(stub({})).toBe('default response');  // SUCCESS
});
Brian Adams
  • 43,011
  • 9
  • 113
  • 111