Describe the bug
Sinon spy calledWith doesn't work with promises
To Reproduce
Steps to reproduce the behavior:
const mySpy = sinon.spy();
mySpy(Promise.resolve("a"));
const output = mySpy.calledWith(Promise.resolve("b"));
console.log(output); // true when it should be false
Expected behavior
calledWith should fail when comparing obviously different arguments than the one it was previously called with.
I guess the deepEqual function used inside this method is not correctly comparing promises.
The example above should be able to fail for either of these 2 options:
calledWith expectation are differentI guess option 1 would be the expected behaviour by most users and it would probably be the easiest to implement.
Context (please complete the following information):
I agree that your example should return false since the promise instances are different. This is a bug.
However, I think we can only do a strict equality check on promises since it's impossible to inspect the state and value of a promise synchronously.
To write an assertion on the resolved promise value, you'd depend on your assertion library to support that, e.g. with referee I would write it like this:
await assert.resolves(mySpy.lastCall.args[0], 'b');
I am personally using chai so what I am currently doing right now is pretty much the same:
expect(await mySpy.getCall(0).args[0]).to.deel.equal('a');
It looks really ugly though :(
But sometimes I have the specific Promise instance right on the test so that would look like
expect(mySpy.calledWith(myPromise)).to.equal(true)
or even prettier with sinonChai
expect(mySpy).to.have.been.calledWith(myPromise);
This will need to be fixed in @sinonjs/samsam (see https://github.com/sinonjs/samsam/issues/216). @NoxWings Would you like to look into it yourself?
I've uploaded a PR. Just let me know if you need anything else there.
I wonder why calledWith does not check for strict equality (===). I am using this type of assertions as a workaround:
const mySpy = sinon.spy();
const anObject = {};
const anotherObject = {};
mySpy(anObject);
const output = mySpy.calledWith(anotherObject);
console.log(output); // true, I expect it to be false
// My workaround with chai
expect(mySpy.calledOnce).to.be.true;
expect(mySpy.firstCall.args[0]).to.be.eq(anObject);
if calledWith checked for strict equality, I would just say:
expect(mySpy.calledWith(anObject)).to.be.true;
This becomes even harder when there are multiple object arguments.
@srknzl You can solve that with expect(mySpy.calledWith(sinon.match.same(anObject))).
Thanks a lot, I checked matchers but looks like I missed that one
PR is pending a small update.
Most helpful comment
I agree that your example should return
falsesince the promise instances are different. This is a bug.However, I think we can only do a strict equality check on promises since it's impossible to inspect the state and value of a promise synchronously.
To write an assertion on the resolved promise value, you'd depend on your assertion library to support that, e.g. with referee I would write it like this: