chai-as-promised 5.3.0 → 7.1.1

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
@@ -5,7 +5,7 @@
5
5
 
6
6
  # Chai Assertions for Promises
7
7
 
8
- **Chai as Promised** extends [Chai][chai] with a fluent language for asserting facts about [promises][presentation].
8
+ **Chai as Promised** extends [Chai](http://chaijs.com/) with a fluent language for asserting facts about [promises](http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript).
9
9
 
10
10
  Instead of manually wiring up your expectations to a promise's fulfilled and rejected handlers:
11
11
 
@@ -90,7 +90,7 @@ return assert.isRejected(promise, /error message matcher/, "optional message");
90
90
 
91
91
  ### Progress Callbacks
92
92
 
93
- Chai as Promised does not have any intrinsic support for testing promise progress callbacks. The properties you would want to test are probably much better suited to a library like [Sinon.JS][sinon], perhaps in conjunction with [Sinon–Chai][sinon-chai]:
93
+ Chai as Promised does not have any intrinsic support for testing promise progress callbacks. The properties you would want to test are probably much better suited to a library like [Sinon.JS](http://sinonjs.org/), perhaps in conjunction with [Sinon–Chai](https://github.com/domenic/sinon-chai):
94
94
 
95
95
  ```javascript
96
96
  var progressSpy = sinon.spy();
@@ -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,11 +144,15 @@ 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](http://promisesaplus.com/).
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](http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/#toc_2) 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
 
151
- Some test runners (e.g. Jasmine, QUnit, or tap/tape) do not have the ability to use the returned promise to signal asynchronous test completion. If possible, I'd recommend switching to ones that do, such as [Mocha][mocha-promises], [Buster][buster-promises], or [blue-tape][]. But if that's not an option, Chai as Promised still has you covered. As long as your test framework takes a callback indicating when the asynchronous test run is over, Chai as Promised can adapt to that situation with its `notify` method, like so:
155
+ Some test runners (e.g. Jasmine, QUnit, or tap/tape) do not have the ability to use the returned promise to signal asynchronous test completion. If possible, I'd recommend switching to ones that do, such as [Mocha](http://mochajs.org/#asynchronous-code), [Buster](http://docs.busterjs.org/en/latest/modules/buster-test/spec/#returning-a-promise), or [blue-tape](https://github.com/spion/blue-tape). But if that's not an option, Chai as Promised still has you covered. As long as your test framework takes a callback indicating when the asynchronous test run is over, Chai as Promised can adapt to that situation with its `notify` method, like so:
152
156
 
153
157
  ```javascript
154
158
  it("should be fulfilled", function (done) {
@@ -202,51 +206,28 @@ var chai = require("chai");
202
206
  var chaiAsPromised = require("chai-as-promised");
203
207
 
204
208
  chai.use(chaiAsPromised);
209
+
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
205
217
  ```
206
218
 
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].
219
+ You can of course put this code in a common test fixture file; for an example using [Mocha](http://mochajs.org), see [the Chai as Promised tests themselves](https://github.com/domenic/chai-as-promised/tree/master/test/).
208
220
 
209
- ### AMD
221
+ **Note when using other Chai plugins:** Chai as Promised finds all currently-registered asserters and promisifies them, at the time it is installed. Thus, you should install Chai as Promised _last_, after any other Chai plugins, if you expect their asserters to be promisified.
210
222
 
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:
223
+ ### In the Browser
212
224
 
213
- ```javascript
214
- define(function (require, exports, module) {
215
- var chai = require("chai");
216
- var chaiAsPromised = require("chai-as-promised");
225
+ 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](http://browserify.org/). See also the note below about browser compatibility.
217
226
 
218
- chai.use(chaiAsPromised);
219
- });
220
- ```
221
-
222
- ### `<script>` tag
227
+ ### Karma
223
228
 
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:
229
+ If you're using [Karma](https://karma-runner.github.io/), check out the accompanying [karma-chai-as-promised](https://github.com/vlkosinov/karma-chai-as-promised) plugin.
225
230
 
226
- ```html
227
- <script src="chai.js"></script>
228
- <script src="chai-as-promised.js"></script>
229
- ```
230
-
231
- ### Karma
231
+ ### Browser/Node Compatibility
232
232
 
233
- If you're using [Karma][], check out the accompanying [karma-chai-as-promised][] plugin.
234
-
235
- ### Browser Compatibility
236
-
237
- Chai as Promised is only compatible with modern browsers (IE ≥9, Safari ≥6, no PhantomJS).
238
-
239
- [presentation]: http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript
240
- [chai]: http://chaijs.com/
241
- [Mocha-promises]: http://mochajs.org/#asynchronous-code
242
- [Buster-promises]: http://docs.busterjs.org/en/latest/modules/buster-test/spec/#returning-a-promise
243
- [blue-tape]: https://github.com/spion/blue-tape
244
- [spec]: http://promisesaplus.com/
245
- [transformation behavior]: http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/#toc_2
246
- [Mocha]: http://mochajs.org
247
- [fixturedemo]: https://github.com/domenic/chai-as-promised/tree/master/test/
248
- [amd]: https://github.com/amdjs/amdjs-api/wiki/AMD
249
- [sinon]: http://sinonjs.org/
250
- [sinon-chai]: https://github.com/domenic/sinon-chai
251
- [Karma]: https://karma-runner.github.io/
252
- [karma-chai-as-promised]: https://github.com/vlkosinov/karma-chai-as-promised
233
+ Chai as Promised requires Node v4+ or a browser with equivalent support for modern JavaScript syntax. If your browser doesn't support modern JavaScript syntax, you'll need to transpile it down using a tool like [Babel](http://babeljs.io/).
@@ -1,375 +1,361 @@
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 */
17
-
18
- // Other environment (usually <script> tag): plug in to global chai instance directly.
19
- chai.use(chaiAsPromised);
20
-
21
- // Expose as a property of the global object so that consumers can configure the `transferPromiseness` property.
22
- self.chaiAsPromised = chaiAsPromised;
1
+ "use strict";
2
+ /* eslint-disable no-invalid-this */
3
+ let checkError = require("check-error");
4
+
5
+ module.exports = (chai, utils) => {
6
+ const Assertion = chai.Assertion;
7
+ const assert = chai.assert;
8
+ const proxify = utils.proxify;
9
+
10
+ // If we are using a version of Chai that has checkError on it,
11
+ // we want to use that version to be consistent. Otherwise, we use
12
+ // what was passed to the factory.
13
+ if (utils.checkError) {
14
+ checkError = utils.checkError;
23
15
  }
24
16
 
25
- chaiAsPromised.transferPromiseness = function (assertion, promise) {
26
- assertion.then = promise.then.bind(promise);
27
- };
28
-
29
- chaiAsPromised.transformAsserterArgs = function (values) {
30
- return values;
31
- };
17
+ function isLegacyJQueryPromise(thenable) {
18
+ // jQuery promises are Promises/A+-compatible since 3.0.0. jQuery 3.0.0 is also the first version
19
+ // to define the catch method.
20
+ return typeof thenable.catch !== "function" &&
21
+ typeof thenable.always === "function" &&
22
+ typeof thenable.done === "function" &&
23
+ typeof thenable.fail === "function" &&
24
+ typeof thenable.pipe === "function" &&
25
+ typeof thenable.progress === "function" &&
26
+ typeof thenable.state === "function";
27
+ }
32
28
 
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";
29
+ function assertIsAboutPromise(assertion) {
30
+ if (typeof assertion._obj.then !== "function") {
31
+ throw new TypeError(utils.inspect(assertion._obj) + " is not a thenable.");
47
32
  }
48
-
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
- }
33
+ if (isLegacyJQueryPromise(assertion._obj)) {
34
+ throw new TypeError("Chai as Promised is incompatible with thenables of jQuery<3.0.0, sorry! Please " +
35
+ "upgrade jQuery or use another Promises/A+ compatible library (see " +
36
+ "http://promisesaplus.com/).");
58
37
  }
38
+ }
59
39
 
60
- function method(name, asserter) {
61
- utils.addMethod(Assertion.prototype, name, function () {
62
- assertIsAboutPromise(this);
63
- return asserter.apply(this, arguments);
64
- });
65
- }
40
+ function proxifyIfSupported(assertion) {
41
+ return proxify === undefined ? assertion : proxify(assertion);
42
+ }
66
43
 
67
- function property(name, asserter) {
68
- utils.addProperty(Assertion.prototype, name, function () {
69
- assertIsAboutPromise(this);
70
- return asserter.apply(this, arguments);
71
- });
72
- }
44
+ function method(name, asserter) {
45
+ utils.addMethod(Assertion.prototype, name, function () {
46
+ assertIsAboutPromise(this);
47
+ return asserter.apply(this, arguments);
48
+ });
49
+ }
73
50
 
74
- function doNotify(promise, done) {
75
- promise.then(function () { done(); }, done);
76
- }
51
+ function property(name, asserter) {
52
+ utils.addProperty(Assertion.prototype, name, function () {
53
+ assertIsAboutPromise(this);
54
+ return proxifyIfSupported(asserter.apply(this, arguments));
55
+ });
56
+ }
77
57
 
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);
81
- }
58
+ function doNotify(promise, done) {
59
+ promise.then(() => done(), done);
60
+ }
82
61
 
83
- function assertIfNotNegated(assertion, message, extra) {
84
- assertion.assert(false, message, null, extra.expected, extra.actual);
85
- }
62
+ // These are for clarity and to bypass Chai refusing to allow `undefined` as actual when used with `assert`.
63
+ function assertIfNegated(assertion, message, extra) {
64
+ assertion.assert(true, null, message, extra.expected, extra.actual);
65
+ }
86
66
 
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;
93
- }
67
+ function assertIfNotNegated(assertion, message, extra) {
68
+ assertion.assert(false, message, null, extra.expected, extra.actual);
69
+ }
94
70
 
95
- // Grab these first, before we modify `Assertion.prototype`.
71
+ function getBasePromise(assertion) {
72
+ // We need to chain subsequent asserters on top of ones in the chain already (consider
73
+ // `eventually.have.property("foo").that.equals("bar")`), only running them after the existing ones pass.
74
+ // So the first base-promise is `assertion._obj`, but after that we use the assertions themselves, i.e.
75
+ // previously derived promises, to chain off of.
76
+ return typeof assertion.then === "function" ? assertion : assertion._obj;
77
+ }
96
78
 
97
- var propertyNames = Object.getOwnPropertyNames(Assertion.prototype);
79
+ function getReasonName(reason) {
80
+ return reason instanceof Error ? reason.toString() : checkError.getConstructorName(reason);
81
+ }
98
82
 
99
- var propertyDescs = {};
100
- propertyNames.forEach(function (name) {
101
- propertyDescs[name] = Object.getOwnPropertyDescriptor(Assertion.prototype, name);
102
- });
83
+ // Grab these first, before we modify `Assertion.prototype`.
103
84
 
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 });
118
- }
119
- );
85
+ const propertyNames = Object.getOwnPropertyNames(Assertion.prototype);
120
86
 
121
- chaiAsPromised.transferPromiseness(that, derivedPromise);
122
- });
87
+ const propertyDescs = {};
88
+ for (const name of propertyNames) {
89
+ propertyDescs[name] = Object.getOwnPropertyDescriptor(Assertion.prototype, name);
90
+ }
123
91
 
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
- );
92
+ property("fulfilled", function () {
93
+ const derivedPromise = getBasePromise(this).then(
94
+ value => {
95
+ assertIfNegated(this,
96
+ "expected promise not to be fulfilled but it was fulfilled with #{act}",
97
+ { actual: value });
98
+ return value;
99
+ },
100
+ reason => {
101
+ assertIfNotNegated(this,
102
+ "expected promise to be fulfilled but it was rejected with #{act}",
103
+ { actual: getReasonName(reason) });
104
+ return reason;
105
+ }
106
+ );
107
+
108
+ module.exports.transferPromiseness(this, derivedPromise);
109
+ return this;
110
+ });
111
+
112
+ property("rejected", function () {
113
+ const derivedPromise = getBasePromise(this).then(
114
+ value => {
115
+ assertIfNotNegated(this,
116
+ "expected promise to be rejected but it was fulfilled with #{act}",
117
+ { actual: value });
118
+ return value;
119
+ },
120
+ reason => {
121
+ assertIfNegated(this,
122
+ "expected promise not to be rejected but it was rejected with #{act}",
123
+ { actual: getReasonName(reason) });
124
+
125
+ // Return the reason, transforming this into a fulfillment, to allow further assertions, e.g.
126
+ // `promise.should.be.rejected.and.eventually.equal("reason")`.
127
+ return reason;
128
+ }
129
+ );
130
+
131
+ module.exports.transferPromiseness(this, derivedPromise);
132
+ return this;
133
+ });
134
+
135
+ method("rejectedWith", function (errorLike, errMsgMatcher, message) {
136
+ let errorLikeName = null;
137
+ const negate = utils.flag(this, "negate") || false;
138
+
139
+ // rejectedWith with that is called without arguments is
140
+ // the same as a plain ".rejected" use.
141
+ if (errorLike === undefined && errMsgMatcher === undefined &&
142
+ message === undefined) {
143
+ /* eslint-disable no-unused-expressions */
144
+ return this.rejected;
145
+ /* eslint-enable no-unused-expressions */
146
+ }
144
147
 
145
- chaiAsPromised.transferPromiseness(that, derivedPromise);
146
- });
148
+ if (message !== undefined) {
149
+ utils.flag(this, "message", message);
150
+ }
147
151
 
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
- }
152
+ if (errorLike instanceof RegExp || typeof errorLike === "string") {
153
+ errMsgMatcher = errorLike;
154
+ errorLike = null;
155
+ } else if (errorLike && errorLike instanceof Error) {
156
+ errorLikeName = errorLike.toString();
157
+ } else if (typeof errorLike === "function") {
158
+ errorLikeName = checkError.getConstructorName(errorLike);
159
+ } else {
160
+ errorLike = null;
161
+ }
162
+ const everyArgIsDefined = Boolean(errorLike && errMsgMatcher);
164
163
 
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;
184
- }
164
+ let matcherRelation = "including";
165
+ if (errMsgMatcher instanceof RegExp) {
166
+ matcherRelation = "matching";
167
+ }
185
168
 
186
- that._obj = value;
169
+ const derivedPromise = getBasePromise(this).then(
170
+ value => {
171
+ let assertionMessage = null;
172
+ let expected = null;
173
+
174
+ if (errorLike) {
175
+ assertionMessage = "expected promise to be rejected with #{exp} but it was fulfilled with #{act}";
176
+ expected = errorLikeName;
177
+ } else if (errMsgMatcher) {
178
+ assertionMessage = `expected promise to be rejected with an error ${matcherRelation} #{exp} but ` +
179
+ `it was fulfilled with #{act}`;
180
+ expected = errMsgMatcher;
181
+ }
187
182
 
188
- assertIfNotNegated(that, assertionMessage, { expected: expected, actual: value });
189
- },
190
- function (reason) {
191
- if (Constructor) {
192
- that.assert(reason instanceof Constructor,
193
- "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);
183
+ assertIfNotNegated(this, assertionMessage, { expected, actual: value });
184
+ return value;
185
+ },
186
+ reason => {
187
+ const errorLikeCompatible = errorLike && (errorLike instanceof Error ?
188
+ checkError.compatibleInstance(reason, errorLike) :
189
+ checkError.compatibleConstructor(reason, errorLike));
190
+
191
+ const errMsgMatcherCompatible = errMsgMatcher && checkError.compatibleMessage(reason, errMsgMatcher);
192
+
193
+ const reasonName = getReasonName(reason);
194
+
195
+ if (negate && everyArgIsDefined) {
196
+ if (errorLikeCompatible && errMsgMatcherCompatible) {
197
+ this.assert(true,
198
+ null,
199
+ "expected promise not to be rejected with #{exp} but it was rejected " +
200
+ "with #{act}",
201
+ errorLikeName,
202
+ reasonName);
197
203
  }
198
-
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
- }
204
+ } else {
205
+ if (errorLike) {
206
+ this.assert(errorLikeCompatible,
207
+ "expected promise to be rejected with #{exp} but it was rejected with #{act}",
208
+ "expected promise not to be rejected with #{exp} but it was rejected " +
209
+ "with #{act}",
210
+ errorLikeName,
211
+ reasonName);
217
212
  }
218
213
 
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);
214
+ if (errMsgMatcher) {
215
+ this.assert(errMsgMatcherCompatible,
216
+ `expected promise to be rejected with an error ${matcherRelation} #{exp} but got ` +
217
+ `#{act}`,
218
+ `expected promise not to be rejected with an error ${matcherRelation} #{exp}`,
219
+ errMsgMatcher,
220
+ checkError.getMessage(reason));
225
221
  }
226
222
  }
227
- );
228
223
 
229
- chaiAsPromised.transferPromiseness(that, derivedPromise);
230
- });
224
+ return reason;
225
+ }
226
+ );
231
227
 
232
- property("eventually", function () {
233
- utils.flag(this, "eventually", true);
234
- });
228
+ module.exports.transferPromiseness(this, derivedPromise);
229
+ return this;
230
+ });
235
231
 
236
- method("notify", function (done) {
237
- doNotify(getBasePromise(this), done);
238
- });
232
+ property("eventually", function () {
233
+ utils.flag(this, "eventually", true);
234
+ return this;
235
+ });
239
236
 
240
- method("become", function (value, message) {
241
- return this.eventually.deep.equal(value, message);
242
- });
237
+ method("notify", function (done) {
238
+ doNotify(getBasePromise(this), done);
239
+ return this;
240
+ });
243
241
 
244
- ////////
245
- // `eventually`
242
+ method("become", function (value, message) {
243
+ return this.eventually.deep.equal(value, message);
244
+ });
246
245
 
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
- });
246
+ // ### `eventually`
251
247
 
252
- methodNames.forEach(function (methodName) {
253
- Assertion.overwriteMethod(methodName, function (originalMethod) {
254
- return function () {
255
- doAsserterAsyncAndAddThen(originalMethod, this, arguments);
256
- };
257
- });
258
- });
248
+ // We need to be careful not to trigger any getters, thus `Object.getOwnPropertyDescriptor` usage.
249
+ const methodNames = propertyNames.filter(name => {
250
+ return name !== "assert" && typeof propertyDescs[name].value === "function";
251
+ });
259
252
 
260
- var getterNames = propertyNames.filter(function (name) {
261
- return name !== "_obj" && typeof propertyDescs[name].get === "function";
253
+ methodNames.forEach(methodName => {
254
+ Assertion.overwriteMethod(methodName, originalMethod => function () {
255
+ return doAsserterAsyncAndAddThen(originalMethod, this, arguments);
262
256
  });
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 () {
286
- doAsserterAsyncAndAddThen(originalGetter, this);
287
- };
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;
257
+ });
258
+
259
+ const getterNames = propertyNames.filter(name => {
260
+ return name !== "_obj" && typeof propertyDescs[name].get === "function";
261
+ });
262
+
263
+ getterNames.forEach(getterName => {
264
+ // Chainable methods are things like `an`, which can work both for `.should.be.an.instanceOf` and as
265
+ // `should.be.an("object")`. We need to handle those specially.
266
+ const isChainableMethod = Assertion.prototype.__methods.hasOwnProperty(getterName);
267
+
268
+ if (isChainableMethod) {
269
+ Assertion.overwriteChainableMethod(
270
+ getterName,
271
+ originalMethod => function () {
272
+ return doAsserterAsyncAndAddThen(originalMethod, this, arguments);
273
+ },
274
+ originalGetter => function () {
275
+ return doAsserterAsyncAndAddThen(originalGetter, this);
276
+ }
277
+ );
278
+ } else {
279
+ Assertion.overwriteProperty(getterName, originalGetter => function () {
280
+ return proxifyIfSupported(doAsserterAsyncAndAddThen(originalGetter, this));
314
281
  });
315
-
316
- chaiAsPromised.transferPromiseness(assertion, derivedPromise);
282
+ }
283
+ });
284
+
285
+ function doAsserterAsyncAndAddThen(asserter, assertion, args) {
286
+ // Since we're intercepting all methods/properties, we need to just pass through if they don't want
287
+ // `eventually`, or if we've already fulfilled the promise (see below).
288
+ if (!utils.flag(assertion, "eventually")) {
289
+ asserter.apply(assertion, args);
290
+ return assertion;
317
291
  }
318
292
 
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";
293
+ const derivedPromise = getBasePromise(assertion).then(value => {
294
+ // Set up the environment for the asserter to actually run: `_obj` should be the fulfillment value, and
295
+ // now that we have the value, we're no longer in "eventually" mode, so we won't run any of this code,
296
+ // just the base Chai code that we get to via the short-circuit above.
297
+ assertion._obj = value;
298
+ utils.flag(assertion, "eventually", false);
299
+
300
+ return args ? module.exports.transformAsserterArgs(args) : args;
301
+ }).then(newArgs => {
302
+ asserter.apply(assertion, newArgs);
303
+
304
+ // Because asserters, for example `property`, can change the value of `_obj` (i.e. change the "object"
305
+ // flag), we need to communicate this value change to subsequent chained asserters. Since we build a
306
+ // promise chain paralleling the asserter chain, we can use it to communicate such changes.
307
+ return assertion._obj;
323
308
  });
324
309
 
325
- assert.isFulfilled = function (promise, message) {
326
- return (new Assertion(promise, message)).to.be.fulfilled;
327
- };
310
+ module.exports.transferPromiseness(assertion, derivedPromise);
311
+ return assertion;
312
+ }
328
313
 
329
- assert.isRejected = function (promise, toTestAgainst, message) {
330
- if (typeof toTestAgainst === "string") {
331
- message = toTestAgainst;
332
- toTestAgainst = undefined;
333
- }
314
+ // ### Now use the `Assertion` framework to build an `assert` interface.
315
+ const originalAssertMethods = Object.getOwnPropertyNames(assert).filter(propName => {
316
+ return typeof assert[propName] === "function";
317
+ });
334
318
 
335
- var assertion = (new Assertion(promise, message));
336
- return toTestAgainst !== undefined ? assertion.to.be.rejectedWith(toTestAgainst) : assertion.to.be.rejected;
337
- };
319
+ assert.isFulfilled = (promise, message) => (new Assertion(promise, message)).to.be.fulfilled;
338
320
 
339
- assert.becomes = function (promise, value, message) {
340
- return assert.eventually.deepEqual(promise, value, message);
341
- };
321
+ assert.isRejected = (promise, errorLike, errMsgMatcher, message) => {
322
+ const assertion = new Assertion(promise, message);
323
+ return assertion.to.be.rejectedWith(errorLike, errMsgMatcher, message);
324
+ };
342
325
 
343
- assert.doesNotBecome = function (promise, value, message) {
344
- return assert.eventually.notDeepEqual(promise, value, message);
345
- };
326
+ assert.becomes = (promise, value, message) => assert.eventually.deepEqual(promise, value, message);
346
327
 
347
- assert.eventually = {};
348
- originalAssertMethods.forEach(function (assertMethodName) {
349
- assert.eventually[assertMethodName] = function (promise) {
350
- var otherArgs = Array.prototype.slice.call(arguments, 1);
351
-
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
- }
328
+ assert.doesNotBecome = (promise, value, message) => assert.eventually.notDeepEqual(promise, value, message);
359
329
 
360
- var returnedPromise = promise.then(
361
- function (fulfillmentValue) {
362
- return assert[assertMethodName].apply(assert, [fulfillmentValue].concat(otherArgs));
363
- },
364
- customRejectionHandler
365
- );
330
+ assert.eventually = {};
331
+ originalAssertMethods.forEach(assertMethodName => {
332
+ assert.eventually[assertMethodName] = function (promise) {
333
+ const otherArgs = Array.prototype.slice.call(arguments, 1);
366
334
 
367
- returnedPromise.notify = function (done) {
368
- doNotify(returnedPromise, done);
335
+ let customRejectionHandler;
336
+ const message = arguments[assert[assertMethodName].length - 1];
337
+ if (typeof message === "string") {
338
+ customRejectionHandler = reason => {
339
+ throw new chai.AssertionError(`${message}\n\nOriginal reason: ${utils.inspect(reason)}`);
369
340
  };
341
+ }
370
342
 
371
- return returnedPromise;
343
+ const returnedPromise = promise.then(
344
+ fulfillmentValue => assert[assertMethodName].apply(assert, [fulfillmentValue].concat(otherArgs)),
345
+ customRejectionHandler
346
+ );
347
+
348
+ returnedPromise.notify = done => {
349
+ doNotify(returnedPromise, done);
372
350
  };
373
- });
374
- }
375
- }());
351
+
352
+ return returnedPromise;
353
+ };
354
+ });
355
+ };
356
+
357
+ module.exports.transferPromiseness = (assertion, promise) => {
358
+ assertion.then = promise.then.bind(promise);
359
+ };
360
+
361
+ module.exports.transformAsserterArgs = values => values;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "promises",
12
12
  "promises-aplus"
13
13
  ],
14
- "version": "5.3.0",
14
+ "version": "7.1.1",
15
15
  "author": "Domenic Denicola <d@domenic.me> (https://domenic.me)",
16
16
  "license": "WTFPL",
17
17
  "repository": "domenic/chai-as-promised",
@@ -20,28 +20,21 @@
20
20
  "lib"
21
21
  ],
22
22
  "scripts": {
23
- "test": "npm run test-plugin && npm run test-intercompatibility",
24
- "test-plugin": "mocha",
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
- "lint": "jshint ./lib",
23
+ "test": "mocha",
24
+ "test-travis": "npm install chai@$CHAI_VERSION && npm test",
25
+ "lint": "eslint .",
30
26
  "cover": "istanbul cover node_modules/mocha/bin/_mocha && opener ./coverage/lcov-report/lib/chai-as-promised.js.html"
31
27
  },
28
+ "dependencies": {
29
+ "check-error": "^1.0.2"
30
+ },
32
31
  "peerDependencies": {
33
- "chai": ">= 2.1.2 < 4"
32
+ "chai": ">= 2.1.2 < 5"
34
33
  },
35
34
  "devDependencies": {
36
- "chai": "^3.0.0",
37
- "coffee-script": "1.10.0",
38
- "istanbul": "0.4.1",
39
- "ecstatic": "^1.3.1",
40
- "glob": "^6.0.1",
41
- "jshint": "^2.8.0",
42
- "mocha": "^2.3.4",
43
- "opener": "^1.4.1",
44
- "q": "^1.4.1",
45
- "underscore": "1.8.3"
35
+ "chai": "^4.0.2",
36
+ "eslint": "^3.19.0",
37
+ "istanbul": "0.4.5",
38
+ "mocha": "^3.4.2"
46
39
  }
47
40
  }