konacha-chai-matchers 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}));
|