chai 5.1.1 → 5.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.
@@ -8,6 +8,7 @@
8
8
  import {Assertion} from '../assertion.js';
9
9
  import {AssertionError} from 'assertion-error';
10
10
  import * as _ from '../utils/index.js';
11
+ import {config} from '../config.js';
11
12
 
12
13
  const {flag} = _;
13
14
 
@@ -42,10 +43,25 @@ const {flag} = _;
42
43
  * @public
43
44
  */
44
45
 
45
- [ 'to', 'be', 'been', 'is'
46
- , 'and', 'has', 'have', 'with'
47
- , 'that', 'which', 'at', 'of'
48
- , 'same', 'but', 'does', 'still', "also" ].forEach(function (chain) {
46
+ [
47
+ 'to',
48
+ 'be',
49
+ 'been',
50
+ 'is',
51
+ 'and',
52
+ 'has',
53
+ 'have',
54
+ 'with',
55
+ 'that',
56
+ 'which',
57
+ 'at',
58
+ 'of',
59
+ 'same',
60
+ 'but',
61
+ 'does',
62
+ 'still',
63
+ 'also'
64
+ ].forEach(function (chain) {
49
65
  Assertion.addProperty(chain);
50
66
  });
51
67
 
@@ -233,18 +249,22 @@ Assertion.addProperty('any', function () {
233
249
  * @namespace BDD
234
250
  * @public
235
251
  */
236
-
237
252
  Assertion.addProperty('all', function () {
238
253
  flag(this, 'all', true);
239
254
  flag(this, 'any', false);
240
255
  });
241
256
 
242
257
  const functionTypes = {
243
- 'function': ['function', 'asyncfunction', 'generatorfunction', 'asyncgeneratorfunction'],
244
- 'asyncfunction': ['asyncfunction', 'asyncgeneratorfunction'],
245
- 'generatorfunction': ['generatorfunction', 'asyncgeneratorfunction'],
246
- 'asyncgeneratorfunction': ['asyncgeneratorfunction']
247
- }
258
+ function: [
259
+ 'function',
260
+ 'asyncfunction',
261
+ 'generatorfunction',
262
+ 'asyncgeneratorfunction'
263
+ ],
264
+ asyncfunction: ['asyncfunction', 'asyncgeneratorfunction'],
265
+ generatorfunction: ['generatorfunction', 'asyncgeneratorfunction'],
266
+ asyncgeneratorfunction: ['asyncgeneratorfunction']
267
+ };
248
268
 
249
269
  /**
250
270
  * ### .a(type[, msg])
@@ -305,25 +325,25 @@ const functionTypes = {
305
325
  * @namespace BDD
306
326
  * @public
307
327
  */
308
- function an (type, msg) {
328
+ function an(type, msg) {
309
329
  if (msg) flag(this, 'message', msg);
310
330
  type = type.toLowerCase();
311
- var obj = flag(this, 'object')
312
- , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';
331
+ var obj = flag(this, 'object'),
332
+ article = ~['a', 'e', 'i', 'o', 'u'].indexOf(type.charAt(0)) ? 'an ' : 'a ';
313
333
 
314
334
  const detectedType = _.type(obj).toLowerCase();
315
335
 
316
336
  if (functionTypes['function'].includes(type)) {
317
337
  this.assert(
318
- functionTypes[type].includes(detectedType)
319
- , 'expected #{this} to be ' + article + type
320
- , 'expected #{this} not to be ' + article + type
338
+ functionTypes[type].includes(detectedType),
339
+ 'expected #{this} to be ' + article + type,
340
+ 'expected #{this} not to be ' + article + type
321
341
  );
322
342
  } else {
323
343
  this.assert(
324
- type === detectedType
325
- , 'expected #{this} to be ' + article + type
326
- , 'expected #{this} not to be ' + article + type
344
+ type === detectedType,
345
+ 'expected #{this} to be ' + article + type,
346
+ 'expected #{this} not to be ' + article + type
327
347
  );
328
348
  }
329
349
  }
@@ -344,7 +364,7 @@ function SameValueZero(a, b) {
344
364
  /**
345
365
  *
346
366
  */
347
- function includeChainingBehavior () {
367
+ function includeChainingBehavior() {
348
368
  flag(this, 'contains', true);
349
369
  }
350
370
 
@@ -494,17 +514,17 @@ function includeChainingBehavior () {
494
514
  * @namespace BDD
495
515
  * @public
496
516
  */
497
- function include (val, msg) {
517
+ function include(val, msg) {
498
518
  if (msg) flag(this, 'message', msg);
499
519
 
500
- var obj = flag(this, 'object')
501
- , objType = _.type(obj).toLowerCase()
502
- , flagMsg = flag(this, 'message')
503
- , negate = flag(this, 'negate')
504
- , ssfi = flag(this, 'ssfi')
505
- , isDeep = flag(this, 'deep')
506
- , descriptor = isDeep ? 'deep ' : ''
507
- , isEql = isDeep ? flag(this, 'eql') : SameValueZero;
520
+ var obj = flag(this, 'object'),
521
+ objType = _.type(obj).toLowerCase(),
522
+ flagMsg = flag(this, 'message'),
523
+ negate = flag(this, 'negate'),
524
+ ssfi = flag(this, 'ssfi'),
525
+ isDeep = flag(this, 'deep'),
526
+ descriptor = isDeep ? 'deep ' : '',
527
+ isEql = isDeep ? flag(this, 'eql') : SameValueZero;
508
528
 
509
529
  flagMsg = flagMsg ? flagMsg + ': ' : '';
510
530
 
@@ -547,7 +567,7 @@ function include (val, msg) {
547
567
  if (isDeep) {
548
568
  included = obj.some(function (item) {
549
569
  return isEql(item, val);
550
- })
570
+ });
551
571
  } else {
552
572
  included = obj.indexOf(val) !== -1;
553
573
  }
@@ -559,21 +579,24 @@ function include (val, msg) {
559
579
  // objects with a custom `@@toStringTag`.
560
580
  if (val !== Object(val)) {
561
581
  throw new AssertionError(
562
- flagMsg + 'the given combination of arguments ('
563
- + objType + ' and '
564
- + _.type(val).toLowerCase() + ')'
565
- + ' is invalid for this assertion. '
566
- + 'You can use an array, a map, an object, a set, a string, '
567
- + 'or a weakset instead of a '
568
- + _.type(val).toLowerCase(),
582
+ flagMsg +
583
+ 'the given combination of arguments (' +
584
+ objType +
585
+ ' and ' +
586
+ _.type(val).toLowerCase() +
587
+ ')' +
588
+ ' is invalid for this assertion. ' +
589
+ 'You can use an array, a map, an object, a set, a string, ' +
590
+ 'or a weakset instead of a ' +
591
+ _.type(val).toLowerCase(),
569
592
  undefined,
570
593
  ssfi
571
594
  );
572
595
  }
573
596
 
574
- var props = Object.keys(val)
575
- , firstErr = null
576
- , numErrs = 0;
597
+ var props = Object.keys(val),
598
+ firstErr = null,
599
+ numErrs = 0;
577
600
 
578
601
  props.forEach(function (prop) {
579
602
  var propAssertion = new Assertion(obj);
@@ -608,9 +631,10 @@ function include (val, msg) {
608
631
 
609
632
  // Assert inclusion in collection or substring in a string.
610
633
  this.assert(
611
- included
612
- , 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
613
- , 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
634
+ included,
635
+ 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val),
636
+ 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val)
637
+ );
614
638
  }
615
639
 
616
640
  Assertion.addChainableMethod('include', include, includeChainingBehavior);
@@ -655,9 +679,10 @@ Assertion.addChainableMethod('includes', include, includeChainingBehavior);
655
679
  */
656
680
  Assertion.addProperty('ok', function () {
657
681
  this.assert(
658
- flag(this, 'object')
659
- , 'expected #{this} to be truthy'
660
- , 'expected #{this} to be falsy');
682
+ flag(this, 'object'),
683
+ 'expected #{this} to be truthy',
684
+ 'expected #{this} to be falsy'
685
+ );
661
686
  });
662
687
 
663
688
  /**
@@ -687,10 +712,21 @@ Assertion.addProperty('ok', function () {
687
712
  */
688
713
  Assertion.addProperty('true', function () {
689
714
  this.assert(
690
- true === flag(this, 'object')
691
- , 'expected #{this} to be true'
692
- , 'expected #{this} to be false'
693
- , flag(this, 'negate') ? false : true
715
+ true === flag(this, 'object'),
716
+ 'expected #{this} to be true',
717
+ 'expected #{this} to be false',
718
+ flag(this, 'negate') ? false : true
719
+ );
720
+ });
721
+
722
+ Assertion.addProperty('numeric', function () {
723
+ const object = flag(this, 'object');
724
+
725
+ this.assert(
726
+ ['Number', 'BigInt'].includes(_.type(object)),
727
+ 'expected #{this} to be numeric',
728
+ 'expected #{this} to not be numeric',
729
+ flag(this, 'negate') ? false : true
694
730
  );
695
731
  });
696
732
 
@@ -710,24 +746,25 @@ Assertion.addProperty('true', function () {
710
746
  * @public
711
747
  */
712
748
  Assertion.addProperty('callable', function () {
713
- const val = flag(this, 'object')
714
- const ssfi = flag(this, 'ssfi')
715
- const message = flag(this, 'message')
716
- const msg = message ? `${message}: ` : ''
749
+ const val = flag(this, 'object');
750
+ const ssfi = flag(this, 'ssfi');
751
+ const message = flag(this, 'message');
752
+ const msg = message ? `${message}: ` : '';
717
753
  const negate = flag(this, 'negate');
718
754
 
719
- const assertionMessage = negate ?
720
- `${msg}expected ${_.inspect(val)} not to be a callable function` :
721
- `${msg}expected ${_.inspect(val)} to be a callable function`;
755
+ const assertionMessage = negate
756
+ ? `${msg}expected ${_.inspect(val)} not to be a callable function`
757
+ : `${msg}expected ${_.inspect(val)} to be a callable function`;
722
758
 
723
- const isCallable = ['Function', 'AsyncFunction', 'GeneratorFunction', 'AsyncGeneratorFunction'].includes(_.type(val));
759
+ const isCallable = [
760
+ 'Function',
761
+ 'AsyncFunction',
762
+ 'GeneratorFunction',
763
+ 'AsyncGeneratorFunction'
764
+ ].includes(_.type(val));
724
765
 
725
766
  if ((isCallable && negate) || (!isCallable && !negate)) {
726
- throw new AssertionError(
727
- assertionMessage,
728
- undefined,
729
- ssfi
730
- );
767
+ throw new AssertionError(assertionMessage, undefined, ssfi);
731
768
  }
732
769
  });
733
770
 
@@ -758,10 +795,10 @@ Assertion.addProperty('callable', function () {
758
795
  */
759
796
  Assertion.addProperty('false', function () {
760
797
  this.assert(
761
- false === flag(this, 'object')
762
- , 'expected #{this} to be false'
763
- , 'expected #{this} to be true'
764
- , flag(this, 'negate') ? true : false
798
+ false === flag(this, 'object'),
799
+ 'expected #{this} to be false',
800
+ 'expected #{this} to be true',
801
+ flag(this, 'negate') ? true : false
765
802
  );
766
803
  });
767
804
 
@@ -789,9 +826,9 @@ Assertion.addProperty('false', function () {
789
826
  */
790
827
  Assertion.addProperty('null', function () {
791
828
  this.assert(
792
- null === flag(this, 'object')
793
- , 'expected #{this} to be null'
794
- , 'expected #{this} not to be null'
829
+ null === flag(this, 'object'),
830
+ 'expected #{this} to be null',
831
+ 'expected #{this} not to be null'
795
832
  );
796
833
  });
797
834
 
@@ -819,9 +856,9 @@ Assertion.addProperty('null', function () {
819
856
  */
820
857
  Assertion.addProperty('undefined', function () {
821
858
  this.assert(
822
- undefined === flag(this, 'object')
823
- , 'expected #{this} to be undefined'
824
- , 'expected #{this} not to be undefined'
859
+ undefined === flag(this, 'object'),
860
+ 'expected #{this} to be undefined',
861
+ 'expected #{this} not to be undefined'
825
862
  );
826
863
  });
827
864
 
@@ -849,9 +886,9 @@ Assertion.addProperty('undefined', function () {
849
886
  */
850
887
  Assertion.addProperty('NaN', function () {
851
888
  this.assert(
852
- _.isNaN(flag(this, 'object'))
853
- , 'expected #{this} to be NaN'
854
- , 'expected #{this} not to be NaN'
889
+ _.isNaN(flag(this, 'object')),
890
+ 'expected #{this} to be NaN',
891
+ 'expected #{this} not to be NaN'
855
892
  );
856
893
  });
857
894
 
@@ -887,12 +924,12 @@ Assertion.addProperty('NaN', function () {
887
924
  * @namespace BDD
888
925
  * @public
889
926
  */
890
- function assertExist () {
927
+ function assertExist() {
891
928
  var val = flag(this, 'object');
892
929
  this.assert(
893
- val !== null && val !== undefined
894
- , 'expected #{this} to exist'
895
- , 'expected #{this} to not exist'
930
+ val !== null && val !== undefined,
931
+ 'expected #{this} to exist',
932
+ 'expected #{this} to not exist'
896
933
  );
897
934
  }
898
935
 
@@ -948,10 +985,10 @@ Assertion.addProperty('exists', assertExist);
948
985
  * @public
949
986
  */
950
987
  Assertion.addProperty('empty', function () {
951
- var val = flag(this, 'object')
952
- , ssfi = flag(this, 'ssfi')
953
- , flagMsg = flag(this, 'message')
954
- , itemsCount;
988
+ var val = flag(this, 'object'),
989
+ ssfi = flag(this, 'ssfi'),
990
+ flagMsg = flag(this, 'message'),
991
+ itemsCount;
955
992
 
956
993
  flagMsg = flagMsg ? flagMsg + ': ' : '';
957
994
 
@@ -986,9 +1023,9 @@ Assertion.addProperty('empty', function () {
986
1023
  }
987
1024
 
988
1025
  this.assert(
989
- 0 === itemsCount
990
- , 'expected #{this} to be empty'
991
- , 'expected #{this} not to be empty'
1026
+ 0 === itemsCount,
1027
+ 'expected #{this} to be empty',
1028
+ 'expected #{this} not to be empty'
992
1029
  );
993
1030
  });
994
1031
 
@@ -1021,13 +1058,13 @@ Assertion.addProperty('empty', function () {
1021
1058
  * @namespace BDD
1022
1059
  * @public
1023
1060
  */
1024
- function checkArguments () {
1025
- var obj = flag(this, 'object')
1026
- , type = _.type(obj);
1061
+ function checkArguments() {
1062
+ var obj = flag(this, 'object'),
1063
+ type = _.type(obj);
1027
1064
  this.assert(
1028
- 'Arguments' === type
1029
- , 'expected #{this} to be arguments but got ' + type
1030
- , 'expected #{this} to not be arguments'
1065
+ 'Arguments' === type,
1066
+ 'expected #{this} to be arguments but got ' + type,
1067
+ 'expected #{this} to not be arguments'
1031
1068
  );
1032
1069
  }
1033
1070
 
@@ -1078,7 +1115,7 @@ Assertion.addProperty('Arguments', checkArguments);
1078
1115
  * @namespace BDD
1079
1116
  * @public
1080
1117
  */
1081
- function assertEqual (val, msg) {
1118
+ function assertEqual(val, msg) {
1082
1119
  if (msg) flag(this, 'message', msg);
1083
1120
  var obj = flag(this, 'object');
1084
1121
  if (flag(this, 'deep')) {
@@ -1088,12 +1125,12 @@ function assertEqual (val, msg) {
1088
1125
  flag(this, 'lockSsfi', prevLockSsfi);
1089
1126
  } else {
1090
1127
  this.assert(
1091
- val === obj
1092
- , 'expected #{this} to equal #{exp}'
1093
- , 'expected #{this} to not equal #{exp}'
1094
- , val
1095
- , this._obj
1096
- , true
1128
+ val === obj,
1129
+ 'expected #{this} to equal #{exp}',
1130
+ 'expected #{this} to not equal #{exp}',
1131
+ val,
1132
+ this._obj,
1133
+ true
1097
1134
  );
1098
1135
  }
1099
1136
  }
@@ -1146,12 +1183,12 @@ function assertEql(obj, msg) {
1146
1183
  if (msg) flag(this, 'message', msg);
1147
1184
  var eql = flag(this, 'eql');
1148
1185
  this.assert(
1149
- eql(obj, flag(this, 'object'))
1150
- , 'expected #{this} to deeply equal #{exp}'
1151
- , 'expected #{this} to not deeply equal #{exp}'
1152
- , obj
1153
- , this._obj
1154
- , true
1186
+ eql(obj, flag(this, 'object')),
1187
+ 'expected #{this} to deeply equal #{exp}',
1188
+ 'expected #{this} to not deeply equal #{exp}',
1189
+ obj,
1190
+ this._obj,
1191
+ true
1155
1192
  );
1156
1193
  }
1157
1194
 
@@ -1200,40 +1237,44 @@ Assertion.addMethod('eqls', assertEql);
1200
1237
  * @namespace BDD
1201
1238
  * @public
1202
1239
  */
1203
- function assertAbove (n, msg) {
1240
+ function assertAbove(n, msg) {
1204
1241
  if (msg) flag(this, 'message', msg);
1205
- var obj = flag(this, 'object')
1206
- , doLength = flag(this, 'doLength')
1207
- , flagMsg = flag(this, 'message')
1208
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1209
- , ssfi = flag(this, 'ssfi')
1210
- , objType = _.type(obj).toLowerCase()
1211
- , nType = _.type(n).toLowerCase()
1212
- , errorMessage
1213
- , shouldThrow = true;
1242
+ var obj = flag(this, 'object'),
1243
+ doLength = flag(this, 'doLength'),
1244
+ flagMsg = flag(this, 'message'),
1245
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1246
+ ssfi = flag(this, 'ssfi'),
1247
+ objType = _.type(obj).toLowerCase(),
1248
+ nType = _.type(n).toLowerCase();
1214
1249
 
1215
1250
  if (doLength && objType !== 'map' && objType !== 'set') {
1216
1251
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1217
1252
  }
1218
1253
 
1219
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1220
- errorMessage = msgPrefix + 'the argument to above must be a date';
1221
- } else if (nType !== 'number' && (doLength || objType === 'number')) {
1222
- errorMessage = msgPrefix + 'the argument to above must be a number';
1223
- } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1224
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1225
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1226
- } else {
1227
- shouldThrow = false;
1228
- }
1229
-
1230
- if (shouldThrow) {
1231
- throw new AssertionError(errorMessage, undefined, ssfi);
1254
+ if (!doLength && objType === 'date' && nType !== 'date') {
1255
+ throw new AssertionError(
1256
+ msgPrefix + 'the argument to above must be a date',
1257
+ undefined,
1258
+ ssfi
1259
+ );
1260
+ } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1261
+ throw new AssertionError(
1262
+ msgPrefix + 'the argument to above must be a number',
1263
+ undefined,
1264
+ ssfi
1265
+ );
1266
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1267
+ var printObj = objType === 'string' ? "'" + obj + "'" : obj;
1268
+ throw new AssertionError(
1269
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date',
1270
+ undefined,
1271
+ ssfi
1272
+ );
1232
1273
  }
1233
1274
 
1234
1275
  if (doLength) {
1235
- var descriptor = 'length'
1236
- , itemsCount;
1276
+ var descriptor = 'length',
1277
+ itemsCount;
1237
1278
  if (objType === 'map' || objType === 'set') {
1238
1279
  descriptor = 'size';
1239
1280
  itemsCount = obj.size;
@@ -1241,18 +1282,20 @@ function assertAbove (n, msg) {
1241
1282
  itemsCount = obj.length;
1242
1283
  }
1243
1284
  this.assert(
1244
- itemsCount > n
1245
- , 'expected #{this} to have a ' + descriptor + ' above #{exp} but got #{act}'
1246
- , 'expected #{this} to not have a ' + descriptor + ' above #{exp}'
1247
- , n
1248
- , itemsCount
1285
+ itemsCount > n,
1286
+ 'expected #{this} to have a ' +
1287
+ descriptor +
1288
+ ' above #{exp} but got #{act}',
1289
+ 'expected #{this} to not have a ' + descriptor + ' above #{exp}',
1290
+ n,
1291
+ itemsCount
1249
1292
  );
1250
1293
  } else {
1251
1294
  this.assert(
1252
- obj > n
1253
- , 'expected #{this} to be above #{exp}'
1254
- , 'expected #{this} to be at most #{exp}'
1255
- , n
1295
+ obj > n,
1296
+ 'expected #{this} to be above #{exp}',
1297
+ 'expected #{this} to be at most #{exp}',
1298
+ n
1256
1299
  );
1257
1300
  }
1258
1301
  }
@@ -1299,34 +1342,35 @@ Assertion.addMethod('greaterThan', assertAbove);
1299
1342
  * @name least
1300
1343
  * @alias gte
1301
1344
  * @alias greaterThanOrEqual
1302
- * @param {number} n
1345
+ * @param {unknown} n
1303
1346
  * @param {string} msg _optional_
1304
1347
  * @namespace BDD
1305
1348
  * @public
1306
1349
  */
1307
- function assertLeast (n, msg) {
1350
+ function assertLeast(n, msg) {
1308
1351
  if (msg) flag(this, 'message', msg);
1309
- var obj = flag(this, 'object')
1310
- , doLength = flag(this, 'doLength')
1311
- , flagMsg = flag(this, 'message')
1312
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1313
- , ssfi = flag(this, 'ssfi')
1314
- , objType = _.type(obj).toLowerCase()
1315
- , nType = _.type(n).toLowerCase()
1316
- , errorMessage
1317
- , shouldThrow = true;
1352
+ var obj = flag(this, 'object'),
1353
+ doLength = flag(this, 'doLength'),
1354
+ flagMsg = flag(this, 'message'),
1355
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1356
+ ssfi = flag(this, 'ssfi'),
1357
+ objType = _.type(obj).toLowerCase(),
1358
+ nType = _.type(n).toLowerCase(),
1359
+ errorMessage,
1360
+ shouldThrow = true;
1318
1361
 
1319
1362
  if (doLength && objType !== 'map' && objType !== 'set') {
1320
1363
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1321
1364
  }
1322
1365
 
1323
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1366
+ if (!doLength && objType === 'date' && nType !== 'date') {
1324
1367
  errorMessage = msgPrefix + 'the argument to least must be a date';
1325
- } else if (nType !== 'number' && (doLength || objType === 'number')) {
1368
+ } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1326
1369
  errorMessage = msgPrefix + 'the argument to least must be a number';
1327
- } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1328
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1329
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1370
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1371
+ var printObj = objType === 'string' ? "'" + obj + "'" : obj;
1372
+ errorMessage =
1373
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1330
1374
  } else {
1331
1375
  shouldThrow = false;
1332
1376
  }
@@ -1336,8 +1380,8 @@ function assertLeast (n, msg) {
1336
1380
  }
1337
1381
 
1338
1382
  if (doLength) {
1339
- var descriptor = 'length'
1340
- , itemsCount;
1383
+ var descriptor = 'length',
1384
+ itemsCount;
1341
1385
  if (objType === 'map' || objType === 'set') {
1342
1386
  descriptor = 'size';
1343
1387
  itemsCount = obj.size;
@@ -1345,18 +1389,20 @@ function assertLeast (n, msg) {
1345
1389
  itemsCount = obj.length;
1346
1390
  }
1347
1391
  this.assert(
1348
- itemsCount >= n
1349
- , 'expected #{this} to have a ' + descriptor + ' at least #{exp} but got #{act}'
1350
- , 'expected #{this} to have a ' + descriptor + ' below #{exp}'
1351
- , n
1352
- , itemsCount
1392
+ itemsCount >= n,
1393
+ 'expected #{this} to have a ' +
1394
+ descriptor +
1395
+ ' at least #{exp} but got #{act}',
1396
+ 'expected #{this} to have a ' + descriptor + ' below #{exp}',
1397
+ n,
1398
+ itemsCount
1353
1399
  );
1354
1400
  } else {
1355
1401
  this.assert(
1356
- obj >= n
1357
- , 'expected #{this} to be at least #{exp}'
1358
- , 'expected #{this} to be below #{exp}'
1359
- , n
1402
+ obj >= n,
1403
+ 'expected #{this} to be at least #{exp}',
1404
+ 'expected #{this} to be below #{exp}',
1405
+ n
1360
1406
  );
1361
1407
  }
1362
1408
  }
@@ -1402,34 +1448,35 @@ Assertion.addMethod('greaterThanOrEqual', assertLeast);
1402
1448
  * @name below
1403
1449
  * @alias lt
1404
1450
  * @alias lessThan
1405
- * @param {number} n
1451
+ * @param {unknown} n
1406
1452
  * @param {string} msg _optional_
1407
1453
  * @namespace BDD
1408
1454
  * @public
1409
1455
  */
1410
- function assertBelow (n, msg) {
1456
+ function assertBelow(n, msg) {
1411
1457
  if (msg) flag(this, 'message', msg);
1412
- var obj = flag(this, 'object')
1413
- , doLength = flag(this, 'doLength')
1414
- , flagMsg = flag(this, 'message')
1415
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1416
- , ssfi = flag(this, 'ssfi')
1417
- , objType = _.type(obj).toLowerCase()
1418
- , nType = _.type(n).toLowerCase()
1419
- , errorMessage
1420
- , shouldThrow = true;
1458
+ var obj = flag(this, 'object'),
1459
+ doLength = flag(this, 'doLength'),
1460
+ flagMsg = flag(this, 'message'),
1461
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1462
+ ssfi = flag(this, 'ssfi'),
1463
+ objType = _.type(obj).toLowerCase(),
1464
+ nType = _.type(n).toLowerCase(),
1465
+ errorMessage,
1466
+ shouldThrow = true;
1421
1467
 
1422
1468
  if (doLength && objType !== 'map' && objType !== 'set') {
1423
1469
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1424
1470
  }
1425
1471
 
1426
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1472
+ if (!doLength && objType === 'date' && nType !== 'date') {
1427
1473
  errorMessage = msgPrefix + 'the argument to below must be a date';
1428
- } else if (nType !== 'number' && (doLength || objType === 'number')) {
1474
+ } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1429
1475
  errorMessage = msgPrefix + 'the argument to below must be a number';
1430
- } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1431
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1432
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1476
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1477
+ var printObj = objType === 'string' ? "'" + obj + "'" : obj;
1478
+ errorMessage =
1479
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1433
1480
  } else {
1434
1481
  shouldThrow = false;
1435
1482
  }
@@ -1439,8 +1486,8 @@ function assertBelow (n, msg) {
1439
1486
  }
1440
1487
 
1441
1488
  if (doLength) {
1442
- var descriptor = 'length'
1443
- , itemsCount;
1489
+ var descriptor = 'length',
1490
+ itemsCount;
1444
1491
  if (objType === 'map' || objType === 'set') {
1445
1492
  descriptor = 'size';
1446
1493
  itemsCount = obj.size;
@@ -1448,18 +1495,20 @@ function assertBelow (n, msg) {
1448
1495
  itemsCount = obj.length;
1449
1496
  }
1450
1497
  this.assert(
1451
- itemsCount < n
1452
- , 'expected #{this} to have a ' + descriptor + ' below #{exp} but got #{act}'
1453
- , 'expected #{this} to not have a ' + descriptor + ' below #{exp}'
1454
- , n
1455
- , itemsCount
1498
+ itemsCount < n,
1499
+ 'expected #{this} to have a ' +
1500
+ descriptor +
1501
+ ' below #{exp} but got #{act}',
1502
+ 'expected #{this} to not have a ' + descriptor + ' below #{exp}',
1503
+ n,
1504
+ itemsCount
1456
1505
  );
1457
1506
  } else {
1458
1507
  this.assert(
1459
- obj < n
1460
- , 'expected #{this} to be below #{exp}'
1461
- , 'expected #{this} to be at least #{exp}'
1462
- , n
1508
+ obj < n,
1509
+ 'expected #{this} to be below #{exp}',
1510
+ 'expected #{this} to be at least #{exp}',
1511
+ n
1463
1512
  );
1464
1513
  }
1465
1514
  }
@@ -1506,34 +1555,35 @@ Assertion.addMethod('lessThan', assertBelow);
1506
1555
  * @name most
1507
1556
  * @alias lte
1508
1557
  * @alias lessThanOrEqual
1509
- * @param {number} n
1558
+ * @param {unknown} n
1510
1559
  * @param {string} msg _optional_
1511
1560
  * @namespace BDD
1512
1561
  * @public
1513
1562
  */
1514
- function assertMost (n, msg) {
1563
+ function assertMost(n, msg) {
1515
1564
  if (msg) flag(this, 'message', msg);
1516
- var obj = flag(this, 'object')
1517
- , doLength = flag(this, 'doLength')
1518
- , flagMsg = flag(this, 'message')
1519
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1520
- , ssfi = flag(this, 'ssfi')
1521
- , objType = _.type(obj).toLowerCase()
1522
- , nType = _.type(n).toLowerCase()
1523
- , errorMessage
1524
- , shouldThrow = true;
1565
+ var obj = flag(this, 'object'),
1566
+ doLength = flag(this, 'doLength'),
1567
+ flagMsg = flag(this, 'message'),
1568
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1569
+ ssfi = flag(this, 'ssfi'),
1570
+ objType = _.type(obj).toLowerCase(),
1571
+ nType = _.type(n).toLowerCase(),
1572
+ errorMessage,
1573
+ shouldThrow = true;
1525
1574
 
1526
1575
  if (doLength && objType !== 'map' && objType !== 'set') {
1527
1576
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1528
1577
  }
1529
1578
 
1530
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1579
+ if (!doLength && objType === 'date' && nType !== 'date') {
1531
1580
  errorMessage = msgPrefix + 'the argument to most must be a date';
1532
- } else if (nType !== 'number' && (doLength || objType === 'number')) {
1581
+ } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1533
1582
  errorMessage = msgPrefix + 'the argument to most must be a number';
1534
- } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1535
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1536
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1583
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1584
+ var printObj = objType === 'string' ? "'" + obj + "'" : obj;
1585
+ errorMessage =
1586
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1537
1587
  } else {
1538
1588
  shouldThrow = false;
1539
1589
  }
@@ -1543,8 +1593,8 @@ function assertMost (n, msg) {
1543
1593
  }
1544
1594
 
1545
1595
  if (doLength) {
1546
- var descriptor = 'length'
1547
- , itemsCount;
1596
+ var descriptor = 'length',
1597
+ itemsCount;
1548
1598
  if (objType === 'map' || objType === 'set') {
1549
1599
  descriptor = 'size';
1550
1600
  itemsCount = obj.size;
@@ -1552,18 +1602,20 @@ function assertMost (n, msg) {
1552
1602
  itemsCount = obj.length;
1553
1603
  }
1554
1604
  this.assert(
1555
- itemsCount <= n
1556
- , 'expected #{this} to have a ' + descriptor + ' at most #{exp} but got #{act}'
1557
- , 'expected #{this} to have a ' + descriptor + ' above #{exp}'
1558
- , n
1559
- , itemsCount
1605
+ itemsCount <= n,
1606
+ 'expected #{this} to have a ' +
1607
+ descriptor +
1608
+ ' at most #{exp} but got #{act}',
1609
+ 'expected #{this} to have a ' + descriptor + ' above #{exp}',
1610
+ n,
1611
+ itemsCount
1560
1612
  );
1561
1613
  } else {
1562
1614
  this.assert(
1563
- obj <= n
1564
- , 'expected #{this} to be at most #{exp}'
1565
- , 'expected #{this} to be above #{exp}'
1566
- , n
1615
+ obj <= n,
1616
+ 'expected #{this} to be at most #{exp}',
1617
+ 'expected #{this} to be above #{exp}',
1618
+ n
1567
1619
  );
1568
1620
  }
1569
1621
  }
@@ -1608,25 +1660,26 @@ Assertion.addMethod('lessThanOrEqual', assertMost);
1608
1660
  * expect(4, 'nooo why fail??').to.be.within(1, 3);
1609
1661
  *
1610
1662
  * @name within
1611
- * @param {number} start lower bound inclusive
1612
- * @param {number} finish upper bound inclusive
1663
+ * @param {unknown} start lower bound inclusive
1664
+ * @param {unknown} finish upper bound inclusive
1613
1665
  * @param {string} msg _optional_
1614
1666
  * @namespace BDD
1615
1667
  * @public
1616
1668
  */
1617
1669
  Assertion.addMethod('within', function (start, finish, msg) {
1618
1670
  if (msg) flag(this, 'message', msg);
1619
- var obj = flag(this, 'object')
1620
- , doLength = flag(this, 'doLength')
1621
- , flagMsg = flag(this, 'message')
1622
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1623
- , ssfi = flag(this, 'ssfi')
1624
- , objType = _.type(obj).toLowerCase()
1625
- , startType = _.type(start).toLowerCase()
1626
- , finishType = _.type(finish).toLowerCase()
1627
- , errorMessage
1628
- , shouldThrow = true
1629
- , range = (startType === 'date' && finishType === 'date')
1671
+ var obj = flag(this, 'object'),
1672
+ doLength = flag(this, 'doLength'),
1673
+ flagMsg = flag(this, 'message'),
1674
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1675
+ ssfi = flag(this, 'ssfi'),
1676
+ objType = _.type(obj).toLowerCase(),
1677
+ startType = _.type(start).toLowerCase(),
1678
+ finishType = _.type(finish).toLowerCase(),
1679
+ errorMessage,
1680
+ shouldThrow = true,
1681
+ range =
1682
+ startType === 'date' && finishType === 'date'
1630
1683
  ? start.toISOString() + '..' + finish.toISOString()
1631
1684
  : start + '..' + finish;
1632
1685
 
@@ -1634,13 +1687,21 @@ Assertion.addMethod('within', function (start, finish, msg) {
1634
1687
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1635
1688
  }
1636
1689
 
1637
- if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {
1690
+ if (
1691
+ !doLength &&
1692
+ objType === 'date' &&
1693
+ (startType !== 'date' || finishType !== 'date')
1694
+ ) {
1638
1695
  errorMessage = msgPrefix + 'the arguments to within must be dates';
1639
- } else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) {
1696
+ } else if (
1697
+ (!_.isNumeric(start) || !_.isNumeric(finish)) &&
1698
+ (doLength || _.isNumeric(obj))
1699
+ ) {
1640
1700
  errorMessage = msgPrefix + 'the arguments to within must be numbers';
1641
- } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1642
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1643
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1701
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1702
+ var printObj = objType === 'string' ? "'" + obj + "'" : obj;
1703
+ errorMessage =
1704
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1644
1705
  } else {
1645
1706
  shouldThrow = false;
1646
1707
  }
@@ -1650,8 +1711,8 @@ Assertion.addMethod('within', function (start, finish, msg) {
1650
1711
  }
1651
1712
 
1652
1713
  if (doLength) {
1653
- var descriptor = 'length'
1654
- , itemsCount;
1714
+ var descriptor = 'length',
1715
+ itemsCount;
1655
1716
  if (objType === 'map' || objType === 'set') {
1656
1717
  descriptor = 'size';
1657
1718
  itemsCount = obj.size;
@@ -1659,15 +1720,15 @@ Assertion.addMethod('within', function (start, finish, msg) {
1659
1720
  itemsCount = obj.length;
1660
1721
  }
1661
1722
  this.assert(
1662
- itemsCount >= start && itemsCount <= finish
1663
- , 'expected #{this} to have a ' + descriptor + ' within ' + range
1664
- , 'expected #{this} to not have a ' + descriptor + ' within ' + range
1723
+ itemsCount >= start && itemsCount <= finish,
1724
+ 'expected #{this} to have a ' + descriptor + ' within ' + range,
1725
+ 'expected #{this} to not have a ' + descriptor + ' within ' + range
1665
1726
  );
1666
1727
  } else {
1667
1728
  this.assert(
1668
- obj >= start && obj <= finish
1669
- , 'expected #{this} to be within ' + range
1670
- , 'expected #{this} to not be within ' + range
1729
+ obj >= start && obj <= finish,
1730
+ 'expected #{this} to be within ' + range,
1731
+ 'expected #{this} to not be within ' + range
1671
1732
  );
1672
1733
  }
1673
1734
  });
@@ -1710,10 +1771,10 @@ Assertion.addMethod('within', function (start, finish, msg) {
1710
1771
  * @namespace BDD
1711
1772
  * @public
1712
1773
  */
1713
- function assertInstanceOf (constructor, msg) {
1774
+ function assertInstanceOf(constructor, msg) {
1714
1775
  if (msg) flag(this, 'message', msg);
1715
1776
 
1716
- var target = flag(this, 'object')
1777
+ var target = flag(this, 'object');
1717
1778
  var ssfi = flag(this, 'ssfi');
1718
1779
  var flagMsg = flag(this, 'message');
1719
1780
 
@@ -1723,8 +1784,10 @@ function assertInstanceOf (constructor, msg) {
1723
1784
  if (err instanceof TypeError) {
1724
1785
  flagMsg = flagMsg ? flagMsg + ': ' : '';
1725
1786
  throw new AssertionError(
1726
- flagMsg + 'The instanceof assertion needs a constructor but '
1727
- + _.type(constructor) + ' was given.',
1787
+ flagMsg +
1788
+ 'The instanceof assertion needs a constructor but ' +
1789
+ _.type(constructor) +
1790
+ ' was given.',
1728
1791
  undefined,
1729
1792
  ssfi
1730
1793
  );
@@ -1738,11 +1801,11 @@ function assertInstanceOf (constructor, msg) {
1738
1801
  }
1739
1802
 
1740
1803
  this.assert(
1741
- isInstanceOf
1742
- , 'expected #{this} to be an instance of ' + name
1743
- , 'expected #{this} to not be an instance of ' + name
1804
+ isInstanceOf,
1805
+ 'expected #{this} to be an instance of ' + name,
1806
+ 'expected #{this} to not be an instance of ' + name
1744
1807
  );
1745
- };
1808
+ }
1746
1809
 
1747
1810
  Assertion.addMethod('instanceof', assertInstanceOf);
1748
1811
  Assertion.addMethod('instanceOf', assertInstanceOf);
@@ -1857,30 +1920,36 @@ Assertion.addMethod('instanceOf', assertInstanceOf);
1857
1920
  * @namespace BDD
1858
1921
  * @public
1859
1922
  */
1860
- function assertProperty (name, val, msg) {
1923
+ function assertProperty(name, val, msg) {
1861
1924
  if (msg) flag(this, 'message', msg);
1862
1925
 
1863
- var isNested = flag(this, 'nested')
1864
- , isOwn = flag(this, 'own')
1865
- , flagMsg = flag(this, 'message')
1866
- , obj = flag(this, 'object')
1867
- , ssfi = flag(this, 'ssfi')
1868
- , nameType = typeof name;
1926
+ var isNested = flag(this, 'nested'),
1927
+ isOwn = flag(this, 'own'),
1928
+ flagMsg = flag(this, 'message'),
1929
+ obj = flag(this, 'object'),
1930
+ ssfi = flag(this, 'ssfi'),
1931
+ nameType = typeof name;
1869
1932
 
1870
1933
  flagMsg = flagMsg ? flagMsg + ': ' : '';
1871
1934
 
1872
1935
  if (isNested) {
1873
1936
  if (nameType !== 'string') {
1874
1937
  throw new AssertionError(
1875
- flagMsg + 'the argument to property must be a string when using nested syntax',
1938
+ flagMsg +
1939
+ 'the argument to property must be a string when using nested syntax',
1876
1940
  undefined,
1877
1941
  ssfi
1878
1942
  );
1879
1943
  }
1880
1944
  } else {
1881
- if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') {
1945
+ if (
1946
+ nameType !== 'string' &&
1947
+ nameType !== 'number' &&
1948
+ nameType !== 'symbol'
1949
+ ) {
1882
1950
  throw new AssertionError(
1883
- flagMsg + 'the argument to property must be a string, number, or symbol',
1951
+ flagMsg +
1952
+ 'the argument to property must be a string, number, or symbol',
1884
1953
  undefined,
1885
1954
  ssfi
1886
1955
  );
@@ -1903,11 +1972,11 @@ function assertProperty (name, val, msg) {
1903
1972
  );
1904
1973
  }
1905
1974
 
1906
- var isDeep = flag(this, 'deep')
1907
- , negate = flag(this, 'negate')
1908
- , pathInfo = isNested ? _.getPathInfo(obj, name) : null
1909
- , value = isNested ? pathInfo.value : obj[name]
1910
- , isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
1975
+ var isDeep = flag(this, 'deep'),
1976
+ negate = flag(this, 'negate'),
1977
+ pathInfo = isNested ? _.getPathInfo(obj, name) : null,
1978
+ value = isNested ? pathInfo.value : obj[name],
1979
+ isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
1911
1980
 
1912
1981
  var descriptor = '';
1913
1982
  if (isDeep) descriptor += 'deep ';
@@ -1927,18 +1996,25 @@ function assertProperty (name, val, msg) {
1927
1996
  // favor of the next.
1928
1997
  if (!negate || arguments.length === 1) {
1929
1998
  this.assert(
1930
- hasProperty
1931
- , 'expected #{this} to have ' + descriptor + _.inspect(name)
1932
- , 'expected #{this} to not have ' + descriptor + _.inspect(name));
1999
+ hasProperty,
2000
+ 'expected #{this} to have ' + descriptor + _.inspect(name),
2001
+ 'expected #{this} to not have ' + descriptor + _.inspect(name)
2002
+ );
1933
2003
  }
1934
2004
 
1935
2005
  if (arguments.length > 1) {
1936
2006
  this.assert(
1937
- hasProperty && isEql(val, value)
1938
- , 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
1939
- , 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}'
1940
- , val
1941
- , value
2007
+ hasProperty && isEql(val, value),
2008
+ 'expected #{this} to have ' +
2009
+ descriptor +
2010
+ _.inspect(name) +
2011
+ ' of #{exp}, but got #{act}',
2012
+ 'expected #{this} to not have ' +
2013
+ descriptor +
2014
+ _.inspect(name) +
2015
+ ' of #{act}',
2016
+ val,
2017
+ value
1942
2018
  );
1943
2019
  }
1944
2020
 
@@ -1949,11 +2025,11 @@ Assertion.addMethod('property', assertProperty);
1949
2025
 
1950
2026
  /**
1951
2027
  *
1952
- * @param {unknown} name
1953
- * @param {unknown} value
1954
- * @param {string} msg
2028
+ * @param {unknown} _name
2029
+ * @param {unknown} _value
2030
+ * @param {string} _msg
1955
2031
  */
1956
- function assertOwnProperty (name, value, msg) {
2032
+ function assertOwnProperty(_name, _value, _msg) {
1957
2033
  flag(this, 'own', true);
1958
2034
  assertProperty.apply(this, arguments);
1959
2035
  }
@@ -2079,7 +2155,7 @@ Assertion.addMethod('haveOwnProperty', assertOwnProperty);
2079
2155
  * @namespace BDD
2080
2156
  * @public
2081
2157
  */
2082
- function assertOwnPropertyDescriptor (name, descriptor, msg) {
2158
+ function assertOwnPropertyDescriptor(name, descriptor, msg) {
2083
2159
  if (typeof descriptor === 'string') {
2084
2160
  msg = descriptor;
2085
2161
  descriptor = null;
@@ -2090,18 +2166,28 @@ function assertOwnPropertyDescriptor (name, descriptor, msg) {
2090
2166
  var eql = flag(this, 'eql');
2091
2167
  if (actualDescriptor && descriptor) {
2092
2168
  this.assert(
2093
- eql(descriptor, actualDescriptor)
2094
- , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)
2095
- , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)
2096
- , descriptor
2097
- , actualDescriptor
2098
- , true
2169
+ eql(descriptor, actualDescriptor),
2170
+ 'expected the own property descriptor for ' +
2171
+ _.inspect(name) +
2172
+ ' on #{this} to match ' +
2173
+ _.inspect(descriptor) +
2174
+ ', got ' +
2175
+ _.inspect(actualDescriptor),
2176
+ 'expected the own property descriptor for ' +
2177
+ _.inspect(name) +
2178
+ ' on #{this} to not match ' +
2179
+ _.inspect(descriptor),
2180
+ descriptor,
2181
+ actualDescriptor,
2182
+ true
2099
2183
  );
2100
2184
  } else {
2101
2185
  this.assert(
2102
- actualDescriptor
2103
- , 'expected #{this} to have an own property descriptor for ' + _.inspect(name)
2104
- , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name)
2186
+ actualDescriptor,
2187
+ 'expected #{this} to have an own property descriptor for ' +
2188
+ _.inspect(name),
2189
+ 'expected #{this} to not have an own property descriptor for ' +
2190
+ _.inspect(name)
2105
2191
  );
2106
2192
  }
2107
2193
  flag(this, 'object', actualDescriptor);
@@ -2113,7 +2199,7 @@ Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor);
2113
2199
  /**
2114
2200
  *
2115
2201
  */
2116
- function assertLengthChain () {
2202
+ function assertLengthChain() {
2117
2203
  flag(this, 'doLength', true);
2118
2204
  }
2119
2205
 
@@ -2174,14 +2260,14 @@ function assertLengthChain () {
2174
2260
  * @namespace BDD
2175
2261
  * @public
2176
2262
  */
2177
- function assertLength (n, msg) {
2263
+ function assertLength(n, msg) {
2178
2264
  if (msg) flag(this, 'message', msg);
2179
- var obj = flag(this, 'object')
2180
- , objType = _.type(obj).toLowerCase()
2181
- , flagMsg = flag(this, 'message')
2182
- , ssfi = flag(this, 'ssfi')
2183
- , descriptor = 'length'
2184
- , itemsCount;
2265
+ var obj = flag(this, 'object'),
2266
+ objType = _.type(obj).toLowerCase(),
2267
+ flagMsg = flag(this, 'message'),
2268
+ ssfi = flag(this, 'ssfi'),
2269
+ descriptor = 'length',
2270
+ itemsCount;
2185
2271
 
2186
2272
  switch (objType) {
2187
2273
  case 'map':
@@ -2195,11 +2281,11 @@ function assertLength (n, msg) {
2195
2281
  }
2196
2282
 
2197
2283
  this.assert(
2198
- itemsCount == n
2199
- , 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}'
2200
- , 'expected #{this} to not have a ' + descriptor + ' of #{act}'
2201
- , n
2202
- , itemsCount
2284
+ itemsCount == n,
2285
+ 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}',
2286
+ 'expected #{this} to not have a ' + descriptor + ' of #{act}',
2287
+ n,
2288
+ itemsCount
2203
2289
  );
2204
2290
  }
2205
2291
 
@@ -2237,9 +2323,9 @@ function assertMatch(re, msg) {
2237
2323
  if (msg) flag(this, 'message', msg);
2238
2324
  var obj = flag(this, 'object');
2239
2325
  this.assert(
2240
- re.exec(obj)
2241
- , 'expected #{this} to match ' + re
2242
- , 'expected #{this} not to match ' + re
2326
+ re.exec(obj),
2327
+ 'expected #{this} to match ' + re,
2328
+ 'expected #{this} not to match ' + re
2243
2329
  );
2244
2330
  }
2245
2331
 
@@ -2272,15 +2358,15 @@ Assertion.addMethod('matches', assertMatch);
2272
2358
  */
2273
2359
  Assertion.addMethod('string', function (str, msg) {
2274
2360
  if (msg) flag(this, 'message', msg);
2275
- var obj = flag(this, 'object')
2276
- , flagMsg = flag(this, 'message')
2277
- , ssfi = flag(this, 'ssfi');
2361
+ var obj = flag(this, 'object'),
2362
+ flagMsg = flag(this, 'message'),
2363
+ ssfi = flag(this, 'ssfi');
2278
2364
  new Assertion(obj, flagMsg, ssfi, true).is.a('string');
2279
2365
 
2280
2366
  this.assert(
2281
- ~obj.indexOf(str)
2282
- , 'expected #{this} to contain ' + _.inspect(str)
2283
- , 'expected #{this} to not contain ' + _.inspect(str)
2367
+ ~obj.indexOf(str),
2368
+ 'expected #{this} to contain ' + _.inspect(str),
2369
+ 'expected #{this} to not contain ' + _.inspect(str)
2284
2370
  );
2285
2371
  });
2286
2372
 
@@ -2387,27 +2473,31 @@ Assertion.addMethod('string', function (str, msg) {
2387
2473
  * @namespace BDD
2388
2474
  * @public
2389
2475
  */
2390
- function assertKeys (keys) {
2391
- var obj = flag(this, 'object')
2392
- , objType = _.type(obj)
2393
- , keysType = _.type(keys)
2394
- , ssfi = flag(this, 'ssfi')
2395
- , isDeep = flag(this, 'deep')
2396
- , str
2397
- , deepStr = ''
2398
- , actual
2399
- , ok = true
2400
- , flagMsg = flag(this, 'message');
2476
+ function assertKeys(keys) {
2477
+ var obj = flag(this, 'object'),
2478
+ objType = _.type(obj),
2479
+ keysType = _.type(keys),
2480
+ ssfi = flag(this, 'ssfi'),
2481
+ isDeep = flag(this, 'deep'),
2482
+ str,
2483
+ deepStr = '',
2484
+ actual,
2485
+ ok = true,
2486
+ flagMsg = flag(this, 'message');
2401
2487
 
2402
2488
  flagMsg = flagMsg ? flagMsg + ': ' : '';
2403
- var mixedArgsMsg = flagMsg + 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments';
2489
+ var mixedArgsMsg =
2490
+ flagMsg +
2491
+ 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments';
2404
2492
 
2405
2493
  if (objType === 'Map' || objType === 'Set') {
2406
2494
  deepStr = isDeep ? 'deeply ' : '';
2407
2495
  actual = [];
2408
2496
 
2409
2497
  // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach.
2410
- obj.forEach(function (val, key) { actual.push(key) });
2498
+ obj.forEach(function (val, key) {
2499
+ actual.push(key);
2500
+ });
2411
2501
 
2412
2502
  if (keysType !== 'Array') {
2413
2503
  keys = Array.prototype.slice.call(arguments);
@@ -2441,11 +2531,11 @@ function assertKeys (keys) {
2441
2531
  throw new AssertionError(flagMsg + 'keys required', undefined, ssfi);
2442
2532
  }
2443
2533
 
2444
- var len = keys.length
2445
- , any = flag(this, 'any')
2446
- , all = flag(this, 'all')
2447
- , expected = keys
2448
- , isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
2534
+ var len = keys.length,
2535
+ any = flag(this, 'any'),
2536
+ all = flag(this, 'all'),
2537
+ expected = keys,
2538
+ isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
2449
2539
 
2450
2540
  if (!any && !all) {
2451
2541
  all = true;
@@ -2453,8 +2543,8 @@ function assertKeys (keys) {
2453
2543
 
2454
2544
  // Has any
2455
2545
  if (any) {
2456
- ok = expected.some(function(expectedKey) {
2457
- return actual.some(function(actualKey) {
2546
+ ok = expected.some(function (expectedKey) {
2547
+ return actual.some(function (actualKey) {
2458
2548
  return isEql(expectedKey, actualKey);
2459
2549
  });
2460
2550
  });
@@ -2462,8 +2552,8 @@ function assertKeys (keys) {
2462
2552
 
2463
2553
  // Has all
2464
2554
  if (all) {
2465
- ok = expected.every(function(expectedKey) {
2466
- return actual.some(function(actualKey) {
2555
+ ok = expected.every(function (expectedKey) {
2556
+ return actual.some(function (actualKey) {
2467
2557
  return isEql(expectedKey, actualKey);
2468
2558
  });
2469
2559
  });
@@ -2475,7 +2565,7 @@ function assertKeys (keys) {
2475
2565
 
2476
2566
  // Key string
2477
2567
  if (len > 1) {
2478
- keys = keys.map(function(key) {
2568
+ keys = keys.map(function (key) {
2479
2569
  return _.inspect(key);
2480
2570
  });
2481
2571
  var last = keys.pop();
@@ -2497,12 +2587,12 @@ function assertKeys (keys) {
2497
2587
 
2498
2588
  // Assertion
2499
2589
  this.assert(
2500
- ok
2501
- , 'expected #{this} to ' + deepStr + str
2502
- , 'expected #{this} to not ' + deepStr + str
2503
- , expected.slice(0).sort(_.compareByInspect)
2504
- , actual.sort(_.compareByInspect)
2505
- , true
2590
+ ok,
2591
+ 'expected #{this} to ' + deepStr + str,
2592
+ 'expected #{this} to not ' + deepStr + str,
2593
+ expected.slice(0).sort(_.compareByInspect),
2594
+ actual.sort(_.compareByInspect),
2595
+ true
2506
2596
  );
2507
2597
  }
2508
2598
 
@@ -2668,12 +2758,12 @@ Assertion.addMethod('key', assertKeys);
2668
2758
  * @namespace BDD
2669
2759
  * @public
2670
2760
  */
2671
- function assertThrows (errorLike, errMsgMatcher, msg) {
2761
+ function assertThrows(errorLike, errMsgMatcher, msg) {
2672
2762
  if (msg) flag(this, 'message', msg);
2673
- var obj = flag(this, 'object')
2674
- , ssfi = flag(this, 'ssfi')
2675
- , flagMsg = flag(this, 'message')
2676
- , negate = flag(this, 'negate') || false;
2763
+ var obj = flag(this, 'object'),
2764
+ ssfi = flag(this, 'ssfi'),
2765
+ flagMsg = flag(this, 'message'),
2766
+ negate = flag(this, 'negate') || false;
2677
2767
  new Assertion(obj, flagMsg, ssfi, true).is.a('function');
2678
2768
 
2679
2769
  if (_.isRegExp(errorLike) || typeof errorLike === 'string') {
@@ -2692,7 +2782,8 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2692
2782
 
2693
2783
  // If we have the negate flag enabled and at least one valid argument it means we do expect an error
2694
2784
  // but we want it to match a given set of criteria
2695
- var everyArgIsUndefined = errorLike === undefined && errMsgMatcher === undefined;
2785
+ var everyArgIsUndefined =
2786
+ errorLike === undefined && errMsgMatcher === undefined;
2696
2787
 
2697
2788
  // If we've got the negate flag enabled and both args, we should only fail if both aren't compatible
2698
2789
  // See Issue #551 and PR #683@GitHub
@@ -2701,7 +2792,7 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2701
2792
  var errMsgMatcherFail = false;
2702
2793
 
2703
2794
  // Checking if error was thrown
2704
- if (everyArgIsUndefined || !everyArgIsUndefined && !negate) {
2795
+ if (everyArgIsUndefined || (!everyArgIsUndefined && !negate)) {
2705
2796
  // We need this to display results correctly according to their types
2706
2797
  var errorLikeString = 'an error';
2707
2798
  if (errorLike instanceof Error) {
@@ -2715,7 +2806,10 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2715
2806
  actual = caughtErr.toString();
2716
2807
  } else if (typeof caughtErr === 'string') {
2717
2808
  actual = caughtErr;
2718
- } else if (caughtErr && (typeof caughtErr === 'object' || typeof caughtErr === 'function')) {
2809
+ } else if (
2810
+ caughtErr &&
2811
+ (typeof caughtErr === 'object' || typeof caughtErr === 'function')
2812
+ ) {
2719
2813
  try {
2720
2814
  actual = _.checkError.getConstructorName(caughtErr);
2721
2815
  } catch (_err) {
@@ -2725,18 +2819,21 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2725
2819
  }
2726
2820
 
2727
2821
  this.assert(
2728
- errorWasThrown
2729
- , 'expected #{this} to throw ' + errorLikeString
2730
- , 'expected #{this} to not throw an error but #{act} was thrown'
2731
- , errorLike && errorLike.toString()
2732
- , actual
2822
+ errorWasThrown,
2823
+ 'expected #{this} to throw ' + errorLikeString,
2824
+ 'expected #{this} to not throw an error but #{act} was thrown',
2825
+ errorLike && errorLike.toString(),
2826
+ actual
2733
2827
  );
2734
2828
  }
2735
2829
 
2736
2830
  if (errorLike && caughtErr) {
2737
2831
  // We should compare instances only if `errorLike` is an instance of `Error`
2738
2832
  if (errorLike instanceof Error) {
2739
- var isCompatibleInstance = _.checkError.compatibleInstance(caughtErr, errorLike);
2833
+ var isCompatibleInstance = _.checkError.compatibleInstance(
2834
+ caughtErr,
2835
+ errorLike
2836
+ );
2740
2837
 
2741
2838
  if (isCompatibleInstance === negate) {
2742
2839
  // These checks were created to ensure we won't fail too soon when we've got both args and a negate
@@ -2745,27 +2842,36 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2745
2842
  errorLikeFail = true;
2746
2843
  } else {
2747
2844
  this.assert(
2748
- negate
2749
- , 'expected #{this} to throw #{exp} but #{act} was thrown'
2750
- , 'expected #{this} to not throw #{exp}' + (caughtErr && !negate ? ' but #{act} was thrown' : '')
2751
- , errorLike.toString()
2752
- , caughtErr.toString()
2845
+ negate,
2846
+ 'expected #{this} to throw #{exp} but #{act} was thrown',
2847
+ 'expected #{this} to not throw #{exp}' +
2848
+ (caughtErr && !negate ? ' but #{act} was thrown' : ''),
2849
+ errorLike.toString(),
2850
+ caughtErr.toString()
2753
2851
  );
2754
2852
  }
2755
2853
  }
2756
2854
  }
2757
2855
 
2758
- var isCompatibleConstructor = _.checkError.compatibleConstructor(caughtErr, errorLike);
2856
+ var isCompatibleConstructor = _.checkError.compatibleConstructor(
2857
+ caughtErr,
2858
+ errorLike
2859
+ );
2759
2860
  if (isCompatibleConstructor === negate) {
2760
2861
  if (everyArgIsDefined && negate) {
2761
- errorLikeFail = true;
2862
+ errorLikeFail = true;
2762
2863
  } else {
2763
2864
  this.assert(
2764
- negate
2765
- , 'expected #{this} to throw #{exp} but #{act} was thrown'
2766
- , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '')
2767
- , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike))
2768
- , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr))
2865
+ negate,
2866
+ 'expected #{this} to throw #{exp} but #{act} was thrown',
2867
+ 'expected #{this} to not throw #{exp}' +
2868
+ (caughtErr ? ' but #{act} was thrown' : ''),
2869
+ errorLike instanceof Error
2870
+ ? errorLike.toString()
2871
+ : errorLike && _.checkError.getConstructorName(errorLike),
2872
+ caughtErr instanceof Error
2873
+ ? caughtErr.toString()
2874
+ : caughtErr && _.checkError.getConstructorName(caughtErr)
2769
2875
  );
2770
2876
  }
2771
2877
  }
@@ -2775,20 +2881,25 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2775
2881
  // Here we check compatible messages
2776
2882
  var placeholder = 'including';
2777
2883
  if (_.isRegExp(errMsgMatcher)) {
2778
- placeholder = 'matching'
2884
+ placeholder = 'matching';
2779
2885
  }
2780
2886
 
2781
- var isCompatibleMessage = _.checkError.compatibleMessage(caughtErr, errMsgMatcher);
2887
+ var isCompatibleMessage = _.checkError.compatibleMessage(
2888
+ caughtErr,
2889
+ errMsgMatcher
2890
+ );
2782
2891
  if (isCompatibleMessage === negate) {
2783
2892
  if (everyArgIsDefined && negate) {
2784
- errMsgMatcherFail = true;
2893
+ errMsgMatcherFail = true;
2785
2894
  } else {
2786
2895
  this.assert(
2787
- negate
2788
- , 'expected #{this} to throw error ' + placeholder + ' #{exp} but got #{act}'
2789
- , 'expected #{this} to throw error not ' + placeholder + ' #{exp}'
2790
- , errMsgMatcher
2791
- , _.checkError.getMessage(caughtErr)
2896
+ negate,
2897
+ 'expected #{this} to throw error ' +
2898
+ placeholder +
2899
+ ' #{exp} but got #{act}',
2900
+ 'expected #{this} to throw error not ' + placeholder + ' #{exp}',
2901
+ errMsgMatcher,
2902
+ _.checkError.getMessage(caughtErr)
2792
2903
  );
2793
2904
  }
2794
2905
  }
@@ -2797,16 +2908,21 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2797
2908
  // If both assertions failed and both should've matched we throw an error
2798
2909
  if (errorLikeFail && errMsgMatcherFail) {
2799
2910
  this.assert(
2800
- negate
2801
- , 'expected #{this} to throw #{exp} but #{act} was thrown'
2802
- , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '')
2803
- , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike))
2804
- , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr))
2911
+ negate,
2912
+ 'expected #{this} to throw #{exp} but #{act} was thrown',
2913
+ 'expected #{this} to not throw #{exp}' +
2914
+ (caughtErr ? ' but #{act} was thrown' : ''),
2915
+ errorLike instanceof Error
2916
+ ? errorLike.toString()
2917
+ : errorLike && _.checkError.getConstructorName(errorLike),
2918
+ caughtErr instanceof Error
2919
+ ? caughtErr.toString()
2920
+ : caughtErr && _.checkError.getConstructorName(caughtErr)
2805
2921
  );
2806
2922
  }
2807
2923
 
2808
2924
  flag(this, 'object', caughtErr);
2809
- };
2925
+ }
2810
2926
 
2811
2927
  Assertion.addMethod('throw', assertThrows);
2812
2928
  Assertion.addMethod('throws', assertThrows);
@@ -2876,18 +2992,19 @@ Assertion.addMethod('Throw', assertThrows);
2876
2992
  * @namespace BDD
2877
2993
  * @public
2878
2994
  */
2879
- function respondTo (method, msg) {
2995
+ function respondTo(method, msg) {
2880
2996
  if (msg) flag(this, 'message', msg);
2881
- var obj = flag(this, 'object')
2882
- , itself = flag(this, 'itself')
2883
- , context = ('function' === typeof obj && !itself)
2884
- ? obj.prototype[method]
2885
- : obj[method];
2997
+ var obj = flag(this, 'object'),
2998
+ itself = flag(this, 'itself'),
2999
+ context =
3000
+ 'function' === typeof obj && !itself
3001
+ ? obj.prototype[method]
3002
+ : obj[method];
2886
3003
 
2887
3004
  this.assert(
2888
- 'function' === typeof context
2889
- , 'expected #{this} to respond to ' + _.inspect(method)
2890
- , 'expected #{this} to not respond to ' + _.inspect(method)
3005
+ 'function' === typeof context,
3006
+ 'expected #{this} to respond to ' + _.inspect(method),
3007
+ 'expected #{this} to not respond to ' + _.inspect(method)
2891
3008
  );
2892
3009
  }
2893
3010
 
@@ -2954,16 +3071,16 @@ Assertion.addProperty('itself', function () {
2954
3071
  * @namespace BDD
2955
3072
  * @public
2956
3073
  */
2957
- function satisfy (matcher, msg) {
3074
+ function satisfy(matcher, msg) {
2958
3075
  if (msg) flag(this, 'message', msg);
2959
3076
  var obj = flag(this, 'object');
2960
3077
  var result = matcher(obj);
2961
3078
  this.assert(
2962
- result
2963
- , 'expected #{this} to satisfy ' + _.objDisplay(matcher)
2964
- , 'expected #{this} to not satisfy' + _.objDisplay(matcher)
2965
- , flag(this, 'negate') ? false : true
2966
- , result
3079
+ result,
3080
+ 'expected #{this} to satisfy ' + _.objDisplay(matcher),
3081
+ 'expected #{this} to not satisfy' + _.objDisplay(matcher),
3082
+ flag(this, 'negate') ? false : true,
3083
+ result
2967
3084
  );
2968
3085
  }
2969
3086
 
@@ -3009,25 +3126,38 @@ Assertion.addMethod('satisfies', satisfy);
3009
3126
  */
3010
3127
  function closeTo(expected, delta, msg) {
3011
3128
  if (msg) flag(this, 'message', msg);
3012
- var obj = flag(this, 'object')
3013
- , flagMsg = flag(this, 'message')
3014
- , ssfi = flag(this, 'ssfi');
3015
-
3016
- new Assertion(obj, flagMsg, ssfi, true).is.a('number');
3017
- if (typeof expected !== 'number' || typeof delta !== 'number') {
3018
- flagMsg = flagMsg ? flagMsg + ': ' : '';
3019
- var deltaMessage = delta === undefined ? ", and a delta is required" : "";
3129
+ var obj = flag(this, 'object'),
3130
+ flagMsg = flag(this, 'message'),
3131
+ ssfi = flag(this, 'ssfi');
3132
+
3133
+ new Assertion(obj, flagMsg, ssfi, true).is.numeric;
3134
+ let message = 'A `delta` value is required for `closeTo`';
3135
+ if (delta == undefined)
3020
3136
  throw new AssertionError(
3021
- flagMsg + 'the arguments to closeTo or approximately must be numbers' + deltaMessage,
3022
- undefined,
3023
- ssfi
3137
+ flagMsg ? `${flagMsg}: ${message}` : message,
3138
+ undefined,
3139
+ ssfi
3024
3140
  );
3025
- }
3141
+ new Assertion(delta, flagMsg, ssfi, true).is.numeric;
3142
+ message = 'A `expected` value is required for `closeTo`';
3143
+ if (expected == undefined)
3144
+ throw new AssertionError(
3145
+ flagMsg ? `${flagMsg}: ${message}` : message,
3146
+ undefined,
3147
+ ssfi
3148
+ );
3149
+ new Assertion(expected, flagMsg, ssfi, true).is.numeric;
3150
+
3151
+ const abs = (x) => (x < 0n ? -x : x);
3152
+
3153
+ // Used to round floating point number precision arithmetics
3154
+ // See: https://stackoverflow.com/a/3644302
3155
+ const strip = (number) => parseFloat(parseFloat(number).toPrecision(12));
3026
3156
 
3027
3157
  this.assert(
3028
- Math.abs(obj - expected) <= delta
3029
- , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
3030
- , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
3158
+ strip(abs(obj - expected)) <= delta,
3159
+ 'expected #{this} to be close to ' + expected + ' +/- ' + delta,
3160
+ 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
3031
3161
  );
3032
3162
  }
3033
3163
 
@@ -3050,7 +3180,7 @@ function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3050
3180
  superset = superset.slice();
3051
3181
  }
3052
3182
 
3053
- return subset.every(function(elem, idx) {
3183
+ return subset.every(function (elem, idx) {
3054
3184
  if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx];
3055
3185
 
3056
3186
  if (!cmp) {
@@ -3062,7 +3192,7 @@ function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3062
3192
  return true;
3063
3193
  }
3064
3194
 
3065
- return superset.some(function(elem2, matchIdx) {
3195
+ return superset.some(function (elem2, matchIdx) {
3066
3196
  if (!cmp(elem, elem2)) return false;
3067
3197
 
3068
3198
  // Remove match from superset so not counted twice if duplicate in subset.
@@ -3142,9 +3272,9 @@ function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3142
3272
  */
3143
3273
  Assertion.addMethod('members', function (subset, msg) {
3144
3274
  if (msg) flag(this, 'message', msg);
3145
- var obj = flag(this, 'object')
3146
- , flagMsg = flag(this, 'message')
3147
- , ssfi = flag(this, 'ssfi');
3275
+ var obj = flag(this, 'object'),
3276
+ flagMsg = flag(this, 'message'),
3277
+ ssfi = flag(this, 'ssfi');
3148
3278
 
3149
3279
  new Assertion(obj, flagMsg, ssfi, true).to.be.iterable;
3150
3280
  new Assertion(subset, flagMsg, ssfi, true).to.be.iterable;
@@ -3161,18 +3291,19 @@ Assertion.addMethod('members', function (subset, msg) {
3161
3291
  } else {
3162
3292
  subject = ordered ? 'ordered members' : 'members';
3163
3293
  failMsg = 'expected #{this} to have the same ' + subject + ' as #{exp}';
3164
- failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}';
3294
+ failNegateMsg =
3295
+ 'expected #{this} to not have the same ' + subject + ' as #{exp}';
3165
3296
  }
3166
3297
 
3167
3298
  var cmp = flag(this, 'deep') ? flag(this, 'eql') : undefined;
3168
3299
 
3169
3300
  this.assert(
3170
- isSubsetOf(subset, obj, cmp, contains, ordered)
3171
- , failMsg
3172
- , failNegateMsg
3173
- , subset
3174
- , obj
3175
- , true
3301
+ isSubsetOf(subset, obj, cmp, contains, ordered),
3302
+ failMsg,
3303
+ failNegateMsg,
3304
+ subset,
3305
+ obj,
3306
+ true
3176
3307
  );
3177
3308
  });
3178
3309
 
@@ -3197,15 +3328,15 @@ Assertion.addMethod('members', function (subset, msg) {
3197
3328
  * @namespace BDD
3198
3329
  * @public
3199
3330
  */
3200
- Assertion.addProperty('iterable', function(msg) {
3331
+ Assertion.addProperty('iterable', function (msg) {
3201
3332
  if (msg) flag(this, 'message', msg);
3202
3333
  var obj = flag(this, 'object');
3203
3334
 
3204
3335
  this.assert(
3205
- obj != undefined && obj[Symbol.iterator]
3206
- , 'expected #{this} to be an iterable'
3207
- , 'expected #{this} to not be an iterable'
3208
- , obj
3336
+ obj != undefined && obj[Symbol.iterator],
3337
+ 'expected #{this} to be an iterable',
3338
+ 'expected #{this} to not be an iterable',
3339
+ obj
3209
3340
  );
3210
3341
  });
3211
3342
 
@@ -3246,40 +3377,44 @@ Assertion.addProperty('iterable', function(msg) {
3246
3377
  * @namespace BDD
3247
3378
  * @public
3248
3379
  */
3249
- function oneOf (list, msg) {
3380
+ function oneOf(list, msg) {
3250
3381
  if (msg) flag(this, 'message', msg);
3251
- var expected = flag(this, 'object')
3252
- , flagMsg = flag(this, 'message')
3253
- , ssfi = flag(this, 'ssfi')
3254
- , contains = flag(this, 'contains')
3255
- , isDeep = flag(this, 'deep')
3256
- , eql = flag(this, 'eql');
3382
+ var expected = flag(this, 'object'),
3383
+ flagMsg = flag(this, 'message'),
3384
+ ssfi = flag(this, 'ssfi'),
3385
+ contains = flag(this, 'contains'),
3386
+ isDeep = flag(this, 'deep'),
3387
+ eql = flag(this, 'eql');
3257
3388
  new Assertion(list, flagMsg, ssfi, true).to.be.an('array');
3258
3389
 
3259
3390
  if (contains) {
3260
3391
  this.assert(
3261
- list.some(function(possibility) { return expected.indexOf(possibility) > -1 })
3262
- , 'expected #{this} to contain one of #{exp}'
3263
- , 'expected #{this} to not contain one of #{exp}'
3264
- , list
3265
- , expected
3392
+ list.some(function (possibility) {
3393
+ return expected.indexOf(possibility) > -1;
3394
+ }),
3395
+ 'expected #{this} to contain one of #{exp}',
3396
+ 'expected #{this} to not contain one of #{exp}',
3397
+ list,
3398
+ expected
3266
3399
  );
3267
3400
  } else {
3268
3401
  if (isDeep) {
3269
3402
  this.assert(
3270
- list.some(function(possibility) { return eql(expected, possibility) })
3271
- , 'expected #{this} to deeply equal one of #{exp}'
3272
- , 'expected #{this} to deeply equal one of #{exp}'
3273
- , list
3274
- , expected
3403
+ list.some(function (possibility) {
3404
+ return eql(expected, possibility);
3405
+ }),
3406
+ 'expected #{this} to deeply equal one of #{exp}',
3407
+ 'expected #{this} to deeply equal one of #{exp}',
3408
+ list,
3409
+ expected
3275
3410
  );
3276
3411
  } else {
3277
3412
  this.assert(
3278
- list.indexOf(expected) > -1
3279
- , 'expected #{this} to be one of #{exp}'
3280
- , 'expected #{this} to not be one of #{exp}'
3281
- , list
3282
- , expected
3413
+ list.indexOf(expected) > -1,
3414
+ 'expected #{this} to be one of #{exp}',
3415
+ 'expected #{this} to not be one of #{exp}',
3416
+ list,
3417
+ expected
3283
3418
  );
3284
3419
  }
3285
3420
  }
@@ -3381,11 +3516,11 @@ Assertion.addMethod('oneOf', oneOf);
3381
3516
  * @namespace BDD
3382
3517
  * @public
3383
3518
  */
3384
- function assertChanges (subject, prop, msg) {
3519
+ function assertChanges(subject, prop, msg) {
3385
3520
  if (msg) flag(this, 'message', msg);
3386
- var fn = flag(this, 'object')
3387
- , flagMsg = flag(this, 'message')
3388
- , ssfi = flag(this, 'ssfi');
3521
+ var fn = flag(this, 'object'),
3522
+ flagMsg = flag(this, 'message'),
3523
+ ssfi = flag(this, 'ssfi');
3389
3524
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');
3390
3525
 
3391
3526
  var initial;
@@ -3410,9 +3545,9 @@ function assertChanges (subject, prop, msg) {
3410
3545
  flag(this, 'realDelta', final !== initial);
3411
3546
 
3412
3547
  this.assert(
3413
- initial !== final
3414
- , 'expected ' + msgObj + ' to change'
3415
- , 'expected ' + msgObj + ' to not change'
3548
+ initial !== final,
3549
+ 'expected ' + msgObj + ' to change',
3550
+ 'expected ' + msgObj + ' to not change'
3416
3551
  );
3417
3552
  }
3418
3553
 
@@ -3497,11 +3632,11 @@ Assertion.addMethod('changes', assertChanges);
3497
3632
  * @namespace BDD
3498
3633
  * @public
3499
3634
  */
3500
- function assertIncreases (subject, prop, msg) {
3635
+ function assertIncreases(subject, prop, msg) {
3501
3636
  if (msg) flag(this, 'message', msg);
3502
- var fn = flag(this, 'object')
3503
- , flagMsg = flag(this, 'message')
3504
- , ssfi = flag(this, 'ssfi');
3637
+ var fn = flag(this, 'object'),
3638
+ flagMsg = flag(this, 'message'),
3639
+ ssfi = flag(this, 'ssfi');
3505
3640
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');
3506
3641
 
3507
3642
  var initial;
@@ -3528,9 +3663,9 @@ function assertIncreases (subject, prop, msg) {
3528
3663
  flag(this, 'realDelta', final - initial);
3529
3664
 
3530
3665
  this.assert(
3531
- final - initial > 0
3532
- , 'expected ' + msgObj + ' to increase'
3533
- , 'expected ' + msgObj + ' to not increase'
3666
+ final - initial > 0,
3667
+ 'expected ' + msgObj + ' to increase',
3668
+ 'expected ' + msgObj + ' to not increase'
3534
3669
  );
3535
3670
  }
3536
3671
 
@@ -3615,11 +3750,11 @@ Assertion.addMethod('increases', assertIncreases);
3615
3750
  * @namespace BDD
3616
3751
  * @public
3617
3752
  */
3618
- function assertDecreases (subject, prop, msg) {
3753
+ function assertDecreases(subject, prop, msg) {
3619
3754
  if (msg) flag(this, 'message', msg);
3620
- var fn = flag(this, 'object')
3621
- , flagMsg = flag(this, 'message')
3622
- , ssfi = flag(this, 'ssfi');
3755
+ var fn = flag(this, 'object'),
3756
+ flagMsg = flag(this, 'message'),
3757
+ ssfi = flag(this, 'ssfi');
3623
3758
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');
3624
3759
 
3625
3760
  var initial;
@@ -3646,9 +3781,9 @@ function assertDecreases (subject, prop, msg) {
3646
3781
  flag(this, 'realDelta', initial - final);
3647
3782
 
3648
3783
  this.assert(
3649
- final - initial < 0
3650
- , 'expected ' + msgObj + ' to decrease'
3651
- , 'expected ' + msgObj + ' to not decrease'
3784
+ final - initial < 0,
3785
+ 'expected ' + msgObj + ' to decrease',
3786
+ 'expected ' + msgObj + ' to not decrease'
3652
3787
  );
3653
3788
  }
3654
3789
 
@@ -3737,9 +3872,9 @@ function assertDelta(delta, msg) {
3737
3872
  }
3738
3873
 
3739
3874
  this.assert(
3740
- expression
3741
- , 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta
3742
- , 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta
3875
+ expression,
3876
+ 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta,
3877
+ 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta
3743
3878
  );
3744
3879
  }
3745
3880
 
@@ -3772,7 +3907,7 @@ Assertion.addMethod('by', assertDelta);
3772
3907
  * @namespace BDD
3773
3908
  * @public
3774
3909
  */
3775
- Assertion.addProperty('extensible', function() {
3910
+ Assertion.addProperty('extensible', function () {
3776
3911
  var obj = flag(this, 'object');
3777
3912
 
3778
3913
  // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.
@@ -3783,9 +3918,9 @@ Assertion.addProperty('extensible', function() {
3783
3918
  var isExtensible = obj === Object(obj) && Object.isExtensible(obj);
3784
3919
 
3785
3920
  this.assert(
3786
- isExtensible
3787
- , 'expected #{this} to be extensible'
3788
- , 'expected #{this} to not be extensible'
3921
+ isExtensible,
3922
+ 'expected #{this} to be extensible',
3923
+ 'expected #{this} to not be extensible'
3789
3924
  );
3790
3925
  });
3791
3926
 
@@ -3816,7 +3951,7 @@ Assertion.addProperty('extensible', function() {
3816
3951
  * @namespace BDD
3817
3952
  * @public
3818
3953
  */
3819
- Assertion.addProperty('sealed', function() {
3954
+ Assertion.addProperty('sealed', function () {
3820
3955
  var obj = flag(this, 'object');
3821
3956
 
3822
3957
  // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.
@@ -3827,9 +3962,9 @@ Assertion.addProperty('sealed', function() {
3827
3962
  var isSealed = obj === Object(obj) ? Object.isSealed(obj) : true;
3828
3963
 
3829
3964
  this.assert(
3830
- isSealed
3831
- , 'expected #{this} to be sealed'
3832
- , 'expected #{this} to not be sealed'
3965
+ isSealed,
3966
+ 'expected #{this} to be sealed',
3967
+ 'expected #{this} to not be sealed'
3833
3968
  );
3834
3969
  });
3835
3970
 
@@ -3857,7 +3992,7 @@ Assertion.addProperty('sealed', function() {
3857
3992
  * @namespace BDD
3858
3993
  * @public
3859
3994
  */
3860
- Assertion.addProperty('frozen', function() {
3995
+ Assertion.addProperty('frozen', function () {
3861
3996
  var obj = flag(this, 'object');
3862
3997
 
3863
3998
  // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.
@@ -3868,9 +4003,9 @@ Assertion.addProperty('frozen', function() {
3868
4003
  var isFrozen = obj === Object(obj) ? Object.isFrozen(obj) : true;
3869
4004
 
3870
4005
  this.assert(
3871
- isFrozen
3872
- , 'expected #{this} to be frozen'
3873
- , 'expected #{this} to not be frozen'
4006
+ isFrozen,
4007
+ 'expected #{this} to be frozen',
4008
+ 'expected #{this} to not be frozen'
3874
4009
  );
3875
4010
  });
3876
4011
 
@@ -3922,12 +4057,101 @@ Assertion.addProperty('frozen', function() {
3922
4057
  * @namespace BDD
3923
4058
  * @public
3924
4059
  */
3925
- Assertion.addProperty('finite', function(msg) {
4060
+ Assertion.addProperty('finite', function (_msg) {
3926
4061
  var obj = flag(this, 'object');
3927
4062
 
3928
4063
  this.assert(
3929
- typeof obj === 'number' && isFinite(obj)
3930
- , 'expected #{this} to be a finite number'
3931
- , 'expected #{this} to not be a finite number'
4064
+ typeof obj === 'number' && isFinite(obj),
4065
+ 'expected #{this} to be a finite number',
4066
+ 'expected #{this} to not be a finite number'
4067
+ );
4068
+ });
4069
+
4070
+ /**
4071
+ * A subset-aware compare function
4072
+ *
4073
+ * @param {unknown} expected
4074
+ * @param {unknown} actual
4075
+ * @returns {boolean}
4076
+ */
4077
+ function compareSubset(expected, actual) {
4078
+ if (expected === actual) {
4079
+ return true;
4080
+ }
4081
+ if (typeof actual !== typeof expected) {
4082
+ return false;
4083
+ }
4084
+ if (typeof expected !== 'object' || expected === null) {
4085
+ return expected === actual;
4086
+ }
4087
+ if (!actual) {
4088
+ return false;
4089
+ }
4090
+
4091
+ if (Array.isArray(expected)) {
4092
+ if (!Array.isArray(actual)) {
4093
+ return false;
4094
+ }
4095
+ return expected.every(function (exp) {
4096
+ return actual.some(function (act) {
4097
+ return compareSubset(exp, act);
4098
+ });
4099
+ });
4100
+ }
4101
+
4102
+ if (expected instanceof Date) {
4103
+ if (actual instanceof Date) {
4104
+ return expected.getTime() === actual.getTime();
4105
+ } else {
4106
+ return false;
4107
+ }
4108
+ }
4109
+
4110
+ return Object.keys(expected).every(function (key) {
4111
+ var expectedValue = expected[key];
4112
+ var actualValue = actual[key];
4113
+ if (
4114
+ typeof expectedValue === 'object' &&
4115
+ expectedValue !== null &&
4116
+ actualValue !== null
4117
+ ) {
4118
+ return compareSubset(expectedValue, actualValue);
4119
+ }
4120
+ if (typeof expectedValue === 'function') {
4121
+ return expectedValue(actualValue);
4122
+ }
4123
+ return actualValue === expectedValue;
4124
+ });
4125
+ }
4126
+
4127
+ /**
4128
+ * ### .containSubset
4129
+ *
4130
+ * Asserts that the target primitive/object/array structure deeply contains all provided fields
4131
+ * at the same key/depth as the provided structure.
4132
+ *
4133
+ * When comparing arrays, the target must contain the subset of at least one of each object/value in the subset array.
4134
+ * Order does not matter.
4135
+ *
4136
+ * expect({name: {first: "John", last: "Smith"}}).to.containSubset({name: {first: "John"}});
4137
+ *
4138
+ * Add `.not` earlier in the chain to negate the assertion. This will cause the assertion to fail
4139
+ * only if the target DOES contains the provided data at the expected keys/depths.
4140
+ *
4141
+ * @name containSubset
4142
+ * @namespace BDD
4143
+ * @public
4144
+ */
4145
+ Assertion.addMethod('containSubset', function (expected) {
4146
+ const actual = _.flag(this, 'object');
4147
+ const showDiff = config.showDiff;
4148
+
4149
+ this.assert(
4150
+ compareSubset(expected, actual),
4151
+ 'expected #{act} to contain subset #{exp}',
4152
+ 'expected #{act} to not contain subset #{exp}',
4153
+ expected,
4154
+ actual,
4155
+ showDiff
3932
4156
  );
3933
4157
  });