chai: expect .to.throw does not work with new Errors

This is my test:

  it('should throw a RangeError when the end date is before the start date', function () {
    var dateRange = {
      start: '2015-04-01',
      end: '2014-04-29',
    };
    var error = new RangeError('Invalid date range');
    var test = function () {
      throw error;
    };
    expect(test).to.throw(new RangeError('Invalid date range'));
  });

which fails with the message:

    AssertionError: expected [Function] to throw 'RangeError: Invalid date range' but 'RangeError: Invalid date range' was thrown
        at Context.<anonymous> (test/widgets/staff-planning-projection.spec.js:90:1)

I couldn’t find any explanations / solutions / workarounds for this, so I think it’s a bug with the expect(x).to.throw assertion. As a redundancy check, I tried:

expect(test).to.throw(error);

and that passed. Any thoughts?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 4
  • Comments: 18 (11 by maintainers)

Most upvoted comments

Hi @suissa. What you’re running into is something different, and not a bug. You need to pass a function to expect instead of calling the function and passing its return value to expect. The way you have it now, your function is being called and throwing an error before expect is called, so expect doesn’t have a chance to catch the error.

Working example:

  describe('An Immutable',  () => {
    it(' cannot accept a value different than OBJECT', () => {
      expect(() => require('../lib/iammutable')(1)).to.throw(TypeError, 'You need to send an OBJECT!')
    })
  })

@keithamus The behavior of checking for both the error and the message when they exist has been fixed, but we took the design decision of doing strict (===) comparisons when an Error instance is passed. So the correct assertion here would be expect(test).to.throw(RangeError, 'Invalid date range');, and not the one with the new operator (since passing an error instance triggers strict comparison).

We did this in order to enable users to choose between both behaviors (strict comparisons and a comparison using the constructor and/or message).

Same bug here.

My code:

'use strict'

module.exports = (obj) => {
  if(obj instanceof Object)
    if(Object.isFrozen(obj)) return obj
    else return Object.freeze(obj)
  else throw new TypeError('You need to send an OBJECT!')
}

test:

  describe('An Immutable',  () => {
    it(' cannot accept a value different than OBJECT', () => {
      expect(require('./iammutable')(1)).to.throw(TypeError, 'You need to send an OBJECT!')
    })
  })

output:

 An Immutable
      1)  cannot accept a value different than OBJECT


  1 failing

  1) I am Mutable, but not!  An Immutable  cannot accept a value different than OBJECT:
     TypeError: You need to send an OBJECT!
      at module.exports (iammutable.js:7:14)
      at Context.it (iammutable.test.js:30:37)