konacha 1.2.4 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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');