What did you expect to happen?
Created a test with a spy that is called with an object that has a property with a JavaScript Error as value.
When I use assert.calledWith to test if the spy was called with an object containing an Error using Sinon's match method, the test succeeds.
What actually happens
When I use assert.calledWith to test if the spy was called with an object containing an Error using Sinon's match method, the test fails.
How to reproduce
Check out my demo project, which contains a simple Mocha/Chai/Sinon test that checks if a spy was called with an object matching an object with a property that has an Error instance as value.
When you run the test, you get this output:
When I pass an object with an error and another property to a spy
the spy
✓ is called with an object matching the foo property
1) is called with an object matching the error
1 passing (13ms)
1 failing
1) When I pass an object with an error and another property to a spy the spy is called with an object matching the error:
AssertError: expected spy to be called with arguments
{ err: Error: WTF?, foo: "bar" } match(err: Error: WTF?)
at Object.fail (node_modules/sinon/lib/sinon/assert.js:96:21)
at failAssertion (node_modules/sinon/lib/sinon/assert.js:55:16)
at Object.assert.(anonymous function) [as calledWith] (node_modules/sinon/lib/sinon/assert.js:80:13)
at Context.it (test/test.js:17:72)
If you check out the branch “sinon1”, which uses the older version of Sinon, the tests are green.
Thanks for reporting and especially for putting together a failing test. I'm not sure whether to classify this as a bug or a feature, but the good news is that there is already a solution 😃
The way you're using the match function it delegates to Sinon's deep equal algorithm for each property value. So it's strictly speaking not "matching" anymore, it's comparing values. You could argue that comparing equal errors (that is they have the same type and message) should return true, you could also argue that your two error objects have different stacks, so they're not really equal.
To match objects within matched objects, you can nest and combine matchers like this:
sinon.match({
err: sinon.match.instanceOf(Error).and(sinon.match.has('name', 'WTF?'))
})
Alternatively, you could create a custom matcher as described under "Custom matchers" in the docs.
Going forward, I can also imagine sort of generic error matcher, like sinon.match.error('Error', 'WFT?').
Do you think these options are good enough or would you still argue that sinon should treat your two error instances as equal?
Hi Maximilian, thanks for the quick reply. Your solution works for me, and I agree that it's cleaner this way. For the record, I think the correct way would be to use has('message', 'WTF?') (not name):
sinon.match({
err: sinon.match.instanceOf(Error).and(sinon.match.has('message', 'WTF?'))
})
Most helpful comment
Thanks for reporting and especially for putting together a failing test. I'm not sure whether to classify this as a bug or a feature, but the good news is that there is already a solution 😃
The way you're using the
matchfunction it delegates to Sinon's deep equal algorithm for each property value. So it's strictly speaking not "matching" anymore, it's comparing values. You could argue that comparing equal errors (that is they have the same type and message) should returntrue, you could also argue that your two error objects have different stacks, so they're not really equal.To match objects within matched objects, you can nest and combine matchers like this:
Alternatively, you could create a custom matcher as described under "Custom matchers" in the docs.
Going forward, I can also imagine sort of generic error matcher, like
sinon.match.error('Error', 'WFT?').Do you think these options are good enough or would you still argue that sinon should treat your two error instances as equal?