konacha 1.2.4 → 1.3.0

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/History.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # master
2
2
 
3
+ # 1.3.0
4
+
5
+ * `rake konacha:run` exits with exit code 1 when spec suite fails
6
+ * Add SPEC environment variable for running individual spec files
7
+ * Update mocha (1.2.1) and chai (1.1.0)
8
+
3
9
  # 1.2.4
4
10
 
5
11
  * Loosen up Rails dependency
data/README.md CHANGED
@@ -68,12 +68,26 @@ describe "Array#sum", ->
68
68
  [1,2,3].sum().should.equal(6)
69
69
  ```
70
70
 
71
+ ## Running (Rake Tasks)
72
+
73
+ ### `rake konacha:serve`
74
+
71
75
  The `konacha:serve` rake task starts a server for your tests. You can go to the root
72
76
  page to run all specs (e.g. `http://localhost:3500/`), a sub page to run an individual
73
77
  spec file (e.g. `http://localhost:3500/array_sum_spec`), or a path to a subdirectory to
74
78
  run a subset of specs (e.g. `http://localhost:3500/models`).
75
79
 
76
- Alternatively, you can run the specs in your shell with the `konacha:run` task.
80
+ ### `rake konacha:run`
81
+
82
+ The `konacha:run` rake task will let you run your tests from the command line.
83
+
84
+ To run individual specs, pass a comma seperated list of spec file names via the
85
+ `SPEC` environment variable.
86
+
87
+ ```
88
+ $ rake konacha:run SPEC=foo_spec
89
+ $ rake konacha:run SPEC=foo_spec,bar_spec,etc_spec
90
+ ```
77
91
 
78
92
  ## Spec Helper
79
93
 
@@ -4,7 +4,11 @@ module Konacha
4
4
  end
5
5
 
6
6
  def self.all
7
- Konacha.spec_paths.map { |path| new(path) }
7
+ paths = Konacha.spec_paths
8
+ if ENV["SPEC"]
9
+ paths = ENV["SPEC"].split(",")
10
+ end
11
+ paths.map {|path| new(path)}
8
12
  end
9
13
 
10
14
  def self.find(path)
data/konacha.gemspec CHANGED
@@ -17,7 +17,7 @@ the asset pipeline and engines.}
17
17
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  gem.name = "konacha"
19
19
  gem.require_paths = ["lib"]
20
- gem.version = "1.2.4"
20
+ gem.version = "1.3.0"
21
21
 
22
22
  gem.add_dependency "railties", "~> 3.1"
23
23
  gem.add_dependency "actionpack", "~> 3.1"
@@ -6,6 +6,10 @@ namespace :konacha do
6
6
 
7
7
  desc "Run JavaScript specs non-interactively"
8
8
  task :run => :environment do
9
- Konacha.run
9
+ passed = Konacha.run
10
+ # Apparently there is no canonical way to fail a rake task other than
11
+ # throwing an exception or exiting.
12
+ # http://stackoverflow.com/a/5117457/525872
13
+ exit 1 unless passed
10
14
  end
11
15
  end
@@ -28,6 +28,15 @@ describe Konacha::Spec do
28
28
  all = described_class.all
29
29
  all.length.should == 2
30
30
  end
31
+
32
+ it "returns specs passed via the ENV['spec'] parameter" do
33
+ ENV["SPEC"] = "foo_spec,bar_spec,baz_spec"
34
+ all = described_class.all
35
+ all.length.should == 3
36
+ paths = all.map {|p| p.path}
37
+ paths =~ %w{foo_spec bar_spec baz_spec}
38
+ ENV["SPEC"] = nil
39
+ end
31
40
  end
32
41
 
33
42
  describe ".find" do
@@ -50,21 +50,102 @@ require.relative = function (parent) {
50
50
  };
51
51
 
52
52
 
53
- require.register("assertion.js", function(module, exports, require){
53
+ require.register("chai.js", function(module, exports, require){
54
54
  /*!
55
55
  * chai
56
- * http://chaijs.com
57
56
  * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
58
57
  * MIT Licensed
59
58
  */
60
59
 
60
+ var used = []
61
+ , exports = module.exports = {};
62
+
63
+ /*!
64
+ * Chai version
65
+ */
66
+
67
+ exports.version = '1.1.0';
68
+
69
+ /*!
70
+ * Primary `Assertion` prototype
71
+ */
72
+
73
+ exports.Assertion = require('./chai/assertion');
74
+
75
+ /*!
76
+ * Assertion Error
77
+ */
78
+
79
+ exports.AssertionError = require('./chai/browser/error');
80
+
81
+ /*!
82
+ * Utils for plugins (not exported)
83
+ */
84
+
85
+ var util = require('./chai/utils');
86
+
87
+ /**
88
+ * # .use(function)
89
+ *
90
+ * Provides a way to extend the internals of Chai
91
+ *
92
+ * @param {Function}
93
+ * @returns {this} for chaining
94
+ * @api public
95
+ */
96
+
97
+ exports.use = function (fn) {
98
+ if (!~used.indexOf(fn)) {
99
+ fn(this, util);
100
+ used.push(fn);
101
+ }
102
+
103
+ return this;
104
+ };
105
+
106
+ /*!
107
+ * Core Assertions
108
+ */
109
+
110
+ var core = require('./chai/core/assertions');
111
+ exports.use(core);
112
+
113
+ /*!
114
+ * Expect interface
115
+ */
116
+
117
+ var expect = require('./chai/interface/expect');
118
+ exports.use(expect);
119
+
120
+ /*!
121
+ * Should interface
122
+ */
123
+
124
+ var should = require('./chai/interface/should');
125
+ exports.use(should);
126
+
127
+ /*!
128
+ * Assert interface
129
+ */
130
+
131
+ var assert = require('./chai/interface/assert');
132
+ exports.use(assert);
133
+
134
+ }); // module: chai.js
135
+
136
+ require.register("chai/assertion.js", function(module, exports, require){
137
+ /*!
138
+ * chai
139
+ * http://chaijs.com
140
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
141
+ * MIT Licensed
142
+ */
61
143
 
62
144
  /*!
63
145
  * Module dependencies.
64
146
  */
65
147
 
66
148
  var AssertionError = require('./browser/error')
67
- , toString = Object.prototype.toString
68
149
  , util = require('./utils')
69
150
  , flag = util.flag;
70
151
 
@@ -153,7 +234,6 @@ Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual)
153
234
  };
154
235
 
155
236
  /*!
156
- *
157
237
  * ### ._obj
158
238
  *
159
239
  * Quick reference to stored `actual` value for plugin developers.
@@ -170,1111 +250,1092 @@ Object.defineProperty(Assertion.prototype, '_obj',
170
250
  }
171
251
  });
172
252
 
173
- /**
174
- * ### Language Chains
175
- *
176
- * The following are provide as chainable getters to
177
- * improve the readability of your assertions. They
178
- * do not provide an testing capability unless they
179
- * have been overwritten by a plugin.
180
- *
181
- * **Chains**
182
- *
183
- * - to
184
- * - be
185
- * - been
186
- * - is
187
- * - and
188
- * - have
189
- * - with
190
- *
191
- * @name language chains
192
- * @api public
193
- */
194
-
195
- [ 'to', 'be', 'been'
196
- , 'is', 'and', 'have'
197
- , 'with' ].forEach(function (chain) {
198
- Object.defineProperty(Assertion.prototype, chain,
199
- { get: function () {
200
- return this;
201
- }
202
- , configurable: true
203
- });
204
- });
205
-
206
- /**
207
- * ### .not
208
- *
209
- * Negates any of assertions following in the chain.
210
- *
211
- * expect(foo).to.not.equal('bar');
212
- * expect(goodFn).to.not.throw(Error);
213
- * expect({ foo: 'baz' }).to.have.property('foo')
214
- * .and.not.equal('bar');
215
- *
216
- * @name not
217
- * @api public
218
- */
219
-
220
- Object.defineProperty(Assertion.prototype, 'not',
221
- { get: function () {
222
- flag(this, 'negate', true);
223
- return this;
224
- }
225
- , configurable: true
226
- });
253
+ }); // module: chai/assertion.js
227
254
 
228
- /**
229
- * ### .deep
230
- *
231
- * Sets the `deep` flag, later used by the `equal` and
232
- * `property` assertions.
233
- *
234
- * expect(foo).to.deep.equal({ bar: 'baz' });
235
- * expect({ foo: { bar: { baz: 'quux' } } })
236
- * .to.have.deep.property('foo.bar.baz', 'quux');
237
- *
238
- * @name deep
239
- * @api public
255
+ require.register("chai/browser/error.js", function(module, exports, require){
256
+ /*!
257
+ * chai
258
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
259
+ * MIT Licensed
240
260
  */
241
261
 
242
- Object.defineProperty(Assertion.prototype, 'deep',
243
- { get: function () {
244
- flag(this, 'deep', true);
245
- return this;
246
- }
247
- , configurable: true
248
- });
249
-
250
- /**
251
- * ### .a(type)
252
- *
253
- * The `a` and `an` assertions are aliases that can be
254
- * used either as language chains or to assert a value's
255
- * type (as revealed by `Object.prototype.toString`).
256
- *
257
- * // typeof
258
- * expect('test').to.be.a('string');
259
- * expect({ foo: 'bar' }).to.be.an('object');
260
- * expect(null).to.be.a('null');
261
- * expect(undefined).to.be.an('undefined');
262
- *
263
- * // language chain
264
- * expect(foo).to.be.an.instanceof(Foo);
265
- *
266
- * @name a
267
- * @alias an
268
- * @param {String} type
269
- * @api public
270
- */
262
+ module.exports = AssertionError;
271
263
 
272
- function an(type) {
273
- var obj = flag(this, 'object')
274
- , klassStart = type.charAt(0).toUpperCase()
275
- , klass = klassStart + type.slice(1)
276
- , article = ~[ 'A', 'E', 'I', 'O', 'U' ].indexOf(klassStart) ? 'an ' : 'a ';
264
+ function AssertionError (options) {
265
+ options = options || {};
266
+ this.message = options.message;
267
+ this.actual = options.actual;
268
+ this.expected = options.expected;
269
+ this.operator = options.operator;
277
270
 
278
- this.assert(
279
- '[object ' + klass + ']' === toString.call(obj)
280
- , 'expected #{this} to be ' + article + type
281
- , 'expected #{this} not to be ' + article + type
282
- , '[object ' + klass + ']'
283
- , toString.call(obj)
284
- );
271
+ if (options.stackStartFunction && Error.captureStackTrace) {
272
+ var stackStartFunction = options.stackStartFunction;
273
+ Error.captureStackTrace(this, stackStartFunction);
274
+ }
285
275
  }
286
276
 
287
- Assertion.addChainableMethod('an', an);
288
- Assertion.addChainableMethod('a', an);
289
-
290
- /**
291
- * ### .include(value)
292
- *
293
- * The `include` and `contain` assertions can be used as either property
294
- * based language chains or as methods to assert the inclusion of an object
295
- * in an array or a substring in a string. When used as language chains,
296
- * they toggle the `contain` flag for the `keys` assertion.
297
- *
298
- * expect([1,2,3]).to.include(2);
299
- * expect('foobar').to.contain('foo');
300
- * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
301
- *
302
- * @name include
303
- * @alias contain
304
- * @param {Object|String|Number} obj
305
- * @api public
306
- */
307
-
308
- function includeChainingBehavior () {
309
- flag(this, 'contains', true);
310
- }
277
+ AssertionError.prototype = Object.create(Error.prototype);
278
+ AssertionError.prototype.name = 'AssertionError';
279
+ AssertionError.prototype.constructor = AssertionError;
311
280
 
312
- function include (val) {
313
- var obj = flag(this, 'object')
314
- this.assert(
315
- ~obj.indexOf(val)
316
- , 'expected #{this} to include ' + util.inspect(val)
317
- , 'expected #{this} to not include ' + util.inspect(val));
318
- }
281
+ AssertionError.prototype.toString = function() {
282
+ return this.message;
283
+ };
319
284
 
320
- Assertion.addChainableMethod('include', include, includeChainingBehavior);
321
- Assertion.addChainableMethod('contain', include, includeChainingBehavior);
285
+ }); // module: chai/browser/error.js
322
286
 
323
- /**
324
- * ### .ok
325
- *
326
- * Asserts that the target is truthy.
327
- *
328
- * expect('everthing').to.be.ok;
329
- * expect(1).to.be.ok;
330
- * expect(false).to.not.be.ok;
331
- * expect(undefined).to.not.be.ok;
332
- * expect(null).to.not.be.ok;
333
- *
334
- * @name ok
335
- * @api public
287
+ require.register("chai/core/assertions.js", function(module, exports, require){
288
+ /*!
289
+ * chai
290
+ * http://chaijs.com
291
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
292
+ * MIT Licensed
336
293
  */
337
294
 
338
- Object.defineProperty(Assertion.prototype, 'ok',
339
- { get: function () {
340
- this.assert(
341
- flag(this, 'object')
342
- , 'expected #{this} to be truthy'
343
- , 'expected #{this} to be falsy');
295
+ module.exports = function (chai, _) {
296
+ var Assertion = chai.Assertion
297
+ , toString = Object.prototype.toString
298
+ , flag = _.flag;
299
+
300
+ /**
301
+ * ### Language Chains
302
+ *
303
+ * The following are provide as chainable getters to
304
+ * improve the readability of your assertions. They
305
+ * do not provide an testing capability unless they
306
+ * have been overwritten by a plugin.
307
+ *
308
+ * **Chains**
309
+ *
310
+ * - to
311
+ * - be
312
+ * - been
313
+ * - is
314
+ * - that
315
+ * - and
316
+ * - have
317
+ * - with
318
+ *
319
+ * @name language chains
320
+ * @api public
321
+ */
344
322
 
323
+ [ 'to', 'be', 'been'
324
+ , 'is', 'and', 'have'
325
+ , 'with', 'that' ].forEach(function (chain) {
326
+ Assertion.addProperty(chain, function () {
345
327
  return this;
346
- }
347
- , configurable: true
348
- });
328
+ });
329
+ });
349
330
 
350
- /**
351
- * ### .true
352
- *
353
- * Asserts that the target is `true`.
354
- *
355
- * expect(true).to.be.true;
356
- * expect(1).to.not.be.true;
357
- *
358
- * @name true
359
- * @api public
360
- */
331
+ /**
332
+ * ### .not
333
+ *
334
+ * Negates any of assertions following in the chain.
335
+ *
336
+ * expect(foo).to.not.equal('bar');
337
+ * expect(goodFn).to.not.throw(Error);
338
+ * expect({ foo: 'baz' }).to.have.property('foo')
339
+ * .and.not.equal('bar');
340
+ *
341
+ * @name not
342
+ * @api public
343
+ */
361
344
 
362
- Object.defineProperty(Assertion.prototype, 'true',
363
- { get: function () {
364
- this.assert(
365
- true === flag(this, 'object')
366
- , 'expected #{this} to be true'
367
- , 'expected #{this} to be false'
368
- , this.negate ? false : true
369
- );
345
+ Assertion.addProperty('not', function () {
346
+ flag(this, 'negate', true);
347
+ });
370
348
 
371
- return this;
372
- }
373
- , configurable: true
374
- });
349
+ /**
350
+ * ### .deep
351
+ *
352
+ * Sets the `deep` flag, later used by the `equal` and
353
+ * `property` assertions.
354
+ *
355
+ * expect(foo).to.deep.equal({ bar: 'baz' });
356
+ * expect({ foo: { bar: { baz: 'quux' } } })
357
+ * .to.have.deep.property('foo.bar.baz', 'quux');
358
+ *
359
+ * @name deep
360
+ * @api public
361
+ */
375
362
 
376
- /**
377
- * ### .false
378
- *
379
- * Asserts that the target is `false`.
380
- *
381
- * expect(false).to.be.false;
382
- * expect(0).to.not.be.false;
383
- *
384
- * @name false
385
- * @api public
386
- */
363
+ Assertion.addProperty('deep', function () {
364
+ flag(this, 'deep', true);
365
+ });
387
366
 
388
- Object.defineProperty(Assertion.prototype, 'false',
389
- { get: function () {
390
- this.assert(
391
- false === flag(this, 'object')
392
- , 'expected #{this} to be false'
393
- , 'expected #{this} to be true'
394
- , this.negate ? true : false
395
- );
367
+ /**
368
+ * ### .a(type)
369
+ *
370
+ * The `a` and `an` assertions are aliases that can be
371
+ * used either as language chains or to assert a value's
372
+ * type (as revealed by `Object.prototype.toString`).
373
+ *
374
+ * // typeof
375
+ * expect('test').to.be.a('string');
376
+ * expect({ foo: 'bar' }).to.be.an('object');
377
+ * expect(null).to.be.a('null');
378
+ * expect(undefined).to.be.an('undefined');
379
+ *
380
+ * // language chain
381
+ * expect(foo).to.be.an.instanceof(Foo);
382
+ *
383
+ * @name a
384
+ * @alias an
385
+ * @param {String} type
386
+ * @api public
387
+ */
396
388
 
397
- return this;
398
- }
399
- , configurable: true
400
- });
389
+ function an(type) {
390
+ var obj = flag(this, 'object')
391
+ , klassStart = type.charAt(0).toUpperCase()
392
+ , klass = klassStart + type.slice(1)
393
+ , article = ~[ 'A', 'E', 'I', 'O', 'U' ].indexOf(klassStart) ? 'an ' : 'a ';
401
394
 
402
- /**
403
- * ### .null
404
- *
405
- * Asserts that the target is `null`.
406
- *
407
- * expect(null).to.be.null;
408
- * expect(undefined).not.to.be.null;
409
- *
410
- * @name null
411
- * @api public
412
- */
395
+ this.assert(
396
+ '[object ' + klass + ']' === toString.call(obj)
397
+ , 'expected #{this} to be ' + article + type
398
+ , 'expected #{this} not to be ' + article + type
399
+ );
400
+ }
413
401
 
414
- Object.defineProperty(Assertion.prototype, 'null',
415
- { get: function () {
416
- this.assert(
417
- null === flag(this, 'object')
418
- , 'expected #{this} to be null'
419
- , 'expected #{this} not to be null'
420
- , this.negate ? false : true
421
- );
402
+ Assertion.addChainableMethod('an', an);
403
+ Assertion.addChainableMethod('a', an);
422
404
 
423
- return this;
424
- }
425
- , configurable: true
426
- });
405
+ /**
406
+ * ### .include(value)
407
+ *
408
+ * The `include` and `contain` assertions can be used as either property
409
+ * based language chains or as methods to assert the inclusion of an object
410
+ * in an array or a substring in a string. When used as language chains,
411
+ * they toggle the `contain` flag for the `keys` assertion.
412
+ *
413
+ * expect([1,2,3]).to.include(2);
414
+ * expect('foobar').to.contain('foo');
415
+ * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
416
+ *
417
+ * @name include
418
+ * @alias contain
419
+ * @param {Object|String|Number} obj
420
+ * @api public
421
+ */
427
422
 
428
- /**
429
- * ### .undefined
430
- *
431
- * Asserts that the target is `undefined`.
432
- *
433
- * expect(undefined).to.be.undefined;
434
- * expect(null).to.not.be.undefined;
435
- *
436
- * @name undefined
437
- * @api public
438
- */
423
+ function includeChainingBehavior () {
424
+ flag(this, 'contains', true);
425
+ }
439
426
 
440
- Object.defineProperty(Assertion.prototype, 'undefined',
441
- { get: function () {
442
- this.assert(
443
- undefined === flag(this, 'object')
444
- , 'expected #{this} to be undefined'
445
- , 'expected #{this} not to be undefined'
446
- , this.negate ? false : true
447
- );
427
+ function include (val) {
428
+ var obj = flag(this, 'object')
429
+ this.assert(
430
+ ~obj.indexOf(val)
431
+ , 'expected #{this} to include ' + _.inspect(val)
432
+ , 'expected #{this} to not include ' + _.inspect(val));
433
+ }
448
434
 
449
- return this;
450
- }
451
- , configurable: true
452
- });
435
+ Assertion.addChainableMethod('include', include, includeChainingBehavior);
436
+ Assertion.addChainableMethod('contain', include, includeChainingBehavior);
453
437
 
454
- /**
455
- * ### .exist
456
- *
457
- * Asserts that the target is neither `null` nor `undefined`.
458
- *
459
- * var foo = 'hi'
460
- * , bar = null
461
- * , baz;
462
- *
463
- * expect(foo).to.exist;
464
- * expect(bar).to.not.exist;
465
- * expect(baz).to.not.exist;
466
- *
467
- * @name exist
468
- * @api public
469
- */
470
-
471
- Object.defineProperty(Assertion.prototype, 'exist',
472
- { get: function () {
473
- this.assert(
474
- null != flag(this, 'object')
475
- , 'expected #{this} to exist'
476
- , 'expected #{this} to not exist'
477
- );
478
-
479
- return this;
480
- }
481
- , configurable: true
482
- });
483
-
484
- /**
485
- * ### .empty
486
- *
487
- * Asserts that the target's length is `0`. For arrays, it checks
488
- * the `length` property. For objects, it gets the count of
489
- * enumerable keys.
490
- *
491
- * expect([]).to.be.empty;
492
- * expect('').to.be.empty;
493
- * expect({}).to.be.empty;
494
- *
495
- * @name empty
496
- * @api public
497
- */
498
-
499
- Object.defineProperty(Assertion.prototype, 'empty',
500
- { get: function () {
501
- var obj = flag(this, 'object')
502
- , expected = obj;
503
-
504
- if (Array.isArray(obj) || 'string' === typeof object) {
505
- expected = obj.length;
506
- } else if (typeof obj === 'object') {
507
- expected = Object.keys(obj).length;
508
- }
509
-
510
- this.assert(
511
- !expected
512
- , 'expected #{this} to be empty'
513
- , 'expected #{this} not to be empty');
514
-
515
- return this;
516
- }
517
- , configurable: true
518
- });
519
-
520
- /**
521
- * ### .arguments
522
- *
523
- * Asserts that the target is an arguments object.
524
- *
525
- * function test () {
526
- * expect(arguments).to.be.arguments;
527
- * }
528
- *
529
- * @name arguments
530
- * @alias Arguments
531
- * @api public
532
- */
533
-
534
- function checkArguments () {
535
- var obj = flag(this, 'object')
536
- , type = Object.prototype.toString.call(obj);
537
- this.assert(
538
- '[object Arguments]' === type
539
- , 'expected #{this} to be arguments but got ' + type
540
- , 'expected #{this} to not be arguments'
541
- );
542
- }
543
-
544
- Assertion.addProperty('arguments', checkArguments);
545
- Assertion.addProperty('Arguments', checkArguments);
546
-
547
- /**
548
- * ### .equal(value)
549
- *
550
- * Asserts that the target is strictly equal (`===`) to `value`.
551
- * Alternately, if the `deep` flag is set, asserts that
552
- * the target is deeply equal to `value`.
553
- *
554
- * expect('hello').to.equal('hello');
555
- * expect(42).to.equal(42);
556
- * expect(1).to.not.equal(true);
557
- * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
558
- * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
559
- *
560
- * @name equal
561
- * @param {Mixed} value
562
- * @api public
563
- */
438
+ /**
439
+ * ### .ok
440
+ *
441
+ * Asserts that the target is truthy.
442
+ *
443
+ * expect('everthing').to.be.ok;
444
+ * expect(1).to.be.ok;
445
+ * expect(false).to.not.be.ok;
446
+ * expect(undefined).to.not.be.ok;
447
+ * expect(null).to.not.be.ok;
448
+ *
449
+ * @name ok
450
+ * @api public
451
+ */
564
452
 
565
- Assertion.prototype.equal = function (val) {
566
- var obj = flag(this, 'object');
567
- if (flag(this, 'deep')) {
568
- return this.eql(val);
569
- } else {
453
+ Assertion.addProperty('ok', function () {
570
454
  this.assert(
571
- val === obj
572
- , 'expected #{this} to equal #{exp}'
573
- , 'expected #{this} to not equal #{exp}'
574
- , val);
575
- }
576
-
577
- return this;
578
- };
579
-
580
- /**
581
- * ### .eql(value)
582
- *
583
- * Asserts that the target is deeply equal to `value`.
584
- *
585
- * expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
586
- * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
587
- *
588
- * @name eql
589
- * @param {Mixed} value
590
- * @api public
591
- */
592
-
593
- Assertion.prototype.eql = function (obj) {
594
- this.assert(
595
- util.eql(obj, flag(this, 'object'))
596
- , 'expected #{this} to deeply equal #{exp}'
597
- , 'expected #{this} to not deeply equal #{exp}'
598
- , obj );
599
-
600
- return this;
601
- };
602
-
603
- /**
604
- * ### .above(value)
605
- *
606
- * Asserts that the target is greater than `value`.
607
- *
608
- * expect(10).to.be.above(5);
609
- *
610
- * @name above
611
- * @alias gt
612
- * @param {Number} value
613
- * @api public
614
- */
615
-
616
- Assertion.prototype.above = function (val) {
617
- this.assert(
618
- flag(this, 'object') > val
619
- , 'expected #{this} to be above ' + val
620
- , 'expected #{this} to be below ' + val);
455
+ flag(this, 'object')
456
+ , 'expected #{this} to be truthy'
457
+ , 'expected #{this} to be falsy');
458
+ });
621
459
 
622
- return this;
623
- };
460
+ /**
461
+ * ### .true
462
+ *
463
+ * Asserts that the target is `true`.
464
+ *
465
+ * expect(true).to.be.true;
466
+ * expect(1).to.not.be.true;
467
+ *
468
+ * @name true
469
+ * @api public
470
+ */
624
471
 
625
- /**
626
- * ### .below(value)
627
- *
628
- * Asserts that the target is less than `value`.
629
- *
630
- * expect(5).to.be.below(10);
631
- *
632
- * @name below
633
- * @alias lt
634
- * @param {Number} value
635
- * @api public
636
- */
472
+ Assertion.addProperty('true', function () {
473
+ this.assert(
474
+ true === flag(this, 'object')
475
+ , 'expected #{this} to be true'
476
+ , 'expected #{this} to be false'
477
+ , this.negate ? false : true
478
+ );
479
+ });
637
480
 
638
- Assertion.prototype.below = function (val) {
639
- this.assert(
640
- flag(this, 'object') < val
641
- , 'expected #{this} to be below ' + val
642
- , 'expected #{this} to be above ' + val);
481
+ /**
482
+ * ### .false
483
+ *
484
+ * Asserts that the target is `false`.
485
+ *
486
+ * expect(false).to.be.false;
487
+ * expect(0).to.not.be.false;
488
+ *
489
+ * @name false
490
+ * @api public
491
+ */
643
492
 
644
- return this;
645
- };
493
+ Assertion.addProperty('false', function () {
494
+ this.assert(
495
+ false === flag(this, 'object')
496
+ , 'expected #{this} to be false'
497
+ , 'expected #{this} to be true'
498
+ , this.negate ? true : false
499
+ );
500
+ });
646
501
 
647
- /**
648
- * ### .within(start, finish)
649
- *
650
- * Asserts that the target is within a range.
651
- *
652
- * expect(7).to.be.within(5,10);
653
- *
654
- * @name within
655
- * @param {Number} start lowerbound inclusive
656
- * @param {Number} finish upperbound inclusive
657
- * @api public
658
- */
502
+ /**
503
+ * ### .null
504
+ *
505
+ * Asserts that the target is `null`.
506
+ *
507
+ * expect(null).to.be.null;
508
+ * expect(undefined).not.to.be.null;
509
+ *
510
+ * @name null
511
+ * @api public
512
+ */
659
513
 
660
- Assertion.prototype.within = function (start, finish) {
661
- var obj = flag(this, 'object')
662
- , range = start + '..' + finish;
514
+ Assertion.addProperty('null', function () {
515
+ this.assert(
516
+ null === flag(this, 'object')
517
+ , 'expected #{this} to be null'
518
+ , 'expected #{this} not to be null'
519
+ );
520
+ });
663
521
 
664
- this.assert(
665
- obj >= start && obj <= finish
666
- , 'expected #{this} to be within ' + range
667
- , 'expected #{this} to not be within ' + range);
522
+ /**
523
+ * ### .undefined
524
+ *
525
+ * Asserts that the target is `undefined`.
526
+ *
527
+ * expect(undefined).to.be.undefined;
528
+ * expect(null).to.not.be.undefined;
529
+ *
530
+ * @name undefined
531
+ * @api public
532
+ */
668
533
 
669
- return this;
670
- };
534
+ Assertion.addProperty('undefined', function () {
535
+ this.assert(
536
+ undefined === flag(this, 'object')
537
+ , 'expected #{this} to be undefined'
538
+ , 'expected #{this} not to be undefined'
539
+ );
540
+ });
671
541
 
672
- /**
673
- * ### .instanceof(constructor)
674
- *
675
- * Asserts that the target is an instance of `constructor`.
676
- *
677
- * var Tea = function (name) { this.name = name; }
678
- * , Chai = new Tea('chai');
679
- *
680
- * expect(Chai).to.be.an.instanceof(Tea);
681
- * expect([ 1, 2, 3 ]).to.be.instanceof(Array);
682
- *
683
- * @name instanceof
684
- * @param {Constructor} constructor
685
- * @alias instanceOf
686
- * @api public
687
- */
542
+ /**
543
+ * ### .exist
544
+ *
545
+ * Asserts that the target is neither `null` nor `undefined`.
546
+ *
547
+ * var foo = 'hi'
548
+ * , bar = null
549
+ * , baz;
550
+ *
551
+ * expect(foo).to.exist;
552
+ * expect(bar).to.not.exist;
553
+ * expect(baz).to.not.exist;
554
+ *
555
+ * @name exist
556
+ * @api public
557
+ */
688
558
 
689
- Assertion.prototype.instanceOf = function (constructor) {
690
- var name = util.getName(constructor);
691
- this.assert(
692
- flag(this, 'object') instanceof constructor
693
- , 'expected #{this} to be an instance of ' + name
694
- , 'expected #{this} to not be an instance of ' + name);
559
+ Assertion.addProperty('exist', function () {
560
+ this.assert(
561
+ null != flag(this, 'object')
562
+ , 'expected #{this} to exist'
563
+ , 'expected #{this} to not exist'
564
+ );
565
+ });
695
566
 
696
- return this;
697
- };
698
567
 
699
- /**
700
- * ### .property(name, [value])
701
- *
702
- * Asserts that the target has a property `name`, optionally asserting that
703
- * the value of that property is strictly equal to `value`.
704
- * If the `deep` flag is set, you can use dot- and bracket-notation for deep
705
- * references into objects and arrays.
706
- *
707
- * // simple referencing
708
- * var obj = { foo: 'bar' };
709
- * expect(obj).to.have.property('foo');
710
- * expect(obj).to.have.property('foo', 'bar');
711
- * expect(obj).to.have.property('foo').to.be.a('string');
712
- *
713
- * // deep referencing
714
- * var deepObj = {
715
- * green: { tea: 'matcha' }
716
- * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
717
- * };
718
-
719
- * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
720
- * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
721
- * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
722
- *
723
- * @name property
724
- * @param {String} name
725
- * @param {Mixed} value (optional)
726
- * @returns value of property for chaining
727
- * @api public
728
- */
568
+ /**
569
+ * ### .empty
570
+ *
571
+ * Asserts that the target's length is `0`. For arrays, it checks
572
+ * the `length` property. For objects, it gets the count of
573
+ * enumerable keys.
574
+ *
575
+ * expect([]).to.be.empty;
576
+ * expect('').to.be.empty;
577
+ * expect({}).to.be.empty;
578
+ *
579
+ * @name empty
580
+ * @api public
581
+ */
729
582
 
730
- Assertion.prototype.property = function (name, val) {
731
- var obj = flag(this, 'object')
732
- , value = flag(this, 'deep') ? util.getPathValue(name, obj) : obj[name]
733
- , descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
734
- , negate = flag(this, 'negate');
583
+ Assertion.addProperty('empty', function () {
584
+ var obj = flag(this, 'object')
585
+ , expected = obj;
735
586
 
736
- if (negate && undefined !== val) {
737
- if (undefined === value) {
738
- throw new Error(util.inspect(obj) + ' has no ' + descriptor + util.inspect(name));
587
+ if (Array.isArray(obj) || 'string' === typeof object) {
588
+ expected = obj.length;
589
+ } else if (typeof obj === 'object') {
590
+ expected = Object.keys(obj).length;
739
591
  }
740
- } else {
741
- this.assert(
742
- undefined !== value
743
- , 'expected #{this} to have a ' + descriptor + util.inspect(name)
744
- , 'expected #{this} to not have ' + descriptor + util.inspect(name));
745
- }
746
592
 
747
- if (undefined !== val) {
748
593
  this.assert(
749
- val === value
750
- , 'expected #{this} to have a ' + descriptor + util.inspect(name) + ' of #{exp}, but got #{act}'
751
- , 'expected #{this} to not have a ' + descriptor + util.inspect(name) + ' of #{act}'
752
- , val
753
- , value
594
+ !expected
595
+ , 'expected #{this} to be empty'
596
+ , 'expected #{this} not to be empty'
754
597
  );
755
- }
756
-
757
- flag(this, 'object', value);
758
- return this;
759
- };
760
-
761
- /**
762
- * ### .ownProperty(name)
763
- *
764
- * Asserts that the target has an own property `name`.
765
- *
766
- * expect('test').to.have.ownProperty('length');
767
- *
768
- * @name ownProperty
769
- * @alias haveOwnProperty
770
- * @param {String} name
771
- * @api public
772
- */
773
-
774
- Assertion.prototype.ownProperty = function (name) {
775
- var obj = flag(this, 'object');
776
- this.assert(
777
- obj.hasOwnProperty(name)
778
- , 'expected #{this} to have own property ' + util.inspect(name)
779
- , 'expected #{this} to not have own property ' + util.inspect(name));
780
- return this;
781
- };
782
-
783
- /**
784
- * ### .length(value)
785
- *
786
- * Asserts that the target's `length` property has the expected value.
787
- *
788
- * expect([1,2,3]).to.have.length(3);
789
- * expect('foobar').to.have.length(6);
790
- *
791
- * @name length
792
- * @alias lengthOf
793
- * @param {Number} length
794
- * @api public
795
- */
796
-
797
- Assertion.prototype.length = function (n) {
798
- var obj = flag(this, 'object');
799
- new Assertion(obj).to.have.property('length');
800
- var len = obj.length;
598
+ });
801
599
 
802
- this.assert(
803
- len == n
804
- , 'expected #{this} to have a length of #{exp} but got #{act}'
805
- , 'expected #{this} to not have a length of #{act}'
806
- , n
807
- , len
808
- );
600
+ /**
601
+ * ### .arguments
602
+ *
603
+ * Asserts that the target is an arguments object.
604
+ *
605
+ * function test () {
606
+ * expect(arguments).to.be.arguments;
607
+ * }
608
+ *
609
+ * @name arguments
610
+ * @alias Arguments
611
+ * @api public
612
+ */
809
613
 
810
- return this;
811
- };
614
+ function checkArguments () {
615
+ var obj = flag(this, 'object')
616
+ , type = Object.prototype.toString.call(obj);
617
+ this.assert(
618
+ '[object Arguments]' === type
619
+ , 'expected #{this} to be arguments but got ' + type
620
+ , 'expected #{this} to not be arguments'
621
+ );
622
+ }
812
623
 
813
- /**
814
- * ### .match(regexp)
815
- *
816
- * Asserts that the target matches a regular expression.
817
- *
818
- * expect('foobar').to.match(/^foo/);
819
- *
820
- * @name match
821
- * @param {RegExp} RegularExpression
822
- * @api public
823
- */
624
+ Assertion.addProperty('arguments', checkArguments);
625
+ Assertion.addProperty('Arguments', checkArguments);
824
626
 
825
- Assertion.prototype.match = function (re) {
826
- var obj = flag(this, 'object');
827
- this.assert(
828
- re.exec(obj)
829
- , 'expected #{this} to match ' + re
830
- , 'expected #{this} not to match ' + re);
627
+ /**
628
+ * ### .equal(value)
629
+ *
630
+ * Asserts that the target is strictly equal (`===`) to `value`.
631
+ * Alternately, if the `deep` flag is set, asserts that
632
+ * the target is deeply equal to `value`.
633
+ *
634
+ * expect('hello').to.equal('hello');
635
+ * expect(42).to.equal(42);
636
+ * expect(1).to.not.equal(true);
637
+ * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
638
+ * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
639
+ *
640
+ * @name equal
641
+ * @alias eq
642
+ * @alias deep.equal
643
+ * @param {Mixed} value
644
+ * @api public
645
+ */
831
646
 
832
- return this;
833
- };
647
+ function assertEqual (val) {
648
+ var obj = flag(this, 'object');
649
+ if (flag(this, 'deep')) {
650
+ return this.eql(val);
651
+ } else {
652
+ this.assert(
653
+ val === obj
654
+ , 'expected #{this} to equal #{exp}'
655
+ , 'expected #{this} to not equal #{exp}'
656
+ , val
657
+ );
658
+ }
659
+ }
834
660
 
661
+ Assertion.addMethod('equal', assertEqual);
662
+ Assertion.addMethod('eq', assertEqual);
835
663
 
836
- /**
837
- * ### .string(string)
838
- *
839
- * Asserts that the string target contains another string.
840
- *
841
- * expect('foobar').to.have.string('bar');
842
- *
843
- * @name string
844
- * @param {String} string
845
- * @api public
846
- */
664
+ /**
665
+ * ### .eql(value)
666
+ *
667
+ * Asserts that the target is deeply equal to `value`.
668
+ *
669
+ * expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
670
+ * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
671
+ *
672
+ * @name eql
673
+ * @param {Mixed} value
674
+ * @api public
675
+ */
847
676
 
848
- Assertion.prototype.string = function (str) {
849
- var obj = flag(this, 'object');
850
- new Assertion(obj).is.a('string');
677
+ Assertion.addMethod('eql', function (obj) {
678
+ this.assert(
679
+ _.eql(obj, flag(this, 'object'))
680
+ , 'expected #{this} to deeply equal #{exp}'
681
+ , 'expected #{this} to not deeply equal #{exp}'
682
+ , obj
683
+ );
684
+ });
851
685
 
852
- this.assert(
853
- ~obj.indexOf(str)
854
- , 'expected #{this} to contain ' + util.inspect(str)
855
- , 'expected #{this} to not contain ' + util.inspect(str));
686
+ /**
687
+ * ### .above(value)
688
+ *
689
+ * Asserts that the target is greater than `value`.
690
+ *
691
+ * expect(10).to.be.above(5);
692
+ *
693
+ * Can also be used in conjunction with `length` to
694
+ * assert a minimum length. The benefit being a
695
+ * more informative error message than if the length
696
+ * was supplied directly.
697
+ *
698
+ * expect('foo').to.have.length.above(2);
699
+ * expect([ 1, 2, 3 ]).to.have.length.above(2);
700
+ *
701
+ * @name above
702
+ * @alias gt
703
+ * @alias greaterThan
704
+ * @param {Number} value
705
+ * @api public
706
+ */
856
707
 
857
- return this;
858
- };
708
+ function assertAbove (n) {
709
+ var obj = flag(this, 'object');
710
+ if (flag(this, 'doLength')) {
711
+ new Assertion(obj).to.have.property('length');
712
+ var len = obj.length;
713
+ this.assert(
714
+ len > n
715
+ , 'expected #{this} to have a length above #{exp} but got #{act}'
716
+ , 'expected #{this} to not have a length above #{exp}'
717
+ , n
718
+ , len
719
+ );
720
+ } else {
721
+ this.assert(
722
+ obj > n
723
+ , 'expected #{this} to be above ' + n
724
+ , 'expected #{this} to be below ' + n
725
+ );
726
+ }
727
+ }
859
728
 
860
- /**
861
- * ### .keys(key1, [key2], [...])
862
- *
863
- * Asserts that the target has exactly the given keys, or
864
- * asserts the inclusion of some keys when using the
865
- * `include` or `contain` modifiers.
866
- *
867
- * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
868
- * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
869
- *
870
- * @name keys
871
- * @alias key
872
- * @param {String...|Array} keys
873
- * @api public
874
- */
729
+ Assertion.addMethod('above', assertAbove);
730
+ Assertion.addMethod('gt', assertAbove);
731
+ Assertion.addMethod('greaterThan', assertAbove);
875
732
 
876
- Assertion.prototype.keys = function(keys) {
877
- var obj = flag(this, 'object')
878
- , str
879
- , ok = true;
733
+ /**
734
+ * ### .below(value)
735
+ *
736
+ * Asserts that the target is less than `value`.
737
+ *
738
+ * expect(5).to.be.below(10);
739
+ *
740
+ * Can also be used in conjunction with `length` to
741
+ * assert a maximum length. The benefit being a
742
+ * more informative error message than if the length
743
+ * was supplied directly.
744
+ *
745
+ * expect('foo').to.have.length.below(4);
746
+ * expect([ 1, 2, 3 ]).to.have.length.below(4);
747
+ *
748
+ * @name below
749
+ * @alias lt
750
+ * @alias lessThan
751
+ * @param {Number} value
752
+ * @api public
753
+ */
880
754
 
881
- keys = keys instanceof Array
882
- ? keys
883
- : Array.prototype.slice.call(arguments);
755
+ function assertBelow (n) {
756
+ var obj = flag(this, 'object');
757
+ if (flag(this, 'doLength')) {
758
+ new Assertion(obj).to.have.property('length');
759
+ var len = obj.length;
760
+ this.assert(
761
+ len < n
762
+ , 'expected #{this} to have a length below #{exp} but got #{act}'
763
+ , 'expected #{this} to not have a length below #{exp}'
764
+ , n
765
+ , len
766
+ );
767
+ } else {
768
+ this.assert(
769
+ obj < n
770
+ , 'expected #{this} to be below ' + n
771
+ , 'expected #{this} to be above ' + n
772
+ );
773
+ }
774
+ }
884
775
 
885
- if (!keys.length) throw new Error('keys required');
776
+ Assertion.addMethod('below', assertBelow);
777
+ Assertion.addMethod('lt', assertBelow);
778
+ Assertion.addMethod('lessThan', assertBelow);
886
779
 
887
- var actual = Object.keys(obj)
888
- , len = keys.length;
780
+ /**
781
+ * ### .within(start, finish)
782
+ *
783
+ * Asserts that the target is within a range.
784
+ *
785
+ * expect(7).to.be.within(5,10);
786
+ *
787
+ * Can also be used in conjunction with `length` to
788
+ * assert a length range. The benefit being a
789
+ * more informative error message than if the length
790
+ * was supplied directly.
791
+ *
792
+ * expect('foo').to.have.length.within(2,4);
793
+ * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
794
+ *
795
+ * @name within
796
+ * @param {Number} start lowerbound inclusive
797
+ * @param {Number} finish upperbound inclusive
798
+ * @api public
799
+ */
889
800
 
890
- // Inclusion
891
- ok = keys.every(function(key){
892
- return ~actual.indexOf(key);
801
+ Assertion.addMethod('within', function (start, finish) {
802
+ var obj = flag(this, 'object')
803
+ , range = start + '..' + finish;
804
+ if (flag(this, 'doLength')) {
805
+ new Assertion(obj).to.have.property('length');
806
+ var len = obj.length;
807
+ this.assert(
808
+ len >= start && len <= finish
809
+ , 'expected #{this} to have a length within ' + range
810
+ , 'expected #{this} to not have a length within ' + range
811
+ );
812
+ } else {
813
+ this.assert(
814
+ obj >= start && obj <= finish
815
+ , 'expected #{this} to be within ' + range
816
+ , 'expected #{this} to not be within ' + range
817
+ );
818
+ }
893
819
  });
894
820
 
895
- // Strict
896
- if (!flag(this, 'negate') && !flag(this, 'contains')) {
897
- ok = ok && keys.length == actual.length;
898
- }
899
-
900
- // Key string
901
- if (len > 1) {
902
- keys = keys.map(function(key){
903
- return util.inspect(key);
904
- });
905
- var last = keys.pop();
906
- str = keys.join(', ') + ', and ' + last;
907
- } else {
908
- str = util.inspect(keys[0]);
909
- }
910
-
911
- // Form
912
- str = (len > 1 ? 'keys ' : 'key ') + str;
913
-
914
- // Have / include
915
- str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
821
+ /**
822
+ * ### .instanceof(constructor)
823
+ *
824
+ * Asserts that the target is an instance of `constructor`.
825
+ *
826
+ * var Tea = function (name) { this.name = name; }
827
+ * , Chai = new Tea('chai');
828
+ *
829
+ * expect(Chai).to.be.an.instanceof(Tea);
830
+ * expect([ 1, 2, 3 ]).to.be.instanceof(Array);
831
+ *
832
+ * @name instanceof
833
+ * @param {Constructor} constructor
834
+ * @alias instanceOf
835
+ * @api public
836
+ */
916
837
 
917
- // Assertion
918
- this.assert(
919
- ok
920
- , 'expected #{this} to ' + str
921
- , 'expected #{this} to not ' + str
922
- , keys
923
- , Object.keys(obj)
924
- );
838
+ function assertInstanceOf (constructor) {
839
+ var name = _.getName(constructor);
840
+ this.assert(
841
+ flag(this, 'object') instanceof constructor
842
+ , 'expected #{this} to be an instance of ' + name
843
+ , 'expected #{this} to not be an instance of ' + name
844
+ );
845
+ };
925
846
 
926
- return this;
927
- }
847
+ Assertion.addMethod('instanceof', assertInstanceOf);
848
+ Assertion.addMethod('instanceOf', assertInstanceOf);
928
849
 
929
- /**
930
- * ### .throw(constructor)
931
- *
932
- * Asserts that the function target will throw a specific error, or specific type of error
933
- * (as determined using `instanceof`), optionally with a RegExp or string inclusion test
934
- * for the error's message.
935
- *
936
- * var err = new ReferenceError('This is a bad function.');
937
- * var fn = function () { throw err; }
938
- * expect(fn).to.throw(ReferenceError);
939
- * expect(fn).to.throw(Error);
940
- * expect(fn).to.throw(/bad function/);
941
- * expect(fn).to.not.throw('good function');
942
- * expect(fn).to.throw(ReferenceError, /bad function/);
943
- * expect(fn).to.throw(err);
944
- * expect(fn).to.not.throw(new RangeError('Out of range.'));
945
- *
946
- * Please note that when a throw expectation is negated, it will check each
947
- * parameter independently, starting with error constructor type. The appropriate way
948
- * to check for the existence of a type of error but for a message that does not match
949
- * is to use `and`.
950
- *
951
- * expect(fn).to.throw(ReferenceError)
952
- * .and.not.throw(/good function/);
953
- *
954
- * @name throw
955
- * @alias throws
956
- * @alias Throw
957
- * @param {ErrorConstructor} constructor
958
- * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
959
- * @api public
960
- */
850
+ /**
851
+ * ### .property(name, [value])
852
+ *
853
+ * Asserts that the target has a property `name`, optionally asserting that
854
+ * the value of that property is strictly equal to `value`.
855
+ * If the `deep` flag is set, you can use dot- and bracket-notation for deep
856
+ * references into objects and arrays.
857
+ *
858
+ * // simple referencing
859
+ * var obj = { foo: 'bar' };
860
+ * expect(obj).to.have.property('foo');
861
+ * expect(obj).to.have.property('foo', 'bar');
862
+ *
863
+ * // deep referencing
864
+ * var deepObj = {
865
+ * green: { tea: 'matcha' }
866
+ * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
867
+ * };
868
+
869
+ * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
870
+ * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
871
+ * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
872
+ *
873
+ * You can also use an array as the starting point of a `deep.property`
874
+ * assertion, or traverse nested arrays.
875
+ *
876
+ * var arr = [
877
+ * [ 'chai', 'matcha', 'konacha' ]
878
+ * , [ { tea: 'chai' }
879
+ * , { tea: 'matcha' }
880
+ * , { tea: 'konacha' } ]
881
+ * ];
882
+ *
883
+ * expect(arr).to.have.deep.property('[0][1]', 'matcha');
884
+ * expect(arr).to.have.deep.property('[1][2].tea', 'konacha');
885
+ *
886
+ * Furthermore, `property` changes the subject of the assertion
887
+ * to be the value of that property from the original object. This
888
+ * permits for further chainable assertions on that property.
889
+ *
890
+ * expect(obj).to.have.property('foo')
891
+ * .that.is.a('string');
892
+ * expect(deepObj).to.have.property('green')
893
+ * .that.is.an('object')
894
+ * .that.deep.equals({ tea: 'matcha' });
895
+ * expect(deepObj).to.have.property('teas')
896
+ * .that.is.an('array')
897
+ * .with.deep.property('[2]')
898
+ * .that.deep.equals({ tea: 'konacha' });
899
+ *
900
+ * @name property
901
+ * @alias deep.property
902
+ * @param {String} name
903
+ * @param {Mixed} value (optional)
904
+ * @returns value of property for chaining
905
+ * @api public
906
+ */
961
907
 
962
- Assertion.prototype.Throw = function (constructor, msg) {
963
- var obj = flag(this, 'object');
964
- new Assertion(obj).is.a('function');
965
-
966
- var thrown = false
967
- , desiredError = null
968
- , name = null;
969
-
970
- if (arguments.length === 0) {
971
- msg = null;
972
- constructor = null;
973
- } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
974
- msg = constructor;
975
- constructor = null;
976
- } else if (constructor && constructor instanceof Error) {
977
- desiredError = constructor;
978
- constructor = null;
979
- msg = null;
980
- } else if (typeof constructor === 'function') {
981
- name = (new constructor()).name;
982
- } else {
983
- constructor = null;
984
- }
908
+ Assertion.addMethod('property', function (name, val) {
909
+ var obj = flag(this, 'object')
910
+ , value = flag(this, 'deep') ? _.getPathValue(name, obj) : obj[name]
911
+ , descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
912
+ , negate = flag(this, 'negate');
985
913
 
986
- try {
987
- obj();
988
- } catch (err) {
989
- // first, check desired error
990
- if (desiredError) {
991
- this.assert(
992
- err === desiredError
993
- , 'expected #{this} to throw ' + util.inspect(desiredError) + ' but ' + util.inspect(err) + ' was thrown'
994
- , 'expected #{this} to not throw ' + util.inspect(desiredError)
995
- );
996
- return this;
997
- }
998
- // next, check constructor
999
- if (constructor) {
914
+ if (negate && undefined !== val) {
915
+ if (undefined === value) {
916
+ throw new Error(_.inspect(obj) + ' has no ' + descriptor + _.inspect(name));
917
+ }
918
+ } else {
1000
919
  this.assert(
1001
- err instanceof constructor
1002
- , 'expected #{this} to throw ' + name + ' but a ' + err.name + ' was thrown'
1003
- , 'expected #{this} to not throw ' + name );
1004
- if (!msg) return this;
920
+ undefined !== value
921
+ , 'expected #{this} to have a ' + descriptor + _.inspect(name)
922
+ , 'expected #{this} to not have ' + descriptor + _.inspect(name));
1005
923
  }
1006
- // next, check message
1007
- if (err.message && msg && msg instanceof RegExp) {
1008
- this.assert(
1009
- msg.exec(err.message)
1010
- , 'expected #{this} to throw error matching ' + msg + ' but got ' + util.inspect(err.message)
1011
- , 'expected #{this} to throw error not matching ' + msg
1012
- );
1013
- return this;
1014
- } else if (err.message && msg && 'string' === typeof msg) {
924
+
925
+ if (undefined !== val) {
1015
926
  this.assert(
1016
- ~err.message.indexOf(msg)
1017
- , 'expected #{this} to throw error including #{exp} but got #{act}'
1018
- , 'expected #{this} to throw error not including #{act}'
1019
- , msg
1020
- , err.message
927
+ val === value
928
+ , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
929
+ , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'
930
+ , val
931
+ , value
1021
932
  );
1022
- return this;
1023
- } else {
1024
- thrown = true;
1025
933
  }
934
+
935
+ flag(this, 'object', value);
936
+ });
937
+
938
+
939
+ /**
940
+ * ### .ownProperty(name)
941
+ *
942
+ * Asserts that the target has an own property `name`.
943
+ *
944
+ * expect('test').to.have.ownProperty('length');
945
+ *
946
+ * @name ownProperty
947
+ * @alias haveOwnProperty
948
+ * @param {String} name
949
+ * @api public
950
+ */
951
+
952
+ function assertOwnProperty (name) {
953
+ var obj = flag(this, 'object');
954
+ this.assert(
955
+ obj.hasOwnProperty(name)
956
+ , 'expected #{this} to have own property ' + _.inspect(name)
957
+ , 'expected #{this} to not have own property ' + _.inspect(name)
958
+ );
1026
959
  }
1027
960
 
1028
- var expectedThrown = name ? name : desiredError ? util.inspect(desiredError) : 'an error';
961
+ Assertion.addMethod('ownProperty', assertOwnProperty);
962
+ Assertion.addMethod('haveOwnProperty', assertOwnProperty);
1029
963
 
1030
- this.assert(
1031
- thrown === true
1032
- , 'expected #{this} to throw ' + expectedThrown
1033
- , 'expected #{this} to not throw ' + expectedThrown);
964
+ /**
965
+ * ### .length(value)
966
+ *
967
+ * Asserts that the target's `length` property has
968
+ * the expected value.
969
+ *
970
+ * expect([ 1, 2, 3]).to.have.length(3);
971
+ * expect('foobar').to.have.length(6);
972
+ *
973
+ * Can also be used as a chain precursor to a value
974
+ * comparison for the length property.
975
+ *
976
+ * expect('foo').to.have.length.above(2);
977
+ * expect([ 1, 2, 3 ]).to.have.length.above(2);
978
+ * expect('foo').to.have.length.below(4);
979
+ * expect([ 1, 2, 3 ]).to.have.length.below(4);
980
+ * expect('foo').to.have.length.within(2,4);
981
+ * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
982
+ *
983
+ * @name length
984
+ * @alias lengthOf
985
+ * @param {Number} length
986
+ * @api public
987
+ */
1034
988
 
1035
- return this;
1036
- };
989
+ function assertLengthChain () {
990
+ flag(this, 'doLength', true);
991
+ }
1037
992
 
1038
- /**
1039
- * ### .respondTo(method)
1040
- *
1041
- * Asserts that the object or class target will respond to a method.
1042
- *
1043
- * Klass.prototype.bar = function(){};
1044
- * expect(Klass).to.respondTo('bar');
1045
- * expect(obj).to.respondTo('bar');
1046
- *
1047
- * To check if a constructor will respond to a static function,
1048
- * set the `itself` flag.
1049
- *
1050
- * Klass.baz = function(){};
1051
- * expect(Klass).itself.to.respondTo('baz');
1052
- *
1053
- * @name respondTo
1054
- * @param {String} method
1055
- * @api public
1056
- */
993
+ function assertLength (n) {
994
+ var obj = flag(this, 'object');
995
+ new Assertion(obj).to.have.property('length');
996
+ var len = obj.length;
1057
997
 
1058
- Assertion.prototype.respondTo = function (method) {
1059
- var obj = flag(this, 'object')
1060
- , itself = flag(this, 'itself')
1061
- , context = ('function' === typeof obj && !itself)
1062
- ? obj.prototype[method]
1063
- : obj[method];
998
+ this.assert(
999
+ len == n
1000
+ , 'expected #{this} to have a length of #{exp} but got #{act}'
1001
+ , 'expected #{this} to not have a length of #{act}'
1002
+ , n
1003
+ , len
1004
+ );
1005
+ }
1064
1006
 
1065
- this.assert(
1066
- 'function' === typeof context
1067
- , 'expected #{this} to respond to ' + util.inspect(method)
1068
- , 'expected #{this} to not respond to ' + util.inspect(method)
1069
- , 'function'
1070
- , typeof context
1071
- );
1007
+ Assertion.addChainableMethod('length', assertLength, assertLengthChain);
1008
+ Assertion.addMethod('lengthOf', assertLength, assertLengthChain);
1072
1009
 
1073
- return this;
1074
- };
1010
+ /**
1011
+ * ### .match(regexp)
1012
+ *
1013
+ * Asserts that the target matches a regular expression.
1014
+ *
1015
+ * expect('foobar').to.match(/^foo/);
1016
+ *
1017
+ * @name match
1018
+ * @param {RegExp} RegularExpression
1019
+ * @api public
1020
+ */
1075
1021
 
1076
- /**
1077
- * ### .itself
1078
- *
1079
- * Sets the `itself` flag, later used by the `respondTo` assertion.
1080
- *
1081
- * function Foo() {}
1082
- * Foo.bar = function() {}
1083
- * Foo.prototype.baz = function() {}
1084
- *
1085
- * expect(Foo).itself.to.respondTo('bar');
1086
- * expect(Foo).itself.not.to.respondTo('baz');
1087
- *
1088
- * @name itself
1089
- * @api public
1090
- */
1091
- Object.defineProperty(Assertion.prototype, 'itself',
1092
- { get: function () {
1093
- flag(this, 'itself', true);
1094
- return this;
1095
- }
1096
- , configurable: true
1097
- });
1022
+ Assertion.addMethod('match', function (re) {
1023
+ var obj = flag(this, 'object');
1024
+ this.assert(
1025
+ re.exec(obj)
1026
+ , 'expected #{this} to match ' + re
1027
+ , 'expected #{this} not to match ' + re
1028
+ );
1029
+ });
1098
1030
 
1099
- /**
1100
- * ### .satisfy(method)
1101
- *
1102
- * Asserts that the target passes a given truth test.
1103
- *
1104
- * expect(1).to.satisfy(function(num) { return num > 0; });
1105
- *
1106
- * @name satisfy
1107
- * @param {Function} matcher
1108
- * @api public
1109
- */
1031
+ /**
1032
+ * ### .string(string)
1033
+ *
1034
+ * Asserts that the string target contains another string.
1035
+ *
1036
+ * expect('foobar').to.have.string('bar');
1037
+ *
1038
+ * @name string
1039
+ * @param {String} string
1040
+ * @api public
1041
+ */
1110
1042
 
1111
- Assertion.prototype.satisfy = function (matcher) {
1112
- var obj = flag(this, 'object');
1113
- this.assert(
1114
- matcher(obj)
1115
- , 'expected #{this} to satisfy ' + util.inspect(matcher)
1116
- , 'expected #{this} to not satisfy' + util.inspect(matcher)
1117
- , this.negate ? false : true
1118
- , matcher(obj)
1119
- );
1043
+ Assertion.addMethod('string', function (str) {
1044
+ var obj = flag(this, 'object');
1045
+ new Assertion(obj).is.a('string');
1120
1046
 
1121
- return this;
1122
- };
1047
+ this.assert(
1048
+ ~obj.indexOf(str)
1049
+ , 'expected #{this} to contain ' + _.inspect(str)
1050
+ , 'expected #{this} to not contain ' + _.inspect(str)
1051
+ );
1052
+ });
1123
1053
 
1124
- /**
1125
- * ### .closeTo(expected, delta)
1126
- *
1127
- * Asserts that the target is equal `expected`, to within a +/- `delta` range.
1128
- *
1129
- * expect(1.5).to.be.closeTo(1, 0.5);
1130
- *
1131
- * @name closeTo
1132
- * @param {Number} expected
1133
- * @param {Number} delta
1134
- * @api public
1135
- */
1136
1054
 
1137
- Assertion.prototype.closeTo = function (expected, delta) {
1138
- var obj = flag(this, 'object');
1139
- this.assert(
1140
- (obj - delta === expected) || (obj + delta === expected)
1141
- , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
1142
- , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta);
1055
+ /**
1056
+ * ### .keys(key1, [key2], [...])
1057
+ *
1058
+ * Asserts that the target has exactly the given keys, or
1059
+ * asserts the inclusion of some keys when using the
1060
+ * `include` or `contain` modifiers.
1061
+ *
1062
+ * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
1063
+ * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
1064
+ *
1065
+ * @name keys
1066
+ * @alias key
1067
+ * @param {String...|Array} keys
1068
+ * @api public
1069
+ */
1143
1070
 
1144
- return this;
1145
- };
1071
+ function assertKeys (keys) {
1072
+ var obj = flag(this, 'object')
1073
+ , str
1074
+ , ok = true;
1146
1075
 
1147
- /*!
1148
- * Aliases.
1149
- */
1150
-
1151
- (function alias(name, as){
1152
- Assertion.prototype[as] = Assertion.prototype[name];
1153
- return alias;
1154
- })
1155
- ('equal', 'eq')
1156
- ('above', 'gt')
1157
- ('below', 'lt')
1158
- ('length', 'lengthOf')
1159
- ('keys', 'key')
1160
- ('ownProperty', 'haveOwnProperty')
1161
- ('above', 'greaterThan')
1162
- ('below', 'lessThan')
1163
- ('Throw', 'throws')
1164
- ('Throw', 'throw')
1165
- ('instanceOf', 'instanceof');
1166
-
1167
- }); // module: assertion.js
1168
-
1169
- require.register("browser/error.js", function(module, exports, require){
1170
- /*!
1171
- * chai
1172
- * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
1173
- * MIT Licensed
1174
- */
1076
+ keys = keys instanceof Array
1077
+ ? keys
1078
+ : Array.prototype.slice.call(arguments);
1175
1079
 
1176
- module.exports = AssertionError;
1080
+ if (!keys.length) throw new Error('keys required');
1177
1081
 
1178
- function AssertionError (options) {
1179
- options = options || {};
1180
- this.message = options.message;
1181
- this.actual = options.actual;
1182
- this.expected = options.expected;
1183
- this.operator = options.operator;
1082
+ var actual = Object.keys(obj)
1083
+ , len = keys.length;
1184
1084
 
1185
- if (options.stackStartFunction && Error.captureStackTrace) {
1186
- var stackStartFunction = options.stackStartFunction;
1187
- Error.captureStackTrace(this, stackStartFunction);
1188
- }
1189
- }
1085
+ // Inclusion
1086
+ ok = keys.every(function(key){
1087
+ return ~actual.indexOf(key);
1088
+ });
1190
1089
 
1191
- AssertionError.prototype = Object.create(Error.prototype);
1192
- AssertionError.prototype.name = 'AssertionError';
1193
- AssertionError.prototype.constructor = AssertionError;
1090
+ // Strict
1091
+ if (!flag(this, 'negate') && !flag(this, 'contains')) {
1092
+ ok = ok && keys.length == actual.length;
1093
+ }
1194
1094
 
1195
- AssertionError.prototype.toString = function() {
1196
- return this.message;
1197
- };
1095
+ // Key string
1096
+ if (len > 1) {
1097
+ keys = keys.map(function(key){
1098
+ return _.inspect(key);
1099
+ });
1100
+ var last = keys.pop();
1101
+ str = keys.join(', ') + ', and ' + last;
1102
+ } else {
1103
+ str = _.inspect(keys[0]);
1104
+ }
1198
1105
 
1199
- }); // module: browser/error.js
1106
+ // Form
1107
+ str = (len > 1 ? 'keys ' : 'key ') + str;
1200
1108
 
1201
- require.register("chai.js", function(module, exports, require){
1202
- /*!
1203
- * chai
1204
- * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
1205
- * MIT Licensed
1206
- */
1109
+ // Have / include
1110
+ str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
1207
1111
 
1208
- var used = []
1209
- , exports = module.exports = {};
1112
+ // Assertion
1113
+ this.assert(
1114
+ ok
1115
+ , 'expected #{this} to ' + str
1116
+ , 'expected #{this} to not ' + str
1117
+ );
1118
+ }
1210
1119
 
1211
- /*!
1212
- * Chai version
1213
- */
1120
+ Assertion.addMethod('keys', assertKeys);
1121
+ Assertion.addMethod('key', assertKeys);
1214
1122
 
1215
- exports.version = '1.0.4';
1123
+ /**
1124
+ * ### .throw(constructor)
1125
+ *
1126
+ * Asserts that the function target will throw a specific error, or specific type of error
1127
+ * (as determined using `instanceof`), optionally with a RegExp or string inclusion test
1128
+ * for the error's message.
1129
+ *
1130
+ * var err = new ReferenceError('This is a bad function.');
1131
+ * var fn = function () { throw err; }
1132
+ * expect(fn).to.throw(ReferenceError);
1133
+ * expect(fn).to.throw(Error);
1134
+ * expect(fn).to.throw(/bad function/);
1135
+ * expect(fn).to.not.throw('good function');
1136
+ * expect(fn).to.throw(ReferenceError, /bad function/);
1137
+ * expect(fn).to.throw(err);
1138
+ * expect(fn).to.not.throw(new RangeError('Out of range.'));
1139
+ *
1140
+ * Please note that when a throw expectation is negated, it will check each
1141
+ * parameter independently, starting with error constructor type. The appropriate way
1142
+ * to check for the existence of a type of error but for a message that does not match
1143
+ * is to use `and`.
1144
+ *
1145
+ * expect(fn).to.throw(ReferenceError)
1146
+ * .and.not.throw(/good function/);
1147
+ *
1148
+ * @name throw
1149
+ * @alias throws
1150
+ * @alias Throw
1151
+ * @param {ErrorConstructor} constructor
1152
+ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
1153
+ * @api public
1154
+ */
1216
1155
 
1217
- /*!
1218
- * Primary `Assertion` prototype
1219
- */
1156
+ function assertThrows (constructor, msg) {
1157
+ var obj = flag(this, 'object');
1158
+ new Assertion(obj).is.a('function');
1159
+
1160
+ var thrown = false
1161
+ , desiredError = null
1162
+ , name = null;
1163
+
1164
+ if (arguments.length === 0) {
1165
+ msg = null;
1166
+ constructor = null;
1167
+ } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
1168
+ msg = constructor;
1169
+ constructor = null;
1170
+ } else if (constructor && constructor instanceof Error) {
1171
+ desiredError = constructor;
1172
+ constructor = null;
1173
+ msg = null;
1174
+ } else if (typeof constructor === 'function') {
1175
+ name = (new constructor()).name;
1176
+ } else {
1177
+ constructor = null;
1178
+ }
1220
1179
 
1221
- exports.Assertion = require('./assertion');
1180
+ try {
1181
+ obj();
1182
+ } catch (err) {
1183
+ // first, check desired error
1184
+ if (desiredError) {
1185
+ this.assert(
1186
+ err === desiredError
1187
+ , 'expected #{this} to throw ' + _.inspect(desiredError) + ' but ' + _.inspect(err) + ' was thrown'
1188
+ , 'expected #{this} to not throw ' + _.inspect(desiredError)
1189
+ );
1190
+ return this;
1191
+ }
1192
+ // next, check constructor
1193
+ if (constructor) {
1194
+ this.assert(
1195
+ err instanceof constructor
1196
+ , 'expected #{this} to throw ' + name + ' but a ' + err.name + ' was thrown'
1197
+ , 'expected #{this} to not throw ' + name );
1198
+ if (!msg) return this;
1199
+ }
1200
+ // next, check message
1201
+ if (err.message && msg && msg instanceof RegExp) {
1202
+ this.assert(
1203
+ msg.exec(err.message)
1204
+ , 'expected #{this} to throw error matching ' + msg + ' but got ' + _.inspect(err.message)
1205
+ , 'expected #{this} to throw error not matching ' + msg
1206
+ );
1207
+ return this;
1208
+ } else if (err.message && msg && 'string' === typeof msg) {
1209
+ this.assert(
1210
+ ~err.message.indexOf(msg)
1211
+ , 'expected #{this} to throw error including #{exp} but got #{act}'
1212
+ , 'expected #{this} to throw error not including #{act}'
1213
+ , msg
1214
+ , err.message
1215
+ );
1216
+ return this;
1217
+ } else {
1218
+ thrown = true;
1219
+ }
1220
+ }
1222
1221
 
1223
- /*!
1224
- * Assertion Error
1225
- */
1222
+ var expectedThrown = name ? name : desiredError ? _.inspect(desiredError) : 'an error';
1226
1223
 
1227
- exports.AssertionError = require('./browser/error');
1224
+ this.assert(
1225
+ thrown === true
1226
+ , 'expected #{this} to throw ' + expectedThrown
1227
+ , 'expected #{this} to not throw ' + expectedThrown
1228
+ );
1229
+ };
1228
1230
 
1229
- /*!
1230
- * Utils for plugins (not exported)
1231
- */
1231
+ Assertion.addMethod('throw', assertThrows);
1232
+ Assertion.addMethod('throws', assertThrows);
1233
+ Assertion.addMethod('Throw', assertThrows);
1232
1234
 
1233
- var util = require('./utils');
1235
+ /**
1236
+ * ### .respondTo(method)
1237
+ *
1238
+ * Asserts that the object or class target will respond to a method.
1239
+ *
1240
+ * Klass.prototype.bar = function(){};
1241
+ * expect(Klass).to.respondTo('bar');
1242
+ * expect(obj).to.respondTo('bar');
1243
+ *
1244
+ * To check if a constructor will respond to a static function,
1245
+ * set the `itself` flag.
1246
+ *
1247
+ * Klass.baz = function(){};
1248
+ * expect(Klass).itself.to.respondTo('baz');
1249
+ *
1250
+ * @name respondTo
1251
+ * @param {String} method
1252
+ * @api public
1253
+ */
1234
1254
 
1235
- /**
1236
- * # .use(function)
1237
- *
1238
- * Provides a way to extend the internals of Chai
1239
- *
1240
- * @param {Function}
1241
- * @returns {this} for chaining
1242
- * @api public
1243
- */
1255
+ Assertion.addMethod('respondTo', function (method) {
1256
+ var obj = flag(this, 'object')
1257
+ , itself = flag(this, 'itself')
1258
+ , context = ('function' === typeof obj && !itself)
1259
+ ? obj.prototype[method]
1260
+ : obj[method];
1244
1261
 
1245
- exports.use = function (fn) {
1246
- if (!~used.indexOf(fn)) {
1247
- fn(this, util);
1248
- used.push(fn);
1249
- }
1262
+ this.assert(
1263
+ 'function' === typeof context
1264
+ , 'expected #{this} to respond to ' + _.inspect(method)
1265
+ , 'expected #{this} to not respond to ' + _.inspect(method)
1266
+ );
1267
+ });
1250
1268
 
1251
- return this;
1252
- };
1269
+ /**
1270
+ * ### .itself
1271
+ *
1272
+ * Sets the `itself` flag, later used by the `respondTo` assertion.
1273
+ *
1274
+ * function Foo() {}
1275
+ * Foo.bar = function() {}
1276
+ * Foo.prototype.baz = function() {}
1277
+ *
1278
+ * expect(Foo).itself.to.respondTo('bar');
1279
+ * expect(Foo).itself.not.to.respondTo('baz');
1280
+ *
1281
+ * @name itself
1282
+ * @api public
1283
+ */
1253
1284
 
1254
- /*!
1255
- * Expect interface
1256
- */
1285
+ Assertion.addProperty('itself', function () {
1286
+ flag(this, 'itself', true);
1287
+ });
1257
1288
 
1258
- var expect = require('./interface/expect');
1259
- exports.use(expect);
1289
+ /**
1290
+ * ### .satisfy(method)
1291
+ *
1292
+ * Asserts that the target passes a given truth test.
1293
+ *
1294
+ * expect(1).to.satisfy(function(num) { return num > 0; });
1295
+ *
1296
+ * @name satisfy
1297
+ * @param {Function} matcher
1298
+ * @api public
1299
+ */
1260
1300
 
1261
- /*!
1262
- * Should interface
1263
- */
1301
+ Assertion.addMethod('satisfy', function (matcher) {
1302
+ var obj = flag(this, 'object');
1303
+ this.assert(
1304
+ matcher(obj)
1305
+ , 'expected #{this} to satisfy ' + _.inspect(matcher)
1306
+ , 'expected #{this} to not satisfy' + _.inspect(matcher)
1307
+ , this.negate ? false : true
1308
+ , matcher(obj)
1309
+ );
1310
+ });
1264
1311
 
1265
- var should = require('./interface/should');
1266
- exports.use(should);
1312
+ /**
1313
+ * ### .closeTo(expected, delta)
1314
+ *
1315
+ * Asserts that the target is equal `expected`, to within a +/- `delta` range.
1316
+ *
1317
+ * expect(1.5).to.be.closeTo(1, 0.5);
1318
+ *
1319
+ * @name closeTo
1320
+ * @param {Number} expected
1321
+ * @param {Number} delta
1322
+ * @api public
1323
+ */
1267
1324
 
1268
- /*!
1269
- * Assert interface
1270
- */
1325
+ Assertion.addMethod('closeTo', function (expected, delta) {
1326
+ var obj = flag(this, 'object');
1327
+ this.assert(
1328
+ Math.abs(obj - expected) <= delta
1329
+ , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
1330
+ , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
1331
+ );
1332
+ });
1271
1333
 
1272
- var assert = require('./interface/assert');
1273
- exports.use(assert);
1334
+ };
1274
1335
 
1275
- }); // module: chai.js
1336
+ }); // module: chai/core/assertions.js
1276
1337
 
1277
- require.register("interface/assert.js", function(module, exports, require){
1338
+ require.register("chai/interface/assert.js", function(module, exports, require){
1278
1339
  /*!
1279
1340
  * chai
1280
1341
  * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
@@ -2239,9 +2300,9 @@ module.exports = function (chai, util) {
2239
2300
  ('Throw', 'throws');
2240
2301
  };
2241
2302
 
2242
- }); // module: interface/assert.js
2303
+ }); // module: chai/interface/assert.js
2243
2304
 
2244
- require.register("interface/expect.js", function(module, exports, require){
2305
+ require.register("chai/interface/expect.js", function(module, exports, require){
2245
2306
  /*!
2246
2307
  * chai
2247
2308
  * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
@@ -2255,9 +2316,9 @@ module.exports = function (chai, util) {
2255
2316
  };
2256
2317
 
2257
2318
 
2258
- }); // module: interface/expect.js
2319
+ }); // module: chai/interface/expect.js
2259
2320
 
2260
- require.register("interface/should.js", function(module, exports, require){
2321
+ require.register("chai/interface/should.js", function(module, exports, require){
2261
2322
  /*!
2262
2323
  * chai
2263
2324
  * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
@@ -2321,9 +2382,9 @@ module.exports = function (chai, util) {
2321
2382
  chai.Should = loadShould;
2322
2383
  };
2323
2384
 
2324
- }); // module: interface/should.js
2385
+ }); // module: chai/interface/should.js
2325
2386
 
2326
- require.register("utils/addChainableMethod.js", function(module, exports, require){
2387
+ require.register("chai/utils/addChainableMethod.js", function(module, exports, require){
2327
2388
  /*!
2328
2389
  * Chai - addChainingMethod utility
2329
2390
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2395,9 +2456,9 @@ module.exports = function (ctx, name, method, chainingBehavior) {
2395
2456
  });
2396
2457
  };
2397
2458
 
2398
- }); // module: utils/addChainableMethod.js
2459
+ }); // module: chai/utils/addChainableMethod.js
2399
2460
 
2400
- require.register("utils/addMethod.js", function(module, exports, require){
2461
+ require.register("chai/utils/addMethod.js", function(module, exports, require){
2401
2462
  /*!
2402
2463
  * Chai - addMethod utility
2403
2464
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2436,9 +2497,9 @@ module.exports = function (ctx, name, method) {
2436
2497
  };
2437
2498
  };
2438
2499
 
2439
- }); // module: utils/addMethod.js
2500
+ }); // module: chai/utils/addMethod.js
2440
2501
 
2441
- require.register("utils/addProperty.js", function(module, exports, require){
2502
+ require.register("chai/utils/addProperty.js", function(module, exports, require){
2442
2503
  /*!
2443
2504
  * Chai - addProperty utility
2444
2505
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2480,9 +2541,9 @@ module.exports = function (ctx, name, getter) {
2480
2541
  });
2481
2542
  };
2482
2543
 
2483
- }); // module: utils/addProperty.js
2544
+ }); // module: chai/utils/addProperty.js
2484
2545
 
2485
- require.register("utils/eql.js", function(module, exports, require){
2546
+ require.register("chai/utils/eql.js", function(module, exports, require){
2486
2547
  // This is directly from Node.js assert
2487
2548
  // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js
2488
2549
 
@@ -2583,9 +2644,9 @@ function objEquiv(a, b) {
2583
2644
  }
2584
2645
  return true;
2585
2646
  }
2586
- }); // module: utils/eql.js
2647
+ }); // module: chai/utils/eql.js
2587
2648
 
2588
- require.register("utils/flag.js", function(module, exports, require){
2649
+ require.register("chai/utils/flag.js", function(module, exports, require){
2589
2650
  /*!
2590
2651
  * Chai - flag utility
2591
2652
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2619,9 +2680,9 @@ module.exports = function (obj, key, value) {
2619
2680
  }
2620
2681
  };
2621
2682
 
2622
- }); // module: utils/flag.js
2683
+ }); // module: chai/utils/flag.js
2623
2684
 
2624
- require.register("utils/getActual.js", function(module, exports, require){
2685
+ require.register("chai/utils/getActual.js", function(module, exports, require){
2625
2686
  /*!
2626
2687
  * Chai - getActual utility
2627
2688
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2642,9 +2703,9 @@ module.exports = function (obj, args) {
2642
2703
  return 'undefined' !== actual ? actual : obj.obj;
2643
2704
  };
2644
2705
 
2645
- }); // module: utils/getActual.js
2706
+ }); // module: chai/utils/getActual.js
2646
2707
 
2647
- require.register("utils/getMessage.js", function(module, exports, require){
2708
+ require.register("chai/utils/getMessage.js", function(module, exports, require){
2648
2709
  /*!
2649
2710
  * Chai - message composition utility
2650
2711
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2692,9 +2753,9 @@ module.exports = function (obj, args) {
2692
2753
  return flagMsg ? flagMsg + ': ' + msg : msg;
2693
2754
  };
2694
2755
 
2695
- }); // module: utils/getMessage.js
2756
+ }); // module: chai/utils/getMessage.js
2696
2757
 
2697
- require.register("utils/getName.js", function(module, exports, require){
2758
+ require.register("chai/utils/getName.js", function(module, exports, require){
2698
2759
  /*!
2699
2760
  * Chai - getName utility
2700
2761
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2716,9 +2777,9 @@ module.exports = function (func) {
2716
2777
  return match && match[1] ? match[1] : "";
2717
2778
  };
2718
2779
 
2719
- }); // module: utils/getName.js
2780
+ }); // module: chai/utils/getName.js
2720
2781
 
2721
- require.register("utils/getPathValue.js", function(module, exports, require){
2782
+ require.register("chai/utils/getPathValue.js", function(module, exports, require){
2722
2783
  /*!
2723
2784
  * Chai - getPathValue utility
2724
2785
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -2780,13 +2841,13 @@ var getPathValue = module.exports = function (path, obj) {
2780
2841
  */
2781
2842
 
2782
2843
  function parsePath (path) {
2783
- var parts = path.split('.').filter(Boolean);
2844
+ var str = path.replace(/\[/g, '.[')
2845
+ , parts = str.match(/(\\\.|[^.]+?)+/g);
2784
2846
  return parts.map(function (value) {
2785
- var re = /([A-Za-z0-9]+)\[(\d+)\]$/
2847
+ var re = /\[(\d+)\]$/
2786
2848
  , mArr = re.exec(value)
2787
- , val;
2788
- if (mArr) val = { p: mArr[1], i: parseFloat(mArr[2]) };
2789
- return val || value;
2849
+ if (mArr) return { i: parseFloat(mArr[1]) };
2850
+ else return { p: value };
2790
2851
  });
2791
2852
  };
2792
2853
 
@@ -2810,11 +2871,10 @@ function _getPathValue (parsed, obj) {
2810
2871
  for (var i = 0, l = parsed.length; i < l; i++) {
2811
2872
  var part = parsed[i];
2812
2873
  if (tmp) {
2813
- if ('object' === typeof part && tmp[part.p]) {
2814
- tmp = tmp[part.p][part.i];
2815
- } else {
2816
- tmp = tmp[part];
2817
- }
2874
+ if ('undefined' !== typeof part.p)
2875
+ tmp = tmp[part.p];
2876
+ else if ('undefined' !== typeof part.i)
2877
+ tmp = tmp[part.i];
2818
2878
  if (i == (l - 1)) res = tmp;
2819
2879
  } else {
2820
2880
  res = undefined;
@@ -2823,9 +2883,9 @@ function _getPathValue (parsed, obj) {
2823
2883
  return res;
2824
2884
  };
2825
2885
 
2826
- }); // module: utils/getPathValue.js
2886
+ }); // module: chai/utils/getPathValue.js
2827
2887
 
2828
- require.register("utils/index.js", function(module, exports, require){
2888
+ require.register("chai/utils/index.js", function(module, exports, require){
2829
2889
  /*!
2830
2890
  * chai
2831
2891
  * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>
@@ -2923,9 +2983,9 @@ exports.overwriteMethod = require('./overwriteMethod');
2923
2983
  exports.addChainableMethod = require('./addChainableMethod');
2924
2984
 
2925
2985
 
2926
- }); // module: utils/index.js
2986
+ }); // module: chai/utils/index.js
2927
2987
 
2928
- require.register("utils/inspect.js", function(module, exports, require){
2988
+ require.register("chai/utils/inspect.js", function(module, exports, require){
2929
2989
  // This is (almost) directly from Node.js utils
2930
2990
  // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js
2931
2991
 
@@ -3007,8 +3067,9 @@ function formatValue(ctx, value, recurseTimes) {
3007
3067
 
3008
3068
  // Make functions say that they are functions
3009
3069
  if (typeof value === 'function') {
3010
- var n = value.name ? ': ' + value.name : '';
3011
- base = ' [Function' + n + ']';
3070
+ var name = getName(value);
3071
+ var nameSuffix = name ? ': ' + name : '';
3072
+ base = ' [Function' + nameSuffix + ']';
3012
3073
  }
3013
3074
 
3014
3075
  // Make RegExps say that they are RegExps
@@ -3205,9 +3266,9 @@ function objectToString(o) {
3205
3266
  return Object.prototype.toString.call(o);
3206
3267
  }
3207
3268
 
3208
- }); // module: utils/inspect.js
3269
+ }); // module: chai/utils/inspect.js
3209
3270
 
3210
- require.register("utils/overwriteMethod.js", function(module, exports, require){
3271
+ require.register("chai/utils/overwriteMethod.js", function(module, exports, require){
3211
3272
  /*!
3212
3273
  * Chai - overwriteMethod utility
3213
3274
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -3260,9 +3321,9 @@ module.exports = function (ctx, name, method) {
3260
3321
  }
3261
3322
  };
3262
3323
 
3263
- }); // module: utils/overwriteMethod.js
3324
+ }); // module: chai/utils/overwriteMethod.js
3264
3325
 
3265
- require.register("utils/overwriteProperty.js", function(module, exports, require){
3326
+ require.register("chai/utils/overwriteProperty.js", function(module, exports, require){
3266
3327
  /*!
3267
3328
  * Chai - overwriteProperty utility
3268
3329
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -3318,9 +3379,9 @@ module.exports = function (ctx, name, getter) {
3318
3379
  });
3319
3380
  };
3320
3381
 
3321
- }); // module: utils/overwriteProperty.js
3382
+ }); // module: chai/utils/overwriteProperty.js
3322
3383
 
3323
- require.register("utils/test.js", function(module, exports, require){
3384
+ require.register("chai/utils/test.js", function(module, exports, require){
3324
3385
  /*!
3325
3386
  * Chai - test utility
3326
3387
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -3348,9 +3409,9 @@ module.exports = function (obj, args) {
3348
3409
  return negate ? !expr : expr;
3349
3410
  };
3350
3411
 
3351
- }); // module: utils/test.js
3412
+ }); // module: chai/utils/test.js
3352
3413
 
3353
- require.register("utils/transferFlags.js", function(module, exports, require){
3414
+ require.register("chai/utils/transferFlags.js", function(module, exports, require){
3354
3415
  /*!
3355
3416
  * Chai - transferFlags utility
3356
3417
  * Copyright(c) 2012 Jake Luer <jake@alogicalparadox.com>
@@ -3396,7 +3457,7 @@ module.exports = function (assertion, object, includeAll) {
3396
3457
  }
3397
3458
  };
3398
3459
 
3399
- }); // module: utils/transferFlags.js
3460
+ }); // module: chai/utils/transferFlags.js
3400
3461
 
3401
3462
 
3402
3463
  return require('chai');