Skip to content

Commit 33ce9df

Browse files
lddubeaudomenic
authored andcommitted
Bring promise rejection tests in line with Chai.
chai-as-promised's `.rejectedWith` and `assert.isRejected` now mirror how Chai's `.throws` works. Fixes #47.
1 parent 10beb9e commit 33ce9df

File tree

1 file changed

+79
-64
lines changed

1 file changed

+79
-64
lines changed

lib/chai-as-promised.js

Lines changed: 79 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@
9797
return typeof assertion.then === "function" ? assertion : assertion._obj;
9898
}
9999

100+
function getReasonName(reason) {
101+
return (reason instanceof Error) ? reason.toString() : checkError.getConstructorName(reason);
102+
}
103+
100104
// Grab these first, before we modify `Assertion.prototype`.
101105

102106
var propertyNames = Object.getOwnPropertyNames(Assertion.prototype);
@@ -118,7 +122,7 @@
118122
function (reason) {
119123
assertIfNotNegated(that,
120124
"expected promise to be fulfilled but it was rejected with #{act}",
121-
{ actual: reason });
125+
{ actual: getReasonName(reason) });
122126
return reason;
123127
}
124128
);
@@ -138,7 +142,7 @@
138142
function (reason) {
139143
assertIfNegated(that,
140144
"expected promise not to be rejected but it was rejected with #{act}",
141-
{ actual: reason });
145+
{ actual: getReasonName(reason) });
142146

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

152-
method("rejectedWith", function (Constructor, message) {
153-
var desiredReason = null;
154-
var constructorName = null;
155-
156-
if (Constructor instanceof RegExp || typeof Constructor === "string") {
157-
message = Constructor;
158-
Constructor = null;
159-
} else if (Constructor && Constructor instanceof Error) {
160-
desiredReason = Constructor;
161-
Constructor = null;
162-
message = null;
163-
} else if (typeof Constructor === "function") {
164-
constructorName = checkError.getConstructorName(Constructor);
156+
method("rejectedWith", function (errorLike, errMsgMatcher, message) {
157+
var errorLikeName = null;
158+
var negate = utils.flag(this, "negate") || false;
159+
160+
// rejectedWith with that is called without arguments is
161+
// the same as a plain ".rejected" use.
162+
if (errorLike === undefined && errMsgMatcher === undefined &&
163+
message === undefined) {
164+
/* jshint expr: true */
165+
this.rejected;
166+
return;
167+
}
168+
169+
if (message !== undefined) {
170+
utils.flag(this, "message", message);
171+
}
172+
173+
if (errorLike instanceof RegExp || typeof errorLike === "string") {
174+
errMsgMatcher = errorLike;
175+
errorLike = null;
176+
} else if (errorLike && errorLike instanceof Error) {
177+
errorLikeName = errorLike.toString();
178+
} else if (typeof errorLike === "function") {
179+
errorLikeName = checkError.getConstructorName(errorLike);
165180
} else {
166-
Constructor = null;
181+
errorLike = null;
182+
}
183+
var everyArgIsDefined = Boolean(errorLike && errMsgMatcher);
184+
185+
var matcherRelation = "including";
186+
if (errMsgMatcher instanceof RegExp) {
187+
matcherRelation = "matching";
167188
}
168189

169190
var that = this;
@@ -172,60 +193,59 @@
172193
var assertionMessage = null;
173194
var expected = null;
174195

175-
if (Constructor) {
196+
if (errorLike) {
176197
assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
177198
"#{act}";
178-
expected = constructorName;
179-
} else if (message) {
180-
var verb = message instanceof RegExp ? "matching" : "including";
181-
assertionMessage = "expected promise to be rejected with an error " + verb + " #{exp} but it " +
182-
"was fulfilled with #{act}";
183-
expected = message;
184-
} else if (desiredReason) {
185-
assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
186-
"#{act}";
187-
expected = desiredReason;
199+
expected = errorLikeName;
200+
} else if (errMsgMatcher) {
201+
assertionMessage = "expected promise to be rejected with an error " + matcherRelation +
202+
" #{exp} but it was fulfilled with #{act}";
203+
expected = errMsgMatcher;
188204
}
189205

190206
assertIfNotNegated(that, assertionMessage, { expected: expected, actual: value });
191207
return value;
192208
},
193209
function (reason) {
194-
if (Constructor) {
195-
that.assert(reason instanceof Constructor,
196-
"expected promise to be rejected with #{exp} but it was rejected with #{act}",
197-
"expected promise not to be rejected with #{exp} but it was rejected with #{act}",
198-
constructorName,
199-
reason);
210+
var errorLikeCompatible = errorLike && (errorLike instanceof Error ?
211+
checkError.compatibleInstance(reason, errorLike) :
212+
checkError.compatibleConstructor(reason, errorLike));
213+
214+
var errMsgMatcherCompatible = errMsgMatcher && checkError.compatibleMessage(reason, errMsgMatcher);
215+
216+
var reasonName = getReasonName(reason);
217+
218+
if (negate && everyArgIsDefined) {
219+
if (errorLikeCompatible && errMsgMatcherCompatible) {
220+
that.assert(true,
221+
null,
222+
"expected promise not to be rejected with #{exp} but it was rejected " +
223+
"with #{act}",
224+
errorLikeName,
225+
reasonName);
226+
}
200227
}
201-
202-
var reasonMessage = utils.type(reason) === "object" && "message" in reason ?
203-
reason.message :
204-
"" + reason;
205-
if (message && reasonMessage !== null && reasonMessage !== undefined) {
206-
if (message instanceof RegExp) {
207-
that.assert(message.test(reasonMessage),
208-
"expected promise to be rejected with an error matching #{exp} but got #{act}",
209-
"expected promise not to be rejected with an error matching #{exp}",
210-
message,
211-
reasonMessage);
228+
else {
229+
if (errorLike) {
230+
that.assert(errorLikeCompatible,
231+
"expected promise to be rejected with #{exp} but it was rejected with #{act}",
232+
"expected promise not to be rejected with #{exp} but it was rejected " +
233+
"with #{act}",
234+
errorLikeName,
235+
reasonName);
212236
}
213-
if (typeof message === "string") {
214-
that.assert(reasonMessage.indexOf(message) !== -1,
215-
"expected promise to be rejected with an error including #{exp} but got #{act}",
216-
"expected promise not to be rejected with an error including #{exp}",
217-
message,
218-
reasonMessage);
237+
238+
if (errMsgMatcher) {
239+
that.assert(errMsgMatcherCompatible,
240+
"expected promise to be rejected with an error " + matcherRelation +
241+
" #{exp} but got #{act}",
242+
"expected promise not to be rejected with an error " + matcherRelation +
243+
" #{exp}",
244+
errMsgMatcher,
245+
checkError.getMessage(reason));
219246
}
220247
}
221248

222-
if (desiredReason) {
223-
that.assert(reason === desiredReason,
224-
"expected promise to be rejected with #{exp} but it was rejected with #{act}",
225-
"expected promise not to be rejected with #{exp}",
226-
desiredReason,
227-
reason);
228-
}
229249
return reason;
230250
}
231251
);
@@ -330,14 +350,9 @@
330350
return (new Assertion(promise, message)).to.be.fulfilled;
331351
};
332352

333-
assert.isRejected = function (promise, toTestAgainst, message) {
334-
if (typeof toTestAgainst === "string") {
335-
message = toTestAgainst;
336-
toTestAgainst = undefined;
337-
}
338-
353+
assert.isRejected = function (promise, errorLike, errMsgMatcher, message) {
339354
var assertion = (new Assertion(promise, message));
340-
return toTestAgainst !== undefined ? assertion.to.be.rejectedWith(toTestAgainst) : assertion.to.be.rejected;
355+
return assertion.to.be.rejectedWith(errorLike, errMsgMatcher, message);
341356
};
342357

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

0 commit comments

Comments
 (0)