diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 622f76b5b..91f020457 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -2393,6 +2393,130 @@ module.exports = function (chai, _) { Assertion.addMethod('keys', assertKeys); Assertion.addMethod('key', assertKeys); + /** + * ### .error([errLike[, errMsgMatcher[, msg]]]) + * + * When no arguments are provided, `.error` asserts that the target is an + * instance of the built-in `Error` constructor. + * + * expect(new Error('Illegal salmon!')).to.be.an.error(); + * + * When one argument is provided, and it's an `Error` constructor, `.error` + * asserts that the target is an instance of that `Error` constructor. + * + * expect(new TypeError('Illegal salmon!')).to.be.an.error(TypeError); + * + * When one argument is provided, and it's an `Error` instance, `.error` + * asserts that the target is strictly (`===`) equal to that `Error` instance. + * + * var err = new TypeError('Illegal salmon!'); + * + * expect(err).to.be.an.error(err); + * + * When one argument is provided, and it's a string, `.error` asserts that + * the target is an instance of `Error` with a message that contains that + * string. + * + * expect(new Error('Illegal salmon!')).to.be.an.error('salmon'); + * + * When one argument is provided, and it's a regular expression, `.error` + * asserts that the target is an instance of `Error` with a message that + * matches that regular expression. + * + * expect(new Error('Illegal salmon!')).to.be.an.error(/salmon/); + * + * When two arguments are provided, and the first is an `Error` constructor, + * and the second is a string or regular expression, `.error` asserts that the + * target is an `Error` instance that fulfills both conditions as described + * above. + * + * var err = new TypeError('Illegal salmon!'); + * + * expect(err).to.be.an.error(TypeError, 'salmon'); + * expect(err).to.be.an.error(TypeError, /salmon/); + * expect(err).to.be.an.error(err, 'salmon'); + * expect(err).to.be.an.error(err, /salmon/); + * + * Add `.not` earlier in the chain to negate `.error`. + * + * expect(42).to.not.be.an.error(); + * + * However, it's dangerous to negate `.error` when providing any arguments. + * The problem is that it creates uncertain expectations by asserting that the + * target either isn't an `Error` instance, or that it is an `Error` instance + * but not of the given `Error` constructor, or that it is an instance of the + * given `Error` constructor but with a message that doesn't include the given + * string. It's often best to identify the exact output that's expected, and + * then write an assertion that only accepts that exact output. + * + * When the target isn't expected to be an `Error` instance, it's often best + * to assert what it's expected to equal. + * + * var myNum = 42; + * + * expect(myNum).to.equal(42); // Recommended + * expect(myNum).to.not.be.an.error(); // Not recommended + * + * When the target is expected to be an `Error` instance, it's often best to + * assert that it's an instance of a certain `Error` constructor, and has a + * message that includes a certain string, rather than asserting that it isn't + * an instance of one of countless `Error` constructors, and doesn't have a + * message that includes one of countless strings. + * + * var err = new TypeError('Illegal salmon!'); + * + * expect(err).to.be.an.error(TypeError, 'salmon'); // Recommended + * expect(err).to.not.be.an.error(ReferenceError, 'x'); // Not recommended + * + * `.error` accepts an optional `msg` argument which is a custom error + * message to show when the assertion fails. The message can also be given as + * the second argument to `expect`. When not providing two arguments, always + * use the second form. + * + * var myNum = 42; + * + * expect(myNum).to.be.an.error(TypeError, 'x', 'nooo why fail??'); + * expect(myNum, 'nooo why fail??').to.be.an.error(); + * + * Due to limitations in ES5, `.error` may not always work as expected when + * using a transpiler such as Babel or TypeScript. In particular, it may + * produce unexpected results when subclassing the built-in `Error` + * constructor and then passing the subclassed constructor to `.error`. See + * your transpiler's docs for details: + * + * - ([Babel](https://babeljs.io/docs/usage/caveats/#classes)) + * - ([TypeScript](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work)) + * + * @name error + * @param {Error|ErrorConstructor} errLike + * @param {String|RegExp} errMsgMatcher error message + * @param {String} msg _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace BDD + * @api public + */ + + Assertion.addMethod('error', function (errLike, errMsgMatcher, msg) { + if (msg) flag(this, 'message', msg); + + var obj = flag(this, 'object'); + var criteria = _.checkError.createCriteria(errLike, errMsgMatcher); + var expectedDesc = _.checkError.describeExpectedError(criteria); + // We append the expected value instead of using #{exp} because #{exp} adds + // single quotes around the expected value, even when it doesn't make sense + // (e.g., "expected [Error] to be 'a TypeError'"). + var failMsg = 'expected #{act} to be ' + expectedDesc; + var negatedFailMsg = 'expected #{act} to not be ' + expectedDesc; + + this.assert( + _.checkError.checkError(obj, criteria), + failMsg, + negatedFailMsg, + errLike, + obj + ); + }); + /** * ### .throw([errLike[, errMsgMatcher[, msg]]]) * diff --git a/test/expect.js b/test/expect.js index c5cff90be..49cb86bc3 100644 --- a/test/expect.js +++ b/test/expect.js @@ -2699,6 +2699,314 @@ describe('expect', function () { expect(badFn).to.throw(Error).with.property('message', 'testing'); }); + describe("error", function () { + var errObj = new Error("i like waffles"); + var subErrObj = new TypeError("i like waffles"); + var nonErrObj = { message: "i like waffles" }; + + describe("given no arguments", function () { + it("passes when target is an `Error` instance", function () { + expect(errObj).to.be.an.error(); + }); + it("passes when target is a subclassed `Error` instance", function () { + expect(subErrObj).to.be.an.error(); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + expect(nonErrObj, "blah").to.be.an.error(); + }, "blah: expected { message: 'i like waffles' } to be an Error"); + }); + it("fails when target is a number", function () { + err(function () { + expect(42, "blah").to.be.an.error(); + }, "blah: expected 42 to be an Error"); + }); + it("fails when target is undefined", function () { + err(function () { + expect(undefined, "blah").to.be.an.error(); + }, "blah: expected undefined to be an Error"); + }); + }); + + describe("given a string only", function () { + it("passes when target is an `Error` instance with a message including the string", function () { + expect(errObj).to.be.an.error("waffles"); + }); + it("passes when target is a subclassed `Error` instance with a message including the string", function () { + expect(subErrObj).to.be.an.error("waffles"); + }); + it("fails when target's message doesn't include the string", function () { + err(function () { + expect(errObj, "blah").to.be.an.error("pancakes"); + }, "blah: expected [Error: i like waffles] to be an Error including 'pancakes'"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + expect(nonErrObj, "blah").to.be.an.error("waffles"); + }, "blah: expected { message: 'i like waffles' } to be an Error including 'waffles'"); + }); + }); + + describe("given a regexp only", function () { + it("passes when target is an `Error` instance with a message matching the regexp", function () { + expect(errObj).to.be.an.error(/waffles/); + }); + it("passes when target is a subclassed `Error` instance with a message matching the regexp", function () { + expect(subErrObj).to.be.an.error(/waffles/); + }); + it("fails when target's message doesn't match the regexp", function () { + err(function () { + expect(errObj, "blah").to.be.an.error(/pancakes/); + }, "blah: expected [Error: i like waffles] to be an Error matching /pancakes/"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + expect(nonErrObj, "blah").to.be.an.error(/waffles/); + }, "blah: expected { message: 'i like waffles' } to be an Error matching /waffles/"); + }); + }); + + describe("given a subclassed `Error` constructor only", function () { + it("passes when target is an instance of the constructor", function () { + expect(subErrObj).to.be.an.error(TypeError); + }); + it("fails when target is an instance of a different subclassed `Error` constructor", function () { + err(function () { + expect(subErrObj, "blah").to.be.an.error(ReferenceError); + }, "blah: expected [TypeError: i like waffles] to be a ReferenceError"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + expect(nonErrObj, "blah").to.be.an.error(TypeError); + }, "blah: expected { message: 'i like waffles' } to be a TypeError"); + }); + }); + + describe("given a subclassed `Error` constructor and string", function () { + it("passes when target is an instance of the constructor with a message including the string", function () { + expect(subErrObj).to.be.an.error(TypeError, "waffles"); + }); + it("fails when target is an instance of a different subclassed `Error` constructor", function () { + err(function () { + expect(subErrObj).to.be.an.error(ReferenceError, "waffles", "blah"); + }, "blah: expected [TypeError: i like waffles] to be a ReferenceError including 'waffles'"); + }); + it("fails when target's message doesn't include the string", function () { + err(function () { + expect(subErrObj).to.be.an.error(TypeError, "pancakes", "blah"); + }, "blah: expected [TypeError: i like waffles] to be a TypeError including 'pancakes'"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + expect(nonErrObj).to.be.an.error(TypeError, "waffles", "blah"); + }, "blah: expected { message: 'i like waffles' } to be a TypeError including 'waffles'"); + }); + }); + + describe("given a subclassed `Error` constructor and regexp", function () { + it("passes when target is an instance of the constructor with a message matching the regexp", function () { + expect(subErrObj).to.be.an.error(TypeError, /waffles/); + }); + it("fails when target is an instance of a different subclassed `Error` constructor", function () { + err(function () { + expect(subErrObj).to.be.an.error(ReferenceError, /waffles/, "blah"); + }, "blah: expected [TypeError: i like waffles] to be a ReferenceError matching /waffles/"); + }); + it("fails when target's message doesn't match the regexp", function () { + err(function () { + expect(subErrObj).to.be.an.error(TypeError, /pancakes/, "blah"); + }, "blah: expected [TypeError: i like waffles] to be a TypeError matching /pancakes/"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + expect(nonErrObj).to.be.an.error(TypeError, /waffles/, "blah"); + }, "blah: expected { message: 'i like waffles' } to be a TypeError matching /waffles/"); + }); + }); + + describe("given an `Error` instance only", function () { + it("passes when target is strictly equal to the instance", function () { + expect(errObj).to.be.an.error(errObj); + }); + it("fails when target is a different instance with the same constructor and message", function () { + err(function () { + expect(errObj, "blah").to.be.an.error(new Error("i like waffles")); + }, "blah: expected [Error: i like waffles] to be [Error: i like waffles]"); + }); + }); + + describe("given invalid arguments", function () { + it("throws when 1st arg is a string and 2rd arg is defined", function () { + err(function () { + expect(errObj).to.be.an.error("testing", "testing"); + }, "errMsgMatcher must be null or undefined when errLike is a string or regular expression", true); + }); + it("throws when 1st arg isn't an `Error` constructor, `Error` instance, string, or regexp", function () { + err(function () { + expect(errObj).to.be.an.error({}); + }, "errLike must be an Error constructor or instance", true); + }); + it("throws when 2nd arg is defined but not a string or regexp", function () { + err(function () { + expect(errObj).to.be.an.error(TypeError, {}); + }, "errMsgMatcher must be a string or regular expression", true); + }); + it("throws when 1st arg is an `Error` instance and 2rd arg is defined", function () { + err(function () { + expect(errObj).to.be.an.error(errObj, "testing"); + }, "errMsgMatcher must be null or undefined when errLike is an Error instance", true); + }); + }); + }); + + describe("not.error", function () { + var errObj = new Error("i like waffles"); + var subErrObj = new TypeError("i like waffles"); + var nonErrObj = { message: "i like waffles" }; + + describe("given no arguments", function () { + it("passes when target is a non-`Error` object", function () { + expect(nonErrObj).to.not.be.an.error(); + }); + it("passes when target is a number", function () { + expect(42).to.not.be.an.error(); + }); + it("passes when target is undefined", function () { + expect(undefined).to.not.be.an.error(); + }); + it("fails when target is an `Error` instance", function () { + err(function () { + expect(errObj, "blah").to.not.be.an.error(); + }, "blah: expected [Error: i like waffles] to not be an Error"); + }); + it("fails when target is a subclassed `Error` instance", function () { + err(function () { + expect(subErrObj, "blah").to.not.be.an.error(); + }, "blah: expected [TypeError: i like waffles] to not be an Error"); + }); + }); + + describe("given a string only", function () { + it("passes when target's message doesn't include the string", function () { + expect(errObj).to.not.be.an.error("pancakes"); + }); + it("passes when target is a non-`Error` object", function () { + expect(nonErrObj).to.not.be.an.error("waffles"); + }); + it("fails when target is an `Error` instance with a message including the string", function () { + err(function () { + expect(errObj, "blah").to.not.be.an.error("waffles"); + }, "blah: expected [Error: i like waffles] to not be an Error including 'waffles'"); + }); + it("fails when target is a subclassed `Error` instance with a message including the string", function () { + err(function () { + expect(subErrObj, "blah").to.not.be.an.error("waffles"); + }, "blah: expected [TypeError: i like waffles] to not be an Error including 'waffles'"); + }); + }); + + describe("given a regexp only", function () { + it("passes when target's message doesn't match the regexp", function () { + expect(errObj).to.not.be.an.error(/pancakes/); + }); + it("passes when target is a non-`Error` object", function () { + expect(nonErrObj).to.not.be.an.error(/waffles/); + }); + it("fails when target is an `Error` instance with a message matching the regexp", function () { + err(function () { + expect(errObj, "blah").to.not.be.an.error(/waffles/); + }, "blah: expected [Error: i like waffles] to not be an Error matching /waffles/"); + }); + it("fails when target is a subclassed `Error` instance with a message matching the regexp", function () { + err(function () { + expect(subErrObj, "blah").to.not.be.an.error(/waffles/); + }, "blah: expected [TypeError: i like waffles] to not be an Error matching /waffles/"); + }); + }); + + describe("given a subclassed `Error` constructor only", function () { + it("passes when target is an instance of a different subclassed `Error` constructor", function () { + expect(subErrObj).to.not.be.an.error(ReferenceError); + }); + it("passes when target is a non-`Error` object", function () { + expect(nonErrObj).to.not.be.an.error(TypeError); + }); + it("fails when target is an instance of the constructor", function () { + err(function () { + expect(subErrObj, "blah").to.not.be.an.error(TypeError); + }, "blah: expected [TypeError: i like waffles] to not be a TypeError"); + }); + }); + + describe("given a subclassed `Error` constructor and string", function () { + it("passes when target is an instance of a different subclassed `Error` constructor", function () { + expect(subErrObj).to.not.be.an.error(ReferenceError, "waffles"); + }); + it("passes when target's message doesn't include the string", function () { + expect(subErrObj).to.not.be.an.error(TypeError, "pancakes"); + }); + it("passes when target is a non-`Error` object", function () { + expect(nonErrObj).to.not.be.an.error(TypeError, "waffles"); + }); + it("fails when target is an instance of the constructor with a message including the string", function () { + err(function () { + expect(subErrObj).to.not.be.an.error(TypeError, "waffles", "blah"); + }, "blah: expected [TypeError: i like waffles] to not be a TypeError including 'waffles'"); + }); + }); + + describe("given a subclassed `Error` constructor and regexp", function () { + it("passes when target is an instance of a different subclassed `Error` constructor", function () { + expect(subErrObj).to.not.be.an.error(ReferenceError, /waffles/); + }); + it("passes when target's message doesn't match the regexp", function () { + expect(subErrObj).to.not.be.an.error(TypeError, /pancakes/); + }); + it("passes when target is a non-`Error` object", function () { + expect(nonErrObj).to.not.be.an.error(TypeError, /waffles/); + }); + it("fails when target is an instance of the constructor with a message matching the regexp", function () { + err(function () { + expect(subErrObj).to.not.be.an.error(TypeError, /waffles/, "blah"); + }, "blah: expected [TypeError: i like waffles] to not be a TypeError matching /waffles/"); + }); + }); + + describe("given an `Error` instance only", function () { + it("passes when target is a different instance with the same constructor and message", function () { + expect(errObj).to.not.be.an.error(new Error("i like waffles")); + }); + it("fails when target is strictly equal to the instance", function () { + err(function () { + expect(errObj, "blah").to.not.be.an.error(errObj); + }, "blah: expected [Error: i like waffles] to not be [Error: i like waffles]"); + }); + }); + + describe("given invalid arguments", function () { + it("throws when 1st arg is a string and 2rd arg is defined", function () { + err(function () { + expect(errObj).to.not.be.an.error("testing", "testing"); + }, "errMsgMatcher must be null or undefined when errLike is a string or regular expression", true); + }); + it("throws when 1st arg isn't an `Error` constructor, `Error` instance, string, or regexp", function () { + err(function () { + expect(errObj, "blah").to.not.be.an.error({}); + }, "errLike must be an Error constructor or instance", true); + }); + it("throws when 2nd arg is defined but not a string or regexp", function () { + err(function () { + expect(errObj).to.not.be.an.error(TypeError, {}); + }, "errMsgMatcher must be a string or regular expression", true); + }); + it("throws when 1st arg is an `Error` instance and 2rd arg is defined", function () { + err(function () { + expect(errObj).to.not.be.an.error(errObj, "testing"); + }, "errMsgMatcher must be null or undefined when errLike is an Error instance", true); + }); + }); + }); + it('throw', function () { // See GH-45: some poorly-constructed custom errors don't have useful names // on either their constructor or their constructor prototype, but instead diff --git a/test/should.js b/test/should.js index 652c3b7db..42fe39e8f 100644 --- a/test/should.js +++ b/test/should.js @@ -2272,6 +2272,306 @@ describe('should', function() { expected.should.deep.equal(original_order); }); + describe("error", function () { + var errObj = new Error("i like waffles"); + var subErrObj = new TypeError("i like waffles"); + var nonErrObj = { message: "i like waffles" }; + + describe("given no arguments", function () { + it("passes when target is an `Error` instance", function () { + errObj.should.be.an.error(); + }); + it("passes when target is a subclassed `Error` instance", function () { + subErrObj.should.be.an.error(); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + nonErrObj.should.be.an.error(); + }, "expected { message: 'i like waffles' } to be an Error"); + }); + it("fails when target is a number", function () { + err(function () { + (42).should.be.an.error(); + }, "expected 42 to be an Error"); + }); + }); + + describe("given a string only", function () { + it("passes when target is an `Error` instance with a message including the string", function () { + errObj.should.be.an.error("waffles"); + }); + it("passes when target is a subclassed `Error` instance with a message including the string", function () { + subErrObj.should.be.an.error("waffles"); + }); + it("fails when target's message doesn't include the string", function () { + err(function () { + errObj.should.be.an.error("pancakes"); + }, "expected [Error: i like waffles] to be an Error including 'pancakes'"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + nonErrObj.should.be.an.error("waffles"); + }, "expected { message: 'i like waffles' } to be an Error including 'waffles'"); + }); + }); + + describe("given a regexp only", function () { + it("passes when target is an `Error` instance with a message matching the regexp", function () { + errObj.should.be.an.error(/waffles/); + }); + it("passes when target is a subclassed `Error` instance with a message matching the regexp", function () { + subErrObj.should.be.an.error(/waffles/); + }); + it("fails when target's message doesn't match the regexp", function () { + err(function () { + errObj.should.be.an.error(/pancakes/); + }, "expected [Error: i like waffles] to be an Error matching /pancakes/"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + nonErrObj.should.be.an.error(/waffles/); + }, "expected { message: 'i like waffles' } to be an Error matching /waffles/"); + }); + }); + + describe("given a subclassed `Error` constructor only", function () { + it("passes when target is an instance of the constructor", function () { + subErrObj.should.be.an.error(TypeError); + }); + it("fails when target is an instance of a different subclassed `Error` constructor", function () { + err(function () { + subErrObj.should.be.an.error(ReferenceError); + }, "expected [TypeError: i like waffles] to be a ReferenceError"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + nonErrObj.should.be.an.error(TypeError); + }, "expected { message: 'i like waffles' } to be a TypeError"); + }); + }); + + describe("given a subclassed `Error` constructor and string", function () { + it("passes when target is an instance of the constructor with a message including the string", function () { + subErrObj.should.be.an.error(TypeError, "waffles"); + }); + it("fails when target is an instance of a different subclassed `Error` constructor", function () { + err(function () { + subErrObj.should.be.an.error(ReferenceError, "waffles", "blah"); + }, "blah: expected [TypeError: i like waffles] to be a ReferenceError including 'waffles'"); + }); + it("fails when target's message doesn't include the string", function () { + err(function () { + subErrObj.should.be.an.error(TypeError, "pancakes", "blah"); + }, "blah: expected [TypeError: i like waffles] to be a TypeError including 'pancakes'"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + nonErrObj.should.be.an.error(TypeError, "waffles", "blah"); + }, "blah: expected { message: 'i like waffles' } to be a TypeError including 'waffles'"); + }); + }); + + describe("given a subclassed `Error` constructor and regexp", function () { + it("passes when target is an instance of the constructor with a message matching the regexp", function () { + subErrObj.should.be.an.error(TypeError, /waffles/); + }); + it("fails when target is an instance of a different subclassed `Error` constructor", function () { + err(function () { + subErrObj.should.be.an.error(ReferenceError, /waffles/, "blah"); + }, "blah: expected [TypeError: i like waffles] to be a ReferenceError matching /waffles/"); + }); + it("fails when target's message doesn't match the regexp", function () { + err(function () { + subErrObj.should.be.an.error(TypeError, /pancakes/, "blah"); + }, "blah: expected [TypeError: i like waffles] to be a TypeError matching /pancakes/"); + }); + it("fails when target is a non-`Error` object", function () { + err(function () { + nonErrObj.should.be.an.error(TypeError, /waffles/, "blah"); + }, "blah: expected { message: 'i like waffles' } to be a TypeError matching /waffles/"); + }); + }); + + describe("given an `Error` instance only", function () { + it("passes when target is strictly equal to the instance", function () { + errObj.should.be.an.error(errObj); + }); + it("fails when target is a different instance with the same constructor and message", function () { + err(function () { + errObj.should.be.an.error(new Error("i like waffles")); + }, "expected [Error: i like waffles] to be [Error: i like waffles]"); + }); + }); + + describe("given invalid arguments", function () { + it("throws when 1st arg is a string and 2rd arg is defined", function () { + err(function () { + errObj.should.be.an.error("testing", "testing"); + }, "errMsgMatcher must be null or undefined when errLike is a string or regular expression", true); + }); + it("throws when 1st arg isn't an `Error` constructor, `Error` instance, string, or regexp", function () { + err(function () { + errObj.should.be.an.error({}); + }, "errLike must be an Error constructor or instance", true); + }); + it("throws when 2nd arg is defined but not a string or regexp", function () { + err(function () { + errObj.should.be.an.error(TypeError, {}); + }, "errMsgMatcher must be a string or regular expression", true); + }); + it("throws when 1st arg is an `Error` instance and 2rd arg is defined", function () { + err(function () { + errObj.should.be.an.error(errObj, "testing"); + }, "errMsgMatcher must be null or undefined when errLike is an Error instance", true); + }); + }); + }); + + describe("not.error", function () { + var errObj = new Error("i like waffles"); + var subErrObj = new TypeError("i like waffles"); + var nonErrObj = { message: "i like waffles" }; + + describe("given no arguments", function () { + it("passes when target is a non-`Error` object", function () { + nonErrObj.should.not.be.an.error(); + }); + it("passes when target is a number", function () { + (42).should.not.be.an.error(); + }); + it("fails when target is an `Error` instance", function () { + err(function () { + errObj.should.not.be.an.error(); + }, "expected [Error: i like waffles] to not be an Error"); + }); + it("fails when target is a subclassed `Error` instance", function () { + err(function () { + subErrObj.should.not.be.an.error(); + }, "expected [TypeError: i like waffles] to not be an Error"); + }); + }); + + describe("given a string only", function () { + it("passes when target's message doesn't include the string", function () { + errObj.should.not.be.an.error("pancakes"); + }); + it("passes when target is a non-`Error` object", function () { + nonErrObj.should.not.be.an.error("waffles"); + }); + it("fails when target is an `Error` instance with a message including the string", function () { + err(function () { + errObj.should.not.be.an.error("waffles"); + }, "expected [Error: i like waffles] to not be an Error including 'waffles'"); + }); + it("fails when target is a subclassed `Error` instance with a message including the string", function () { + err(function () { + subErrObj.should.not.be.an.error("waffles"); + }, "expected [TypeError: i like waffles] to not be an Error including 'waffles'"); + }); + }); + + describe("given a regexp only", function () { + it("passes when target's message doesn't match the regexp", function () { + errObj.should.not.be.an.error(/pancakes/); + }); + it("passes when target is a non-`Error` object", function () { + nonErrObj.should.not.be.an.error(/waffles/); + }); + it("fails when target is an `Error` instance with a message matching the regexp", function () { + err(function () { + errObj.should.not.be.an.error(/waffles/); + }, "expected [Error: i like waffles] to not be an Error matching /waffles/"); + }); + it("fails when target is a subclassed `Error` instance with a message matching the regexp", function () { + err(function () { + subErrObj.should.not.be.an.error(/waffles/); + }, "expected [TypeError: i like waffles] to not be an Error matching /waffles/"); + }); + }); + + describe("given a subclassed `Error` constructor only", function () { + it("passes when target is an instance of a different subclassed `Error` constructor", function () { + subErrObj.should.not.be.an.error(ReferenceError); + }); + it("passes when target is a non-`Error` object", function () { + nonErrObj.should.not.be.an.error(TypeError); + }); + it("fails when target is an instance of the constructor", function () { + err(function () { + subErrObj.should.not.be.an.error(TypeError); + }, "expected [TypeError: i like waffles] to not be a TypeError"); + }); + }); + + describe("given a subclassed `Error` constructor and string", function () { + it("passes when target is an instance of a different subclassed `Error` constructor", function () { + subErrObj.should.not.be.an.error(ReferenceError, "waffles"); + }); + it("passes when target's message doesn't include the string", function () { + subErrObj.should.not.be.an.error(TypeError, "pancakes"); + }); + it("passes when target is a non-`Error` object", function () { + nonErrObj.should.not.be.an.error(TypeError, "waffles"); + }); + it("fails when target is an instance of the constructor with a message including the string", function () { + err(function () { + subErrObj.should.not.be.an.error(TypeError, "waffles", "blah"); + }, "blah: expected [TypeError: i like waffles] to not be a TypeError including 'waffles'"); + }); + }); + + describe("given a subclassed `Error` constructor and regexp", function () { + it("passes when target is an instance of a different subclassed `Error` constructor", function () { + subErrObj.should.not.be.an.error(ReferenceError, /waffles/); + }); + it("passes when target's message doesn't match the regexp", function () { + subErrObj.should.not.be.an.error(TypeError, /pancakes/); + }); + it("passes when target is a non-`Error` object", function () { + nonErrObj.should.not.be.an.error(TypeError, /waffles/); + }); + it("fails when target is an instance of the constructor with a message matching the regexp", function () { + err(function () { + subErrObj.should.not.be.an.error(TypeError, /waffles/, "blah"); + }, "blah: expected [TypeError: i like waffles] to not be a TypeError matching /waffles/"); + }); + }); + + describe("given an `Error` instance only", function () { + it("passes when target is a different instance with the same constructor and message", function () { + errObj.should.not.be.an.error(new Error("i like waffles")); + }); + it("fails when target is strictly equal to the instance", function () { + err(function () { + errObj.should.not.be.an.error(errObj); + }, "expected [Error: i like waffles] to not be [Error: i like waffles]"); + }); + }); + + describe("given invalid arguments", function () { + it("throws when 1st arg is a string and 2rd arg is defined", function () { + err(function () { + errObj.should.not.be.an.error("testing", "testing"); + }, "errMsgMatcher must be null or undefined when errLike is a string or regular expression", true); + }); + it("throws when 1st arg isn't an `Error` constructor, `Error` instance, string, or regexp", function () { + err(function () { + errObj.should.not.be.an.error({}); + }, "errLike must be an Error constructor or instance", true); + }); + it("throws when 2nd arg is defined but not a string or regexp", function () { + err(function () { + errObj.should.not.be.an.error(TypeError, {}); + }, "errMsgMatcher must be a string or regular expression", true); + }); + it("throws when 1st arg is an `Error` instance and 2rd arg is defined", function () { + err(function () { + errObj.should.not.be.an.error(errObj, "testing"); + }, "errMsgMatcher must be null or undefined when errLike is an Error instance", true); + }); + }); + }); + it('throw', function () { // See GH-45: some poorly-constructed custom errors don't have useful names // on either their constructor or their constructor prototype, but instead