ende 0.4.5 → 0.4.6
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.
- checksums.yaml +4 -4
- data/lib/assets/javascripts/aura/extensions/devise.js.coffee +0 -2
- data/lib/assets/javascripts/aura/extensions/platform.js.coffee +3 -0
- data/lib/assets/javascripts/aura/extensions/rivets.js.coffee +17 -1
- data/lib/assets/javascripts/aura/extensions/routes.js.coffee +8 -7
- data/lib/assets/javascripts/aura/extensions/states.js.coffee +13 -1
- data/lib/assets/javascripts/aura/extensions/widget/eventable.js.coffee +4 -2
- data/lib/assets/javascripts/config/load_components.js.coffee +19 -12
- data/lib/assets/javascripts/ende.js.coffee +33 -12
- data/lib/ende/version.rb +1 -1
- data/vendor/assets/components/build.css +111 -0
- data/vendor/assets/components/ende_build.js +160 -41
- data/vendor/components/indefinido-indemma/build/development.js +3 -118
- data/vendor/components/indefinido-indemma/build/release.js +39 -4170
- data/vendor/components/indefinido-indemma/build/test.js +3 -118
- data/vendor/components/indefinido-indemma/lib/record/associable.js +10 -2
- data/vendor/components/indefinido-indemma/lib/record/restfulable.js +26 -15
- data/vendor/components/indefinido-indemma/lib/record.js +3 -1
- data/vendor/components/indefinido-indemma/src/lib/record/associable.coffee +15 -1
- data/vendor/components/indefinido-indemma/src/lib/record/restfulable.coffee +37 -12
- data/vendor/components/indefinido-indemma/src/lib/record.coffee +3 -1
- data/vendor/components/indefinido-observable/.gitignore +15 -0
- data/vendor/components/indefinido-observable/.ruby-gemset +1 -0
- data/vendor/components/indefinido-observable/.ruby-version +1 -0
- data/vendor/components/indefinido-observable/Gemfile +13 -0
- data/vendor/components/indefinido-observable/Guardfile +39 -0
- data/vendor/components/indefinido-observable/History.md +0 -0
- data/vendor/components/indefinido-observable/Readme.md +116 -0
- data/vendor/components/indefinido-observable/build/build.js +14798 -0
- data/vendor/components/indefinido-observable/build/development.js +339 -0
- data/vendor/components/indefinido-observable/build/release.js +14937 -0
- data/vendor/components/indefinido-observable/build/test.js +339 -0
- data/vendor/components/indefinido-observable/component.json +5 -1
- data/vendor/components/indefinido-observable/components/chaijs-chai/component.json +46 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/index.js +1 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/assertion.js +132 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/core/assertions.js +1270 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/error.js +60 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/assert.js +1060 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/expect.js +12 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/should.js +76 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addChainableMethod.js +94 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addMethod.js +37 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addProperty.js +40 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/eql.js +124 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/flag.js +32 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getActual.js +19 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getEnumerableProperties.js +25 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getMessage.js +49 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getName.js +20 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getPathValue.js +102 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getProperties.js +35 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/index.js +108 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/inspect.js +316 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/objDisplay.js +48 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/overwriteMethod.js +51 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/overwriteProperty.js +54 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/test.js +26 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/transferFlags.js +44 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/type.js +45 -0
- data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai.js +79 -0
- data/vendor/components/indefinido-observable/components/component-jquery/component.json +14 -0
- data/vendor/components/indefinido-observable/components/component-jquery/index.js +9601 -0
- data/vendor/components/indefinido-observable/components/kapit-observe-shim/component.json +11 -0
- data/vendor/components/indefinido-observable/components/kapit-observe-utils/component.json +13 -0
- data/vendor/components/indefinido-observable/karma.conf.js +92 -0
- data/vendor/components/indefinido-observable/lib/adapters/rivets.js +3 -1
- data/vendor/components/indefinido-observable/lib/observable.js +47 -13
- data/vendor/components/indefinido-observable/spec/legacy/observable_spec.js +126 -0
- data/vendor/components/indefinido-observable/spec/observable_spec.js +92 -0
- data/vendor/components/indefinido-observable/spec/spec_helper.js +8 -0
- data/vendor/components/indefinido-observable/spec/vendor/accessors_spec.js +63 -0
- data/vendor/components/indefinido-observable/src/lib/adapters/rivets.js.coffee +15 -0
- data/vendor/components/indefinido-observable/src/spec/legacy/observable_spec.coffee +132 -0
- data/vendor/components/indefinido-observable/src/spec/observable_spec.coffee +85 -0
- data/vendor/components/indefinido-observable/src/spec/spec_helper.coffee +5 -0
- data/vendor/components/indefinido-observable/src/spec/vendor/accessors_spec.coffee +59 -0
- data/vendor/components/indefinido-observable/vendor/shims/accessors.js +71 -9
- data/vendor/components/indefinido-observable/vendor/spec/boot.js +104 -0
- data/vendor/components/indefinido-observable/vendor/spec/jasmine.js +2054 -0
- metadata +58 -2
data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/core/assertions.js
ADDED
@@ -0,0 +1,1270 @@
|
|
1
|
+
/*!
|
2
|
+
* chai
|
3
|
+
* http://chaijs.com
|
4
|
+
* Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
|
5
|
+
* MIT Licensed
|
6
|
+
*/
|
7
|
+
|
8
|
+
module.exports = function (chai, _) {
|
9
|
+
var Assertion = chai.Assertion
|
10
|
+
, toString = Object.prototype.toString
|
11
|
+
, flag = _.flag;
|
12
|
+
|
13
|
+
/**
|
14
|
+
* ### Language Chains
|
15
|
+
*
|
16
|
+
* The following are provide as chainable getters to
|
17
|
+
* improve the readability of your assertions. They
|
18
|
+
* do not provide an testing capability unless they
|
19
|
+
* have been overwritten by a plugin.
|
20
|
+
*
|
21
|
+
* **Chains**
|
22
|
+
*
|
23
|
+
* - to
|
24
|
+
* - be
|
25
|
+
* - been
|
26
|
+
* - is
|
27
|
+
* - that
|
28
|
+
* - and
|
29
|
+
* - have
|
30
|
+
* - with
|
31
|
+
* - at
|
32
|
+
* - of
|
33
|
+
* - same
|
34
|
+
*
|
35
|
+
* @name language chains
|
36
|
+
* @api public
|
37
|
+
*/
|
38
|
+
|
39
|
+
[ 'to', 'be', 'been'
|
40
|
+
, 'is', 'and', 'have'
|
41
|
+
, 'with', 'that', 'at'
|
42
|
+
, 'of', 'same' ].forEach(function (chain) {
|
43
|
+
Assertion.addProperty(chain, function () {
|
44
|
+
return this;
|
45
|
+
});
|
46
|
+
});
|
47
|
+
|
48
|
+
/**
|
49
|
+
* ### .not
|
50
|
+
*
|
51
|
+
* Negates any of assertions following in the chain.
|
52
|
+
*
|
53
|
+
* expect(foo).to.not.equal('bar');
|
54
|
+
* expect(goodFn).to.not.throw(Error);
|
55
|
+
* expect({ foo: 'baz' }).to.have.property('foo')
|
56
|
+
* .and.not.equal('bar');
|
57
|
+
*
|
58
|
+
* @name not
|
59
|
+
* @api public
|
60
|
+
*/
|
61
|
+
|
62
|
+
Assertion.addProperty('not', function () {
|
63
|
+
flag(this, 'negate', true);
|
64
|
+
});
|
65
|
+
|
66
|
+
/**
|
67
|
+
* ### .deep
|
68
|
+
*
|
69
|
+
* Sets the `deep` flag, later used by the `equal` and
|
70
|
+
* `property` assertions.
|
71
|
+
*
|
72
|
+
* expect(foo).to.deep.equal({ bar: 'baz' });
|
73
|
+
* expect({ foo: { bar: { baz: 'quux' } } })
|
74
|
+
* .to.have.deep.property('foo.bar.baz', 'quux');
|
75
|
+
*
|
76
|
+
* @name deep
|
77
|
+
* @api public
|
78
|
+
*/
|
79
|
+
|
80
|
+
Assertion.addProperty('deep', function () {
|
81
|
+
flag(this, 'deep', true);
|
82
|
+
});
|
83
|
+
|
84
|
+
/**
|
85
|
+
* ### .a(type)
|
86
|
+
*
|
87
|
+
* The `a` and `an` assertions are aliases that can be
|
88
|
+
* used either as language chains or to assert a value's
|
89
|
+
* type.
|
90
|
+
*
|
91
|
+
* // typeof
|
92
|
+
* expect('test').to.be.a('string');
|
93
|
+
* expect({ foo: 'bar' }).to.be.an('object');
|
94
|
+
* expect(null).to.be.a('null');
|
95
|
+
* expect(undefined).to.be.an('undefined');
|
96
|
+
*
|
97
|
+
* // language chain
|
98
|
+
* expect(foo).to.be.an.instanceof(Foo);
|
99
|
+
*
|
100
|
+
* @name a
|
101
|
+
* @alias an
|
102
|
+
* @param {String} type
|
103
|
+
* @param {String} message _optional_
|
104
|
+
* @api public
|
105
|
+
*/
|
106
|
+
|
107
|
+
function an (type, msg) {
|
108
|
+
if (msg) flag(this, 'message', msg);
|
109
|
+
type = type.toLowerCase();
|
110
|
+
var obj = flag(this, 'object')
|
111
|
+
, article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';
|
112
|
+
|
113
|
+
this.assert(
|
114
|
+
type === _.type(obj)
|
115
|
+
, 'expected #{this} to be ' + article + type
|
116
|
+
, 'expected #{this} not to be ' + article + type
|
117
|
+
);
|
118
|
+
}
|
119
|
+
|
120
|
+
Assertion.addChainableMethod('an', an);
|
121
|
+
Assertion.addChainableMethod('a', an);
|
122
|
+
|
123
|
+
/**
|
124
|
+
* ### .include(value)
|
125
|
+
*
|
126
|
+
* The `include` and `contain` assertions can be used as either property
|
127
|
+
* based language chains or as methods to assert the inclusion of an object
|
128
|
+
* in an array or a substring in a string. When used as language chains,
|
129
|
+
* they toggle the `contain` flag for the `keys` assertion.
|
130
|
+
*
|
131
|
+
* expect([1,2,3]).to.include(2);
|
132
|
+
* expect('foobar').to.contain('foo');
|
133
|
+
* expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
|
134
|
+
*
|
135
|
+
* @name include
|
136
|
+
* @alias contain
|
137
|
+
* @param {Object|String|Number} obj
|
138
|
+
* @param {String} message _optional_
|
139
|
+
* @api public
|
140
|
+
*/
|
141
|
+
|
142
|
+
function includeChainingBehavior () {
|
143
|
+
flag(this, 'contains', true);
|
144
|
+
}
|
145
|
+
|
146
|
+
function include (val, msg) {
|
147
|
+
if (msg) flag(this, 'message', msg);
|
148
|
+
var obj = flag(this, 'object')
|
149
|
+
this.assert(
|
150
|
+
~obj.indexOf(val)
|
151
|
+
, 'expected #{this} to include ' + _.inspect(val)
|
152
|
+
, 'expected #{this} to not include ' + _.inspect(val));
|
153
|
+
}
|
154
|
+
|
155
|
+
Assertion.addChainableMethod('include', include, includeChainingBehavior);
|
156
|
+
Assertion.addChainableMethod('contain', include, includeChainingBehavior);
|
157
|
+
|
158
|
+
/**
|
159
|
+
* ### .ok
|
160
|
+
*
|
161
|
+
* Asserts that the target is truthy.
|
162
|
+
*
|
163
|
+
* expect('everthing').to.be.ok;
|
164
|
+
* expect(1).to.be.ok;
|
165
|
+
* expect(false).to.not.be.ok;
|
166
|
+
* expect(undefined).to.not.be.ok;
|
167
|
+
* expect(null).to.not.be.ok;
|
168
|
+
*
|
169
|
+
* @name ok
|
170
|
+
* @api public
|
171
|
+
*/
|
172
|
+
|
173
|
+
Assertion.addProperty('ok', function () {
|
174
|
+
this.assert(
|
175
|
+
flag(this, 'object')
|
176
|
+
, 'expected #{this} to be truthy'
|
177
|
+
, 'expected #{this} to be falsy');
|
178
|
+
});
|
179
|
+
|
180
|
+
/**
|
181
|
+
* ### .true
|
182
|
+
*
|
183
|
+
* Asserts that the target is `true`.
|
184
|
+
*
|
185
|
+
* expect(true).to.be.true;
|
186
|
+
* expect(1).to.not.be.true;
|
187
|
+
*
|
188
|
+
* @name true
|
189
|
+
* @api public
|
190
|
+
*/
|
191
|
+
|
192
|
+
Assertion.addProperty('true', function () {
|
193
|
+
this.assert(
|
194
|
+
true === flag(this, 'object')
|
195
|
+
, 'expected #{this} to be true'
|
196
|
+
, 'expected #{this} to be false'
|
197
|
+
, this.negate ? false : true
|
198
|
+
);
|
199
|
+
});
|
200
|
+
|
201
|
+
/**
|
202
|
+
* ### .false
|
203
|
+
*
|
204
|
+
* Asserts that the target is `false`.
|
205
|
+
*
|
206
|
+
* expect(false).to.be.false;
|
207
|
+
* expect(0).to.not.be.false;
|
208
|
+
*
|
209
|
+
* @name false
|
210
|
+
* @api public
|
211
|
+
*/
|
212
|
+
|
213
|
+
Assertion.addProperty('false', function () {
|
214
|
+
this.assert(
|
215
|
+
false === flag(this, 'object')
|
216
|
+
, 'expected #{this} to be false'
|
217
|
+
, 'expected #{this} to be true'
|
218
|
+
, this.negate ? true : false
|
219
|
+
);
|
220
|
+
});
|
221
|
+
|
222
|
+
/**
|
223
|
+
* ### .null
|
224
|
+
*
|
225
|
+
* Asserts that the target is `null`.
|
226
|
+
*
|
227
|
+
* expect(null).to.be.null;
|
228
|
+
* expect(undefined).not.to.be.null;
|
229
|
+
*
|
230
|
+
* @name null
|
231
|
+
* @api public
|
232
|
+
*/
|
233
|
+
|
234
|
+
Assertion.addProperty('null', function () {
|
235
|
+
this.assert(
|
236
|
+
null === flag(this, 'object')
|
237
|
+
, 'expected #{this} to be null'
|
238
|
+
, 'expected #{this} not to be null'
|
239
|
+
);
|
240
|
+
});
|
241
|
+
|
242
|
+
/**
|
243
|
+
* ### .undefined
|
244
|
+
*
|
245
|
+
* Asserts that the target is `undefined`.
|
246
|
+
*
|
247
|
+
* expect(undefined).to.be.undefined;
|
248
|
+
* expect(null).to.not.be.undefined;
|
249
|
+
*
|
250
|
+
* @name undefined
|
251
|
+
* @api public
|
252
|
+
*/
|
253
|
+
|
254
|
+
Assertion.addProperty('undefined', function () {
|
255
|
+
this.assert(
|
256
|
+
undefined === flag(this, 'object')
|
257
|
+
, 'expected #{this} to be undefined'
|
258
|
+
, 'expected #{this} not to be undefined'
|
259
|
+
);
|
260
|
+
});
|
261
|
+
|
262
|
+
/**
|
263
|
+
* ### .exist
|
264
|
+
*
|
265
|
+
* Asserts that the target is neither `null` nor `undefined`.
|
266
|
+
*
|
267
|
+
* var foo = 'hi'
|
268
|
+
* , bar = null
|
269
|
+
* , baz;
|
270
|
+
*
|
271
|
+
* expect(foo).to.exist;
|
272
|
+
* expect(bar).to.not.exist;
|
273
|
+
* expect(baz).to.not.exist;
|
274
|
+
*
|
275
|
+
* @name exist
|
276
|
+
* @api public
|
277
|
+
*/
|
278
|
+
|
279
|
+
Assertion.addProperty('exist', function () {
|
280
|
+
this.assert(
|
281
|
+
null != flag(this, 'object')
|
282
|
+
, 'expected #{this} to exist'
|
283
|
+
, 'expected #{this} to not exist'
|
284
|
+
);
|
285
|
+
});
|
286
|
+
|
287
|
+
|
288
|
+
/**
|
289
|
+
* ### .empty
|
290
|
+
*
|
291
|
+
* Asserts that the target's length is `0`. For arrays, it checks
|
292
|
+
* the `length` property. For objects, it gets the count of
|
293
|
+
* enumerable keys.
|
294
|
+
*
|
295
|
+
* expect([]).to.be.empty;
|
296
|
+
* expect('').to.be.empty;
|
297
|
+
* expect({}).to.be.empty;
|
298
|
+
*
|
299
|
+
* @name empty
|
300
|
+
* @api public
|
301
|
+
*/
|
302
|
+
|
303
|
+
Assertion.addProperty('empty', function () {
|
304
|
+
var obj = flag(this, 'object')
|
305
|
+
, expected = obj;
|
306
|
+
|
307
|
+
if (Array.isArray(obj) || 'string' === typeof object) {
|
308
|
+
expected = obj.length;
|
309
|
+
} else if (typeof obj === 'object') {
|
310
|
+
expected = Object.keys(obj).length;
|
311
|
+
}
|
312
|
+
|
313
|
+
this.assert(
|
314
|
+
!expected
|
315
|
+
, 'expected #{this} to be empty'
|
316
|
+
, 'expected #{this} not to be empty'
|
317
|
+
);
|
318
|
+
});
|
319
|
+
|
320
|
+
/**
|
321
|
+
* ### .arguments
|
322
|
+
*
|
323
|
+
* Asserts that the target is an arguments object.
|
324
|
+
*
|
325
|
+
* function test () {
|
326
|
+
* expect(arguments).to.be.arguments;
|
327
|
+
* }
|
328
|
+
*
|
329
|
+
* @name arguments
|
330
|
+
* @alias Arguments
|
331
|
+
* @api public
|
332
|
+
*/
|
333
|
+
|
334
|
+
function checkArguments () {
|
335
|
+
var obj = flag(this, 'object')
|
336
|
+
, type = Object.prototype.toString.call(obj);
|
337
|
+
this.assert(
|
338
|
+
'[object Arguments]' === type
|
339
|
+
, 'expected #{this} to be arguments but got ' + type
|
340
|
+
, 'expected #{this} to not be arguments'
|
341
|
+
);
|
342
|
+
}
|
343
|
+
|
344
|
+
Assertion.addProperty('arguments', checkArguments);
|
345
|
+
Assertion.addProperty('Arguments', checkArguments);
|
346
|
+
|
347
|
+
/**
|
348
|
+
* ### .equal(value)
|
349
|
+
*
|
350
|
+
* Asserts that the target is strictly equal (`===`) to `value`.
|
351
|
+
* Alternately, if the `deep` flag is set, asserts that
|
352
|
+
* the target is deeply equal to `value`.
|
353
|
+
*
|
354
|
+
* expect('hello').to.equal('hello');
|
355
|
+
* expect(42).to.equal(42);
|
356
|
+
* expect(1).to.not.equal(true);
|
357
|
+
* expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
|
358
|
+
* expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
|
359
|
+
*
|
360
|
+
* @name equal
|
361
|
+
* @alias equals
|
362
|
+
* @alias eq
|
363
|
+
* @alias deep.equal
|
364
|
+
* @param {Mixed} value
|
365
|
+
* @param {String} message _optional_
|
366
|
+
* @api public
|
367
|
+
*/
|
368
|
+
|
369
|
+
function assertEqual (val, msg) {
|
370
|
+
if (msg) flag(this, 'message', msg);
|
371
|
+
var obj = flag(this, 'object');
|
372
|
+
if (flag(this, 'deep')) {
|
373
|
+
return this.eql(val);
|
374
|
+
} else {
|
375
|
+
this.assert(
|
376
|
+
val === obj
|
377
|
+
, 'expected #{this} to equal #{exp}'
|
378
|
+
, 'expected #{this} to not equal #{exp}'
|
379
|
+
, val
|
380
|
+
, this._obj
|
381
|
+
, true
|
382
|
+
);
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
Assertion.addMethod('equal', assertEqual);
|
387
|
+
Assertion.addMethod('equals', assertEqual);
|
388
|
+
Assertion.addMethod('eq', assertEqual);
|
389
|
+
|
390
|
+
/**
|
391
|
+
* ### .eql(value)
|
392
|
+
*
|
393
|
+
* Asserts that the target is deeply equal to `value`.
|
394
|
+
*
|
395
|
+
* expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
|
396
|
+
* expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
|
397
|
+
*
|
398
|
+
* @name eql
|
399
|
+
* @alias eqls
|
400
|
+
* @param {Mixed} value
|
401
|
+
* @param {String} message _optional_
|
402
|
+
* @api public
|
403
|
+
*/
|
404
|
+
|
405
|
+
function assertEql(obj, msg) {
|
406
|
+
if (msg) flag(this, 'message', msg);
|
407
|
+
this.assert(
|
408
|
+
_.eql(obj, flag(this, 'object'))
|
409
|
+
, 'expected #{this} to deeply equal #{exp}'
|
410
|
+
, 'expected #{this} to not deeply equal #{exp}'
|
411
|
+
, obj
|
412
|
+
, this._obj
|
413
|
+
, true
|
414
|
+
);
|
415
|
+
}
|
416
|
+
|
417
|
+
Assertion.addMethod('eql', assertEql);
|
418
|
+
Assertion.addMethod('eqls', assertEql);
|
419
|
+
|
420
|
+
/**
|
421
|
+
* ### .above(value)
|
422
|
+
*
|
423
|
+
* Asserts that the target is greater than `value`.
|
424
|
+
*
|
425
|
+
* expect(10).to.be.above(5);
|
426
|
+
*
|
427
|
+
* Can also be used in conjunction with `length` to
|
428
|
+
* assert a minimum length. The benefit being a
|
429
|
+
* more informative error message than if the length
|
430
|
+
* was supplied directly.
|
431
|
+
*
|
432
|
+
* expect('foo').to.have.length.above(2);
|
433
|
+
* expect([ 1, 2, 3 ]).to.have.length.above(2);
|
434
|
+
*
|
435
|
+
* @name above
|
436
|
+
* @alias gt
|
437
|
+
* @alias greaterThan
|
438
|
+
* @param {Number} value
|
439
|
+
* @param {String} message _optional_
|
440
|
+
* @api public
|
441
|
+
*/
|
442
|
+
|
443
|
+
function assertAbove (n, msg) {
|
444
|
+
if (msg) flag(this, 'message', msg);
|
445
|
+
var obj = flag(this, 'object');
|
446
|
+
if (flag(this, 'doLength')) {
|
447
|
+
new Assertion(obj, msg).to.have.property('length');
|
448
|
+
var len = obj.length;
|
449
|
+
this.assert(
|
450
|
+
len > n
|
451
|
+
, 'expected #{this} to have a length above #{exp} but got #{act}'
|
452
|
+
, 'expected #{this} to not have a length above #{exp}'
|
453
|
+
, n
|
454
|
+
, len
|
455
|
+
);
|
456
|
+
} else {
|
457
|
+
this.assert(
|
458
|
+
obj > n
|
459
|
+
, 'expected #{this} to be above ' + n
|
460
|
+
, 'expected #{this} to be at most ' + n
|
461
|
+
);
|
462
|
+
}
|
463
|
+
}
|
464
|
+
|
465
|
+
Assertion.addMethod('above', assertAbove);
|
466
|
+
Assertion.addMethod('gt', assertAbove);
|
467
|
+
Assertion.addMethod('greaterThan', assertAbove);
|
468
|
+
|
469
|
+
/**
|
470
|
+
* ### .least(value)
|
471
|
+
*
|
472
|
+
* Asserts that the target is greater than or equal to `value`.
|
473
|
+
*
|
474
|
+
* expect(10).to.be.at.least(10);
|
475
|
+
*
|
476
|
+
* Can also be used in conjunction with `length` to
|
477
|
+
* assert a minimum length. The benefit being a
|
478
|
+
* more informative error message than if the length
|
479
|
+
* was supplied directly.
|
480
|
+
*
|
481
|
+
* expect('foo').to.have.length.of.at.least(2);
|
482
|
+
* expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);
|
483
|
+
*
|
484
|
+
* @name least
|
485
|
+
* @alias gte
|
486
|
+
* @param {Number} value
|
487
|
+
* @param {String} message _optional_
|
488
|
+
* @api public
|
489
|
+
*/
|
490
|
+
|
491
|
+
function assertLeast (n, msg) {
|
492
|
+
if (msg) flag(this, 'message', msg);
|
493
|
+
var obj = flag(this, 'object');
|
494
|
+
if (flag(this, 'doLength')) {
|
495
|
+
new Assertion(obj, msg).to.have.property('length');
|
496
|
+
var len = obj.length;
|
497
|
+
this.assert(
|
498
|
+
len >= n
|
499
|
+
, 'expected #{this} to have a length at least #{exp} but got #{act}'
|
500
|
+
, 'expected #{this} to have a length below #{exp}'
|
501
|
+
, n
|
502
|
+
, len
|
503
|
+
);
|
504
|
+
} else {
|
505
|
+
this.assert(
|
506
|
+
obj >= n
|
507
|
+
, 'expected #{this} to be at least ' + n
|
508
|
+
, 'expected #{this} to be below ' + n
|
509
|
+
);
|
510
|
+
}
|
511
|
+
}
|
512
|
+
|
513
|
+
Assertion.addMethod('least', assertLeast);
|
514
|
+
Assertion.addMethod('gte', assertLeast);
|
515
|
+
|
516
|
+
/**
|
517
|
+
* ### .below(value)
|
518
|
+
*
|
519
|
+
* Asserts that the target is less than `value`.
|
520
|
+
*
|
521
|
+
* expect(5).to.be.below(10);
|
522
|
+
*
|
523
|
+
* Can also be used in conjunction with `length` to
|
524
|
+
* assert a maximum length. The benefit being a
|
525
|
+
* more informative error message than if the length
|
526
|
+
* was supplied directly.
|
527
|
+
*
|
528
|
+
* expect('foo').to.have.length.below(4);
|
529
|
+
* expect([ 1, 2, 3 ]).to.have.length.below(4);
|
530
|
+
*
|
531
|
+
* @name below
|
532
|
+
* @alias lt
|
533
|
+
* @alias lessThan
|
534
|
+
* @param {Number} value
|
535
|
+
* @param {String} message _optional_
|
536
|
+
* @api public
|
537
|
+
*/
|
538
|
+
|
539
|
+
function assertBelow (n, msg) {
|
540
|
+
if (msg) flag(this, 'message', msg);
|
541
|
+
var obj = flag(this, 'object');
|
542
|
+
if (flag(this, 'doLength')) {
|
543
|
+
new Assertion(obj, msg).to.have.property('length');
|
544
|
+
var len = obj.length;
|
545
|
+
this.assert(
|
546
|
+
len < n
|
547
|
+
, 'expected #{this} to have a length below #{exp} but got #{act}'
|
548
|
+
, 'expected #{this} to not have a length below #{exp}'
|
549
|
+
, n
|
550
|
+
, len
|
551
|
+
);
|
552
|
+
} else {
|
553
|
+
this.assert(
|
554
|
+
obj < n
|
555
|
+
, 'expected #{this} to be below ' + n
|
556
|
+
, 'expected #{this} to be at least ' + n
|
557
|
+
);
|
558
|
+
}
|
559
|
+
}
|
560
|
+
|
561
|
+
Assertion.addMethod('below', assertBelow);
|
562
|
+
Assertion.addMethod('lt', assertBelow);
|
563
|
+
Assertion.addMethod('lessThan', assertBelow);
|
564
|
+
|
565
|
+
/**
|
566
|
+
* ### .most(value)
|
567
|
+
*
|
568
|
+
* Asserts that the target is less than or equal to `value`.
|
569
|
+
*
|
570
|
+
* expect(5).to.be.at.most(5);
|
571
|
+
*
|
572
|
+
* Can also be used in conjunction with `length` to
|
573
|
+
* assert a maximum length. The benefit being a
|
574
|
+
* more informative error message than if the length
|
575
|
+
* was supplied directly.
|
576
|
+
*
|
577
|
+
* expect('foo').to.have.length.of.at.most(4);
|
578
|
+
* expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);
|
579
|
+
*
|
580
|
+
* @name most
|
581
|
+
* @alias lte
|
582
|
+
* @param {Number} value
|
583
|
+
* @param {String} message _optional_
|
584
|
+
* @api public
|
585
|
+
*/
|
586
|
+
|
587
|
+
function assertMost (n, msg) {
|
588
|
+
if (msg) flag(this, 'message', msg);
|
589
|
+
var obj = flag(this, 'object');
|
590
|
+
if (flag(this, 'doLength')) {
|
591
|
+
new Assertion(obj, msg).to.have.property('length');
|
592
|
+
var len = obj.length;
|
593
|
+
this.assert(
|
594
|
+
len <= n
|
595
|
+
, 'expected #{this} to have a length at most #{exp} but got #{act}'
|
596
|
+
, 'expected #{this} to have a length above #{exp}'
|
597
|
+
, n
|
598
|
+
, len
|
599
|
+
);
|
600
|
+
} else {
|
601
|
+
this.assert(
|
602
|
+
obj <= n
|
603
|
+
, 'expected #{this} to be at most ' + n
|
604
|
+
, 'expected #{this} to be above ' + n
|
605
|
+
);
|
606
|
+
}
|
607
|
+
}
|
608
|
+
|
609
|
+
Assertion.addMethod('most', assertMost);
|
610
|
+
Assertion.addMethod('lte', assertMost);
|
611
|
+
|
612
|
+
/**
|
613
|
+
* ### .within(start, finish)
|
614
|
+
*
|
615
|
+
* Asserts that the target is within a range.
|
616
|
+
*
|
617
|
+
* expect(7).to.be.within(5,10);
|
618
|
+
*
|
619
|
+
* Can also be used in conjunction with `length` to
|
620
|
+
* assert a length range. The benefit being a
|
621
|
+
* more informative error message than if the length
|
622
|
+
* was supplied directly.
|
623
|
+
*
|
624
|
+
* expect('foo').to.have.length.within(2,4);
|
625
|
+
* expect([ 1, 2, 3 ]).to.have.length.within(2,4);
|
626
|
+
*
|
627
|
+
* @name within
|
628
|
+
* @param {Number} start lowerbound inclusive
|
629
|
+
* @param {Number} finish upperbound inclusive
|
630
|
+
* @param {String} message _optional_
|
631
|
+
* @api public
|
632
|
+
*/
|
633
|
+
|
634
|
+
Assertion.addMethod('within', function (start, finish, msg) {
|
635
|
+
if (msg) flag(this, 'message', msg);
|
636
|
+
var obj = flag(this, 'object')
|
637
|
+
, range = start + '..' + finish;
|
638
|
+
if (flag(this, 'doLength')) {
|
639
|
+
new Assertion(obj, msg).to.have.property('length');
|
640
|
+
var len = obj.length;
|
641
|
+
this.assert(
|
642
|
+
len >= start && len <= finish
|
643
|
+
, 'expected #{this} to have a length within ' + range
|
644
|
+
, 'expected #{this} to not have a length within ' + range
|
645
|
+
);
|
646
|
+
} else {
|
647
|
+
this.assert(
|
648
|
+
obj >= start && obj <= finish
|
649
|
+
, 'expected #{this} to be within ' + range
|
650
|
+
, 'expected #{this} to not be within ' + range
|
651
|
+
);
|
652
|
+
}
|
653
|
+
});
|
654
|
+
|
655
|
+
/**
|
656
|
+
* ### .instanceof(constructor)
|
657
|
+
*
|
658
|
+
* Asserts that the target is an instance of `constructor`.
|
659
|
+
*
|
660
|
+
* var Tea = function (name) { this.name = name; }
|
661
|
+
* , Chai = new Tea('chai');
|
662
|
+
*
|
663
|
+
* expect(Chai).to.be.an.instanceof(Tea);
|
664
|
+
* expect([ 1, 2, 3 ]).to.be.instanceof(Array);
|
665
|
+
*
|
666
|
+
* @name instanceof
|
667
|
+
* @param {Constructor} constructor
|
668
|
+
* @param {String} message _optional_
|
669
|
+
* @alias instanceOf
|
670
|
+
* @api public
|
671
|
+
*/
|
672
|
+
|
673
|
+
function assertInstanceOf (constructor, msg) {
|
674
|
+
if (msg) flag(this, 'message', msg);
|
675
|
+
var name = _.getName(constructor);
|
676
|
+
this.assert(
|
677
|
+
flag(this, 'object') instanceof constructor
|
678
|
+
, 'expected #{this} to be an instance of ' + name
|
679
|
+
, 'expected #{this} to not be an instance of ' + name
|
680
|
+
);
|
681
|
+
};
|
682
|
+
|
683
|
+
Assertion.addMethod('instanceof', assertInstanceOf);
|
684
|
+
Assertion.addMethod('instanceOf', assertInstanceOf);
|
685
|
+
|
686
|
+
/**
|
687
|
+
* ### .property(name, [value])
|
688
|
+
*
|
689
|
+
* Asserts that the target has a property `name`, optionally asserting that
|
690
|
+
* the value of that property is strictly equal to `value`.
|
691
|
+
* If the `deep` flag is set, you can use dot- and bracket-notation for deep
|
692
|
+
* references into objects and arrays.
|
693
|
+
*
|
694
|
+
* // simple referencing
|
695
|
+
* var obj = { foo: 'bar' };
|
696
|
+
* expect(obj).to.have.property('foo');
|
697
|
+
* expect(obj).to.have.property('foo', 'bar');
|
698
|
+
*
|
699
|
+
* // deep referencing
|
700
|
+
* var deepObj = {
|
701
|
+
* green: { tea: 'matcha' }
|
702
|
+
* , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
|
703
|
+
* };
|
704
|
+
|
705
|
+
* expect(deepObj).to.have.deep.property('green.tea', 'matcha');
|
706
|
+
* expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
|
707
|
+
* expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
|
708
|
+
*
|
709
|
+
* You can also use an array as the starting point of a `deep.property`
|
710
|
+
* assertion, or traverse nested arrays.
|
711
|
+
*
|
712
|
+
* var arr = [
|
713
|
+
* [ 'chai', 'matcha', 'konacha' ]
|
714
|
+
* , [ { tea: 'chai' }
|
715
|
+
* , { tea: 'matcha' }
|
716
|
+
* , { tea: 'konacha' } ]
|
717
|
+
* ];
|
718
|
+
*
|
719
|
+
* expect(arr).to.have.deep.property('[0][1]', 'matcha');
|
720
|
+
* expect(arr).to.have.deep.property('[1][2].tea', 'konacha');
|
721
|
+
*
|
722
|
+
* Furthermore, `property` changes the subject of the assertion
|
723
|
+
* to be the value of that property from the original object. This
|
724
|
+
* permits for further chainable assertions on that property.
|
725
|
+
*
|
726
|
+
* expect(obj).to.have.property('foo')
|
727
|
+
* .that.is.a('string');
|
728
|
+
* expect(deepObj).to.have.property('green')
|
729
|
+
* .that.is.an('object')
|
730
|
+
* .that.deep.equals({ tea: 'matcha' });
|
731
|
+
* expect(deepObj).to.have.property('teas')
|
732
|
+
* .that.is.an('array')
|
733
|
+
* .with.deep.property('[2]')
|
734
|
+
* .that.deep.equals({ tea: 'konacha' });
|
735
|
+
*
|
736
|
+
* @name property
|
737
|
+
* @alias deep.property
|
738
|
+
* @param {String} name
|
739
|
+
* @param {Mixed} value (optional)
|
740
|
+
* @param {String} message _optional_
|
741
|
+
* @returns value of property for chaining
|
742
|
+
* @api public
|
743
|
+
*/
|
744
|
+
|
745
|
+
Assertion.addMethod('property', function (name, val, msg) {
|
746
|
+
if (msg) flag(this, 'message', msg);
|
747
|
+
|
748
|
+
var descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
|
749
|
+
, negate = flag(this, 'negate')
|
750
|
+
, obj = flag(this, 'object')
|
751
|
+
, value = flag(this, 'deep')
|
752
|
+
? _.getPathValue(name, obj)
|
753
|
+
: obj[name];
|
754
|
+
|
755
|
+
if (negate && undefined !== val) {
|
756
|
+
if (undefined === value) {
|
757
|
+
msg = (msg != null) ? msg + ': ' : '';
|
758
|
+
throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));
|
759
|
+
}
|
760
|
+
} else {
|
761
|
+
this.assert(
|
762
|
+
undefined !== value
|
763
|
+
, 'expected #{this} to have a ' + descriptor + _.inspect(name)
|
764
|
+
, 'expected #{this} to not have ' + descriptor + _.inspect(name));
|
765
|
+
}
|
766
|
+
|
767
|
+
if (undefined !== val) {
|
768
|
+
this.assert(
|
769
|
+
val === value
|
770
|
+
, 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
|
771
|
+
, 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'
|
772
|
+
, val
|
773
|
+
, value
|
774
|
+
);
|
775
|
+
}
|
776
|
+
|
777
|
+
flag(this, 'object', value);
|
778
|
+
});
|
779
|
+
|
780
|
+
|
781
|
+
/**
|
782
|
+
* ### .ownProperty(name)
|
783
|
+
*
|
784
|
+
* Asserts that the target has an own property `name`.
|
785
|
+
*
|
786
|
+
* expect('test').to.have.ownProperty('length');
|
787
|
+
*
|
788
|
+
* @name ownProperty
|
789
|
+
* @alias haveOwnProperty
|
790
|
+
* @param {String} name
|
791
|
+
* @param {String} message _optional_
|
792
|
+
* @api public
|
793
|
+
*/
|
794
|
+
|
795
|
+
function assertOwnProperty (name, msg) {
|
796
|
+
if (msg) flag(this, 'message', msg);
|
797
|
+
var obj = flag(this, 'object');
|
798
|
+
this.assert(
|
799
|
+
obj.hasOwnProperty(name)
|
800
|
+
, 'expected #{this} to have own property ' + _.inspect(name)
|
801
|
+
, 'expected #{this} to not have own property ' + _.inspect(name)
|
802
|
+
);
|
803
|
+
}
|
804
|
+
|
805
|
+
Assertion.addMethod('ownProperty', assertOwnProperty);
|
806
|
+
Assertion.addMethod('haveOwnProperty', assertOwnProperty);
|
807
|
+
|
808
|
+
/**
|
809
|
+
* ### .length(value)
|
810
|
+
*
|
811
|
+
* Asserts that the target's `length` property has
|
812
|
+
* the expected value.
|
813
|
+
*
|
814
|
+
* expect([ 1, 2, 3]).to.have.length(3);
|
815
|
+
* expect('foobar').to.have.length(6);
|
816
|
+
*
|
817
|
+
* Can also be used as a chain precursor to a value
|
818
|
+
* comparison for the length property.
|
819
|
+
*
|
820
|
+
* expect('foo').to.have.length.above(2);
|
821
|
+
* expect([ 1, 2, 3 ]).to.have.length.above(2);
|
822
|
+
* expect('foo').to.have.length.below(4);
|
823
|
+
* expect([ 1, 2, 3 ]).to.have.length.below(4);
|
824
|
+
* expect('foo').to.have.length.within(2,4);
|
825
|
+
* expect([ 1, 2, 3 ]).to.have.length.within(2,4);
|
826
|
+
*
|
827
|
+
* @name length
|
828
|
+
* @alias lengthOf
|
829
|
+
* @param {Number} length
|
830
|
+
* @param {String} message _optional_
|
831
|
+
* @api public
|
832
|
+
*/
|
833
|
+
|
834
|
+
function assertLengthChain () {
|
835
|
+
flag(this, 'doLength', true);
|
836
|
+
}
|
837
|
+
|
838
|
+
function assertLength (n, msg) {
|
839
|
+
if (msg) flag(this, 'message', msg);
|
840
|
+
var obj = flag(this, 'object');
|
841
|
+
new Assertion(obj, msg).to.have.property('length');
|
842
|
+
var len = obj.length;
|
843
|
+
|
844
|
+
this.assert(
|
845
|
+
len == n
|
846
|
+
, 'expected #{this} to have a length of #{exp} but got #{act}'
|
847
|
+
, 'expected #{this} to not have a length of #{act}'
|
848
|
+
, n
|
849
|
+
, len
|
850
|
+
);
|
851
|
+
}
|
852
|
+
|
853
|
+
Assertion.addChainableMethod('length', assertLength, assertLengthChain);
|
854
|
+
Assertion.addMethod('lengthOf', assertLength, assertLengthChain);
|
855
|
+
|
856
|
+
/**
|
857
|
+
* ### .match(regexp)
|
858
|
+
*
|
859
|
+
* Asserts that the target matches a regular expression.
|
860
|
+
*
|
861
|
+
* expect('foobar').to.match(/^foo/);
|
862
|
+
*
|
863
|
+
* @name match
|
864
|
+
* @param {RegExp} RegularExpression
|
865
|
+
* @param {String} message _optional_
|
866
|
+
* @api public
|
867
|
+
*/
|
868
|
+
|
869
|
+
Assertion.addMethod('match', function (re, msg) {
|
870
|
+
if (msg) flag(this, 'message', msg);
|
871
|
+
var obj = flag(this, 'object');
|
872
|
+
this.assert(
|
873
|
+
re.exec(obj)
|
874
|
+
, 'expected #{this} to match ' + re
|
875
|
+
, 'expected #{this} not to match ' + re
|
876
|
+
);
|
877
|
+
});
|
878
|
+
|
879
|
+
/**
|
880
|
+
* ### .string(string)
|
881
|
+
*
|
882
|
+
* Asserts that the string target contains another string.
|
883
|
+
*
|
884
|
+
* expect('foobar').to.have.string('bar');
|
885
|
+
*
|
886
|
+
* @name string
|
887
|
+
* @param {String} string
|
888
|
+
* @param {String} message _optional_
|
889
|
+
* @api public
|
890
|
+
*/
|
891
|
+
|
892
|
+
Assertion.addMethod('string', function (str, msg) {
|
893
|
+
if (msg) flag(this, 'message', msg);
|
894
|
+
var obj = flag(this, 'object');
|
895
|
+
new Assertion(obj, msg).is.a('string');
|
896
|
+
|
897
|
+
this.assert(
|
898
|
+
~obj.indexOf(str)
|
899
|
+
, 'expected #{this} to contain ' + _.inspect(str)
|
900
|
+
, 'expected #{this} to not contain ' + _.inspect(str)
|
901
|
+
);
|
902
|
+
});
|
903
|
+
|
904
|
+
|
905
|
+
/**
|
906
|
+
* ### .keys(key1, [key2], [...])
|
907
|
+
*
|
908
|
+
* Asserts that the target has exactly the given keys, or
|
909
|
+
* asserts the inclusion of some keys when using the
|
910
|
+
* `include` or `contain` modifiers.
|
911
|
+
*
|
912
|
+
* expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
|
913
|
+
* expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
|
914
|
+
*
|
915
|
+
* @name keys
|
916
|
+
* @alias key
|
917
|
+
* @param {String...|Array} keys
|
918
|
+
* @api public
|
919
|
+
*/
|
920
|
+
|
921
|
+
function assertKeys (keys) {
|
922
|
+
var obj = flag(this, 'object')
|
923
|
+
, str
|
924
|
+
, ok = true;
|
925
|
+
|
926
|
+
keys = keys instanceof Array
|
927
|
+
? keys
|
928
|
+
: Array.prototype.slice.call(arguments);
|
929
|
+
|
930
|
+
if (!keys.length) throw new Error('keys required');
|
931
|
+
|
932
|
+
var actual = Object.keys(obj)
|
933
|
+
, len = keys.length;
|
934
|
+
|
935
|
+
// Inclusion
|
936
|
+
ok = keys.every(function(key){
|
937
|
+
return ~actual.indexOf(key);
|
938
|
+
});
|
939
|
+
|
940
|
+
// Strict
|
941
|
+
if (!flag(this, 'negate') && !flag(this, 'contains')) {
|
942
|
+
ok = ok && keys.length == actual.length;
|
943
|
+
}
|
944
|
+
|
945
|
+
// Key string
|
946
|
+
if (len > 1) {
|
947
|
+
keys = keys.map(function(key){
|
948
|
+
return _.inspect(key);
|
949
|
+
});
|
950
|
+
var last = keys.pop();
|
951
|
+
str = keys.join(', ') + ', and ' + last;
|
952
|
+
} else {
|
953
|
+
str = _.inspect(keys[0]);
|
954
|
+
}
|
955
|
+
|
956
|
+
// Form
|
957
|
+
str = (len > 1 ? 'keys ' : 'key ') + str;
|
958
|
+
|
959
|
+
// Have / include
|
960
|
+
str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
|
961
|
+
|
962
|
+
// Assertion
|
963
|
+
this.assert(
|
964
|
+
ok
|
965
|
+
, 'expected #{this} to ' + str
|
966
|
+
, 'expected #{this} to not ' + str
|
967
|
+
);
|
968
|
+
}
|
969
|
+
|
970
|
+
Assertion.addMethod('keys', assertKeys);
|
971
|
+
Assertion.addMethod('key', assertKeys);
|
972
|
+
|
973
|
+
/**
|
974
|
+
* ### .throw(constructor)
|
975
|
+
*
|
976
|
+
* Asserts that the function target will throw a specific error, or specific type of error
|
977
|
+
* (as determined using `instanceof`), optionally with a RegExp or string inclusion test
|
978
|
+
* for the error's message.
|
979
|
+
*
|
980
|
+
* var err = new ReferenceError('This is a bad function.');
|
981
|
+
* var fn = function () { throw err; }
|
982
|
+
* expect(fn).to.throw(ReferenceError);
|
983
|
+
* expect(fn).to.throw(Error);
|
984
|
+
* expect(fn).to.throw(/bad function/);
|
985
|
+
* expect(fn).to.not.throw('good function');
|
986
|
+
* expect(fn).to.throw(ReferenceError, /bad function/);
|
987
|
+
* expect(fn).to.throw(err);
|
988
|
+
* expect(fn).to.not.throw(new RangeError('Out of range.'));
|
989
|
+
*
|
990
|
+
* Please note that when a throw expectation is negated, it will check each
|
991
|
+
* parameter independently, starting with error constructor type. The appropriate way
|
992
|
+
* to check for the existence of a type of error but for a message that does not match
|
993
|
+
* is to use `and`.
|
994
|
+
*
|
995
|
+
* expect(fn).to.throw(ReferenceError)
|
996
|
+
* .and.not.throw(/good function/);
|
997
|
+
*
|
998
|
+
* @name throw
|
999
|
+
* @alias throws
|
1000
|
+
* @alias Throw
|
1001
|
+
* @param {ErrorConstructor} constructor
|
1002
|
+
* @param {String|RegExp} expected error message
|
1003
|
+
* @param {String} message _optional_
|
1004
|
+
* @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
|
1005
|
+
* @api public
|
1006
|
+
*/
|
1007
|
+
|
1008
|
+
function assertThrows (constructor, errMsg, msg) {
|
1009
|
+
if (msg) flag(this, 'message', msg);
|
1010
|
+
var obj = flag(this, 'object');
|
1011
|
+
new Assertion(obj, msg).is.a('function');
|
1012
|
+
|
1013
|
+
var thrown = false
|
1014
|
+
, desiredError = null
|
1015
|
+
, name = null
|
1016
|
+
, thrownError = null;
|
1017
|
+
|
1018
|
+
if (arguments.length === 0) {
|
1019
|
+
errMsg = null;
|
1020
|
+
constructor = null;
|
1021
|
+
} else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
|
1022
|
+
errMsg = constructor;
|
1023
|
+
constructor = null;
|
1024
|
+
} else if (constructor && constructor instanceof Error) {
|
1025
|
+
desiredError = constructor;
|
1026
|
+
constructor = null;
|
1027
|
+
errMsg = null;
|
1028
|
+
} else if (typeof constructor === 'function') {
|
1029
|
+
name = (new constructor()).name;
|
1030
|
+
} else {
|
1031
|
+
constructor = null;
|
1032
|
+
}
|
1033
|
+
|
1034
|
+
try {
|
1035
|
+
obj();
|
1036
|
+
} catch (err) {
|
1037
|
+
// first, check desired error
|
1038
|
+
if (desiredError) {
|
1039
|
+
this.assert(
|
1040
|
+
err === desiredError
|
1041
|
+
, 'expected #{this} to throw #{exp} but #{act} was thrown'
|
1042
|
+
, 'expected #{this} to not throw #{exp}'
|
1043
|
+
, desiredError
|
1044
|
+
, err
|
1045
|
+
);
|
1046
|
+
|
1047
|
+
return this;
|
1048
|
+
}
|
1049
|
+
// next, check constructor
|
1050
|
+
if (constructor) {
|
1051
|
+
this.assert(
|
1052
|
+
err instanceof constructor
|
1053
|
+
, 'expected #{this} to throw #{exp} but #{act} was thrown'
|
1054
|
+
, 'expected #{this} to not throw #{exp} but #{act} was thrown'
|
1055
|
+
, name
|
1056
|
+
, err
|
1057
|
+
);
|
1058
|
+
|
1059
|
+
if (!errMsg) return this;
|
1060
|
+
}
|
1061
|
+
// next, check message
|
1062
|
+
var message = 'object' === _.type(err) && "message" in err
|
1063
|
+
? err.message
|
1064
|
+
: '' + err;
|
1065
|
+
|
1066
|
+
if ((message != null) && errMsg && errMsg instanceof RegExp) {
|
1067
|
+
this.assert(
|
1068
|
+
errMsg.exec(message)
|
1069
|
+
, 'expected #{this} to throw error matching #{exp} but got #{act}'
|
1070
|
+
, 'expected #{this} to throw error not matching #{exp}'
|
1071
|
+
, errMsg
|
1072
|
+
, message
|
1073
|
+
);
|
1074
|
+
|
1075
|
+
return this;
|
1076
|
+
} else if ((message != null) && errMsg && 'string' === typeof errMsg) {
|
1077
|
+
this.assert(
|
1078
|
+
~message.indexOf(errMsg)
|
1079
|
+
, 'expected #{this} to throw error including #{exp} but got #{act}'
|
1080
|
+
, 'expected #{this} to throw error not including #{act}'
|
1081
|
+
, errMsg
|
1082
|
+
, message
|
1083
|
+
);
|
1084
|
+
|
1085
|
+
return this;
|
1086
|
+
} else {
|
1087
|
+
thrown = true;
|
1088
|
+
thrownError = err;
|
1089
|
+
}
|
1090
|
+
}
|
1091
|
+
|
1092
|
+
var actuallyGot = ''
|
1093
|
+
, expectedThrown = name !== null
|
1094
|
+
? name
|
1095
|
+
: desiredError
|
1096
|
+
? '#{exp}' //_.inspect(desiredError)
|
1097
|
+
: 'an error';
|
1098
|
+
|
1099
|
+
if (thrown) {
|
1100
|
+
actuallyGot = ' but #{act} was thrown'
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
this.assert(
|
1104
|
+
thrown === true
|
1105
|
+
, 'expected #{this} to throw ' + expectedThrown + actuallyGot
|
1106
|
+
, 'expected #{this} to not throw ' + expectedThrown + actuallyGot
|
1107
|
+
, desiredError
|
1108
|
+
, thrownError
|
1109
|
+
);
|
1110
|
+
};
|
1111
|
+
|
1112
|
+
Assertion.addMethod('throw', assertThrows);
|
1113
|
+
Assertion.addMethod('throws', assertThrows);
|
1114
|
+
Assertion.addMethod('Throw', assertThrows);
|
1115
|
+
|
1116
|
+
/**
|
1117
|
+
* ### .respondTo(method)
|
1118
|
+
*
|
1119
|
+
* Asserts that the object or class target will respond to a method.
|
1120
|
+
*
|
1121
|
+
* Klass.prototype.bar = function(){};
|
1122
|
+
* expect(Klass).to.respondTo('bar');
|
1123
|
+
* expect(obj).to.respondTo('bar');
|
1124
|
+
*
|
1125
|
+
* To check if a constructor will respond to a static function,
|
1126
|
+
* set the `itself` flag.
|
1127
|
+
*
|
1128
|
+
* Klass.baz = function(){};
|
1129
|
+
* expect(Klass).itself.to.respondTo('baz');
|
1130
|
+
*
|
1131
|
+
* @name respondTo
|
1132
|
+
* @param {String} method
|
1133
|
+
* @param {String} message _optional_
|
1134
|
+
* @api public
|
1135
|
+
*/
|
1136
|
+
|
1137
|
+
Assertion.addMethod('respondTo', function (method, msg) {
|
1138
|
+
if (msg) flag(this, 'message', msg);
|
1139
|
+
var obj = flag(this, 'object')
|
1140
|
+
, itself = flag(this, 'itself')
|
1141
|
+
, context = ('function' === _.type(obj) && !itself)
|
1142
|
+
? obj.prototype[method]
|
1143
|
+
: obj[method];
|
1144
|
+
|
1145
|
+
this.assert(
|
1146
|
+
'function' === typeof context
|
1147
|
+
, 'expected #{this} to respond to ' + _.inspect(method)
|
1148
|
+
, 'expected #{this} to not respond to ' + _.inspect(method)
|
1149
|
+
);
|
1150
|
+
});
|
1151
|
+
|
1152
|
+
/**
|
1153
|
+
* ### .itself
|
1154
|
+
*
|
1155
|
+
* Sets the `itself` flag, later used by the `respondTo` assertion.
|
1156
|
+
*
|
1157
|
+
* function Foo() {}
|
1158
|
+
* Foo.bar = function() {}
|
1159
|
+
* Foo.prototype.baz = function() {}
|
1160
|
+
*
|
1161
|
+
* expect(Foo).itself.to.respondTo('bar');
|
1162
|
+
* expect(Foo).itself.not.to.respondTo('baz');
|
1163
|
+
*
|
1164
|
+
* @name itself
|
1165
|
+
* @api public
|
1166
|
+
*/
|
1167
|
+
|
1168
|
+
Assertion.addProperty('itself', function () {
|
1169
|
+
flag(this, 'itself', true);
|
1170
|
+
});
|
1171
|
+
|
1172
|
+
/**
|
1173
|
+
* ### .satisfy(method)
|
1174
|
+
*
|
1175
|
+
* Asserts that the target passes a given truth test.
|
1176
|
+
*
|
1177
|
+
* expect(1).to.satisfy(function(num) { return num > 0; });
|
1178
|
+
*
|
1179
|
+
* @name satisfy
|
1180
|
+
* @param {Function} matcher
|
1181
|
+
* @param {String} message _optional_
|
1182
|
+
* @api public
|
1183
|
+
*/
|
1184
|
+
|
1185
|
+
Assertion.addMethod('satisfy', function (matcher, msg) {
|
1186
|
+
if (msg) flag(this, 'message', msg);
|
1187
|
+
var obj = flag(this, 'object');
|
1188
|
+
this.assert(
|
1189
|
+
matcher(obj)
|
1190
|
+
, 'expected #{this} to satisfy ' + _.objDisplay(matcher)
|
1191
|
+
, 'expected #{this} to not satisfy' + _.objDisplay(matcher)
|
1192
|
+
, this.negate ? false : true
|
1193
|
+
, matcher(obj)
|
1194
|
+
);
|
1195
|
+
});
|
1196
|
+
|
1197
|
+
/**
|
1198
|
+
* ### .closeTo(expected, delta)
|
1199
|
+
*
|
1200
|
+
* Asserts that the target is equal `expected`, to within a +/- `delta` range.
|
1201
|
+
*
|
1202
|
+
* expect(1.5).to.be.closeTo(1, 0.5);
|
1203
|
+
*
|
1204
|
+
* @name closeTo
|
1205
|
+
* @param {Number} expected
|
1206
|
+
* @param {Number} delta
|
1207
|
+
* @param {String} message _optional_
|
1208
|
+
* @api public
|
1209
|
+
*/
|
1210
|
+
|
1211
|
+
Assertion.addMethod('closeTo', function (expected, delta, msg) {
|
1212
|
+
if (msg) flag(this, 'message', msg);
|
1213
|
+
var obj = flag(this, 'object');
|
1214
|
+
this.assert(
|
1215
|
+
Math.abs(obj - expected) <= delta
|
1216
|
+
, 'expected #{this} to be close to ' + expected + ' +/- ' + delta
|
1217
|
+
, 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
|
1218
|
+
);
|
1219
|
+
});
|
1220
|
+
|
1221
|
+
function isSubsetOf(subset, superset) {
|
1222
|
+
return subset.every(function(elem) {
|
1223
|
+
return superset.indexOf(elem) !== -1;
|
1224
|
+
})
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
/**
|
1228
|
+
* ### .members
|
1229
|
+
*
|
1230
|
+
* Asserts that the target is a superset of `set`,
|
1231
|
+
* or that the target and `set` have the same members.
|
1232
|
+
*
|
1233
|
+
* expect([1, 2, 3]).to.include.members([3, 2]);
|
1234
|
+
* expect([1, 2, 3]).to.not.include.members([3, 2, 8]);
|
1235
|
+
*
|
1236
|
+
* expect([4, 2]).to.have.members([2, 4]);
|
1237
|
+
* expect([5, 2]).to.not.have.members([5, 2, 1]);
|
1238
|
+
*
|
1239
|
+
* @name members
|
1240
|
+
* @param {Array} set
|
1241
|
+
* @param {String} message _optional_
|
1242
|
+
* @api public
|
1243
|
+
*/
|
1244
|
+
|
1245
|
+
Assertion.addMethod('members', function (subset, msg) {
|
1246
|
+
if (msg) flag(this, 'message', msg);
|
1247
|
+
var obj = flag(this, 'object');
|
1248
|
+
|
1249
|
+
new Assertion(obj).to.be.an('array');
|
1250
|
+
new Assertion(subset).to.be.an('array');
|
1251
|
+
|
1252
|
+
if (flag(this, 'contains')) {
|
1253
|
+
return this.assert(
|
1254
|
+
isSubsetOf(subset, obj)
|
1255
|
+
, 'expected #{this} to be a superset of #{act}'
|
1256
|
+
, 'expected #{this} to not be a superset of #{act}'
|
1257
|
+
, obj
|
1258
|
+
, subset
|
1259
|
+
);
|
1260
|
+
}
|
1261
|
+
|
1262
|
+
this.assert(
|
1263
|
+
isSubsetOf(obj, subset) && isSubsetOf(subset, obj)
|
1264
|
+
, 'expected #{this} to have the same members as #{act}'
|
1265
|
+
, 'expected #{this} to not have the same members as #{act}'
|
1266
|
+
, obj
|
1267
|
+
, subset
|
1268
|
+
);
|
1269
|
+
});
|
1270
|
+
};
|