chai-as-promised 5.3.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2012–2015 Domenic Denicola <d@domenic.me>
1
+ Copyright © 2012–2016 Domenic Denicola <d@domenic.me>
2
2
 
3
3
  This work is free. You can redistribute it and/or modify it under the
4
4
  terms of the Do What The Fuck You Want To Public License, Version 2,
package/README.md CHANGED
@@ -124,7 +124,7 @@ chaiAsPromised.transformAsserterArgs = function (args) {
124
124
  }
125
125
 
126
126
  Promise.resolve(2).should.eventually.equal(2); // will now fail!
127
- Promise.resolve(2).should.eventually.equal(3); // will now pass!
127
+ Promise.resolve(3).should.eventually.equal(2); // will now pass!
128
128
  ```
129
129
 
130
130
  The transform can even be asynchronous, returning a promise for an array instead of an array directly. An example of that might be using `Promise.all` so that an array of promises becomes a promise for an array. If you do that, then you can compare promises against other promises using the asserters:
@@ -144,7 +144,11 @@ Promise.resolve(2).should.eventually.be.within(Promise.resolve(1), Promise.resol
144
144
 
145
145
  ### Compatibility
146
146
 
147
- Chai as Promised is compatible with all promises following the [Promises/A+ specification][spec]. Notably, jQuery's promises were not up to spec before jQuery 3.0, and Chai as Promised will not work with them. In particular, Chai as Promised makes extensive use of the standard [transformation behavior][] of `then`, which jQuery<3.0 does not support.
147
+ Chai as Promised is compatible with all promises following the [Promises/A+ specification][spec].
148
+
149
+ Notably, jQuery's promises were not up to spec before jQuery 3.0, and Chai as Promised will not work with them. In particular, Chai as Promised makes extensive use of the standard [transformation behavior][] of `then`, which jQuery<3.0 does not support.
150
+
151
+ Angular promises have a special digest cycle for their processing, and [need extra setup code to work with Chai as Promised](http://stackoverflow.com/a/37374041/3191).
148
152
 
149
153
  ### Working with Non-Promise–Friendly Test Runners
150
154
 
@@ -202,31 +206,21 @@ var chai = require("chai");
202
206
  var chaiAsPromised = require("chai-as-promised");
203
207
 
204
208
  chai.use(chaiAsPromised);
205
- ```
206
-
207
- You can of course put this code in a common test fixture file; for an example using [Mocha][], see [the Chai as Promised tests themselves][fixturedemo].
208
-
209
- ### AMD
210
209
 
211
- Chai as Promised supports being used as an [AMD][amd] module, registering itself anonymously (just like Chai). So, assuming you have configured your loader to map the Chai and Chai as Promised files to the respective module IDs `"chai"` and `"chai-as-promised"`, you can use them as follows:
212
-
213
- ```javascript
214
- define(function (require, exports, module) {
215
- var chai = require("chai");
216
- var chaiAsPromised = require("chai-as-promised");
217
-
218
- chai.use(chaiAsPromised);
219
- });
210
+ // Then either:
211
+ var expect = chai.expect;
212
+ // or:
213
+ var assert = chai.assert;
214
+ // or:
215
+ chai.should();
216
+ // according to your preference of assertion style
220
217
  ```
221
218
 
222
- ### `<script>` tag
219
+ You can of course put this code in a common test fixture file; for an example using [Mocha][], see [the Chai as Promised tests themselves][fixturedemo].
223
220
 
224
- If you include Chai as Promised directly with a `<script>` tag, after the one for Chai itself, then it will automatically plug in to Chai and be ready for use:
221
+ ### In the Browser
225
222
 
226
- ```html
227
- <script src="chai.js"></script>
228
- <script src="chai-as-promised.js"></script>
229
- ```
223
+ To use Chai as Promised in environments that don't support Node.js-like CommonJS modules, you'll need to use a bundling tool like [browserify][].
230
224
 
231
225
  ### Karma
232
226
 
@@ -250,3 +244,4 @@ Chai as Promised is only compatible with modern browsers (IE ≥9, Safari ≥6,
250
244
  [sinon-chai]: https://github.com/domenic/sinon-chai
251
245
  [Karma]: https://karma-runner.github.io/
252
246
  [karma-chai-as-promised]: https://github.com/vlkosinov/karma-chai-as-promised
247
+ [browserify]: http://browserify.org/
@@ -1,375 +1,374 @@
1
- (function () {
2
- "use strict";
3
-
4
- // Module systems magic dance.
5
-
6
- /* istanbul ignore else */
7
- if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
8
- // NodeJS
9
- module.exports = chaiAsPromised;
10
- } else if (typeof define === "function" && define.amd) {
11
- // AMD
12
- define(function () {
13
- return chaiAsPromised;
14
- });
15
- } else {
16
- /*global self: false */
1
+ "use strict";
2
+ var checkError = require("check-error");
3
+
4
+ module.exports = function (chai, utils) {
5
+ var Assertion = chai.Assertion;
6
+ var assert = chai.assert;
7
+
8
+ // If we are using a version of Chai that has checkError on it,
9
+ // we want to use that version to be consistent. Otherwise, we use
10
+ // what was passed to the factory.
11
+ if (utils.checkError) {
12
+ checkError = utils.checkError;
13
+ }
17
14
 
18
- // Other environment (usually <script> tag): plug in to global chai instance directly.
19
- chai.use(chaiAsPromised);
15
+ function isLegacyJQueryPromise(thenable) {
16
+ // jQuery promises are Promises/A+-compatible since 3.0.0. jQuery 3.0.0 is also the first version
17
+ // to define the catch method.
18
+ return typeof thenable.catch !== "function" &&
19
+ typeof thenable.always === "function" &&
20
+ typeof thenable.done === "function" &&
21
+ typeof thenable.fail === "function" &&
22
+ typeof thenable.pipe === "function" &&
23
+ typeof thenable.progress === "function" &&
24
+ typeof thenable.state === "function";
25
+ }
20
26
 
21
- // Expose as a property of the global object so that consumers can configure the `transferPromiseness` property.
22
- self.chaiAsPromised = chaiAsPromised;
27
+ function assertIsAboutPromise(assertion) {
28
+ if (typeof assertion._obj.then !== "function") {
29
+ throw new TypeError(utils.inspect(assertion._obj) + " is not a thenable.");
30
+ }
31
+ if (isLegacyJQueryPromise(assertion._obj)) {
32
+ throw new TypeError("Chai as Promised is incompatible with thenables of jQuery<3.0.0, sorry! Please " +
33
+ "upgrade jQuery or use another Promises/A+ compatible library (see " +
34
+ "http://promisesaplus.com/).");
35
+ }
23
36
  }
24
37
 
25
- chaiAsPromised.transferPromiseness = function (assertion, promise) {
26
- assertion.then = promise.then.bind(promise);
27
- };
38
+ function method(name, asserter) {
39
+ utils.addMethod(Assertion.prototype, name, function () {
40
+ assertIsAboutPromise(this);
41
+ return asserter.apply(this, arguments);
42
+ });
43
+ }
28
44
 
29
- chaiAsPromised.transformAsserterArgs = function (values) {
30
- return values;
31
- };
45
+ function property(name, asserter) {
46
+ utils.addProperty(Assertion.prototype, name, function () {
47
+ assertIsAboutPromise(this);
48
+ return asserter.apply(this, arguments);
49
+ });
50
+ }
32
51
 
33
- function chaiAsPromised(chai, utils) {
34
- var Assertion = chai.Assertion;
35
- var assert = chai.assert;
36
-
37
- function isLegacyJQueryPromise(thenable) {
38
- // jQuery promises are Promises/A+-compatible since 3.0.0. jQuery 3.0.0 is also the first version
39
- // to define the catch method.
40
- return typeof thenable.catch !== "function" &&
41
- typeof thenable.always === "function" &&
42
- typeof thenable.done === "function" &&
43
- typeof thenable.fail === "function" &&
44
- typeof thenable.pipe === "function" &&
45
- typeof thenable.progress === "function" &&
46
- typeof thenable.state === "function";
47
- }
52
+ function doNotify(promise, done) {
53
+ promise.then(function () { done(); }, done);
54
+ }
48
55
 
49
- function assertIsAboutPromise(assertion) {
50
- if (typeof assertion._obj.then !== "function") {
51
- throw new TypeError(utils.inspect(assertion._obj) + " is not a thenable.");
52
- }
53
- if (isLegacyJQueryPromise(assertion._obj)) {
54
- throw new TypeError("Chai as Promised is incompatible with thenables of jQuery<3.0.0, sorry! Please " +
55
- "upgrade jQuery or use another Promises/A+ compatible library (see " +
56
- "http://promisesaplus.com/).");
57
- }
58
- }
56
+ // These are for clarity and to bypass Chai refusing to allow `undefined` as actual when used with `assert`.
57
+ function assertIfNegated(assertion, message, extra) {
58
+ assertion.assert(true, null, message, extra.expected, extra.actual);
59
+ }
59
60
 
60
- function method(name, asserter) {
61
- utils.addMethod(Assertion.prototype, name, function () {
62
- assertIsAboutPromise(this);
63
- return asserter.apply(this, arguments);
64
- });
65
- }
61
+ function assertIfNotNegated(assertion, message, extra) {
62
+ assertion.assert(false, message, null, extra.expected, extra.actual);
63
+ }
66
64
 
67
- function property(name, asserter) {
68
- utils.addProperty(Assertion.prototype, name, function () {
69
- assertIsAboutPromise(this);
70
- return asserter.apply(this, arguments);
71
- });
72
- }
65
+ function getBasePromise(assertion) {
66
+ // We need to chain subsequent asserters on top of ones in the chain already (consider
67
+ // `eventually.have.property("foo").that.equals("bar")`), only running them after the existing ones pass.
68
+ // So the first base-promise is `assertion._obj`, but after that we use the assertions themselves, i.e.
69
+ // previously derived promises, to chain off of.
70
+ return typeof assertion.then === "function" ? assertion : assertion._obj;
71
+ }
73
72
 
74
- function doNotify(promise, done) {
75
- promise.then(function () { done(); }, done);
76
- }
73
+ function getReasonName(reason) {
74
+ return (reason instanceof Error) ? reason.toString() : checkError.getConstructorName(reason);
75
+ }
77
76
 
78
- // These are for clarity and to bypass Chai refusing to allow `undefined` as actual when used with `assert`.
79
- function assertIfNegated(assertion, message, extra) {
80
- assertion.assert(true, null, message, extra.expected, extra.actual);
77
+ // Grab these first, before we modify `Assertion.prototype`.
78
+
79
+ var propertyNames = Object.getOwnPropertyNames(Assertion.prototype);
80
+
81
+ var propertyDescs = {};
82
+ propertyNames.forEach(function (name) {
83
+ propertyDescs[name] = Object.getOwnPropertyDescriptor(Assertion.prototype, name);
84
+ });
85
+
86
+ property("fulfilled", function () {
87
+ var that = this;
88
+ var derivedPromise = getBasePromise(that).then(
89
+ function (value) {
90
+ assertIfNegated(that,
91
+ "expected promise not to be fulfilled but it was fulfilled with #{act}",
92
+ { actual: value });
93
+ return value;
94
+ },
95
+ function (reason) {
96
+ assertIfNotNegated(that,
97
+ "expected promise to be fulfilled but it was rejected with #{act}",
98
+ { actual: getReasonName(reason) });
99
+ return reason;
100
+ }
101
+ );
102
+
103
+ module.exports.transferPromiseness(that, derivedPromise);
104
+ });
105
+
106
+ property("rejected", function () {
107
+ var that = this;
108
+ var derivedPromise = getBasePromise(that).then(
109
+ function (value) {
110
+ assertIfNotNegated(that,
111
+ "expected promise to be rejected but it was fulfilled with #{act}",
112
+ { actual: value });
113
+ return value;
114
+ },
115
+ function (reason) {
116
+ assertIfNegated(that,
117
+ "expected promise not to be rejected but it was rejected with #{act}",
118
+ { actual: getReasonName(reason) });
119
+
120
+ // Return the reason, transforming this into a fulfillment, to allow further assertions, e.g.
121
+ // `promise.should.be.rejected.and.eventually.equal("reason")`.
122
+ return reason;
123
+ }
124
+ );
125
+
126
+ module.exports.transferPromiseness(that, derivedPromise);
127
+ });
128
+
129
+ method("rejectedWith", function (errorLike, errMsgMatcher, message) {
130
+ var errorLikeName = null;
131
+ var negate = utils.flag(this, "negate") || false;
132
+
133
+ // rejectedWith with that is called without arguments is
134
+ // the same as a plain ".rejected" use.
135
+ if (errorLike === undefined && errMsgMatcher === undefined &&
136
+ message === undefined) {
137
+ /* jshint expr: true */
138
+ this.rejected;
139
+ return;
81
140
  }
82
141
 
83
- function assertIfNotNegated(assertion, message, extra) {
84
- assertion.assert(false, message, null, extra.expected, extra.actual);
142
+ if (message !== undefined) {
143
+ utils.flag(this, "message", message);
85
144
  }
86
145
 
87
- function getBasePromise(assertion) {
88
- // We need to chain subsequent asserters on top of ones in the chain already (consider
89
- // `eventually.have.property("foo").that.equals("bar")`), only running them after the existing ones pass.
90
- // So the first base-promise is `assertion._obj`, but after that we use the assertions themselves, i.e.
91
- // previously derived promises, to chain off of.
92
- return typeof assertion.then === "function" ? assertion : assertion._obj;
146
+ if (errorLike instanceof RegExp || typeof errorLike === "string") {
147
+ errMsgMatcher = errorLike;
148
+ errorLike = null;
149
+ } else if (errorLike && errorLike instanceof Error) {
150
+ errorLikeName = errorLike.toString();
151
+ } else if (typeof errorLike === "function") {
152
+ errorLikeName = checkError.getConstructorName(errorLike);
153
+ } else {
154
+ errorLike = null;
93
155
  }
156
+ var everyArgIsDefined = Boolean(errorLike && errMsgMatcher);
94
157
 
95
- // Grab these first, before we modify `Assertion.prototype`.
96
-
97
- var propertyNames = Object.getOwnPropertyNames(Assertion.prototype);
98
-
99
- var propertyDescs = {};
100
- propertyNames.forEach(function (name) {
101
- propertyDescs[name] = Object.getOwnPropertyDescriptor(Assertion.prototype, name);
102
- });
158
+ var matcherRelation = "including";
159
+ if (errMsgMatcher instanceof RegExp) {
160
+ matcherRelation = "matching";
161
+ }
103
162
 
104
- property("fulfilled", function () {
105
- var that = this;
106
- var derivedPromise = getBasePromise(that).then(
107
- function (value) {
108
- that._obj = value;
109
- assertIfNegated(that,
110
- "expected promise not to be fulfilled but it was fulfilled with #{act}",
111
- { actual: value });
112
- return value;
113
- },
114
- function (reason) {
115
- assertIfNotNegated(that,
116
- "expected promise to be fulfilled but it was rejected with #{act}",
117
- { actual: reason });
163
+ var that = this;
164
+ var derivedPromise = getBasePromise(that).then(
165
+ function (value) {
166
+ var assertionMessage = null;
167
+ var expected = null;
168
+
169
+ if (errorLike) {
170
+ assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
171
+ "#{act}";
172
+ expected = errorLikeName;
173
+ } else if (errMsgMatcher) {
174
+ assertionMessage = "expected promise to be rejected with an error " + matcherRelation +
175
+ " #{exp} but it was fulfilled with #{act}";
176
+ expected = errMsgMatcher;
118
177
  }
119
- );
120
-
121
- chaiAsPromised.transferPromiseness(that, derivedPromise);
122
- });
123
178
 
124
- property("rejected", function () {
125
- var that = this;
126
- var derivedPromise = getBasePromise(that).then(
127
- function (value) {
128
- that._obj = value;
129
- assertIfNotNegated(that,
130
- "expected promise to be rejected but it was fulfilled with #{act}",
131
- { actual: value });
132
- return value;
133
- },
134
- function (reason) {
135
- assertIfNegated(that,
136
- "expected promise not to be rejected but it was rejected with #{act}",
137
- { actual: reason });
138
-
139
- // Return the reason, transforming this into a fulfillment, to allow further assertions, e.g.
140
- // `promise.should.be.rejected.and.eventually.equal("reason")`.
141
- return reason;
142
- }
143
- );
144
-
145
- chaiAsPromised.transferPromiseness(that, derivedPromise);
146
- });
147
-
148
- method("rejectedWith", function (Constructor, message) {
149
- var desiredReason = null;
150
- var constructorName = null;
151
-
152
- if (Constructor instanceof RegExp || typeof Constructor === "string") {
153
- message = Constructor;
154
- Constructor = null;
155
- } else if (Constructor && Constructor instanceof Error) {
156
- desiredReason = Constructor;
157
- Constructor = null;
158
- message = null;
159
- } else if (typeof Constructor === "function") {
160
- constructorName = (new Constructor()).name;
161
- } else {
162
- Constructor = null;
163
- }
164
-
165
- var that = this;
166
- var derivedPromise = getBasePromise(that).then(
167
- function (value) {
168
- var assertionMessage = null;
169
- var expected = null;
170
-
171
- if (Constructor) {
172
- assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
173
- "#{act}";
174
- expected = constructorName;
175
- } else if (message) {
176
- var verb = message instanceof RegExp ? "matching" : "including";
177
- assertionMessage = "expected promise to be rejected with an error " + verb + " #{exp} but it " +
178
- "was fulfilled with #{act}";
179
- expected = message;
180
- } else if (desiredReason) {
181
- assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with " +
182
- "#{act}";
183
- expected = desiredReason;
179
+ assertIfNotNegated(that, assertionMessage, { expected: expected, actual: value });
180
+ return value;
181
+ },
182
+ function (reason) {
183
+ var errorLikeCompatible = errorLike && (errorLike instanceof Error ?
184
+ checkError.compatibleInstance(reason, errorLike) :
185
+ checkError.compatibleConstructor(reason, errorLike));
186
+
187
+ var errMsgMatcherCompatible = errMsgMatcher && checkError.compatibleMessage(reason, errMsgMatcher);
188
+
189
+ var reasonName = getReasonName(reason);
190
+
191
+ if (negate && everyArgIsDefined) {
192
+ if (errorLikeCompatible && errMsgMatcherCompatible) {
193
+ that.assert(true,
194
+ null,
195
+ "expected promise not to be rejected with #{exp} but it was rejected " +
196
+ "with #{act}",
197
+ errorLikeName,
198
+ reasonName);
184
199
  }
185
-
186
- that._obj = value;
187
-
188
- assertIfNotNegated(that, assertionMessage, { expected: expected, actual: value });
189
- },
190
- function (reason) {
191
- if (Constructor) {
192
- that.assert(reason instanceof Constructor,
200
+ }
201
+ else {
202
+ if (errorLike) {
203
+ that.assert(errorLikeCompatible,
193
204
  "expected promise to be rejected with #{exp} but it was rejected with #{act}",
194
- "expected promise not to be rejected with #{exp} but it was rejected with #{act}",
195
- constructorName,
196
- reason);
205
+ "expected promise not to be rejected with #{exp} but it was rejected " +
206
+ "with #{act}",
207
+ errorLikeName,
208
+ reasonName);
197
209
  }
198
210
 
199
- var reasonMessage = utils.type(reason) === "object" && "message" in reason ?
200
- reason.message :
201
- "" + reason;
202
- if (message && reasonMessage !== null && reasonMessage !== undefined) {
203
- if (message instanceof RegExp) {
204
- that.assert(message.test(reasonMessage),
205
- "expected promise to be rejected with an error matching #{exp} but got #{act}",
206
- "expected promise not to be rejected with an error matching #{exp}",
207
- message,
208
- reasonMessage);
209
- }
210
- if (typeof message === "string") {
211
- that.assert(reasonMessage.indexOf(message) !== -1,
212
- "expected promise to be rejected with an error including #{exp} but got #{act}",
213
- "expected promise not to be rejected with an error including #{exp}",
214
- message,
215
- reasonMessage);
216
- }
217
- }
218
-
219
- if (desiredReason) {
220
- that.assert(reason === desiredReason,
221
- "expected promise to be rejected with #{exp} but it was rejected with #{act}",
222
- "expected promise not to be rejected with #{exp}",
223
- desiredReason,
224
- reason);
211
+ if (errMsgMatcher) {
212
+ that.assert(errMsgMatcherCompatible,
213
+ "expected promise to be rejected with an error " + matcherRelation +
214
+ " #{exp} but got #{act}",
215
+ "expected promise not to be rejected with an error " + matcherRelation +
216
+ " #{exp}",
217
+ errMsgMatcher,
218
+ checkError.getMessage(reason));
225
219
  }
226
220
  }
227
- );
228
221
 
229
- chaiAsPromised.transferPromiseness(that, derivedPromise);
230
- });
222
+ return reason;
223
+ }
224
+ );
231
225
 
232
- property("eventually", function () {
233
- utils.flag(this, "eventually", true);
234
- });
226
+ module.exports.transferPromiseness(that, derivedPromise);
227
+ });
235
228
 
236
- method("notify", function (done) {
237
- doNotify(getBasePromise(this), done);
238
- });
229
+ property("eventually", function () {
230
+ utils.flag(this, "eventually", true);
231
+ });
239
232
 
240
- method("become", function (value, message) {
241
- return this.eventually.deep.equal(value, message);
242
- });
233
+ method("notify", function (done) {
234
+ doNotify(getBasePromise(this), done);
235
+ });
243
236
 
244
- ////////
245
- // `eventually`
237
+ method("become", function (value, message) {
238
+ return this.eventually.deep.equal(value, message);
239
+ });
246
240
 
247
- // We need to be careful not to trigger any getters, thus `Object.getOwnPropertyDescriptor` usage.
248
- var methodNames = propertyNames.filter(function (name) {
249
- return name !== "assert" && typeof propertyDescs[name].value === "function";
250
- });
241
+ ////////
242
+ // `eventually`
251
243
 
252
- methodNames.forEach(function (methodName) {
253
- Assertion.overwriteMethod(methodName, function (originalMethod) {
254
- return function () {
255
- doAsserterAsyncAndAddThen(originalMethod, this, arguments);
256
- };
257
- });
258
- });
244
+ // We need to be careful not to trigger any getters, thus `Object.getOwnPropertyDescriptor` usage.
245
+ var methodNames = propertyNames.filter(function (name) {
246
+ return name !== "assert" && typeof propertyDescs[name].value === "function";
247
+ });
259
248
 
260
- var getterNames = propertyNames.filter(function (name) {
261
- return name !== "_obj" && typeof propertyDescs[name].get === "function";
249
+ methodNames.forEach(function (methodName) {
250
+ Assertion.overwriteMethod(methodName, function (originalMethod) {
251
+ return function () {
252
+ doAsserterAsyncAndAddThen(originalMethod, this, arguments);
253
+ };
262
254
  });
263
-
264
- getterNames.forEach(function (getterName) {
265
- // Chainable methods are things like `an`, which can work both for `.should.be.an.instanceOf` and as
266
- // `should.be.an("object")`. We need to handle those specially.
267
- var isChainableMethod = Assertion.prototype.__methods.hasOwnProperty(getterName);
268
-
269
- if (isChainableMethod) {
270
- Assertion.overwriteChainableMethod(
271
- getterName,
272
- function (originalMethod) {
273
- return function() {
274
- doAsserterAsyncAndAddThen(originalMethod, this, arguments);
275
- };
276
- },
277
- function (originalGetter) {
278
- return function() {
279
- doAsserterAsyncAndAddThen(originalGetter, this);
280
- };
281
- }
282
- );
283
- } else {
284
- Assertion.overwriteProperty(getterName, function (originalGetter) {
285
- return function () {
255
+ });
256
+
257
+ var getterNames = propertyNames.filter(function (name) {
258
+ return name !== "_obj" && typeof propertyDescs[name].get === "function";
259
+ });
260
+
261
+ getterNames.forEach(function (getterName) {
262
+ // Chainable methods are things like `an`, which can work both for `.should.be.an.instanceOf` and as
263
+ // `should.be.an("object")`. We need to handle those specially.
264
+ var isChainableMethod = Assertion.prototype.__methods.hasOwnProperty(getterName);
265
+
266
+ if (isChainableMethod) {
267
+ Assertion.overwriteChainableMethod(
268
+ getterName,
269
+ function (originalMethod) {
270
+ return function() {
271
+ doAsserterAsyncAndAddThen(originalMethod, this, arguments);
272
+ };
273
+ },
274
+ function (originalGetter) {
275
+ return function() {
286
276
  doAsserterAsyncAndAddThen(originalGetter, this);
287
277
  };
288
- });
289
- }
290
- });
291
-
292
- function doAsserterAsyncAndAddThen(asserter, assertion, args) {
293
- // Since we're intercepting all methods/properties, we need to just pass through if they don't want
294
- // `eventually`, or if we've already fulfilled the promise (see below).
295
- if (!utils.flag(assertion, "eventually")) {
296
- return asserter.apply(assertion, args);
297
- }
298
-
299
- var derivedPromise = getBasePromise(assertion).then(function (value) {
300
- // Set up the environment for the asserter to actually run: `_obj` should be the fulfillment value, and
301
- // now that we have the value, we're no longer in "eventually" mode, so we won't run any of this code,
302
- // just the base Chai code that we get to via the short-circuit above.
303
- assertion._obj = value;
304
- utils.flag(assertion, "eventually", false);
305
-
306
- return args ? chaiAsPromised.transformAsserterArgs(args) : args;
307
- }).then(function (args) {
308
- asserter.apply(assertion, args);
309
-
310
- // Because asserters, for example `property`, can change the value of `_obj` (i.e. change the "object"
311
- // flag), we need to communicate this value change to subsequent chained asserters. Since we build a
312
- // promise chain paralleling the asserter chain, we can use it to communicate such changes.
313
- return assertion._obj;
278
+ }
279
+ );
280
+ } else {
281
+ Assertion.overwriteProperty(getterName, function (originalGetter) {
282
+ return function () {
283
+ doAsserterAsyncAndAddThen(originalGetter, this);
284
+ };
314
285
  });
286
+ }
287
+ });
315
288
 
316
- chaiAsPromised.transferPromiseness(assertion, derivedPromise);
289
+ function doAsserterAsyncAndAddThen(asserter, assertion, args) {
290
+ // Since we're intercepting all methods/properties, we need to just pass through if they don't want
291
+ // `eventually`, or if we've already fulfilled the promise (see below).
292
+ if (!utils.flag(assertion, "eventually")) {
293
+ return asserter.apply(assertion, args);
317
294
  }
318
295
 
319
- ///////
320
- // Now use the `Assertion` framework to build an `assert` interface.
321
- var originalAssertMethods = Object.getOwnPropertyNames(assert).filter(function (propName) {
322
- return typeof assert[propName] === "function";
296
+ var derivedPromise = getBasePromise(assertion).then(function (value) {
297
+ // Set up the environment for the asserter to actually run: `_obj` should be the fulfillment value, and
298
+ // now that we have the value, we're no longer in "eventually" mode, so we won't run any of this code,
299
+ // just the base Chai code that we get to via the short-circuit above.
300
+ assertion._obj = value;
301
+ utils.flag(assertion, "eventually", false);
302
+
303
+ return args ? module.exports.transformAsserterArgs(args) : args;
304
+ }).then(function (args) {
305
+ asserter.apply(assertion, args);
306
+
307
+ // Because asserters, for example `property`, can change the value of `_obj` (i.e. change the "object"
308
+ // flag), we need to communicate this value change to subsequent chained asserters. Since we build a
309
+ // promise chain paralleling the asserter chain, we can use it to communicate such changes.
310
+ return assertion._obj;
323
311
  });
324
312
 
325
- assert.isFulfilled = function (promise, message) {
326
- return (new Assertion(promise, message)).to.be.fulfilled;
327
- };
328
-
329
- assert.isRejected = function (promise, toTestAgainst, message) {
330
- if (typeof toTestAgainst === "string") {
331
- message = toTestAgainst;
332
- toTestAgainst = undefined;
333
- }
313
+ module.exports.transferPromiseness(assertion, derivedPromise);
314
+ }
334
315
 
335
- var assertion = (new Assertion(promise, message));
336
- return toTestAgainst !== undefined ? assertion.to.be.rejectedWith(toTestAgainst) : assertion.to.be.rejected;
337
- };
316
+ ///////
317
+ // Now use the `Assertion` framework to build an `assert` interface.
318
+ var originalAssertMethods = Object.getOwnPropertyNames(assert).filter(function (propName) {
319
+ return typeof assert[propName] === "function";
320
+ });
338
321
 
339
- assert.becomes = function (promise, value, message) {
340
- return assert.eventually.deepEqual(promise, value, message);
341
- };
322
+ assert.isFulfilled = function (promise, message) {
323
+ return (new Assertion(promise, message)).to.be.fulfilled;
324
+ };
342
325
 
343
- assert.doesNotBecome = function (promise, value, message) {
344
- return assert.eventually.notDeepEqual(promise, value, message);
345
- };
326
+ assert.isRejected = function (promise, errorLike, errMsgMatcher, message) {
327
+ var assertion = (new Assertion(promise, message));
328
+ return assertion.to.be.rejectedWith(errorLike, errMsgMatcher, message);
329
+ };
346
330
 
347
- assert.eventually = {};
348
- originalAssertMethods.forEach(function (assertMethodName) {
349
- assert.eventually[assertMethodName] = function (promise) {
350
- var otherArgs = Array.prototype.slice.call(arguments, 1);
331
+ assert.becomes = function (promise, value, message) {
332
+ return assert.eventually.deepEqual(promise, value, message);
333
+ };
351
334
 
352
- var customRejectionHandler;
353
- var message = arguments[assert[assertMethodName].length - 1];
354
- if (typeof message === "string") {
355
- customRejectionHandler = function (reason) {
356
- throw new chai.AssertionError(message + "\n\nOriginal reason: " + utils.inspect(reason));
357
- };
358
- }
335
+ assert.doesNotBecome = function (promise, value, message) {
336
+ return assert.eventually.notDeepEqual(promise, value, message);
337
+ };
359
338
 
360
- var returnedPromise = promise.then(
361
- function (fulfillmentValue) {
362
- return assert[assertMethodName].apply(assert, [fulfillmentValue].concat(otherArgs));
363
- },
364
- customRejectionHandler
365
- );
339
+ assert.eventually = {};
340
+ originalAssertMethods.forEach(function (assertMethodName) {
341
+ assert.eventually[assertMethodName] = function (promise) {
342
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
366
343
 
367
- returnedPromise.notify = function (done) {
368
- doNotify(returnedPromise, done);
344
+ var customRejectionHandler;
345
+ var message = arguments[assert[assertMethodName].length - 1];
346
+ if (typeof message === "string") {
347
+ customRejectionHandler = function (reason) {
348
+ throw new chai.AssertionError(message + "\n\nOriginal reason: " + utils.inspect(reason));
369
349
  };
350
+ }
351
+
352
+ var returnedPromise = promise.then(
353
+ function (fulfillmentValue) {
354
+ return assert[assertMethodName].apply(assert, [fulfillmentValue].concat(otherArgs));
355
+ },
356
+ customRejectionHandler
357
+ );
370
358
 
371
- return returnedPromise;
359
+ returnedPromise.notify = function (done) {
360
+ doNotify(returnedPromise, done);
372
361
  };
373
- });
374
- }
375
- }());
362
+
363
+ return returnedPromise;
364
+ };
365
+ });
366
+ };
367
+
368
+ module.exports.transferPromiseness = function (assertion, promise) {
369
+ assertion.then = promise.then.bind(promise);
370
+ };
371
+
372
+ module.exports.transformAsserterArgs = function (values) {
373
+ return values;
374
+ };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "promises",
12
12
  "promises-aplus"
13
13
  ],
14
- "version": "5.3.0",
14
+ "version": "6.0.0",
15
15
  "author": "Domenic Denicola <d@domenic.me> (https://domenic.me)",
16
16
  "license": "WTFPL",
17
17
  "repository": "domenic/chai-as-promised",
@@ -23,21 +23,21 @@
23
23
  "test": "npm run test-plugin && npm run test-intercompatibility",
24
24
  "test-plugin": "mocha",
25
25
  "test-intercompatibility": "mocha test-intercompatibility --opts test-intercompatibility/mocha.opts",
26
- "test-browser-jquery": "coffee ./test/browser/runner.coffee jquery",
27
- "test-browser-q": "coffee ./test/browser/runner.coffee q",
28
- "test-browser-when": "coffee ./test/browser/runner.coffee when",
29
26
  "lint": "jshint ./lib",
30
27
  "cover": "istanbul cover node_modules/mocha/bin/_mocha && opener ./coverage/lcov-report/lib/chai-as-promised.js.html"
31
28
  },
29
+ "dependencies": {
30
+ "check-error": "^1.0.2"
31
+ },
32
32
  "peerDependencies": {
33
33
  "chai": ">= 2.1.2 < 4"
34
34
  },
35
35
  "devDependencies": {
36
36
  "chai": "^3.0.0",
37
37
  "coffee-script": "1.10.0",
38
- "istanbul": "0.4.1",
39
38
  "ecstatic": "^1.3.1",
40
39
  "glob": "^6.0.1",
40
+ "istanbul": "0.4.1",
41
41
  "jshint": "^2.8.0",
42
42
  "mocha": "^2.3.4",
43
43
  "opener": "^1.4.1",