chai 4.0.2 → 4.2.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.
- package/CODEOWNERS +1 -0
- package/CONTRIBUTING.md +2 -2
- package/LICENSE +1 -1
- package/README.md +4 -4
- package/chai.js +684 -813
- package/lib/chai/config.js +1 -1
- package/lib/chai/core/assertions.js +404 -207
- package/lib/chai/interface/assert.js +73 -58
- package/lib/chai/interface/expect.js +13 -0
- package/lib/chai/interface/should.js +14 -0
- package/lib/chai/utils/addLengthGuard.js +0 -2
- package/lib/chai/utils/addProperty.js +1 -1
- package/lib/chai/utils/compareByInspect.js +2 -2
- package/lib/chai/utils/expectTypes.js +3 -4
- package/lib/chai/utils/getMessage.js +1 -2
- package/lib/chai/utils/getOwnEnumerableProperties.js +1 -1
- package/lib/chai/utils/inspect.js +2 -9
- package/lib/chai/utils/isProxyEnabled.js +1 -1
- package/lib/chai/utils/objDisplay.js +1 -1
- package/lib/chai/utils/overwriteChainableMethod.js +1 -1
- package/lib/chai/utils/overwriteMethod.js +1 -1
- package/lib/chai/utils/overwriteProperty.js +1 -1
- package/lib/chai/utils/proxify.js +54 -32
- package/lib/chai/utils/test.js +1 -1
- package/lib/chai/utils/transferFlags.js +1 -1
- package/lib/chai.js +1 -1
- package/package.json +11 -10
- package/sauce.browsers.js +0 -9
- package/.npmignore +0 -14
|
@@ -33,16 +33,17 @@ module.exports = function (chai, _) {
|
|
|
33
33
|
* - same
|
|
34
34
|
* - but
|
|
35
35
|
* - does
|
|
36
|
+
* - still
|
|
36
37
|
*
|
|
37
38
|
* @name language chains
|
|
38
39
|
* @namespace BDD
|
|
39
40
|
* @api public
|
|
40
41
|
*/
|
|
41
42
|
|
|
42
|
-
[ 'to', 'be', 'been'
|
|
43
|
-
, '
|
|
44
|
-
, '
|
|
45
|
-
, '
|
|
43
|
+
[ 'to', 'be', 'been', 'is'
|
|
44
|
+
, 'and', 'has', 'have', 'with'
|
|
45
|
+
, 'that', 'which', 'at', 'of'
|
|
46
|
+
, 'same', 'but', 'does', 'still' ].forEach(function (chain) {
|
|
46
47
|
Assertion.addProperty(chain);
|
|
47
48
|
});
|
|
48
49
|
|
|
@@ -149,7 +150,8 @@ module.exports = function (chai, _) {
|
|
|
149
150
|
* Object.prototype.b = 2;
|
|
150
151
|
*
|
|
151
152
|
* expect({a: 1}).to.have.own.property('a');
|
|
152
|
-
* expect({a: 1}).to.have.property('b')
|
|
153
|
+
* expect({a: 1}).to.have.property('b');
|
|
154
|
+
* expect({a: 1}).to.not.have.own.property('b');
|
|
153
155
|
*
|
|
154
156
|
* expect({a: 1}).to.own.include({a: 1});
|
|
155
157
|
* expect({a: 1}).to.include({b: 2}).but.not.own.include({b: 2});
|
|
@@ -210,7 +212,6 @@ module.exports = function (chai, _) {
|
|
|
210
212
|
flag(this, 'all', false);
|
|
211
213
|
});
|
|
212
214
|
|
|
213
|
-
|
|
214
215
|
/**
|
|
215
216
|
* ### .all
|
|
216
217
|
*
|
|
@@ -282,7 +283,7 @@ module.exports = function (chai, _) {
|
|
|
282
283
|
* expect(1, 'nooo why fail??').to.be.a('string');
|
|
283
284
|
*
|
|
284
285
|
* `.a` can also be used as a language chain to improve the readability of
|
|
285
|
-
* your assertions.
|
|
286
|
+
* your assertions.
|
|
286
287
|
*
|
|
287
288
|
* expect({b: 2}).to.have.a.property('b');
|
|
288
289
|
*
|
|
@@ -330,6 +331,16 @@ module.exports = function (chai, _) {
|
|
|
330
331
|
*
|
|
331
332
|
* expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2});
|
|
332
333
|
*
|
|
334
|
+
* When the target is a Set or WeakSet, `.include` asserts that the given `val` is a
|
|
335
|
+
* member of the target. SameValueZero equality algorithm is used.
|
|
336
|
+
*
|
|
337
|
+
* expect(new Set([1, 2])).to.include(2);
|
|
338
|
+
*
|
|
339
|
+
* When the target is a Map, `.include` asserts that the given `val` is one of
|
|
340
|
+
* the values of the target. SameValueZero equality algorithm is used.
|
|
341
|
+
*
|
|
342
|
+
* expect(new Map([['a', 1], ['b', 2]])).to.include(2);
|
|
343
|
+
*
|
|
333
344
|
* Because `.include` does different things based on the target's type, it's
|
|
334
345
|
* important to check the target's type before using `.include`. See the `.a`
|
|
335
346
|
* doc for info on testing a target's type.
|
|
@@ -338,8 +349,8 @@ module.exports = function (chai, _) {
|
|
|
338
349
|
*
|
|
339
350
|
* By default, strict (`===`) equality is used to compare array members and
|
|
340
351
|
* object properties. Add `.deep` earlier in the chain to use deep equality
|
|
341
|
-
* instead. See the `deep-eql` project
|
|
342
|
-
* algorithm: https://github.com/chaijs/deep-eql.
|
|
352
|
+
* instead (WeakSet targets are not supported). See the `deep-eql` project
|
|
353
|
+
* page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql.
|
|
343
354
|
*
|
|
344
355
|
* // Target array deeply (but not strictly) includes `{a: 1}`
|
|
345
356
|
* expect([{a: 1}]).to.deep.include({a: 1});
|
|
@@ -386,7 +397,7 @@ module.exports = function (chai, _) {
|
|
|
386
397
|
*
|
|
387
398
|
* expect('foobar').to.not.include('taco');
|
|
388
399
|
* expect([1, 2, 3]).to.not.include(4);
|
|
389
|
-
*
|
|
400
|
+
*
|
|
390
401
|
* However, it's dangerous to negate `.include` when the target is an object.
|
|
391
402
|
* The problem is that it creates uncertain expectations by asserting that the
|
|
392
403
|
* target object doesn't have all of `val`'s key/value pairs but may or may
|
|
@@ -449,65 +460,124 @@ module.exports = function (chai, _) {
|
|
|
449
460
|
* @api public
|
|
450
461
|
*/
|
|
451
462
|
|
|
452
|
-
function
|
|
453
|
-
|
|
463
|
+
function SameValueZero(a, b) {
|
|
464
|
+
return (_.isNaN(a) && _.isNaN(b)) || a === b;
|
|
454
465
|
}
|
|
455
466
|
|
|
456
|
-
function
|
|
457
|
-
|
|
458
|
-
return _.eql(arrVal, val);
|
|
459
|
-
});
|
|
467
|
+
function includeChainingBehavior () {
|
|
468
|
+
flag(this, 'contains', true);
|
|
460
469
|
}
|
|
461
470
|
|
|
462
471
|
function include (val, msg) {
|
|
463
472
|
if (msg) flag(this, 'message', msg);
|
|
464
473
|
|
|
465
|
-
_.expectTypes(this, ['array', 'object', 'string'], flag(this, 'ssfi'));
|
|
466
|
-
|
|
467
474
|
var obj = flag(this, 'object')
|
|
468
475
|
, objType = _.type(obj).toLowerCase()
|
|
476
|
+
, flagMsg = flag(this, 'message')
|
|
477
|
+
, negate = flag(this, 'negate')
|
|
478
|
+
, ssfi = flag(this, 'ssfi')
|
|
469
479
|
, isDeep = flag(this, 'deep')
|
|
470
480
|
, descriptor = isDeep ? 'deep ' : '';
|
|
471
481
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
482
|
+
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
|
483
|
+
|
|
484
|
+
var included = false;
|
|
485
|
+
|
|
486
|
+
switch (objType) {
|
|
487
|
+
case 'string':
|
|
488
|
+
included = obj.indexOf(val) !== -1;
|
|
489
|
+
break;
|
|
490
|
+
|
|
491
|
+
case 'weakset':
|
|
492
|
+
if (isDeep) {
|
|
493
|
+
throw new AssertionError(
|
|
494
|
+
flagMsg + 'unable to use .deep.include with WeakSet',
|
|
495
|
+
undefined,
|
|
496
|
+
ssfi
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
included = obj.has(val);
|
|
501
|
+
break;
|
|
502
|
+
|
|
503
|
+
case 'map':
|
|
504
|
+
var isEql = isDeep ? _.eql : SameValueZero;
|
|
505
|
+
obj.forEach(function (item) {
|
|
506
|
+
included = included || isEql(item, val);
|
|
507
|
+
});
|
|
508
|
+
break;
|
|
509
|
+
|
|
510
|
+
case 'set':
|
|
511
|
+
if (isDeep) {
|
|
512
|
+
obj.forEach(function (item) {
|
|
513
|
+
included = included || _.eql(item, val);
|
|
514
|
+
});
|
|
515
|
+
} else {
|
|
516
|
+
included = obj.has(val);
|
|
487
517
|
}
|
|
518
|
+
break;
|
|
488
519
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
520
|
+
case 'array':
|
|
521
|
+
if (isDeep) {
|
|
522
|
+
included = obj.some(function (item) {
|
|
523
|
+
return _.eql(item, val);
|
|
524
|
+
})
|
|
525
|
+
} else {
|
|
526
|
+
included = obj.indexOf(val) !== -1;
|
|
527
|
+
}
|
|
528
|
+
break;
|
|
529
|
+
|
|
530
|
+
default:
|
|
531
|
+
// This block is for asserting a subset of properties in an object.
|
|
532
|
+
// `_.expectTypes` isn't used here because `.include` should work with
|
|
533
|
+
// objects with a custom `@@toStringTag`.
|
|
534
|
+
if (val !== Object(val)) {
|
|
535
|
+
throw new AssertionError(
|
|
536
|
+
flagMsg + 'object tested must be an array, a map, an object,'
|
|
537
|
+
+ ' a set, a string, or a weakset, but ' + objType + ' given',
|
|
538
|
+
undefined,
|
|
539
|
+
ssfi
|
|
540
|
+
);
|
|
495
541
|
}
|
|
496
|
-
}, this);
|
|
497
542
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
543
|
+
var props = Object.keys(val)
|
|
544
|
+
, firstErr = null
|
|
545
|
+
, numErrs = 0;
|
|
546
|
+
|
|
547
|
+
props.forEach(function (prop) {
|
|
548
|
+
var propAssertion = new Assertion(obj);
|
|
549
|
+
_.transferFlags(this, propAssertion, true);
|
|
550
|
+
flag(propAssertion, 'lockSsfi', true);
|
|
503
551
|
|
|
504
|
-
|
|
552
|
+
if (!negate || props.length === 1) {
|
|
553
|
+
propAssertion.property(prop, val[prop]);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
try {
|
|
558
|
+
propAssertion.property(prop, val[prop]);
|
|
559
|
+
} catch (err) {
|
|
560
|
+
if (!_.checkError.compatibleConstructor(err, AssertionError)) {
|
|
561
|
+
throw err;
|
|
562
|
+
}
|
|
563
|
+
if (firstErr === null) firstErr = err;
|
|
564
|
+
numErrs++;
|
|
565
|
+
}
|
|
566
|
+
}, this);
|
|
567
|
+
|
|
568
|
+
// When validating .not.include with multiple properties, we only want
|
|
569
|
+
// to throw an assertion error if all of the properties are included,
|
|
570
|
+
// in which case we throw the first property assertion error that we
|
|
571
|
+
// encountered.
|
|
572
|
+
if (negate && props.length > 1 && numErrs === props.length) {
|
|
573
|
+
throw firstErr;
|
|
574
|
+
}
|
|
575
|
+
return;
|
|
505
576
|
}
|
|
506
577
|
|
|
507
|
-
// Assert inclusion in
|
|
578
|
+
// Assert inclusion in collection or substring in a string.
|
|
508
579
|
this.assert(
|
|
509
|
-
|
|
510
|
-
: isDeepIncluded(obj, val)
|
|
580
|
+
included
|
|
511
581
|
, 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
|
|
512
582
|
, 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
|
|
513
583
|
}
|
|
@@ -520,9 +590,9 @@ module.exports = function (chai, _) {
|
|
|
520
590
|
/**
|
|
521
591
|
* ### .ok
|
|
522
592
|
*
|
|
523
|
-
* Asserts that the target is
|
|
524
|
-
* often best to assert that the target is strictly (`===`) or
|
|
525
|
-
* its expected value.
|
|
593
|
+
* Asserts that the target is a truthy value (considered `true` in boolean context).
|
|
594
|
+
* However, it's often best to assert that the target is strictly (`===`) or
|
|
595
|
+
* deeply equal to its expected value.
|
|
526
596
|
*
|
|
527
597
|
* expect(1).to.equal(1); // Recommended
|
|
528
598
|
* expect(1).to.be.ok; // Not recommended
|
|
@@ -906,7 +976,7 @@ module.exports = function (chai, _) {
|
|
|
906
976
|
*
|
|
907
977
|
* expect(1).to.equal(1);
|
|
908
978
|
* expect('foo').to.equal('foo');
|
|
909
|
-
*
|
|
979
|
+
*
|
|
910
980
|
* Add `.deep` earlier in the chain to use deep equality instead. See the
|
|
911
981
|
* `deep-eql` project page for info on the deep equality algorithm:
|
|
912
982
|
* https://github.com/chaijs/deep-eql.
|
|
@@ -948,7 +1018,10 @@ module.exports = function (chai, _) {
|
|
|
948
1018
|
if (msg) flag(this, 'message', msg);
|
|
949
1019
|
var obj = flag(this, 'object');
|
|
950
1020
|
if (flag(this, 'deep')) {
|
|
951
|
-
|
|
1021
|
+
var prevLockSsfi = flag(this, 'lockSsfi');
|
|
1022
|
+
flag(this, 'lockSsfi', true);
|
|
1023
|
+
this.eql(val);
|
|
1024
|
+
flag(this, 'lockSsfi', prevLockSsfi);
|
|
952
1025
|
} else {
|
|
953
1026
|
this.assert(
|
|
954
1027
|
val === obj
|
|
@@ -1024,15 +1097,15 @@ module.exports = function (chai, _) {
|
|
|
1024
1097
|
/**
|
|
1025
1098
|
* ### .above(n[, msg])
|
|
1026
1099
|
*
|
|
1027
|
-
* Asserts that the target is a number greater than the given number `n
|
|
1100
|
+
* Asserts that the target is a number or a date greater than the given number or date `n` respectively.
|
|
1028
1101
|
* However, it's often best to assert that the target is equal to its expected
|
|
1029
1102
|
* value.
|
|
1030
1103
|
*
|
|
1031
1104
|
* expect(2).to.equal(2); // Recommended
|
|
1032
1105
|
* expect(2).to.be.above(1); // Not recommended
|
|
1033
1106
|
*
|
|
1034
|
-
* Add `.lengthOf` earlier in the chain to assert that the
|
|
1035
|
-
*
|
|
1107
|
+
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
|
|
1108
|
+
* or `size` is greater than the given number `n`.
|
|
1036
1109
|
*
|
|
1037
1110
|
* expect('foo').to.have.lengthOf(3); // Recommended
|
|
1038
1111
|
* expect('foo').to.have.lengthOf.above(2); // Not recommended
|
|
@@ -1069,37 +1142,54 @@ module.exports = function (chai, _) {
|
|
|
1069
1142
|
var obj = flag(this, 'object')
|
|
1070
1143
|
, doLength = flag(this, 'doLength')
|
|
1071
1144
|
, flagMsg = flag(this, 'message')
|
|
1072
|
-
,
|
|
1145
|
+
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
|
1146
|
+
, ssfi = flag(this, 'ssfi')
|
|
1147
|
+
, objType = _.type(obj).toLowerCase()
|
|
1148
|
+
, nType = _.type(n).toLowerCase()
|
|
1149
|
+
, errorMessage
|
|
1150
|
+
, shouldThrow = true;
|
|
1073
1151
|
|
|
1074
|
-
if (doLength) {
|
|
1152
|
+
if (doLength && objType !== 'map' && objType !== 'set') {
|
|
1075
1153
|
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
|
1157
|
+
errorMessage = msgPrefix + 'the argument to above must be a date';
|
|
1158
|
+
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
|
1159
|
+
errorMessage = msgPrefix + 'the argument to above must be a number';
|
|
1160
|
+
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
|
1161
|
+
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
|
1162
|
+
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
|
1076
1163
|
} else {
|
|
1077
|
-
|
|
1164
|
+
shouldThrow = false;
|
|
1078
1165
|
}
|
|
1079
1166
|
|
|
1080
|
-
if (
|
|
1081
|
-
|
|
1082
|
-
throw new AssertionError(
|
|
1083
|
-
flagMsg + 'the argument to above must be a number',
|
|
1084
|
-
undefined,
|
|
1085
|
-
ssfi
|
|
1086
|
-
);
|
|
1167
|
+
if (shouldThrow) {
|
|
1168
|
+
throw new AssertionError(errorMessage, undefined, ssfi);
|
|
1087
1169
|
}
|
|
1088
1170
|
|
|
1089
1171
|
if (doLength) {
|
|
1090
|
-
var
|
|
1172
|
+
var descriptor = 'length'
|
|
1173
|
+
, itemsCount;
|
|
1174
|
+
if (objType === 'map' || objType === 'set') {
|
|
1175
|
+
descriptor = 'size';
|
|
1176
|
+
itemsCount = obj.size;
|
|
1177
|
+
} else {
|
|
1178
|
+
itemsCount = obj.length;
|
|
1179
|
+
}
|
|
1091
1180
|
this.assert(
|
|
1092
|
-
|
|
1093
|
-
, 'expected #{this} to have a
|
|
1094
|
-
, 'expected #{this} to not have a
|
|
1181
|
+
itemsCount > n
|
|
1182
|
+
, 'expected #{this} to have a ' + descriptor + ' above #{exp} but got #{act}'
|
|
1183
|
+
, 'expected #{this} to not have a ' + descriptor + ' above #{exp}'
|
|
1095
1184
|
, n
|
|
1096
|
-
,
|
|
1185
|
+
, itemsCount
|
|
1097
1186
|
);
|
|
1098
1187
|
} else {
|
|
1099
1188
|
this.assert(
|
|
1100
1189
|
obj > n
|
|
1101
|
-
, 'expected #{this} to be above '
|
|
1102
|
-
, 'expected #{this} to be at most '
|
|
1190
|
+
, 'expected #{this} to be above #{exp}'
|
|
1191
|
+
, 'expected #{this} to be at most #{exp}'
|
|
1192
|
+
, n
|
|
1103
1193
|
);
|
|
1104
1194
|
}
|
|
1105
1195
|
}
|
|
@@ -1111,17 +1201,16 @@ module.exports = function (chai, _) {
|
|
|
1111
1201
|
/**
|
|
1112
1202
|
* ### .least(n[, msg])
|
|
1113
1203
|
*
|
|
1114
|
-
* Asserts that the target is a number greater than or equal to the given
|
|
1115
|
-
* number `n
|
|
1204
|
+
* Asserts that the target is a number or a date greater than or equal to the given
|
|
1205
|
+
* number or date `n` respectively. However, it's often best to assert that the target is equal to
|
|
1116
1206
|
* its expected value.
|
|
1117
1207
|
*
|
|
1118
1208
|
* expect(2).to.equal(2); // Recommended
|
|
1119
1209
|
* expect(2).to.be.at.least(1); // Not recommended
|
|
1120
1210
|
* expect(2).to.be.at.least(2); // Not recommended
|
|
1121
1211
|
*
|
|
1122
|
-
* Add `.lengthOf` earlier in the chain to assert that the
|
|
1123
|
-
*
|
|
1124
|
-
* `n`.
|
|
1212
|
+
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
|
|
1213
|
+
* or `size` is greater than or equal to the given number `n`.
|
|
1125
1214
|
*
|
|
1126
1215
|
* expect('foo').to.have.lengthOf(3); // Recommended
|
|
1127
1216
|
* expect('foo').to.have.lengthOf.at.least(2); // Not recommended
|
|
@@ -1156,37 +1245,54 @@ module.exports = function (chai, _) {
|
|
|
1156
1245
|
var obj = flag(this, 'object')
|
|
1157
1246
|
, doLength = flag(this, 'doLength')
|
|
1158
1247
|
, flagMsg = flag(this, 'message')
|
|
1159
|
-
,
|
|
1248
|
+
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
|
1249
|
+
, ssfi = flag(this, 'ssfi')
|
|
1250
|
+
, objType = _.type(obj).toLowerCase()
|
|
1251
|
+
, nType = _.type(n).toLowerCase()
|
|
1252
|
+
, errorMessage
|
|
1253
|
+
, shouldThrow = true;
|
|
1160
1254
|
|
|
1161
|
-
if (doLength) {
|
|
1255
|
+
if (doLength && objType !== 'map' && objType !== 'set') {
|
|
1162
1256
|
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
|
1260
|
+
errorMessage = msgPrefix + 'the argument to least must be a date';
|
|
1261
|
+
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
|
1262
|
+
errorMessage = msgPrefix + 'the argument to least must be a number';
|
|
1263
|
+
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
|
1264
|
+
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
|
1265
|
+
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
|
1163
1266
|
} else {
|
|
1164
|
-
|
|
1267
|
+
shouldThrow = false;
|
|
1165
1268
|
}
|
|
1166
1269
|
|
|
1167
|
-
if (
|
|
1168
|
-
|
|
1169
|
-
throw new AssertionError(
|
|
1170
|
-
flagMsg + 'the argument to least must be a number',
|
|
1171
|
-
undefined,
|
|
1172
|
-
ssfi
|
|
1173
|
-
);
|
|
1270
|
+
if (shouldThrow) {
|
|
1271
|
+
throw new AssertionError(errorMessage, undefined, ssfi);
|
|
1174
1272
|
}
|
|
1175
1273
|
|
|
1176
1274
|
if (doLength) {
|
|
1177
|
-
var
|
|
1275
|
+
var descriptor = 'length'
|
|
1276
|
+
, itemsCount;
|
|
1277
|
+
if (objType === 'map' || objType === 'set') {
|
|
1278
|
+
descriptor = 'size';
|
|
1279
|
+
itemsCount = obj.size;
|
|
1280
|
+
} else {
|
|
1281
|
+
itemsCount = obj.length;
|
|
1282
|
+
}
|
|
1178
1283
|
this.assert(
|
|
1179
|
-
|
|
1180
|
-
, 'expected #{this} to have a
|
|
1181
|
-
, 'expected #{this} to have a
|
|
1284
|
+
itemsCount >= n
|
|
1285
|
+
, 'expected #{this} to have a ' + descriptor + ' at least #{exp} but got #{act}'
|
|
1286
|
+
, 'expected #{this} to have a ' + descriptor + ' below #{exp}'
|
|
1182
1287
|
, n
|
|
1183
|
-
,
|
|
1288
|
+
, itemsCount
|
|
1184
1289
|
);
|
|
1185
1290
|
} else {
|
|
1186
1291
|
this.assert(
|
|
1187
1292
|
obj >= n
|
|
1188
|
-
, 'expected #{this} to be at least '
|
|
1189
|
-
, 'expected #{this} to be below '
|
|
1293
|
+
, 'expected #{this} to be at least #{exp}'
|
|
1294
|
+
, 'expected #{this} to be below #{exp}'
|
|
1295
|
+
, n
|
|
1190
1296
|
);
|
|
1191
1297
|
}
|
|
1192
1298
|
}
|
|
@@ -1197,15 +1303,15 @@ module.exports = function (chai, _) {
|
|
|
1197
1303
|
/**
|
|
1198
1304
|
* ### .below(n[, msg])
|
|
1199
1305
|
*
|
|
1200
|
-
* Asserts that the target is a number less than the given number `n
|
|
1306
|
+
* Asserts that the target is a number or a date less than the given number or date `n` respectively.
|
|
1201
1307
|
* However, it's often best to assert that the target is equal to its expected
|
|
1202
1308
|
* value.
|
|
1203
1309
|
*
|
|
1204
1310
|
* expect(1).to.equal(1); // Recommended
|
|
1205
1311
|
* expect(1).to.be.below(2); // Not recommended
|
|
1206
1312
|
*
|
|
1207
|
-
* Add `.lengthOf` earlier in the chain to assert that the
|
|
1208
|
-
*
|
|
1313
|
+
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
|
|
1314
|
+
* or `size` is less than the given number `n`.
|
|
1209
1315
|
*
|
|
1210
1316
|
* expect('foo').to.have.lengthOf(3); // Recommended
|
|
1211
1317
|
* expect('foo').to.have.lengthOf.below(4); // Not recommended
|
|
@@ -1242,37 +1348,54 @@ module.exports = function (chai, _) {
|
|
|
1242
1348
|
var obj = flag(this, 'object')
|
|
1243
1349
|
, doLength = flag(this, 'doLength')
|
|
1244
1350
|
, flagMsg = flag(this, 'message')
|
|
1245
|
-
,
|
|
1351
|
+
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
|
1352
|
+
, ssfi = flag(this, 'ssfi')
|
|
1353
|
+
, objType = _.type(obj).toLowerCase()
|
|
1354
|
+
, nType = _.type(n).toLowerCase()
|
|
1355
|
+
, errorMessage
|
|
1356
|
+
, shouldThrow = true;
|
|
1246
1357
|
|
|
1247
|
-
if (doLength) {
|
|
1358
|
+
if (doLength && objType !== 'map' && objType !== 'set') {
|
|
1248
1359
|
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
|
1363
|
+
errorMessage = msgPrefix + 'the argument to below must be a date';
|
|
1364
|
+
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
|
1365
|
+
errorMessage = msgPrefix + 'the argument to below must be a number';
|
|
1366
|
+
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
|
1367
|
+
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
|
1368
|
+
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
|
1249
1369
|
} else {
|
|
1250
|
-
|
|
1370
|
+
shouldThrow = false;
|
|
1251
1371
|
}
|
|
1252
1372
|
|
|
1253
|
-
if (
|
|
1254
|
-
|
|
1255
|
-
throw new AssertionError(
|
|
1256
|
-
flagMsg + 'the argument to below must be a number',
|
|
1257
|
-
undefined,
|
|
1258
|
-
ssfi
|
|
1259
|
-
);
|
|
1373
|
+
if (shouldThrow) {
|
|
1374
|
+
throw new AssertionError(errorMessage, undefined, ssfi);
|
|
1260
1375
|
}
|
|
1261
1376
|
|
|
1262
1377
|
if (doLength) {
|
|
1263
|
-
var
|
|
1378
|
+
var descriptor = 'length'
|
|
1379
|
+
, itemsCount;
|
|
1380
|
+
if (objType === 'map' || objType === 'set') {
|
|
1381
|
+
descriptor = 'size';
|
|
1382
|
+
itemsCount = obj.size;
|
|
1383
|
+
} else {
|
|
1384
|
+
itemsCount = obj.length;
|
|
1385
|
+
}
|
|
1264
1386
|
this.assert(
|
|
1265
|
-
|
|
1266
|
-
, 'expected #{this} to have a
|
|
1267
|
-
, 'expected #{this} to not have a
|
|
1387
|
+
itemsCount < n
|
|
1388
|
+
, 'expected #{this} to have a ' + descriptor + ' below #{exp} but got #{act}'
|
|
1389
|
+
, 'expected #{this} to not have a ' + descriptor + ' below #{exp}'
|
|
1268
1390
|
, n
|
|
1269
|
-
,
|
|
1391
|
+
, itemsCount
|
|
1270
1392
|
);
|
|
1271
1393
|
} else {
|
|
1272
1394
|
this.assert(
|
|
1273
1395
|
obj < n
|
|
1274
|
-
, 'expected #{this} to be below '
|
|
1275
|
-
, 'expected #{this} to be at least '
|
|
1396
|
+
, 'expected #{this} to be below #{exp}'
|
|
1397
|
+
, 'expected #{this} to be at least #{exp}'
|
|
1398
|
+
, n
|
|
1276
1399
|
);
|
|
1277
1400
|
}
|
|
1278
1401
|
}
|
|
@@ -1284,16 +1407,16 @@ module.exports = function (chai, _) {
|
|
|
1284
1407
|
/**
|
|
1285
1408
|
* ### .most(n[, msg])
|
|
1286
1409
|
*
|
|
1287
|
-
* Asserts that the target is a number less than or equal to the given number
|
|
1288
|
-
* `n
|
|
1410
|
+
* Asserts that the target is a number or a date less than or equal to the given number
|
|
1411
|
+
* or date `n` respectively. However, it's often best to assert that the target is equal to its
|
|
1289
1412
|
* expected value.
|
|
1290
1413
|
*
|
|
1291
1414
|
* expect(1).to.equal(1); // Recommended
|
|
1292
1415
|
* expect(1).to.be.at.most(2); // Not recommended
|
|
1293
1416
|
* expect(1).to.be.at.most(1); // Not recommended
|
|
1294
1417
|
*
|
|
1295
|
-
* Add `.lengthOf` earlier in the chain to assert that the
|
|
1296
|
-
*
|
|
1418
|
+
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
|
|
1419
|
+
* or `size` is less than or equal to the given number `n`.
|
|
1297
1420
|
*
|
|
1298
1421
|
* expect('foo').to.have.lengthOf(3); // Recommended
|
|
1299
1422
|
* expect('foo').to.have.lengthOf.at.most(4); // Not recommended
|
|
@@ -1328,37 +1451,54 @@ module.exports = function (chai, _) {
|
|
|
1328
1451
|
var obj = flag(this, 'object')
|
|
1329
1452
|
, doLength = flag(this, 'doLength')
|
|
1330
1453
|
, flagMsg = flag(this, 'message')
|
|
1331
|
-
,
|
|
1454
|
+
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
|
1455
|
+
, ssfi = flag(this, 'ssfi')
|
|
1456
|
+
, objType = _.type(obj).toLowerCase()
|
|
1457
|
+
, nType = _.type(n).toLowerCase()
|
|
1458
|
+
, errorMessage
|
|
1459
|
+
, shouldThrow = true;
|
|
1332
1460
|
|
|
1333
|
-
if (doLength) {
|
|
1461
|
+
if (doLength && objType !== 'map' && objType !== 'set') {
|
|
1334
1462
|
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
|
1466
|
+
errorMessage = msgPrefix + 'the argument to most must be a date';
|
|
1467
|
+
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
|
1468
|
+
errorMessage = msgPrefix + 'the argument to most must be a number';
|
|
1469
|
+
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
|
1470
|
+
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
|
1471
|
+
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
|
1335
1472
|
} else {
|
|
1336
|
-
|
|
1473
|
+
shouldThrow = false;
|
|
1337
1474
|
}
|
|
1338
1475
|
|
|
1339
|
-
if (
|
|
1340
|
-
|
|
1341
|
-
throw new AssertionError(
|
|
1342
|
-
flagMsg + 'the argument to most must be a number',
|
|
1343
|
-
undefined,
|
|
1344
|
-
ssfi
|
|
1345
|
-
);
|
|
1476
|
+
if (shouldThrow) {
|
|
1477
|
+
throw new AssertionError(errorMessage, undefined, ssfi);
|
|
1346
1478
|
}
|
|
1347
1479
|
|
|
1348
1480
|
if (doLength) {
|
|
1349
|
-
var
|
|
1481
|
+
var descriptor = 'length'
|
|
1482
|
+
, itemsCount;
|
|
1483
|
+
if (objType === 'map' || objType === 'set') {
|
|
1484
|
+
descriptor = 'size';
|
|
1485
|
+
itemsCount = obj.size;
|
|
1486
|
+
} else {
|
|
1487
|
+
itemsCount = obj.length;
|
|
1488
|
+
}
|
|
1350
1489
|
this.assert(
|
|
1351
|
-
|
|
1352
|
-
, 'expected #{this} to have a
|
|
1353
|
-
, 'expected #{this} to have a
|
|
1490
|
+
itemsCount <= n
|
|
1491
|
+
, 'expected #{this} to have a ' + descriptor + ' at most #{exp} but got #{act}'
|
|
1492
|
+
, 'expected #{this} to have a ' + descriptor + ' above #{exp}'
|
|
1354
1493
|
, n
|
|
1355
|
-
,
|
|
1494
|
+
, itemsCount
|
|
1356
1495
|
);
|
|
1357
1496
|
} else {
|
|
1358
1497
|
this.assert(
|
|
1359
1498
|
obj <= n
|
|
1360
|
-
, 'expected #{this} to be at most '
|
|
1361
|
-
, 'expected #{this} to be above '
|
|
1499
|
+
, 'expected #{this} to be at most #{exp}'
|
|
1500
|
+
, 'expected #{this} to be above #{exp}'
|
|
1501
|
+
, n
|
|
1362
1502
|
);
|
|
1363
1503
|
}
|
|
1364
1504
|
}
|
|
@@ -1369,8 +1509,8 @@ module.exports = function (chai, _) {
|
|
|
1369
1509
|
/**
|
|
1370
1510
|
* ### .within(start, finish[, msg])
|
|
1371
1511
|
*
|
|
1372
|
-
* Asserts that the target is a number greater than or equal to the given
|
|
1373
|
-
* number `start`, and less than or equal to the given number `finish
|
|
1512
|
+
* Asserts that the target is a number or a date greater than or equal to the given
|
|
1513
|
+
* number or date `start`, and less than or equal to the given number or date `finish` respectively.
|
|
1374
1514
|
* However, it's often best to assert that the target is equal to its expected
|
|
1375
1515
|
* value.
|
|
1376
1516
|
*
|
|
@@ -1379,9 +1519,9 @@ module.exports = function (chai, _) {
|
|
|
1379
1519
|
* expect(2).to.be.within(2, 3); // Not recommended
|
|
1380
1520
|
* expect(2).to.be.within(1, 2); // Not recommended
|
|
1381
1521
|
*
|
|
1382
|
-
* Add `.lengthOf` earlier in the chain to assert that the
|
|
1383
|
-
*
|
|
1384
|
-
*
|
|
1522
|
+
* Add `.lengthOf` earlier in the chain to assert that the target's `length`
|
|
1523
|
+
* or `size` is greater than or equal to the given number `start`, and less
|
|
1524
|
+
* than or equal to the given number `finish`.
|
|
1385
1525
|
*
|
|
1386
1526
|
* expect('foo').to.have.lengthOf(3); // Recommended
|
|
1387
1527
|
* expect('foo').to.have.lengthOf.within(2, 4); // Not recommended
|
|
@@ -1412,32 +1552,51 @@ module.exports = function (chai, _) {
|
|
|
1412
1552
|
Assertion.addMethod('within', function (start, finish, msg) {
|
|
1413
1553
|
if (msg) flag(this, 'message', msg);
|
|
1414
1554
|
var obj = flag(this, 'object')
|
|
1415
|
-
, range = start + '..' + finish
|
|
1416
1555
|
, doLength = flag(this, 'doLength')
|
|
1417
1556
|
, flagMsg = flag(this, 'message')
|
|
1418
|
-
,
|
|
1419
|
-
|
|
1420
|
-
|
|
1557
|
+
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
|
1558
|
+
, ssfi = flag(this, 'ssfi')
|
|
1559
|
+
, objType = _.type(obj).toLowerCase()
|
|
1560
|
+
, startType = _.type(start).toLowerCase()
|
|
1561
|
+
, finishType = _.type(finish).toLowerCase()
|
|
1562
|
+
, errorMessage
|
|
1563
|
+
, shouldThrow = true
|
|
1564
|
+
, range = (startType === 'date' && finishType === 'date')
|
|
1565
|
+
? start.toUTCString() + '..' + finish.toUTCString()
|
|
1566
|
+
: start + '..' + finish;
|
|
1567
|
+
|
|
1568
|
+
if (doLength && objType !== 'map' && objType !== 'set') {
|
|
1421
1569
|
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {
|
|
1573
|
+
errorMessage = msgPrefix + 'the arguments to within must be dates';
|
|
1574
|
+
} else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) {
|
|
1575
|
+
errorMessage = msgPrefix + 'the arguments to within must be numbers';
|
|
1576
|
+
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
|
1577
|
+
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
|
1578
|
+
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
|
1422
1579
|
} else {
|
|
1423
|
-
|
|
1580
|
+
shouldThrow = false;
|
|
1424
1581
|
}
|
|
1425
1582
|
|
|
1426
|
-
if (
|
|
1427
|
-
|
|
1428
|
-
throw new AssertionError(
|
|
1429
|
-
flagMsg + 'the arguments to within must be numbers',
|
|
1430
|
-
undefined,
|
|
1431
|
-
ssfi
|
|
1432
|
-
);
|
|
1583
|
+
if (shouldThrow) {
|
|
1584
|
+
throw new AssertionError(errorMessage, undefined, ssfi);
|
|
1433
1585
|
}
|
|
1434
1586
|
|
|
1435
1587
|
if (doLength) {
|
|
1436
|
-
var
|
|
1588
|
+
var descriptor = 'length'
|
|
1589
|
+
, itemsCount;
|
|
1590
|
+
if (objType === 'map' || objType === 'set') {
|
|
1591
|
+
descriptor = 'size';
|
|
1592
|
+
itemsCount = obj.size;
|
|
1593
|
+
} else {
|
|
1594
|
+
itemsCount = obj.length;
|
|
1595
|
+
}
|
|
1437
1596
|
this.assert(
|
|
1438
|
-
|
|
1439
|
-
, 'expected #{this} to have a
|
|
1440
|
-
, 'expected #{this} to not have a
|
|
1597
|
+
itemsCount >= start && itemsCount <= finish
|
|
1598
|
+
, 'expected #{this} to have a ' + descriptor + ' within ' + range
|
|
1599
|
+
, 'expected #{this} to not have a ' + descriptor + ' within ' + range
|
|
1441
1600
|
);
|
|
1442
1601
|
} else {
|
|
1443
1602
|
this.assert(
|
|
@@ -1493,28 +1652,25 @@ module.exports = function (chai, _) {
|
|
|
1493
1652
|
var target = flag(this, 'object')
|
|
1494
1653
|
var ssfi = flag(this, 'ssfi');
|
|
1495
1654
|
var flagMsg = flag(this, 'message');
|
|
1496
|
-
var validInstanceOfTarget = constructor === Object(constructor) && (
|
|
1497
|
-
typeof constructor === 'function' ||
|
|
1498
|
-
(typeof Symbol !== 'undefined' &&
|
|
1499
|
-
typeof Symbol.hasInstance !== 'undefined' &&
|
|
1500
|
-
Symbol.hasInstance in constructor)
|
|
1501
|
-
);
|
|
1502
1655
|
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
flagMsg
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1656
|
+
try {
|
|
1657
|
+
var isInstanceOf = target instanceof constructor;
|
|
1658
|
+
} catch (err) {
|
|
1659
|
+
if (err instanceof TypeError) {
|
|
1660
|
+
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
|
1661
|
+
throw new AssertionError(
|
|
1662
|
+
flagMsg + 'The instanceof assertion needs a constructor but '
|
|
1663
|
+
+ _.type(constructor) + ' was given.',
|
|
1664
|
+
undefined,
|
|
1665
|
+
ssfi
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
throw err;
|
|
1511
1669
|
}
|
|
1512
1670
|
|
|
1513
|
-
var isInstanceOf = target instanceof constructor
|
|
1514
|
-
|
|
1515
1671
|
var name = _.getName(constructor);
|
|
1516
1672
|
if (name === null) {
|
|
1517
|
-
|
|
1673
|
+
name = 'an unnamed constructor';
|
|
1518
1674
|
}
|
|
1519
1675
|
|
|
1520
1676
|
this.assert(
|
|
@@ -1556,7 +1712,8 @@ module.exports = function (chai, _) {
|
|
|
1556
1712
|
*
|
|
1557
1713
|
* expect({a: 1}).to.have.own.property('a');
|
|
1558
1714
|
* expect({a: 1}).to.have.own.property('a', 1);
|
|
1559
|
-
* expect({a: 1}).to.have.property('b')
|
|
1715
|
+
* expect({a: 1}).to.have.property('b');
|
|
1716
|
+
* expect({a: 1}).to.not.have.own.property('b');
|
|
1560
1717
|
*
|
|
1561
1718
|
* `.deep` and `.own` can be combined.
|
|
1562
1719
|
*
|
|
@@ -1583,7 +1740,7 @@ module.exports = function (chai, _) {
|
|
|
1583
1740
|
* Add `.not` earlier in the chain to negate `.property`.
|
|
1584
1741
|
*
|
|
1585
1742
|
* expect({a: 1}).to.not.have.property('b');
|
|
1586
|
-
*
|
|
1743
|
+
*
|
|
1587
1744
|
* However, it's dangerous to negate `.property` when providing `val`. The
|
|
1588
1745
|
* problem is that it creates uncertain expectations by asserting that the
|
|
1589
1746
|
* target either doesn't have a property with the given key `name`, or that it
|
|
@@ -1621,7 +1778,7 @@ module.exports = function (chai, _) {
|
|
|
1621
1778
|
*
|
|
1622
1779
|
* // Not recommended
|
|
1623
1780
|
* expect({a: 1}).to.have.property('b', undefined, 'nooo why fail??');
|
|
1624
|
-
*
|
|
1781
|
+
*
|
|
1625
1782
|
* The above assertion isn't the same thing as not providing `val`. Instead,
|
|
1626
1783
|
* it's asserting that the target object has a `b` property that's equal to
|
|
1627
1784
|
* `undefined`.
|
|
@@ -1644,10 +1801,31 @@ module.exports = function (chai, _) {
|
|
|
1644
1801
|
var isNested = flag(this, 'nested')
|
|
1645
1802
|
, isOwn = flag(this, 'own')
|
|
1646
1803
|
, flagMsg = flag(this, 'message')
|
|
1647
|
-
,
|
|
1804
|
+
, obj = flag(this, 'object')
|
|
1805
|
+
, ssfi = flag(this, 'ssfi')
|
|
1806
|
+
, nameType = typeof name;
|
|
1807
|
+
|
|
1808
|
+
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
|
1809
|
+
|
|
1810
|
+
if (isNested) {
|
|
1811
|
+
if (nameType !== 'string') {
|
|
1812
|
+
throw new AssertionError(
|
|
1813
|
+
flagMsg + 'the argument to property must be a string when using nested syntax',
|
|
1814
|
+
undefined,
|
|
1815
|
+
ssfi
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
} else {
|
|
1819
|
+
if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') {
|
|
1820
|
+
throw new AssertionError(
|
|
1821
|
+
flagMsg + 'the argument to property must be a string, number, or symbol',
|
|
1822
|
+
undefined,
|
|
1823
|
+
ssfi
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1648
1827
|
|
|
1649
1828
|
if (isNested && isOwn) {
|
|
1650
|
-
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
|
1651
1829
|
throw new AssertionError(
|
|
1652
1830
|
flagMsg + 'The "nested" and "own" flags cannot be combined.',
|
|
1653
1831
|
undefined,
|
|
@@ -1655,9 +1833,16 @@ module.exports = function (chai, _) {
|
|
|
1655
1833
|
);
|
|
1656
1834
|
}
|
|
1657
1835
|
|
|
1836
|
+
if (obj === null || obj === undefined) {
|
|
1837
|
+
throw new AssertionError(
|
|
1838
|
+
flagMsg + 'Target cannot be null or undefined.',
|
|
1839
|
+
undefined,
|
|
1840
|
+
ssfi
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1658
1844
|
var isDeep = flag(this, 'deep')
|
|
1659
1845
|
, negate = flag(this, 'negate')
|
|
1660
|
-
, obj = flag(this, 'object')
|
|
1661
1846
|
, pathInfo = isNested ? _.getPathInfo(obj, name) : null
|
|
1662
1847
|
, value = isNested ? pathInfo.value : obj[name];
|
|
1663
1848
|
|
|
@@ -1731,7 +1916,7 @@ module.exports = function (chai, _) {
|
|
|
1731
1916
|
* Add `.not` earlier in the chain to negate `.ownPropertyDescriptor`.
|
|
1732
1917
|
*
|
|
1733
1918
|
* expect({a: 1}).to.not.have.ownPropertyDescriptor('b');
|
|
1734
|
-
*
|
|
1919
|
+
*
|
|
1735
1920
|
* However, it's dangerous to negate `.ownPropertyDescriptor` when providing
|
|
1736
1921
|
* a `descriptor`. The problem is that it creates uncertain expectations by
|
|
1737
1922
|
* asserting that the target either doesn't have a property descriptor with
|
|
@@ -1802,7 +1987,7 @@ module.exports = function (chai, _) {
|
|
|
1802
1987
|
* writable: true,
|
|
1803
1988
|
* value: 2,
|
|
1804
1989
|
* });
|
|
1805
|
-
*
|
|
1990
|
+
*
|
|
1806
1991
|
* // Recommended
|
|
1807
1992
|
* expect({a: 1}, 'nooo why fail??').to.have.ownPropertyDescriptor('b');
|
|
1808
1993
|
*
|
|
@@ -1859,11 +2044,13 @@ module.exports = function (chai, _) {
|
|
|
1859
2044
|
/**
|
|
1860
2045
|
* ### .lengthOf(n[, msg])
|
|
1861
2046
|
*
|
|
1862
|
-
* Asserts that the target's `length`
|
|
2047
|
+
* Asserts that the target's `length` or `size` is equal to the given number
|
|
1863
2048
|
* `n`.
|
|
1864
2049
|
*
|
|
1865
2050
|
* expect([1, 2, 3]).to.have.lengthOf(3);
|
|
1866
2051
|
* expect('foo').to.have.lengthOf(3);
|
|
2052
|
+
* expect(new Set([1, 2, 3])).to.have.lengthOf(3);
|
|
2053
|
+
* expect(new Map([['a', 1], ['b', 2], ['c', 3]])).to.have.lengthOf(3);
|
|
1867
2054
|
*
|
|
1868
2055
|
* Add `.not` earlier in the chain to negate `.lengthOf`. However, it's often
|
|
1869
2056
|
* best to assert that the target's `length` property is equal to its expected
|
|
@@ -1919,17 +2106,29 @@ module.exports = function (chai, _) {
|
|
|
1919
2106
|
function assertLength (n, msg) {
|
|
1920
2107
|
if (msg) flag(this, 'message', msg);
|
|
1921
2108
|
var obj = flag(this, 'object')
|
|
2109
|
+
, objType = _.type(obj).toLowerCase()
|
|
1922
2110
|
, flagMsg = flag(this, 'message')
|
|
1923
|
-
, ssfi = flag(this, 'ssfi')
|
|
1924
|
-
|
|
1925
|
-
|
|
2111
|
+
, ssfi = flag(this, 'ssfi')
|
|
2112
|
+
, descriptor = 'length'
|
|
2113
|
+
, itemsCount;
|
|
2114
|
+
|
|
2115
|
+
switch (objType) {
|
|
2116
|
+
case 'map':
|
|
2117
|
+
case 'set':
|
|
2118
|
+
descriptor = 'size';
|
|
2119
|
+
itemsCount = obj.size;
|
|
2120
|
+
break;
|
|
2121
|
+
default:
|
|
2122
|
+
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
|
2123
|
+
itemsCount = obj.length;
|
|
2124
|
+
}
|
|
1926
2125
|
|
|
1927
2126
|
this.assert(
|
|
1928
|
-
|
|
1929
|
-
, 'expected #{this} to have a
|
|
1930
|
-
, 'expected #{this} to not have a
|
|
2127
|
+
itemsCount == n
|
|
2128
|
+
, 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}'
|
|
2129
|
+
, 'expected #{this} to not have a ' + descriptor + ' of #{act}'
|
|
1931
2130
|
, n
|
|
1932
|
-
,
|
|
2131
|
+
, itemsCount
|
|
1933
2132
|
);
|
|
1934
2133
|
}
|
|
1935
2134
|
|
|
@@ -1991,8 +2190,8 @@ module.exports = function (chai, _) {
|
|
|
1991
2190
|
* message to show when the assertion fails. The message can also be given as
|
|
1992
2191
|
* the second argument to `expect`.
|
|
1993
2192
|
*
|
|
1994
|
-
* expect('foobar').to.have.string(
|
|
1995
|
-
* expect('foobar', 'nooo why fail??').to.have.string(
|
|
2193
|
+
* expect('foobar').to.have.string('taco', 'nooo why fail??');
|
|
2194
|
+
* expect('foobar', 'nooo why fail??').to.have.string('taco');
|
|
1996
2195
|
*
|
|
1997
2196
|
* @name string
|
|
1998
2197
|
* @param {String} str
|
|
@@ -2019,7 +2218,7 @@ module.exports = function (chai, _) {
|
|
|
2019
2218
|
* ### .keys(key1[, key2[, ...]])
|
|
2020
2219
|
*
|
|
2021
2220
|
* Asserts that the target object, array, map, or set has the given keys. Only
|
|
2022
|
-
* the target's own inherited properties are included in the search.
|
|
2221
|
+
* the target's own inherited properties are included in the search.
|
|
2023
2222
|
*
|
|
2024
2223
|
* When the target is an object or array, keys can be provided as one or more
|
|
2025
2224
|
* string arguments, a single array argument, or a single object argument. In
|
|
@@ -2127,6 +2326,7 @@ module.exports = function (chai, _) {
|
|
|
2127
2326
|
, isDeep = flag(this, 'deep')
|
|
2128
2327
|
, str
|
|
2129
2328
|
, deepStr = ''
|
|
2329
|
+
, actual
|
|
2130
2330
|
, ok = true
|
|
2131
2331
|
, flagMsg = flag(this, 'message');
|
|
2132
2332
|
|
|
@@ -2143,7 +2343,6 @@ module.exports = function (chai, _) {
|
|
|
2143
2343
|
if (keysType !== 'Array') {
|
|
2144
2344
|
keys = Array.prototype.slice.call(arguments);
|
|
2145
2345
|
}
|
|
2146
|
-
|
|
2147
2346
|
} else {
|
|
2148
2347
|
actual = _.getOwnEnumerableProperties(obj);
|
|
2149
2348
|
|
|
@@ -2176,8 +2375,7 @@ module.exports = function (chai, _) {
|
|
|
2176
2375
|
var len = keys.length
|
|
2177
2376
|
, any = flag(this, 'any')
|
|
2178
2377
|
, all = flag(this, 'all')
|
|
2179
|
-
, expected = keys
|
|
2180
|
-
, actual;
|
|
2378
|
+
, expected = keys;
|
|
2181
2379
|
|
|
2182
2380
|
if (!any && !all) {
|
|
2183
2381
|
all = true;
|
|
@@ -2254,7 +2452,7 @@ module.exports = function (chai, _) {
|
|
|
2254
2452
|
*
|
|
2255
2453
|
* When no arguments are provided, `.throw` invokes the target function and
|
|
2256
2454
|
* asserts that an error is thrown.
|
|
2257
|
-
*
|
|
2455
|
+
*
|
|
2258
2456
|
* var badFn = function () { throw new TypeError('Illegal salmon!'); };
|
|
2259
2457
|
*
|
|
2260
2458
|
* expect(badFn).to.throw();
|
|
@@ -2306,11 +2504,11 @@ module.exports = function (chai, _) {
|
|
|
2306
2504
|
* expect(badFn).to.throw(err, /salmon/);
|
|
2307
2505
|
*
|
|
2308
2506
|
* Add `.not` earlier in the chain to negate `.throw`.
|
|
2309
|
-
*
|
|
2507
|
+
*
|
|
2310
2508
|
* var goodFn = function () {};
|
|
2311
2509
|
*
|
|
2312
2510
|
* expect(goodFn).to.not.throw();
|
|
2313
|
-
*
|
|
2511
|
+
*
|
|
2314
2512
|
* However, it's dangerous to negate `.throw` when providing any arguments.
|
|
2315
2513
|
* The problem is that it creates uncertain expectations by asserting that the
|
|
2316
2514
|
* target either doesn't throw an error, or that it throws an error but of a
|
|
@@ -2658,7 +2856,7 @@ module.exports = function (chai, _) {
|
|
|
2658
2856
|
* first argument, and asserts that the value returned is truthy.
|
|
2659
2857
|
*
|
|
2660
2858
|
* expect(1).to.satisfy(function(num) {
|
|
2661
|
-
* return num > 0;
|
|
2859
|
+
* return num > 0;
|
|
2662
2860
|
* });
|
|
2663
2861
|
*
|
|
2664
2862
|
* Add `.not` earlier in the chain to negate `.satisfy`.
|
|
@@ -2879,7 +3077,7 @@ module.exports = function (chai, _) {
|
|
|
2879
3077
|
var contains = flag(this, 'contains');
|
|
2880
3078
|
var ordered = flag(this, 'ordered');
|
|
2881
3079
|
|
|
2882
|
-
var subject, failMsg, failNegateMsg
|
|
3080
|
+
var subject, failMsg, failNegateMsg;
|
|
2883
3081
|
|
|
2884
3082
|
if (contains) {
|
|
2885
3083
|
subject = ordered ? 'an ordered superset' : 'a superset';
|
|
@@ -2951,7 +3149,6 @@ module.exports = function (chai, _) {
|
|
|
2951
3149
|
|
|
2952
3150
|
Assertion.addMethod('oneOf', oneOf);
|
|
2953
3151
|
|
|
2954
|
-
|
|
2955
3152
|
/**
|
|
2956
3153
|
* ### .change(subject[, prop[, msg]])
|
|
2957
3154
|
*
|
|
@@ -3127,7 +3324,7 @@ module.exports = function (chai, _) {
|
|
|
3127
3324
|
*
|
|
3128
3325
|
* expect(subtractTwo).to.decrease(myObj, 'val').by(2); // Recommended
|
|
3129
3326
|
* expect(subtractTwo).to.not.increase(myObj, 'val'); // Not recommended
|
|
3130
|
-
*
|
|
3327
|
+
*
|
|
3131
3328
|
* When the subject is expected to stay the same, it's often best to assert
|
|
3132
3329
|
* exactly that.
|
|
3133
3330
|
*
|
|
@@ -3224,7 +3421,7 @@ module.exports = function (chai, _) {
|
|
|
3224
3421
|
*
|
|
3225
3422
|
* When two arguments are provided, `.decrease` asserts that the value of the
|
|
3226
3423
|
* given object `subject`'s `prop` property is lesser after invoking the
|
|
3227
|
-
* target function compared to beforehand.
|
|
3424
|
+
* target function compared to beforehand.
|
|
3228
3425
|
*
|
|
3229
3426
|
* var myObj = {val: 1}
|
|
3230
3427
|
* , subtractTwo = function () { myObj.val -= 2; };
|
|
@@ -3246,7 +3443,7 @@ module.exports = function (chai, _) {
|
|
|
3246
3443
|
*
|
|
3247
3444
|
* expect(addTwo).to.increase(myObj, 'val').by(2); // Recommended
|
|
3248
3445
|
* expect(addTwo).to.not.decrease(myObj, 'val'); // Not recommended
|
|
3249
|
-
*
|
|
3446
|
+
*
|
|
3250
3447
|
* When the subject is expected to stay the same, it's often best to assert
|
|
3251
3448
|
* exactly that.
|
|
3252
3449
|
*
|
|
@@ -3599,7 +3796,7 @@ module.exports = function (chai, _) {
|
|
|
3599
3796
|
var obj = flag(this, 'object');
|
|
3600
3797
|
|
|
3601
3798
|
this.assert(
|
|
3602
|
-
typeof obj ===
|
|
3799
|
+
typeof obj === 'number' && isFinite(obj)
|
|
3603
3800
|
, 'expected #{this} to be a finite number'
|
|
3604
3801
|
, 'expected #{this} to not be a finite number'
|
|
3605
3802
|
);
|