diff --git a/lib/chai-as-promised.js b/lib/chai-as-promised.js index c6808e0..219a504 100644 --- a/lib/chai-as-promised.js +++ b/lib/chai-as-promised.js @@ -1,26 +1,24 @@ -(function () { +(function (factory) { "use strict"; - - // Module systems magic dance. - /* istanbul ignore else */ if (typeof require === "function" && typeof exports === "object" && typeof module === "object") { // NodeJS - module.exports = chaiAsPromised; + module.exports = factory(require("check-error")); } else if (typeof define === "function" && define.amd) { // AMD - define(function () { - return chaiAsPromised; - }); + define(["check-error"], factory); } else { /*global self: false */ // Other environment (usually + diff --git a/test/should-promise-specific.coffee b/test/should-promise-specific.coffee index 957a83f..39fdd1b 100644 --- a/test/should-promise-specific.coffee +++ b/test/should-promise-specific.coffee @@ -3,6 +3,8 @@ describe "Promise-specific extensions:", => promise = null error = new Error("boo") + error.myProp = ["myProp value"] + custom = "No. I am your father." assertingDoneFactory = (done) => (result) => @@ -15,45 +17,70 @@ describe "Promise-specific extensions:", => describe "when the promise is fulfilled", => beforeEach => - promise = fulfilledPromise() + promise = fulfilledPromise(42) return undefined describe ".fulfilled", => shouldPass => promise.should.be.fulfilled + + describe ".fulfilled passes the fulfilled value", => + shouldPass => promise.should.be.fulfilled.then (passedValue) => + passedValue.should.equal(42) + + describe ".fulfilled allows chaining", => + shouldPass => promise.should.be.fulfilled.and.eventually.equal(42) + describe ".not.fulfilled", => shouldFail op: => promise.should.not.be.fulfilled - message: "not to be fulfilled but it was fulfilled with undefined" + message: "not to be fulfilled but it was fulfilled with 42" describe ".rejected", => shouldFail op: => promise.should.be.rejected - message: "to be rejected but it was fulfilled with undefined" + message: "to be rejected but it was fulfilled with 42" + + describe ".not.rejected passes the fulfilled value", => + shouldPass => promise.should.not.be.rejected.then (passedValue) => + passedValue.should.equal(42) + + # .not inverts all following assertions so the following test is + # equivalent to promise.should.eventually.not.equal(31) + describe ".not.rejected allows chaining", => + shouldPass => promise.should.not.be.rejected.and.eventually.equal(31) + describe ".rejectedWith(TypeError)", => shouldFail op: => promise.should.be.rejectedWith(TypeError) - message: "to be rejected with 'TypeError' but it was fulfilled with undefined" + message: "to be rejected with 'TypeError' but it was fulfilled with 42" + describe ".not.rejectedWith(TypeError) passes the fulfilled value", => + shouldPass => promise.should.not.be.rejectedWith(TypeError).then (passedValue) => + passedValue.should.equal(42) + + describe ".not.rejectedWith(TypeError) allows chaining", => + shouldPass => promise.should.not.be.rejectedWith(TypeError).and.eventually.equal(31) + describe ".rejectedWith('message substring')", => shouldFail op: => promise.should.be.rejectedWith("message substring") message: "to be rejected with an error including 'message substring' but it was fulfilled with " + - "undefined" + "42" describe ".rejectedWith(/regexp/)", => shouldFail op: => promise.should.be.rejectedWith(/regexp/) - message: "to be rejected with an error matching /regexp/ but it was fulfilled with undefined" + message: "to be rejected with an error matching /regexp/ but it was fulfilled with 42" describe ".rejectedWith(TypeError, 'message substring')", => shouldFail op: => promise.should.be.rejectedWith(TypeError, "message substring") - message: "to be rejected with 'TypeError' but it was fulfilled with undefined" + message: "to be rejected with 'TypeError' but it was fulfilled with 42" describe ".rejectedWith(TypeError, /regexp/)", => shouldFail op: => promise.should.be.rejectedWith(TypeError, /regexp/) - message: "to be rejected with 'TypeError' but it was fulfilled with undefined" + message: "to be rejected with 'TypeError' but it was fulfilled with 42" describe ".rejectedWith(errorInstance)", => shouldFail op: => promise.should.be.rejectedWith(error) - message: "to be rejected with [Error: boo] but it was fulfilled with undefined" + message: "to be rejected with 'Error: boo' but it was fulfilled with 42" describe ".not.rejected", => shouldPass => promise.should.not.be.rejected @@ -82,27 +109,67 @@ describe "Promise-specific extensions:", => describe ".fulfilled", => shouldFail op: => promise.should.be.fulfilled - message: "to be fulfilled but it was rejected with [Error: boo]" + message: "to be fulfilled but it was rejected with 'Error: boo'" + describe ".not.fulfilled", => shouldPass => promise.should.not.be.fulfilled + describe ".not.fulfilled should allow chaining", => + shouldPass => promise.should.not.be.fulfilled.and.eventually.have.property("nonexistent") + + describe ".not.fulfilled should pass the rejection reason", => + shouldPass => promise.should.not.be.fulfilled.then (passedError) => + passedError.should.equal(error) + describe ".rejected", => shouldPass => promise.should.be.rejected + describe ".not.rejected", => + shouldFail + op: => promise.should.not.be.rejected + message: "not to be rejected but it was rejected with 'Error: boo'" + describe ".rejected should allow chaining", => + shouldPass => promise.should.be.rejected.and.eventually.have.property("myProp") + + describe ".rejected passes the rejection reason", => + shouldPass => promise.should.be.rejected.then (passedError) => + passedError.should.equal(error) + describe ".rejectedWith(theError)", => shouldPass => promise.should.be.rejectedWith(error) + describe ".not.rejectedWith(theError)", => shouldFail op: => promise.should.not.be.rejectedWith(error) - message: "not to be rejected with [Error: boo]" + message: "not to be rejected with 'Error: boo'" + + describe ".rejectedWith(theError) should allow chaining", => + shouldPass => promise.should.be.rejectedWith(error).and.eventually.have.property("myProp") + + describe ".rejectedWith(theError) passes the rejection reason", => + shouldPass => promise.should.be.rejectedWith(error).then (passedError) => + passedError.should.equal(error) describe ".rejectedWith(differentError)", => shouldFail op: => promise.should.be.rejectedWith(new Error) - message: "to be rejected with [Error] but it was rejected with [Error: boo]" + message: "to be rejected with 'Error' but it was rejected with 'Error: boo'" + describe ".not.rejectedWith(differentError)", => shouldPass => promise.should.not.be.rejectedWith(new Error) + # Chai 3.5.0 never interprets the 2nd paramter to + # expect(fn).to.throw(a, b) as a custom error message. This is + # what we are testing here. + describe ".rejectedWith(differentError, custom)", => + shouldFail + op: => promise.should.be.rejectedWith(new Error, custom) + message: "to be rejected with 'Error' but it was rejected with 'Error: boo'" + notMessage: custom + + describe ".not.rejectedWith(differentError, custom)", => + shouldPass => promise.should.not.be.rejectedWith(new Error, custom) + describe "with an Error having message 'foo bar'", => beforeEach => promise = rejectedPromise(new Error("foo bar")) @@ -110,31 +177,56 @@ describe "Promise-specific extensions:", => describe ".rejectedWith('foo')", => shouldPass => promise.should.be.rejectedWith("foo") + + describe ".not.rejectedWith('foo')", => + shouldFail + op: => promise.should.not.be.rejectedWith("foo") + message: "not to be rejected with an error including 'foo'" + describe ".rejectedWith(/bar/)", => shouldPass => promise.should.be.rejectedWith(/bar/) + describe ".not.rejectedWith(/bar/)", => + shouldFail + op: => promise.should.not.be.rejectedWith(/bar/) + message: "not to be rejected with an error matching /bar/" + describe ".rejectedWith('quux')", => shouldFail op: => promise.should.be.rejectedWith("quux") - message: "to be rejected with an error including 'quux' but got 'Error: foo bar'" + message: "to be rejected with an error including 'quux' but got 'foo bar'" + + describe ".not.rejectedWith('quux')", => + shouldPass => promise.should.be.not.rejectedWith("quux") + describe ".rejectedWith(/quux/)", => shouldFail op: => promise.should.be.rejectedWith(/quux/) - message: "to be rejected with an error matching /quux/ but got 'Error: foo bar'" + message: "to be rejected with an error matching /quux/ but got 'foo bar'" - describe ".not.rejectedWith('foo')", => + describe ".not.rejectedWith(/quux/)", => + shouldPass => promise.should.not.be.rejectedWith(/quux/) + + # Chai 3.5.0 never interprets the 2nd paramter to + # expect(fn).to.throw(a, b) as a custom error + # message. This is what we are testing here. + describe ".rejectedWith('foo', custom)", => + shouldPass => promise.should.be.rejectedWith("foo", custom) + + describe ".not.rejectedWith('foo', custom)", => shouldFail - op: => promise.should.not.be.rejectedWith("foo") + op: => promise.should.not.be.rejectedWith("foo", custom) message: "not to be rejected with an error including 'foo'" - describe ".not.rejectedWith(/bar/)", => + notMessage: custom + + describe ".rejectedWith(/bar/, custom)", => + shouldPass => promise.should.be.rejectedWith(/bar/, custom) + + describe ".not.rejectedWith(/bar/, custom)", => shouldFail op: => promise.should.not.be.rejectedWith(/bar/) message: "not to be rejected with an error matching /bar/" - - describe ".not.rejectedWith('quux')", => - shouldPass => promise.should.not.be.rejectedWith("quux") - describe ".not.rejectedWith(/quux/)", => - shouldPass => promise.should.not.be.rejectedWith(/quux/) + notMessage: custom describe "with a RangeError", => beforeEach => @@ -143,15 +235,23 @@ describe "Promise-specific extensions:", => describe ".rejectedWith(RangeError)", => shouldPass => promise.should.be.rejectedWith(RangeError) + + describe ".not.rejectedWith(RangeError)", => + shouldFail + op: => promise.should.not.be.rejectedWith(RangeError) + message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError'" + describe ".rejectedWith(TypeError)", => shouldFail op: => promise.should.be.rejectedWith(TypeError) - message: "to be rejected with 'TypeError' but it was rejected with [RangeError]" + message: "to be rejected with 'TypeError' but it was rejected with 'RangeError'" - describe ".not.rejectedWith(RangeError)", => + # Case for issue #64. + describe ".rejectedWith(Array)", => shouldFail - op: => promise.should.not.be.rejectedWith(RangeError) - message: "not to be rejected with 'RangeError' but it was rejected with [RangeError]" + op: => promise.should.be.rejectedWith(Array) + message: "to be rejected with 'Array' but it was rejected with 'RangeError'" + describe ".not.rejectedWith(TypeError)", => shouldPass => promise.should.not.be.rejectedWith(TypeError) @@ -162,67 +262,115 @@ describe "Promise-specific extensions:", => describe ".rejectedWith(RangeError, 'foo')", => shouldPass => promise.should.be.rejectedWith(RangeError, "foo") + + describe ".not.rejectedWith(RangeError, 'foo')", => + shouldFail + op: => promise.should.not.be.rejectedWith(RangeError, "foo") + message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" + describe ".rejectedWith(RangeError, /bar/)", => shouldPass => promise.should.be.rejectedWith(RangeError, /bar/) + describe ".not.rejectedWith(RangeError, /bar/)", => + shouldFail + op: => promise.should.not.be.rejectedWith(RangeError, /bar/) + message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" + describe ".rejectedWith(RangeError, 'quux')", => shouldFail op: => promise.should.be.rejectedWith(RangeError, "quux") - message: "to be rejected with an error including 'quux' but got 'RangeError: foo bar'" + message: "to be rejected with an error including 'quux' but got 'foo bar'" describe ".rejectedWith(RangeError, /quux/)", => shouldFail op: => promise.should.be.rejectedWith(RangeError, /quux/) - message: "to be rejected with an error matching /quux/ but got 'RangeError: foo bar'" + message: "to be rejected with an error matching /quux/ but got 'foo bar'" describe ".rejectedWith(TypeError, 'foo')", => shouldFail - op: => promise.should.be.rejectedWith(TypeError) - message: "to be rejected with 'TypeError' but it was rejected with [RangeError: foo bar]" + op: => promise.should.be.rejectedWith(TypeError, 'foo') + message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" describe ".rejectedWith(TypeError, /bar/)", => shouldFail - op: => promise.should.be.rejectedWith(TypeError) - message: "to be rejected with 'TypeError' but it was rejected with [RangeError: foo bar]" + op: => promise.should.be.rejectedWith(TypeError, /bar/) + message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" describe ".rejectedWith(TypeError, 'quux')", => shouldFail - op: => promise.should.be.rejectedWith(TypeError) - message: "to be rejected with 'TypeError' but it was rejected with [RangeError: foo bar]" + op: => promise.should.be.rejectedWith(TypeError, 'quux') + message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" describe ".rejectedWith(TypeError, /quux/)", => shouldFail - op: => promise.should.be.rejectedWith(TypeError) - message: "to be rejected with 'TypeError' but it was rejected with [RangeError: foo bar]" + op: => promise.should.be.rejectedWith(TypeError, /quux/) + message: "to be rejected with 'TypeError' but it was rejected with 'RangeError: foo bar'" describe ".not.rejectedWith(RangeError, 'foo')", => shouldFail - op: => promise.should.not.be.rejectedWith(RangeError) - message: "not to be rejected with 'RangeError' but it was rejected with [RangeError: foo bar]" + op: => promise.should.not.be.rejectedWith(RangeError, 'foo') + message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" describe ".not.rejectedWith(RangeError, /bar/)", => shouldFail - op: => promise.should.not.be.rejectedWith(RangeError) - message: "not to be rejected with 'RangeError' but it was rejected with [RangeError: foo bar]" + op: => promise.should.not.be.rejectedWith(RangeError, /bar/) + message: "not to be rejected with 'RangeError' but it was rejected with 'RangeError: foo bar'" describe ".not.rejectedWith(RangeError, 'quux')", => - shouldFail - op: => promise.should.not.be.rejectedWith(RangeError) - message: "not to be rejected with 'RangeError' but it was rejected with [RangeError: foo bar]" + shouldPass => promise.should.not.be.rejectedWith(RangeError, 'quux') describe ".not.rejectedWith(RangeError, /quux/)", => - shouldFail - op: => promise.should.not.be.rejectedWith(RangeError) - message: "not to be rejected with 'RangeError' but it was rejected with [RangeError: foo bar]" - + shouldPass => promise.should.not.be.rejectedWith(RangeError, /quux/) describe ".not.rejectedWith(TypeError, 'foo')", => - shouldFail - op: => promise.should.not.be.rejectedWith(TypeError, "foo") - message: "not to be rejected with an error including 'foo'" + shouldPass => promise.should.not.be.rejectedWith(TypeError, "foo") describe ".not.rejectedWith(TypeError, /bar/)", => - shouldFail - op: => promise.should.not.be.rejectedWith(TypeError, /bar/) - message: "not to be rejected with an error matching /bar/" - + shouldPass => promise.should.not.be.rejectedWith(TypeError, /bar/) describe ".not.rejectedWith(TypeError, 'quux')", => shouldPass => promise.should.not.be.rejectedWith(TypeError, "quux") describe ".not.rejectedWith(TypeError, /quux/)", => shouldPass => promise.should.not.be.rejectedWith(TypeError, /quux/) + describe ".rejectedWith(RangeError, 'foo', custom)", => + shouldPass => promise.should.be.rejectedWith(RangeError, "foo", custom) + + describe ".not.rejectedWith(RangeError, 'foo', custom)", => + shouldFail + op: => promise.should.not.be.rejectedWith(RangeError, "foo", custom) + message: custom + + describe ".rejectedWith(RangeError, /bar/, custom)", => + shouldPass => promise.should.be.rejectedWith(RangeError, /bar/, custom) + + describe ".not.rejectedWith(RangeError, /bar/, custom)", => + shouldFail + op: => promise.should.not.be.rejectedWith(RangeError, /bar/, custom) + message: custom + + describe ".rejectedWith(RangeError, 'quux', custom)", => + shouldFail + op: => promise.should.be.rejectedWith(RangeError, "quux", custom) + message: custom + + describe ".not.rejectedWith(TypeError, 'quux', custom)", => + shouldPass => promise.should.not.be.rejectedWith(TypeError, "quux", custom) + + describe ".rejectedWith(RangeError, /quux/, custom)", => + shouldFail + op: => promise.should.be.rejectedWith(RangeError, /quux/, custom) + message: custom + + describe ".not.rejectedWith(TypeError, /quux/, custom)", => + shouldPass => promise.should.not.be.rejectedWith(TypeError, /quux/, custom) + + describe ".rejectedWith(RangeError, undefined, custom)", => + shouldPass => promise.should.be.rejectedWith(RangeError, undefined, custom) + + describe ".not.rejectedWith(RangeError, undefined, custom)", => + shouldFail + op: => promise.should.not.be.rejectedWith(RangeError, undefined, custom) + message: custom + + describe ".rejectedWith(TypeError, undefined, custom)", => + shouldFail + op: => promise.should.be.rejectedWith(TypeError, undefined, custom) + message: custom + + describe ".not.rejectedWith(TypeError, undefined, custom)", => + shouldPass => promise.should.not.be.rejectedWith(TypeError, undefined, custom) describe ".should.notify(done)", => it "should fail the test with the original error", (done) => diff --git a/test/support/common.js b/test/support/common.js index b11681c..b58ef2e 100644 --- a/test/support/common.js +++ b/test/support/common.js @@ -25,22 +25,27 @@ global.shouldPass = function (promiseProducer) { global.shouldFail = function (options) { var promiseProducer = options.op; var desiredMessageSubstring = options.message; + var nonDesiredMessageSubstring = options.notMessage; it("should return a promise rejected with an assertion error", function (done) { promiseProducer().then(function () { - done(new Error("Expected promise to be rejected with an assertion error, but it was fulfilled")); + throw new Error("Expected promise to be rejected with an assertion error, but it was fulfilled"); }, function (reason) { if (Object(reason) !== reason || reason.constructor.name !== "AssertionError") { - done(new Error("Expected promise to be rejected with an AssertionError but it was rejected with " + - reason)); - } else { - if (desiredMessageSubstring && reason.message.indexOf(desiredMessageSubstring) === -1) { - done(new Error("Expected promise to be rejected with an AssertionError containing \"" + - desiredMessageSubstring + "\" but it was rejected with " + reason)); - } else { - done(); - } + throw new Error("Expected promise to be rejected with an AssertionError but it was rejected with " + + reason); } - }); + + if (desiredMessageSubstring && reason.message.indexOf(desiredMessageSubstring) === -1) { + throw new Error("Expected promise to be rejected with an AssertionError containing \"" + + desiredMessageSubstring + "\" but it was rejected with " + reason); + } + + if (nonDesiredMessageSubstring && reason.message.indexOf(nonDesiredMessageSubstring) !== -1) { + throw new Error("Expected promise to be rejected with an AssertionError not containing \"" + + nonDesiredMessageSubstring + "\" but it was rejected with " + reason); + } + }).then(done, done); + }); };