Chai version: 3.5.0
New to using Chai so may not be using it correctly, but my "expect .to.throw" tests are not working correctly (contrast with working try/catch version):
/*jshint node:true, mocha:true, expr:true*/
'use strict';
var expect = require('chai').expect;
function Foo () {
this._instance = false;
}
Foo.prototype.init = function () {
if (this._instance) {
throw new Error('Already initialised');
}
this._instance = true;
};
Foo.prototype.bar = function () {
if (!this._instance) {
throw new Error('Not intialised');
}
};
describe('test - normal', function () {
var foo = new Foo();
it('throws exception when not initialised', function () {
expect(foo.bar).to.throw('Not intialised');
});
it('initialise', function () {
expect(foo.init).to.be.ok;
expect(foo.bar).to.be.ok;
});
it('throws exception when re-initialised', function () {
expect(foo.init).to.throw('Already initialised');
});
});
describe('test - try/catch', function () {
var foo = new Foo();
it('throws exception when not initialised', function () {
try {
foo.bar();
} catch (e) {
expect(e.message).to.equal('Not intialised');
}
});
it('initialise', function () {
expect(foo.init).to.be.ok;
expect(foo.bar).to.be.ok;
});
it('throws exception when re-initialised', function () {
try {
foo.init();
} catch (e) {
expect(e.message).to.equal('Already intialised');
}
});
});
returns:
test - normal
1) throws exception when not initialised
✓ initialise
2) throws exception when re-initialised
test - try/catch
✓ throws exception when not initialised
✓ initialise
✓ throws exception when re-initialised
4 passing (11ms)
2 failing
1) test - normal throws exception when not initialised:
AssertionError: expected [Function] to throw error including 'Not intialised' but got 'Cannot read property \'_instance\' of undefined'
at Context.<anonymous> (test/testSpec.js:28:33)
2) test - normal throws exception when re-initialised:
AssertionError: expected [Function] to throw error including 'Already initialised' but got 'Cannot read property \'_instance\' of undefined'
at Context.<anonymous> (test/testSpec.js:37:34)
Hey @borisovg, thanks for the issue.
When expect(foo.bar) is called, it passes bar method to Chai without the context (given strict mode, this would be undefined, not foo) and it causes unexpected error messages.
Please, try expect(() => foo.bar()) or expect(foo.bar.bind(foo)).
Thanks @shvaikalesh: using .bind(foo) does indeed work. Still somewhat unexpected. :)
Just to be clear, there's nothing Chai could do programmatically to avoid this issue. However, it might be good to create a "common pitfalls" note at the end of the throw documentation that mentions this pitfall as well as the other common pitfall of passing the result of a function instead of the actual function (e.g., expect(fn()).to.throw();).
Great idea, @meeber! 😄
I've done a PR for that, please let me know if you remember anything else to add there.
Also, it might have a few grammar mistakes since I'm not a native speaker, so I'm counting on your English skills for the review 😆
Is there any preference which style is better to expect error thrown? normal vs try/catch?
Most helpful comment
Hey @borisovg, thanks for the issue.
When
expect(foo.bar)is called, it passesbarmethod to Chai without the context (given strict mode,thiswould beundefined, notfoo) and it causes unexpected error messages.Please, try
expect(() => foo.bar())orexpect(foo.bar.bind(foo)).