Sinon: Sinon.match Does Not Work Property With Error Instances

Created on 3 Apr 2017  ·  2Comments  ·  Source: sinonjs/sinon

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.

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 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?

All 2 comments

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?'))
})
Was this page helpful?
0 / 5 - 0 ratings

Related issues

brettz9 picture brettz9  ·  3Comments

tinganho picture tinganho  ·  3Comments

ljian3377 picture ljian3377  ·  3Comments

zimtsui picture zimtsui  ·  3Comments

optimatex picture optimatex  ·  4Comments