Skip to content

Commit

Permalink
Bring promise rejection tests in line with Chai.
Browse files Browse the repository at this point in the history
chai-as-promised's `.rejectedWith` and `assert.isRejected` now mirror how Chai's `.throws` works. Fixes #47.
  • Loading branch information
lddubeau authored and domenic committed Sep 27, 2016
1 parent 10beb9e commit 33ce9df
Showing 1 changed file with 79 additions and 64 deletions.
143 changes: 79 additions & 64 deletions lib/chai-as-promised.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
return typeof assertion.then === "function" ? assertion : assertion._obj;
}

function getReasonName(reason) {
return (reason instanceof Error) ? reason.toString() : checkError.getConstructorName(reason);
}

// Grab these first, before we modify `Assertion.prototype`.

var propertyNames = Object.getOwnPropertyNames(Assertion.prototype);
Expand All @@ -118,7 +122,7 @@
function (reason) {
assertIfNotNegated(that,
"expected promise to be fulfilled but it was rejected with #{act}",
{ actual: reason });
{ actual: getReasonName(reason) });
return reason;
}
);
Expand All @@ -138,7 +142,7 @@
function (reason) {
assertIfNegated(that,
"expected promise not to be rejected but it was rejected with #{act}",
{ actual: reason });
{ actual: getReasonName(reason) });

// Return the reason, transforming this into a fulfillment, to allow further assertions, e.g.
// `promise.should.be.rejected.and.eventually.equal("reason")`.
Expand All @@ -149,21 +153,38 @@
chaiAsPromised.transferPromiseness(that, derivedPromise);
});

method("rejectedWith", function (Constructor, message) {
var desiredReason = null;
var constructorName = null;

if (Constructor instanceof RegExp || typeof Constructor === "string") {
message = Constructor;
Constructor = null;
} else if (Constructor && Constructor instanceof Error) {
desiredReason = Constructor;
Constructor = null;
message = null;
} else if (typeof Constructor === "function") {
constructorName = checkError.getConstructorName(Constructor);
method("rejectedWith", function (errorLike, errMsgMatcher, message) {
var errorLikeName = null;
var negate = utils.flag(this, "negate") || false;

// rejectedWith with that is called without arguments is
// the same as a plain ".rejected" use.
if (errorLike === undefined && errMsgMatcher === undefined &&
message === undefined) {
/* jshint expr: true */
this.rejected;
return;
}

if (message !== undefined) {
utils.flag(this, "message", message);
}

if (errorLike instanceof RegExp || typeof errorLike === "string") {
errMsgMatcher = errorLike;
errorLike = null;
} else if (errorLike && errorLike instanceof Error) {
errorLikeName = errorLike.toString();
} else if (typeof errorLike === "function") {
errorLikeName = checkError.getConstructorName(errorLike);
} else {
Constructor = null;
errorLike = null;
}
var everyArgIsDefined = Boolean(errorLike && errMsgMatcher);

var matcherRelation = "including";
if (errMsgMatcher instanceof RegExp) {
matcherRelation = "matching";
}

var that = this;
Expand All @@ -172,60 +193,59 @@
var assertionMessage = null;
var expected = null;

if (Constructor) {
if (errorLike) {
assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
"#{act}";
expected = constructorName;
} else if (message) {
var verb = message instanceof RegExp ? "matching" : "including";
assertionMessage = "expected promise to be rejected with an error " + verb + " #{exp} but it " +
"was fulfilled with #{act}";
expected = message;
} else if (desiredReason) {
assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
"#{act}";
expected = desiredReason;
expected = errorLikeName;
} else if (errMsgMatcher) {
assertionMessage = "expected promise to be rejected with an error " + matcherRelation +
" #{exp} but it was fulfilled with #{act}";
expected = errMsgMatcher;
}

assertIfNotNegated(that, assertionMessage, { expected: expected, actual: value });
return value;
},
function (reason) {
if (Constructor) {
that.assert(reason instanceof Constructor,
"expected promise to be rejected with #{exp} but it was rejected with #{act}",
"expected promise not to be rejected with #{exp} but it was rejected with #{act}",
constructorName,
reason);
var errorLikeCompatible = errorLike && (errorLike instanceof Error ?
checkError.compatibleInstance(reason, errorLike) :
checkError.compatibleConstructor(reason, errorLike));

var errMsgMatcherCompatible = errMsgMatcher && checkError.compatibleMessage(reason, errMsgMatcher);

var reasonName = getReasonName(reason);

if (negate && everyArgIsDefined) {
if (errorLikeCompatible && errMsgMatcherCompatible) {
that.assert(true,
null,
"expected promise not to be rejected with #{exp} but it was rejected " +
"with #{act}",
errorLikeName,
reasonName);
}
}

var reasonMessage = utils.type(reason) === "object" && "message" in reason ?
reason.message :
"" + reason;
if (message && reasonMessage !== null && reasonMessage !== undefined) {
if (message instanceof RegExp) {
that.assert(message.test(reasonMessage),
"expected promise to be rejected with an error matching #{exp} but got #{act}",
"expected promise not to be rejected with an error matching #{exp}",
message,
reasonMessage);
else {
if (errorLike) {
that.assert(errorLikeCompatible,
"expected promise to be rejected with #{exp} but it was rejected with #{act}",
"expected promise not to be rejected with #{exp} but it was rejected " +
"with #{act}",
errorLikeName,
reasonName);
}
if (typeof message === "string") {
that.assert(reasonMessage.indexOf(message) !== -1,
"expected promise to be rejected with an error including #{exp} but got #{act}",
"expected promise not to be rejected with an error including #{exp}",
message,
reasonMessage);

if (errMsgMatcher) {
that.assert(errMsgMatcherCompatible,
"expected promise to be rejected with an error " + matcherRelation +
" #{exp} but got #{act}",
"expected promise not to be rejected with an error " + matcherRelation +
" #{exp}",
errMsgMatcher,
checkError.getMessage(reason));
}
}

if (desiredReason) {
that.assert(reason === desiredReason,
"expected promise to be rejected with #{exp} but it was rejected with #{act}",
"expected promise not to be rejected with #{exp}",
desiredReason,
reason);
}
return reason;
}
);
Expand Down Expand Up @@ -330,14 +350,9 @@
return (new Assertion(promise, message)).to.be.fulfilled;
};

assert.isRejected = function (promise, toTestAgainst, message) {
if (typeof toTestAgainst === "string") {
message = toTestAgainst;
toTestAgainst = undefined;
}

assert.isRejected = function (promise, errorLike, errMsgMatcher, message) {
var assertion = (new Assertion(promise, message));
return toTestAgainst !== undefined ? assertion.to.be.rejectedWith(toTestAgainst) : assertion.to.be.rejected;
return assertion.to.be.rejectedWith(errorLike, errMsgMatcher, message);
};

assert.becomes = function (promise, value, message) {
Expand Down

0 comments on commit 33ce9df

Please sign in to comment.