konacha-chai-matchers 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.gitmodules +36 -0
- data/Gemfile +7 -0
- data/LICENSE +22 -0
- data/README.md +38 -0
- data/Rakefile +2 -0
- data/konacha-chai-matchers.gemspec +21 -0
- data/lib/konacha-chai-matchers.rb +11 -0
- data/lib/konacha-chai-matchers/version.rb +7 -0
- data/tasks/update.rb +47 -0
- data/vendor/assets/javascripts/chai-as-promised.js +391 -0
- data/vendor/assets/javascripts/chai-backbone.js +101 -0
- data/vendor/assets/javascripts/chai-changes.js +173 -0
- data/vendor/assets/javascripts/chai-factories.js +166 -0
- data/vendor/assets/javascripts/chai-jquery.js +232 -0
- data/vendor/assets/javascripts/chai-null.js +136 -0
- data/vendor/assets/javascripts/chai-spies.js +372 -0
- data/vendor/assets/javascripts/chai-stats.js +286 -0
- data/vendor/assets/javascripts/chai-timers.js +174 -0
- data/vendor/assets/javascripts/js-factories.js +71 -0
- data/vendor/assets/javascripts/sinon-chai.js +106 -0
- data/vendor/assets/javascripts/sinon.js +3738 -0
- metadata +74 -0
data/.gitignore
ADDED
data/.gitmodules
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
[submodule "chai-spies"]
|
2
|
+
path = chai-spies
|
3
|
+
url = git://github.com/chaijs/chai-spies.git
|
4
|
+
[submodule "sinon-chai"]
|
5
|
+
path = sinon-chai
|
6
|
+
url = git://github.com/domenic/sinon-chai.git
|
7
|
+
[submodule "chai-as-promised"]
|
8
|
+
path = chai-as-promised
|
9
|
+
url = git://github.com/domenic/chai-as-promised.git
|
10
|
+
[submodule "chai-jquery"]
|
11
|
+
path = chai-jquery
|
12
|
+
url = git://github.com/chaijs/chai-jquery.git
|
13
|
+
[submodule "chai-timers"]
|
14
|
+
path = chai-timers
|
15
|
+
url = git://github.com/chaijs/chai-timers.git
|
16
|
+
[submodule "chai-stats"]
|
17
|
+
path = chai-stats
|
18
|
+
url = git://github.com/chaijs/chai-stats.git
|
19
|
+
[submodule "chai-null"]
|
20
|
+
path = chai-null
|
21
|
+
url = git://github.com/chaijs/chai-null.git
|
22
|
+
[submodule "chai-factories"]
|
23
|
+
path = chai-factories
|
24
|
+
url = git://github.com/chaijs/chai-factories.git
|
25
|
+
[submodule "chai-changes"]
|
26
|
+
path = chai-changes
|
27
|
+
url = https://github.com/matthijsgroen/chai-changes.git
|
28
|
+
[submodule "chai-backbone"]
|
29
|
+
path = chai-backbone
|
30
|
+
url = https://github.com/matthijsgroen/chai-backbone.git
|
31
|
+
[submodule "Sinon.JS"]
|
32
|
+
path = Sinon.JS
|
33
|
+
url = git://github.com/cjohansen/Sinon.JS.git
|
34
|
+
[submodule "js-factories"]
|
35
|
+
path = js-factories
|
36
|
+
url = git://github.com/matthijsgroen/js-factories.git
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Matthijs Groen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
Konacha Chai Matchers
|
2
|
+
=====================
|
3
|
+
|
4
|
+
This library contains all [Chai.js plugins](http://chaijs.com/plugins)
|
5
|
+
|
6
|
+
Not all plugins are tested!
|
7
|
+
|
8
|
+
Installation
|
9
|
+
------------
|
10
|
+
|
11
|
+
Add in the `Gemfile`:
|
12
|
+
|
13
|
+
gem 'konacha-chai-matchers'
|
14
|
+
|
15
|
+
|
16
|
+
Usage
|
17
|
+
-----
|
18
|
+
|
19
|
+
1. Check the vendor/assets/javascripts
|
20
|
+
2. Require the files needed
|
21
|
+
|
22
|
+
Example:
|
23
|
+
|
24
|
+
#= require sinon
|
25
|
+
#= require chai-changes
|
26
|
+
#= require js-factories
|
27
|
+
#= require chai-backbone
|
28
|
+
#= require chai-jquery
|
29
|
+
|
30
|
+
Contribution
|
31
|
+
------------
|
32
|
+
|
33
|
+
Please submit an Github issue for libraries you want included or where the wrong file ends up in the `vendor` folder.
|
34
|
+
|
35
|
+
Updating the vendor libraries is done through `rake update`
|
36
|
+
|
37
|
+
please check `tasks/update.rb` for the code
|
38
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "konacha-chai-matchers/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "konacha-chai-matchers"
|
7
|
+
s.version = Konacha::Chai::Matchers::VERSION
|
8
|
+
s.authors = ["Matthijs Groen"]
|
9
|
+
s.email = ["matthijs.groen@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Chai.js plugins collection for Konacha}
|
12
|
+
s.description = %q{A set of Chai.js libraries ready to use for Konacha}
|
13
|
+
|
14
|
+
s.rubyforge_project = "konacha-chai-matchers"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.license = 'MIT'
|
21
|
+
end
|
data/tasks/update.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
desc 'updates all submodules'
|
4
|
+
task :update do
|
5
|
+
modules = collect_modules
|
6
|
+
update_modules modules
|
7
|
+
vendor_files modules
|
8
|
+
end
|
9
|
+
|
10
|
+
def collect_modules
|
11
|
+
modules = []
|
12
|
+
File.open('.gitmodules') do |f|
|
13
|
+
contents = f.read
|
14
|
+
contents.each_line do |line|
|
15
|
+
modules << $1 if line =~ /\[submodule "(.*)"\]/
|
16
|
+
end
|
17
|
+
end
|
18
|
+
modules
|
19
|
+
end
|
20
|
+
|
21
|
+
def main_files folders
|
22
|
+
folders.map do |f|
|
23
|
+
file_search = f.downcase
|
24
|
+
file_search << '.js' unless file_search =~ /\.js$/
|
25
|
+
|
26
|
+
path_order = ["./#{f}/pkg/#{file_search}", "./#{f}/#{file_search}", "./#{f}/lib/#{file_search}"]
|
27
|
+
|
28
|
+
r = path_order.map do |p|
|
29
|
+
p if File.exist? p
|
30
|
+
end.flatten.compact.first
|
31
|
+
end.flatten.compact
|
32
|
+
end
|
33
|
+
|
34
|
+
def vendor_files modules
|
35
|
+
files = main_files modules
|
36
|
+
puts "found #{files.length} of the #{modules.length} lib files" unless files.length == modules.length
|
37
|
+
path = "./vendor/assets/javascripts/"
|
38
|
+
Pathname.new(path).mkpath()
|
39
|
+
FileUtils.cp files, path
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_modules modules
|
43
|
+
modules.each do |mod|
|
44
|
+
`cd ./#{mod} && git pull`
|
45
|
+
`cd ./#{mod} && ./build` if File.exist? "./#{mod}/build"
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,391 @@
|
|
1
|
+
(function (chaiAsPromised) {
|
2
|
+
"use strict";
|
3
|
+
|
4
|
+
// Module systems magic dance.
|
5
|
+
|
6
|
+
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
|
7
|
+
// NodeJS
|
8
|
+
module.exports = chaiAsPromised;
|
9
|
+
} else if (typeof define === "function" && define.amd) {
|
10
|
+
// AMD
|
11
|
+
define(function () {
|
12
|
+
return chaiAsPromised;
|
13
|
+
});
|
14
|
+
} else {
|
15
|
+
// Other environment (usually <script> tag): plug in to global chai instance directly.
|
16
|
+
chai.use(chaiAsPromised);
|
17
|
+
}
|
18
|
+
}(function chaiAsPromised(chai, utils) {
|
19
|
+
"use strict";
|
20
|
+
|
21
|
+
var Assertion = chai.Assertion;
|
22
|
+
var assert = chai.assert;
|
23
|
+
|
24
|
+
function assertIsAboutPromise(assertion) {
|
25
|
+
if (typeof assertion._obj.then !== "function") {
|
26
|
+
throw new TypeError(utils.inspect(assertion._obj) + " is not a promise!");
|
27
|
+
}
|
28
|
+
if (typeof assertion._obj.pipe === "function") {
|
29
|
+
throw new TypeError("Chai as Promised is incompatible with jQuery's so-called “promises.” Sorry!");
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
function property(name, asserter) {
|
34
|
+
utils.addProperty(Assertion.prototype, name, function () {
|
35
|
+
assertIsAboutPromise(this);
|
36
|
+
return asserter.apply(this, arguments);
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
40
|
+
function method(name, asserter) {
|
41
|
+
utils.addMethod(Assertion.prototype, name, function () {
|
42
|
+
assertIsAboutPromise(this);
|
43
|
+
return asserter.apply(this, arguments);
|
44
|
+
});
|
45
|
+
}
|
46
|
+
|
47
|
+
function notify(promise, callback) {
|
48
|
+
return promise.then(function () { callback(); }, callback);
|
49
|
+
}
|
50
|
+
|
51
|
+
function addNotifyMethod(extensiblePromise) {
|
52
|
+
extensiblePromise.notify = function (callback) {
|
53
|
+
return notify(extensiblePromise, callback);
|
54
|
+
};
|
55
|
+
}
|
56
|
+
|
57
|
+
var fulfilledAsserter = function () {
|
58
|
+
var transformedPromise = this._obj.then(
|
59
|
+
function (value) {
|
60
|
+
if (utils.flag(this, "negate")) {
|
61
|
+
// If we're negated, `this.assert`'s behavior is actually flipped, so `this.assert(true, ...)` will
|
62
|
+
// throw an error, as desired.
|
63
|
+
this.assert(true, null, "expected promise to be rejected but it was fulfilled with " +
|
64
|
+
utils.inspect(value));
|
65
|
+
}
|
66
|
+
|
67
|
+
return value;
|
68
|
+
}.bind(this),
|
69
|
+
function (reason) {
|
70
|
+
// If we're in a negated state (i.e. `.not.fulfilled`) then this assertion will get flipped and thus
|
71
|
+
// pass, as desired.
|
72
|
+
this.assert(false, "expected promise to be fulfilled but it was rejected with " +
|
73
|
+
utils.inspect(reason));
|
74
|
+
}.bind(this)
|
75
|
+
);
|
76
|
+
|
77
|
+
return makeAssertionPromise(transformedPromise, this);
|
78
|
+
};
|
79
|
+
|
80
|
+
var rejectedAsserter = function () {
|
81
|
+
// THIS SHIT IS COMPLICATED. Best illustrated by exhaustive example.
|
82
|
+
////////////////////////////////////////////////////////////////////
|
83
|
+
// `fulfilledPromise.should.be.rejected`:
|
84
|
+
// `onOriginalFulfilled` → `this.assert(false, …)` throws → rejects
|
85
|
+
// `fulfilledPromise.should.not.be.rejected`:
|
86
|
+
// `onOriginalFulfilled` → `this.assert(false, …)` does nothing → fulfills
|
87
|
+
// `rejectedPromise.should.be.rejected`:
|
88
|
+
// `onOriginalRejected` does nothing relevant → fulfills
|
89
|
+
// `rejectedPromise.should.not.be.rejected`:
|
90
|
+
// `onOriginalRejected` → `this.assert(true, …)` throws → rejects
|
91
|
+
// `rejectedPromise.should.be.rejected.with(xxx)`:
|
92
|
+
// `onOriginalRejected` saves `rejectionReason` → fulfills →
|
93
|
+
// `with(xxx)` called → `onTransformedFulfilled` → assert about xxx → fulfills/rejects based on asserts
|
94
|
+
// `rejectedPromise.should.not.be.rejected.with(xxx)`:
|
95
|
+
// `onOriginalRejected` saves `rejectionReason`, `this.assert(true, …)` throws → rejects →
|
96
|
+
// `with(xxx)` called → `onTransformedRejected` → assert about xxx → fulfills/rejects based on asserts
|
97
|
+
// `fulfilledPromise.should.be.rejected.with(xxx)`:
|
98
|
+
// `onOriginalFulfilled` → `this.assert(false, …)` throws → rejects →
|
99
|
+
// `with(xxx)` called → `onTransformedRejected` → `this.assert(false, …)` throws → rejected
|
100
|
+
// `fulfilledPromise.should.not.be.rejected.with(xxx)`:
|
101
|
+
// `onOriginalFulfilled` → `this.assert(false, …)` does nothing → fulfills →
|
102
|
+
// `with(xxx)` called → `onTransformedFulfilled` → fulfills
|
103
|
+
|
104
|
+
var rejectionReason = null;
|
105
|
+
|
106
|
+
var onOriginalFulfilled = function (value) {
|
107
|
+
this.assert(false, "expected promise to be rejected but it was fulfilled with " + utils.inspect(value));
|
108
|
+
}.bind(this);
|
109
|
+
|
110
|
+
var onOriginalRejected = function (reason) {
|
111
|
+
// Store the reason so that `with` can look at it later. Be sure to do this before asserting, since
|
112
|
+
// throwing an error from the assert would cancel the process.
|
113
|
+
rejectionReason = reason;
|
114
|
+
|
115
|
+
if (utils.flag(this, "negate")) {
|
116
|
+
this.assert(true, null, "expected promise to be fulfilled but it was rejected with " +
|
117
|
+
utils.inspect(reason));
|
118
|
+
}
|
119
|
+
|
120
|
+
// If we didn't throw from the assert, transform rejections into fulfillments, by not re-throwing the
|
121
|
+
// reason.
|
122
|
+
}.bind(this);
|
123
|
+
|
124
|
+
var withMethod = function (Constructor, message) {
|
125
|
+
var desiredReason = null;
|
126
|
+
|
127
|
+
if (Constructor instanceof RegExp || typeof Constructor === "string") {
|
128
|
+
message = Constructor;
|
129
|
+
Constructor = null;
|
130
|
+
} else if (Constructor && Constructor instanceof Error) {
|
131
|
+
desiredReason = Constructor;
|
132
|
+
Constructor = null;
|
133
|
+
message = null;
|
134
|
+
}
|
135
|
+
|
136
|
+
var messageVerb = null;
|
137
|
+
var messageIsGood = null;
|
138
|
+
|
139
|
+
if (message instanceof RegExp) {
|
140
|
+
messageVerb = "matching";
|
141
|
+
messageIsGood = function () {
|
142
|
+
return message.test(rejectionReason.message);
|
143
|
+
};
|
144
|
+
} else {
|
145
|
+
messageVerb = "including";
|
146
|
+
messageIsGood = function () {
|
147
|
+
return rejectionReason.message.indexOf(message) !== -1;
|
148
|
+
};
|
149
|
+
}
|
150
|
+
|
151
|
+
function constructorIsGood() {
|
152
|
+
return rejectionReason instanceof Constructor;
|
153
|
+
}
|
154
|
+
|
155
|
+
function matchesDesiredReason() {
|
156
|
+
return rejectionReason === desiredReason;
|
157
|
+
}
|
158
|
+
|
159
|
+
var onTransformedFulfilled = function () {
|
160
|
+
if (!utils.flag(this, "negate")) {
|
161
|
+
if (desiredReason) {
|
162
|
+
this.assert(matchesDesiredReason(),
|
163
|
+
null,
|
164
|
+
"expected promise to be rejected with " + utils.inspect(desiredReason) + " but " +
|
165
|
+
"it was rejected with " + utils.inspect(rejectionReason));
|
166
|
+
}
|
167
|
+
|
168
|
+
if (Constructor) {
|
169
|
+
this.assert(constructorIsGood(),
|
170
|
+
"expected promise to be rejected with " + Constructor.prototype.name + " but it " +
|
171
|
+
"was rejected with " + utils.inspect(rejectionReason));
|
172
|
+
}
|
173
|
+
|
174
|
+
if (message) {
|
175
|
+
this.assert(messageIsGood(),
|
176
|
+
"expected promise to be rejected with an error " + messageVerb + " " + message +
|
177
|
+
" but got " + utils.inspect(rejectionReason.message));
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}.bind(this);
|
181
|
+
|
182
|
+
var onTransformedRejected = function () {
|
183
|
+
if (utils.flag(this, "negate")) {
|
184
|
+
if (desiredReason) {
|
185
|
+
this.assert(matchesDesiredReason(),
|
186
|
+
null,
|
187
|
+
"expected promise to not be rejected with " + utils.inspect(desiredReason));
|
188
|
+
}
|
189
|
+
|
190
|
+
if (Constructor) {
|
191
|
+
this.assert(constructorIsGood(),
|
192
|
+
null,
|
193
|
+
"expected promise to not be rejected with " + Constructor.prototype.name);
|
194
|
+
}
|
195
|
+
|
196
|
+
if (message) {
|
197
|
+
this.assert(messageIsGood(),
|
198
|
+
null,
|
199
|
+
"expected promise to be not be rejected with an error " + messageVerb + " " +
|
200
|
+
message);
|
201
|
+
}
|
202
|
+
} else {
|
203
|
+
if (desiredReason) {
|
204
|
+
this.assert(false,
|
205
|
+
"expected promise to be rejected with " + utils.inspect(desiredReason) +
|
206
|
+
" but it was fulfilled");
|
207
|
+
}
|
208
|
+
|
209
|
+
if (Constructor) {
|
210
|
+
this.assert(false, "expected promise to be rejected with " + Constructor.prototype.name +
|
211
|
+
" but it was fulfilled");
|
212
|
+
}
|
213
|
+
|
214
|
+
if (message) {
|
215
|
+
this.assert(false, "expected promise to be rejected with an error " + messageVerb + " " +
|
216
|
+
message + " but it was fulfilled");
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}.bind(this);
|
220
|
+
|
221
|
+
return makeAssertionPromise(transformedPromise.then(onTransformedFulfilled, onTransformedRejected), this);
|
222
|
+
}.bind(this);
|
223
|
+
|
224
|
+
var transformedPromise = makeAssertionPromise(this._obj.then(onOriginalFulfilled, onOriginalRejected), this);
|
225
|
+
Object.defineProperty(transformedPromise, "with", { enumerable: true, configurable: true, value: withMethod });
|
226
|
+
|
227
|
+
return transformedPromise;
|
228
|
+
};
|
229
|
+
|
230
|
+
function isChaiAsPromisedAsserter(asserterName) {
|
231
|
+
return ["fulfilled", "rejected", "broken", "eventually", "become"].indexOf(asserterName) !== -1;
|
232
|
+
}
|
233
|
+
|
234
|
+
function makeAssertionPromiseToDoAsserter(currentAssertionPromise, previousAssertionPromise, doAsserter) {
|
235
|
+
var promiseToDoAsserter = currentAssertionPromise.then(function (fulfillmentValue) {
|
236
|
+
// The previous assertion promise might have picked up some flags while waiting for fulfillment.
|
237
|
+
utils.transferFlags(previousAssertionPromise, currentAssertionPromise);
|
238
|
+
|
239
|
+
// Replace the object flag with the fulfillment value, so that doAsserter can operate properly.
|
240
|
+
utils.flag(currentAssertionPromise, "object", fulfillmentValue);
|
241
|
+
|
242
|
+
// Perform the actual asserter action and return the result of it.
|
243
|
+
return doAsserter();
|
244
|
+
});
|
245
|
+
return makeAssertionPromise(promiseToDoAsserter, currentAssertionPromise);
|
246
|
+
}
|
247
|
+
|
248
|
+
function makeAssertionPromise(promise, baseAssertion) {
|
249
|
+
// An assertion-promise is an (extensible!) promise with the following additions:
|
250
|
+
var assertionPromise = Object.create(promise);
|
251
|
+
|
252
|
+
// 1. A `notify` method.
|
253
|
+
addNotifyMethod(assertionPromise);
|
254
|
+
|
255
|
+
// 2. An `assert` method that acts exactly as it would on an assertion. This is called by promisified
|
256
|
+
// asserters after the promise fulfills.
|
257
|
+
assertionPromise.assert = function () {
|
258
|
+
return Assertion.prototype.assert.apply(assertionPromise, arguments);
|
259
|
+
};
|
260
|
+
|
261
|
+
// 3. Chai asserters, which act upon the promise's fulfillment value.
|
262
|
+
var asserterNames = Object.getOwnPropertyNames(Assertion.prototype);
|
263
|
+
asserterNames.forEach(function (asserterName) {
|
264
|
+
// We already added `notify` and `assert`; don't mess with those.
|
265
|
+
if (asserterName === "notify" || asserterName === "assert") {
|
266
|
+
return;
|
267
|
+
}
|
268
|
+
|
269
|
+
// Only add asserters for other libraries; poison-pill Chai as Promised ones.
|
270
|
+
if (isChaiAsPromisedAsserter(asserterName)) {
|
271
|
+
utils.addProperty(assertionPromise, asserterName, function () {
|
272
|
+
throw new Error("Cannot use Chai as Promised asserters more than once in an assertion.");
|
273
|
+
});
|
274
|
+
return;
|
275
|
+
}
|
276
|
+
|
277
|
+
// The asserter will need to be added differently depending on its type. In all cases we use
|
278
|
+
// `makeAssertionPromiseToDoAsserter`, which, given this current `assertionPromise` we are going to
|
279
|
+
// return, plus the `baseAssertion` we are basing it off of, will return a new assertion-promise that
|
280
|
+
// builds off of `assertionPromise` and `baseAssertion` to perform the actual asserter action upon
|
281
|
+
// fulfillment.
|
282
|
+
var propertyDescriptor = Object.getOwnPropertyDescriptor(Assertion.prototype, asserterName);
|
283
|
+
|
284
|
+
if (typeof propertyDescriptor.value === "function") {
|
285
|
+
// Case 1: simple method asserters
|
286
|
+
utils.addMethod(assertionPromise, asserterName, function () {
|
287
|
+
var args = arguments;
|
288
|
+
|
289
|
+
return makeAssertionPromiseToDoAsserter(assertionPromise, baseAssertion, function () {
|
290
|
+
return propertyDescriptor.value.apply(assertionPromise, args);
|
291
|
+
});
|
292
|
+
});
|
293
|
+
} else if (typeof propertyDescriptor.get === "function") {
|
294
|
+
// Case 2: property asserters. These break down into two subcases: chainable methods, and pure
|
295
|
+
// properties. An example of the former is `a`/`an`: `.should.be.an.instanceOf` vs.
|
296
|
+
// `should.be.an("object")`.
|
297
|
+
var isChainableMethod = false;
|
298
|
+
try {
|
299
|
+
isChainableMethod = typeof propertyDescriptor.get.call({}) === "function";
|
300
|
+
} catch (e) { }
|
301
|
+
|
302
|
+
if (isChainableMethod) {
|
303
|
+
// Case 2A: chainable methods. Recreate the chainable method, but operating on the augmented
|
304
|
+
// promise. We need to copy both the assertion behavior and the chaining behavior, since the
|
305
|
+
// chaining behavior might for example set flags on the object.
|
306
|
+
utils.addChainableMethod(
|
307
|
+
assertionPromise,
|
308
|
+
asserterName,
|
309
|
+
function () {
|
310
|
+
var args = arguments;
|
311
|
+
|
312
|
+
return makeAssertionPromiseToDoAsserter(assertionPromise, baseAssertion, function () {
|
313
|
+
return propertyDescriptor.get().apply(assertionPromise, args);
|
314
|
+
});
|
315
|
+
},
|
316
|
+
function () {
|
317
|
+
return propertyDescriptor.get.call(assertionPromise);
|
318
|
+
}
|
319
|
+
);
|
320
|
+
} else {
|
321
|
+
// Case 2B: pure property case
|
322
|
+
utils.addProperty(assertionPromise, asserterName, function () {
|
323
|
+
return makeAssertionPromiseToDoAsserter(assertionPromise, baseAssertion, function () {
|
324
|
+
return propertyDescriptor.get.call(assertionPromise);
|
325
|
+
});
|
326
|
+
});
|
327
|
+
}
|
328
|
+
}
|
329
|
+
});
|
330
|
+
|
331
|
+
return assertionPromise;
|
332
|
+
}
|
333
|
+
|
334
|
+
property("fulfilled", fulfilledAsserter);
|
335
|
+
property("rejected", rejectedAsserter);
|
336
|
+
property("broken", rejectedAsserter);
|
337
|
+
|
338
|
+
property("eventually", function () {
|
339
|
+
return makeAssertionPromise(this._obj, this);
|
340
|
+
});
|
341
|
+
|
342
|
+
method("become", function (value) {
|
343
|
+
return this.eventually.eql(value);
|
344
|
+
});
|
345
|
+
|
346
|
+
method("notify", function (callback) {
|
347
|
+
return notify(this._obj, callback);
|
348
|
+
});
|
349
|
+
|
350
|
+
// Now use the Assertion framework to build an `assert` interface.
|
351
|
+
var originalAssertMethods = Object.getOwnPropertyNames(assert).filter(function (propName) {
|
352
|
+
return typeof assert[propName] === "function";
|
353
|
+
});
|
354
|
+
|
355
|
+
assert.isFulfilled = function (promise, message) {
|
356
|
+
return (new Assertion(promise, message)).to.be.fulfilled;
|
357
|
+
};
|
358
|
+
|
359
|
+
assert.isRejected = assert.isBroken = function (promise, toTestAgainst, message) {
|
360
|
+
if (typeof toTestAgainst === "string") {
|
361
|
+
message = toTestAgainst;
|
362
|
+
toTestAgainst = null;
|
363
|
+
}
|
364
|
+
|
365
|
+
var shouldBeRejectedPromise = (new Assertion(promise, message)).to.be.rejected;
|
366
|
+
return toTestAgainst ? shouldBeRejectedPromise.with(toTestAgainst) : shouldBeRejectedPromise;
|
367
|
+
};
|
368
|
+
|
369
|
+
assert.eventually = {};
|
370
|
+
originalAssertMethods.forEach(function (assertMethodName) {
|
371
|
+
assert.eventually[assertMethodName] = function (promise) {
|
372
|
+
var otherArgs = Array.prototype.slice.call(arguments, 1);
|
373
|
+
|
374
|
+
var promiseToAssert = promise.then(function (fulfillmentValue) {
|
375
|
+
return assert[assertMethodName].apply(assert, [fulfillmentValue].concat(otherArgs));
|
376
|
+
});
|
377
|
+
|
378
|
+
var augmentedPromiseToAssert = Object.create(promiseToAssert);
|
379
|
+
addNotifyMethod(augmentedPromiseToAssert);
|
380
|
+
return augmentedPromiseToAssert;
|
381
|
+
};
|
382
|
+
});
|
383
|
+
|
384
|
+
assert.becomes = function (promise, value) {
|
385
|
+
return assert.eventually.deepEqual(promise, value);
|
386
|
+
};
|
387
|
+
|
388
|
+
assert.doesNotBecome = function (promise, value) {
|
389
|
+
return assert.eventually.notDeepEqual(promise, value);
|
390
|
+
};
|
391
|
+
}));
|