chai 5.1.2 → 5.2.1

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.
Files changed (38) hide show
  1. package/.prettierrc.json +10 -0
  2. package/README.md +1 -1
  3. package/chai.js +892 -542
  4. package/eslint.config.js +15 -0
  5. package/lib/chai/assertion.js +181 -141
  6. package/lib/chai/config.js +0 -2
  7. package/lib/chai/core/assertions.js +760 -538
  8. package/lib/chai/interface/assert.js +437 -260
  9. package/lib/chai/interface/expect.js +11 -7
  10. package/lib/chai/interface/should.js +27 -21
  11. package/lib/chai/utils/addChainableMethod.js +69 -70
  12. package/lib/chai/utils/addLengthGuard.js +18 -5
  13. package/lib/chai/utils/addMethod.js +4 -5
  14. package/lib/chai/utils/addProperty.js +27 -28
  15. package/lib/chai/utils/expectTypes.js +18 -10
  16. package/lib/chai/utils/flag.js +4 -3
  17. package/lib/chai/utils/getMessage.js +18 -12
  18. package/lib/chai/utils/getOperator.js +7 -7
  19. package/lib/chai/utils/getProperties.js +2 -2
  20. package/lib/chai/utils/index.js +8 -2
  21. package/lib/chai/utils/inspect.js +3 -3
  22. package/lib/chai/utils/isNaN.js +1 -20
  23. package/lib/chai/utils/isProxyEnabled.js +4 -2
  24. package/lib/chai/utils/objDisplay.js +7 -6
  25. package/lib/chai/utils/overwriteChainableMethod.js +15 -14
  26. package/lib/chai/utils/overwriteMethod.js +8 -9
  27. package/lib/chai/utils/overwriteProperty.js +38 -39
  28. package/lib/chai/utils/proxify.js +40 -29
  29. package/lib/chai/utils/test.js +2 -2
  30. package/lib/chai/utils/transferFlags.js +9 -4
  31. package/lib/chai/utils/type-detect.js +1 -1
  32. package/lib/chai.js +2 -1
  33. package/package.json +15 -7
  34. package/tsconfig.json +18 -0
  35. package/lib/chai/utils/getEnumerableProperties.js +0 -25
  36. package/register-assert.cjs +0 -3
  37. package/register-expect.cjs +0 -3
  38. package/register-should.cjs +0 -3
@@ -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
 
@@ -239,11 +255,16 @@ Assertion.addProperty('all', function () {
239
255
  });
240
256
 
241
257
  const functionTypes = {
242
- 'function': ['function', 'asyncfunction', 'generatorfunction', 'asyncgeneratorfunction'],
243
- 'asyncfunction': ['asyncfunction', 'asyncgeneratorfunction'],
244
- 'generatorfunction': ['generatorfunction', 'asyncgeneratorfunction'],
245
- 'asyncgeneratorfunction': ['asyncgeneratorfunction']
246
- }
258
+ function: [
259
+ 'function',
260
+ 'asyncfunction',
261
+ 'generatorfunction',
262
+ 'asyncgeneratorfunction'
263
+ ],
264
+ asyncfunction: ['asyncfunction', 'asyncgeneratorfunction'],
265
+ generatorfunction: ['generatorfunction', 'asyncgeneratorfunction'],
266
+ asyncgeneratorfunction: ['asyncgeneratorfunction']
267
+ };
247
268
 
248
269
  /**
249
270
  * ### .a(type[, msg])
@@ -304,25 +325,25 @@ const functionTypes = {
304
325
  * @namespace BDD
305
326
  * @public
306
327
  */
307
- function an (type, msg) {
328
+ function an(type, msg) {
308
329
  if (msg) flag(this, 'message', msg);
309
330
  type = type.toLowerCase();
310
- var obj = flag(this, 'object')
311
- , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';
331
+ let obj = flag(this, 'object'),
332
+ article = ~['a', 'e', 'i', 'o', 'u'].indexOf(type.charAt(0)) ? 'an ' : 'a ';
312
333
 
313
334
  const detectedType = _.type(obj).toLowerCase();
314
335
 
315
336
  if (functionTypes['function'].includes(type)) {
316
337
  this.assert(
317
- functionTypes[type].includes(detectedType)
318
- , 'expected #{this} to be ' + article + type
319
- , '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
320
341
  );
321
342
  } else {
322
343
  this.assert(
323
- type === detectedType
324
- , 'expected #{this} to be ' + article + type
325
- , '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
326
347
  );
327
348
  }
328
349
  }
@@ -331,7 +352,6 @@ Assertion.addChainableMethod('an', an);
331
352
  Assertion.addChainableMethod('a', an);
332
353
 
333
354
  /**
334
- *
335
355
  * @param {unknown} a
336
356
  * @param {unknown} b
337
357
  * @returns {boolean}
@@ -340,10 +360,8 @@ function SameValueZero(a, b) {
340
360
  return (_.isNaN(a) && _.isNaN(b)) || a === b;
341
361
  }
342
362
 
343
- /**
344
- *
345
- */
346
- function includeChainingBehavior () {
363
+ /** */
364
+ function includeChainingBehavior() {
347
365
  flag(this, 'contains', true);
348
366
  }
349
367
 
@@ -493,21 +511,21 @@ function includeChainingBehavior () {
493
511
  * @namespace BDD
494
512
  * @public
495
513
  */
496
- function include (val, msg) {
514
+ function include(val, msg) {
497
515
  if (msg) flag(this, 'message', msg);
498
516
 
499
- var obj = flag(this, 'object')
500
- , objType = _.type(obj).toLowerCase()
501
- , flagMsg = flag(this, 'message')
502
- , negate = flag(this, 'negate')
503
- , ssfi = flag(this, 'ssfi')
504
- , isDeep = flag(this, 'deep')
505
- , descriptor = isDeep ? 'deep ' : ''
506
- , isEql = isDeep ? flag(this, 'eql') : SameValueZero;
517
+ let obj = flag(this, 'object'),
518
+ objType = _.type(obj).toLowerCase(),
519
+ flagMsg = flag(this, 'message'),
520
+ negate = flag(this, 'negate'),
521
+ ssfi = flag(this, 'ssfi'),
522
+ isDeep = flag(this, 'deep'),
523
+ descriptor = isDeep ? 'deep ' : '',
524
+ isEql = isDeep ? flag(this, 'eql') : SameValueZero;
507
525
 
508
526
  flagMsg = flagMsg ? flagMsg + ': ' : '';
509
527
 
510
- var included = false;
528
+ let included = false;
511
529
 
512
530
  switch (objType) {
513
531
  case 'string':
@@ -546,36 +564,39 @@ function include (val, msg) {
546
564
  if (isDeep) {
547
565
  included = obj.some(function (item) {
548
566
  return isEql(item, val);
549
- })
567
+ });
550
568
  } else {
551
569
  included = obj.indexOf(val) !== -1;
552
570
  }
553
571
  break;
554
572
 
555
- default:
573
+ default: {
556
574
  // This block is for asserting a subset of properties in an object.
557
575
  // `_.expectTypes` isn't used here because `.include` should work with
558
576
  // objects with a custom `@@toStringTag`.
559
577
  if (val !== Object(val)) {
560
578
  throw new AssertionError(
561
- flagMsg + 'the given combination of arguments ('
562
- + objType + ' and '
563
- + _.type(val).toLowerCase() + ')'
564
- + ' is invalid for this assertion. '
565
- + 'You can use an array, a map, an object, a set, a string, '
566
- + 'or a weakset instead of a '
567
- + _.type(val).toLowerCase(),
579
+ flagMsg +
580
+ 'the given combination of arguments (' +
581
+ objType +
582
+ ' and ' +
583
+ _.type(val).toLowerCase() +
584
+ ')' +
585
+ ' is invalid for this assertion. ' +
586
+ 'You can use an array, a map, an object, a set, a string, ' +
587
+ 'or a weakset instead of a ' +
588
+ _.type(val).toLowerCase(),
568
589
  undefined,
569
590
  ssfi
570
591
  );
571
592
  }
572
593
 
573
- var props = Object.keys(val)
574
- , firstErr = null
575
- , numErrs = 0;
594
+ let props = Object.keys(val);
595
+ let firstErr = null;
596
+ let numErrs = 0;
576
597
 
577
598
  props.forEach(function (prop) {
578
- var propAssertion = new Assertion(obj);
599
+ let propAssertion = new Assertion(obj);
579
600
  _.transferFlags(this, propAssertion, true);
580
601
  flag(propAssertion, 'lockSsfi', true);
581
602
 
@@ -603,13 +624,15 @@ function include (val, msg) {
603
624
  throw firstErr;
604
625
  }
605
626
  return;
627
+ }
606
628
  }
607
629
 
608
630
  // Assert inclusion in collection or substring in a string.
609
631
  this.assert(
610
- included
611
- , 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
612
- , 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
632
+ included,
633
+ 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val),
634
+ 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val)
635
+ );
613
636
  }
614
637
 
615
638
  Assertion.addChainableMethod('include', include, includeChainingBehavior);
@@ -654,9 +677,10 @@ Assertion.addChainableMethod('includes', include, includeChainingBehavior);
654
677
  */
655
678
  Assertion.addProperty('ok', function () {
656
679
  this.assert(
657
- flag(this, 'object')
658
- , 'expected #{this} to be truthy'
659
- , 'expected #{this} to be falsy');
680
+ flag(this, 'object'),
681
+ 'expected #{this} to be truthy',
682
+ 'expected #{this} to be falsy'
683
+ );
660
684
  });
661
685
 
662
686
  /**
@@ -686,10 +710,10 @@ Assertion.addProperty('ok', function () {
686
710
  */
687
711
  Assertion.addProperty('true', function () {
688
712
  this.assert(
689
- true === flag(this, 'object')
690
- , 'expected #{this} to be true'
691
- , 'expected #{this} to be false'
692
- , flag(this, 'negate') ? false : true
713
+ true === flag(this, 'object'),
714
+ 'expected #{this} to be true',
715
+ 'expected #{this} to be false',
716
+ flag(this, 'negate') ? false : true
693
717
  );
694
718
  });
695
719
 
@@ -697,10 +721,10 @@ Assertion.addProperty('numeric', function () {
697
721
  const object = flag(this, 'object');
698
722
 
699
723
  this.assert(
700
- ['Number', 'BigInt'].includes(_.type(object))
701
- , 'expected #{this} to be numeric'
702
- , 'expected #{this} to not be numeric'
703
- , flag(this, 'negate') ? false : true
724
+ ['Number', 'BigInt'].includes(_.type(object)),
725
+ 'expected #{this} to be numeric',
726
+ 'expected #{this} to not be numeric',
727
+ flag(this, 'negate') ? false : true
704
728
  );
705
729
  });
706
730
 
@@ -720,24 +744,25 @@ Assertion.addProperty('numeric', function () {
720
744
  * @public
721
745
  */
722
746
  Assertion.addProperty('callable', function () {
723
- const val = flag(this, 'object')
724
- const ssfi = flag(this, 'ssfi')
725
- const message = flag(this, 'message')
726
- const msg = message ? `${message}: ` : ''
747
+ const val = flag(this, 'object');
748
+ const ssfi = flag(this, 'ssfi');
749
+ const message = flag(this, 'message');
750
+ const msg = message ? `${message}: ` : '';
727
751
  const negate = flag(this, 'negate');
728
752
 
729
- const assertionMessage = negate ?
730
- `${msg}expected ${_.inspect(val)} not to be a callable function` :
731
- `${msg}expected ${_.inspect(val)} to be a callable function`;
753
+ const assertionMessage = negate
754
+ ? `${msg}expected ${_.inspect(val)} not to be a callable function`
755
+ : `${msg}expected ${_.inspect(val)} to be a callable function`;
732
756
 
733
- const isCallable = ['Function', 'AsyncFunction', 'GeneratorFunction', 'AsyncGeneratorFunction'].includes(_.type(val));
757
+ const isCallable = [
758
+ 'Function',
759
+ 'AsyncFunction',
760
+ 'GeneratorFunction',
761
+ 'AsyncGeneratorFunction'
762
+ ].includes(_.type(val));
734
763
 
735
764
  if ((isCallable && negate) || (!isCallable && !negate)) {
736
- throw new AssertionError(
737
- assertionMessage,
738
- undefined,
739
- ssfi
740
- );
765
+ throw new AssertionError(assertionMessage, undefined, ssfi);
741
766
  }
742
767
  });
743
768
 
@@ -768,10 +793,10 @@ Assertion.addProperty('callable', function () {
768
793
  */
769
794
  Assertion.addProperty('false', function () {
770
795
  this.assert(
771
- false === flag(this, 'object')
772
- , 'expected #{this} to be false'
773
- , 'expected #{this} to be true'
774
- , flag(this, 'negate') ? true : false
796
+ false === flag(this, 'object'),
797
+ 'expected #{this} to be false',
798
+ 'expected #{this} to be true',
799
+ flag(this, 'negate') ? true : false
775
800
  );
776
801
  });
777
802
 
@@ -799,9 +824,9 @@ Assertion.addProperty('false', function () {
799
824
  */
800
825
  Assertion.addProperty('null', function () {
801
826
  this.assert(
802
- null === flag(this, 'object')
803
- , 'expected #{this} to be null'
804
- , 'expected #{this} not to be null'
827
+ null === flag(this, 'object'),
828
+ 'expected #{this} to be null',
829
+ 'expected #{this} not to be null'
805
830
  );
806
831
  });
807
832
 
@@ -829,9 +854,9 @@ Assertion.addProperty('null', function () {
829
854
  */
830
855
  Assertion.addProperty('undefined', function () {
831
856
  this.assert(
832
- undefined === flag(this, 'object')
833
- , 'expected #{this} to be undefined'
834
- , 'expected #{this} not to be undefined'
857
+ undefined === flag(this, 'object'),
858
+ 'expected #{this} to be undefined',
859
+ 'expected #{this} not to be undefined'
835
860
  );
836
861
  });
837
862
 
@@ -859,9 +884,9 @@ Assertion.addProperty('undefined', function () {
859
884
  */
860
885
  Assertion.addProperty('NaN', function () {
861
886
  this.assert(
862
- _.isNaN(flag(this, 'object'))
863
- , 'expected #{this} to be NaN'
864
- , 'expected #{this} not to be NaN'
887
+ _.isNaN(flag(this, 'object')),
888
+ 'expected #{this} to be NaN',
889
+ 'expected #{this} not to be NaN'
865
890
  );
866
891
  });
867
892
 
@@ -897,12 +922,12 @@ Assertion.addProperty('NaN', function () {
897
922
  * @namespace BDD
898
923
  * @public
899
924
  */
900
- function assertExist () {
901
- var val = flag(this, 'object');
925
+ function assertExist() {
926
+ let val = flag(this, 'object');
902
927
  this.assert(
903
- val !== null && val !== undefined
904
- , 'expected #{this} to exist'
905
- , 'expected #{this} to not exist'
928
+ val !== null && val !== undefined,
929
+ 'expected #{this} to exist',
930
+ 'expected #{this} to not exist'
906
931
  );
907
932
  }
908
933
 
@@ -958,10 +983,10 @@ Assertion.addProperty('exists', assertExist);
958
983
  * @public
959
984
  */
960
985
  Assertion.addProperty('empty', function () {
961
- var val = flag(this, 'object')
962
- , ssfi = flag(this, 'ssfi')
963
- , flagMsg = flag(this, 'message')
964
- , itemsCount;
986
+ let val = flag(this, 'object'),
987
+ ssfi = flag(this, 'ssfi'),
988
+ flagMsg = flag(this, 'message'),
989
+ itemsCount;
965
990
 
966
991
  flagMsg = flagMsg ? flagMsg + ': ' : '';
967
992
 
@@ -981,9 +1006,10 @@ Assertion.addProperty('empty', function () {
981
1006
  undefined,
982
1007
  ssfi
983
1008
  );
984
- case 'function':
985
- var msg = flagMsg + '.empty was passed a function ' + _.getName(val);
1009
+ case 'function': {
1010
+ const msg = flagMsg + '.empty was passed a function ' + _.getName(val);
986
1011
  throw new AssertionError(msg.trim(), undefined, ssfi);
1012
+ }
987
1013
  default:
988
1014
  if (val !== Object(val)) {
989
1015
  throw new AssertionError(
@@ -996,9 +1022,9 @@ Assertion.addProperty('empty', function () {
996
1022
  }
997
1023
 
998
1024
  this.assert(
999
- 0 === itemsCount
1000
- , 'expected #{this} to be empty'
1001
- , 'expected #{this} not to be empty'
1025
+ 0 === itemsCount,
1026
+ 'expected #{this} to be empty',
1027
+ 'expected #{this} not to be empty'
1002
1028
  );
1003
1029
  });
1004
1030
 
@@ -1031,13 +1057,13 @@ Assertion.addProperty('empty', function () {
1031
1057
  * @namespace BDD
1032
1058
  * @public
1033
1059
  */
1034
- function checkArguments () {
1035
- var obj = flag(this, 'object')
1036
- , type = _.type(obj);
1060
+ function checkArguments() {
1061
+ let obj = flag(this, 'object'),
1062
+ type = _.type(obj);
1037
1063
  this.assert(
1038
- 'Arguments' === type
1039
- , 'expected #{this} to be arguments but got ' + type
1040
- , 'expected #{this} to not be arguments'
1064
+ 'Arguments' === type,
1065
+ 'expected #{this} to be arguments but got ' + type,
1066
+ 'expected #{this} to not be arguments'
1041
1067
  );
1042
1068
  }
1043
1069
 
@@ -1088,22 +1114,22 @@ Assertion.addProperty('Arguments', checkArguments);
1088
1114
  * @namespace BDD
1089
1115
  * @public
1090
1116
  */
1091
- function assertEqual (val, msg) {
1117
+ function assertEqual(val, msg) {
1092
1118
  if (msg) flag(this, 'message', msg);
1093
- var obj = flag(this, 'object');
1119
+ let obj = flag(this, 'object');
1094
1120
  if (flag(this, 'deep')) {
1095
- var prevLockSsfi = flag(this, 'lockSsfi');
1121
+ let prevLockSsfi = flag(this, 'lockSsfi');
1096
1122
  flag(this, 'lockSsfi', true);
1097
1123
  this.eql(val);
1098
1124
  flag(this, 'lockSsfi', prevLockSsfi);
1099
1125
  } else {
1100
1126
  this.assert(
1101
- val === obj
1102
- , 'expected #{this} to equal #{exp}'
1103
- , 'expected #{this} to not equal #{exp}'
1104
- , val
1105
- , this._obj
1106
- , true
1127
+ val === obj,
1128
+ 'expected #{this} to equal #{exp}',
1129
+ 'expected #{this} to not equal #{exp}',
1130
+ val,
1131
+ this._obj,
1132
+ true
1107
1133
  );
1108
1134
  }
1109
1135
  }
@@ -1154,14 +1180,14 @@ Assertion.addMethod('eq', assertEqual);
1154
1180
  */
1155
1181
  function assertEql(obj, msg) {
1156
1182
  if (msg) flag(this, 'message', msg);
1157
- var eql = flag(this, 'eql');
1183
+ let eql = flag(this, 'eql');
1158
1184
  this.assert(
1159
- eql(obj, flag(this, 'object'))
1160
- , 'expected #{this} to deeply equal #{exp}'
1161
- , 'expected #{this} to not deeply equal #{exp}'
1162
- , obj
1163
- , this._obj
1164
- , true
1185
+ eql(obj, flag(this, 'object')),
1186
+ 'expected #{this} to deeply equal #{exp}',
1187
+ 'expected #{this} to not deeply equal #{exp}',
1188
+ obj,
1189
+ this._obj,
1190
+ true
1165
1191
  );
1166
1192
  }
1167
1193
 
@@ -1210,32 +1236,44 @@ Assertion.addMethod('eqls', assertEql);
1210
1236
  * @namespace BDD
1211
1237
  * @public
1212
1238
  */
1213
- function assertAbove (n, msg) {
1239
+ function assertAbove(n, msg) {
1214
1240
  if (msg) flag(this, 'message', msg);
1215
- var obj = flag(this, 'object')
1216
- , doLength = flag(this, 'doLength')
1217
- , flagMsg = flag(this, 'message')
1218
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1219
- , ssfi = flag(this, 'ssfi')
1220
- , objType = _.type(obj).toLowerCase()
1221
- , nType = _.type(n).toLowerCase();
1241
+ let obj = flag(this, 'object'),
1242
+ doLength = flag(this, 'doLength'),
1243
+ flagMsg = flag(this, 'message'),
1244
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1245
+ ssfi = flag(this, 'ssfi'),
1246
+ objType = _.type(obj).toLowerCase(),
1247
+ nType = _.type(n).toLowerCase();
1222
1248
 
1223
1249
  if (doLength && objType !== 'map' && objType !== 'set') {
1224
1250
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1225
1251
  }
1226
1252
 
1227
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1228
- throw new AssertionError(msgPrefix + 'the argument to above must be a date', undefined, ssfi);
1253
+ if (!doLength && objType === 'date' && nType !== 'date') {
1254
+ throw new AssertionError(
1255
+ msgPrefix + 'the argument to above must be a date',
1256
+ undefined,
1257
+ ssfi
1258
+ );
1229
1259
  } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1230
- throw new AssertionError(msgPrefix + 'the argument to above must be a number', undefined, ssfi);
1231
- } else if (!doLength && (objType !== 'date' && !_.isNumeric(obj))) {
1232
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1233
- throw new AssertionError(msgPrefix + 'expected ' + printObj + ' to be a number or a date', undefined, ssfi);
1260
+ throw new AssertionError(
1261
+ msgPrefix + 'the argument to above must be a number',
1262
+ undefined,
1263
+ ssfi
1264
+ );
1265
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1266
+ let printObj = objType === 'string' ? "'" + obj + "'" : obj;
1267
+ throw new AssertionError(
1268
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date',
1269
+ undefined,
1270
+ ssfi
1271
+ );
1234
1272
  }
1235
1273
 
1236
1274
  if (doLength) {
1237
- var descriptor = 'length'
1238
- , itemsCount;
1275
+ let descriptor = 'length',
1276
+ itemsCount;
1239
1277
  if (objType === 'map' || objType === 'set') {
1240
1278
  descriptor = 'size';
1241
1279
  itemsCount = obj.size;
@@ -1243,18 +1281,20 @@ function assertAbove (n, msg) {
1243
1281
  itemsCount = obj.length;
1244
1282
  }
1245
1283
  this.assert(
1246
- itemsCount > n
1247
- , 'expected #{this} to have a ' + descriptor + ' above #{exp} but got #{act}'
1248
- , 'expected #{this} to not have a ' + descriptor + ' above #{exp}'
1249
- , n
1250
- , itemsCount
1284
+ itemsCount > n,
1285
+ 'expected #{this} to have a ' +
1286
+ descriptor +
1287
+ ' above #{exp} but got #{act}',
1288
+ 'expected #{this} to not have a ' + descriptor + ' above #{exp}',
1289
+ n,
1290
+ itemsCount
1251
1291
  );
1252
1292
  } else {
1253
1293
  this.assert(
1254
- obj > n
1255
- , 'expected #{this} to be above #{exp}'
1256
- , 'expected #{this} to be at most #{exp}'
1257
- , n
1294
+ obj > n,
1295
+ 'expected #{this} to be above #{exp}',
1296
+ 'expected #{this} to be at most #{exp}',
1297
+ n
1258
1298
  );
1259
1299
  }
1260
1300
  }
@@ -1306,29 +1346,30 @@ Assertion.addMethod('greaterThan', assertAbove);
1306
1346
  * @namespace BDD
1307
1347
  * @public
1308
1348
  */
1309
- function assertLeast (n, msg) {
1349
+ function assertLeast(n, msg) {
1310
1350
  if (msg) flag(this, 'message', msg);
1311
- var obj = flag(this, 'object')
1312
- , doLength = flag(this, 'doLength')
1313
- , flagMsg = flag(this, 'message')
1314
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1315
- , ssfi = flag(this, 'ssfi')
1316
- , objType = _.type(obj).toLowerCase()
1317
- , nType = _.type(n).toLowerCase()
1318
- , errorMessage
1319
- , shouldThrow = true;
1351
+ let obj = flag(this, 'object'),
1352
+ doLength = flag(this, 'doLength'),
1353
+ flagMsg = flag(this, 'message'),
1354
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1355
+ ssfi = flag(this, 'ssfi'),
1356
+ objType = _.type(obj).toLowerCase(),
1357
+ nType = _.type(n).toLowerCase(),
1358
+ errorMessage,
1359
+ shouldThrow = true;
1320
1360
 
1321
1361
  if (doLength && objType !== 'map' && objType !== 'set') {
1322
1362
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1323
1363
  }
1324
1364
 
1325
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1365
+ if (!doLength && objType === 'date' && nType !== 'date') {
1326
1366
  errorMessage = msgPrefix + 'the argument to least must be a date';
1327
1367
  } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1328
1368
  errorMessage = msgPrefix + 'the argument to least must be a number';
1329
- } else if (!doLength && (objType !== 'date' && !_.isNumeric(obj))) {
1330
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1331
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1369
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1370
+ let printObj = objType === 'string' ? "'" + obj + "'" : obj;
1371
+ errorMessage =
1372
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1332
1373
  } else {
1333
1374
  shouldThrow = false;
1334
1375
  }
@@ -1338,8 +1379,8 @@ function assertLeast (n, msg) {
1338
1379
  }
1339
1380
 
1340
1381
  if (doLength) {
1341
- var descriptor = 'length'
1342
- , itemsCount;
1382
+ let descriptor = 'length',
1383
+ itemsCount;
1343
1384
  if (objType === 'map' || objType === 'set') {
1344
1385
  descriptor = 'size';
1345
1386
  itemsCount = obj.size;
@@ -1347,18 +1388,20 @@ function assertLeast (n, msg) {
1347
1388
  itemsCount = obj.length;
1348
1389
  }
1349
1390
  this.assert(
1350
- itemsCount >= n
1351
- , 'expected #{this} to have a ' + descriptor + ' at least #{exp} but got #{act}'
1352
- , 'expected #{this} to have a ' + descriptor + ' below #{exp}'
1353
- , n
1354
- , itemsCount
1391
+ itemsCount >= n,
1392
+ 'expected #{this} to have a ' +
1393
+ descriptor +
1394
+ ' at least #{exp} but got #{act}',
1395
+ 'expected #{this} to have a ' + descriptor + ' below #{exp}',
1396
+ n,
1397
+ itemsCount
1355
1398
  );
1356
1399
  } else {
1357
1400
  this.assert(
1358
- obj >= n
1359
- , 'expected #{this} to be at least #{exp}'
1360
- , 'expected #{this} to be below #{exp}'
1361
- , n
1401
+ obj >= n,
1402
+ 'expected #{this} to be at least #{exp}',
1403
+ 'expected #{this} to be below #{exp}',
1404
+ n
1362
1405
  );
1363
1406
  }
1364
1407
  }
@@ -1409,29 +1452,30 @@ Assertion.addMethod('greaterThanOrEqual', assertLeast);
1409
1452
  * @namespace BDD
1410
1453
  * @public
1411
1454
  */
1412
- function assertBelow (n, msg) {
1455
+ function assertBelow(n, msg) {
1413
1456
  if (msg) flag(this, 'message', msg);
1414
- var obj = flag(this, 'object')
1415
- , doLength = flag(this, 'doLength')
1416
- , flagMsg = flag(this, 'message')
1417
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1418
- , ssfi = flag(this, 'ssfi')
1419
- , objType = _.type(obj).toLowerCase()
1420
- , nType = _.type(n).toLowerCase()
1421
- , errorMessage
1422
- , shouldThrow = true;
1457
+ let obj = flag(this, 'object'),
1458
+ doLength = flag(this, 'doLength'),
1459
+ flagMsg = flag(this, 'message'),
1460
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1461
+ ssfi = flag(this, 'ssfi'),
1462
+ objType = _.type(obj).toLowerCase(),
1463
+ nType = _.type(n).toLowerCase(),
1464
+ errorMessage,
1465
+ shouldThrow = true;
1423
1466
 
1424
1467
  if (doLength && objType !== 'map' && objType !== 'set') {
1425
1468
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1426
1469
  }
1427
-
1428
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1470
+
1471
+ if (!doLength && objType === 'date' && nType !== 'date') {
1429
1472
  errorMessage = msgPrefix + 'the argument to below must be a date';
1430
1473
  } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1431
1474
  errorMessage = msgPrefix + 'the argument to below must be a number';
1432
- } else if (!doLength && (objType !== 'date' && !_.isNumeric(obj))) {
1433
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1434
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1475
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1476
+ let printObj = objType === 'string' ? "'" + obj + "'" : obj;
1477
+ errorMessage =
1478
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1435
1479
  } else {
1436
1480
  shouldThrow = false;
1437
1481
  }
@@ -1441,8 +1485,8 @@ function assertBelow (n, msg) {
1441
1485
  }
1442
1486
 
1443
1487
  if (doLength) {
1444
- var descriptor = 'length'
1445
- , itemsCount;
1488
+ let descriptor = 'length',
1489
+ itemsCount;
1446
1490
  if (objType === 'map' || objType === 'set') {
1447
1491
  descriptor = 'size';
1448
1492
  itemsCount = obj.size;
@@ -1450,18 +1494,20 @@ function assertBelow (n, msg) {
1450
1494
  itemsCount = obj.length;
1451
1495
  }
1452
1496
  this.assert(
1453
- itemsCount < n
1454
- , 'expected #{this} to have a ' + descriptor + ' below #{exp} but got #{act}'
1455
- , 'expected #{this} to not have a ' + descriptor + ' below #{exp}'
1456
- , n
1457
- , itemsCount
1497
+ itemsCount < n,
1498
+ 'expected #{this} to have a ' +
1499
+ descriptor +
1500
+ ' below #{exp} but got #{act}',
1501
+ 'expected #{this} to not have a ' + descriptor + ' below #{exp}',
1502
+ n,
1503
+ itemsCount
1458
1504
  );
1459
1505
  } else {
1460
1506
  this.assert(
1461
- obj < n
1462
- , 'expected #{this} to be below #{exp}'
1463
- , 'expected #{this} to be at least #{exp}'
1464
- , n
1507
+ obj < n,
1508
+ 'expected #{this} to be below #{exp}',
1509
+ 'expected #{this} to be at least #{exp}',
1510
+ n
1465
1511
  );
1466
1512
  }
1467
1513
  }
@@ -1513,29 +1559,30 @@ Assertion.addMethod('lessThan', assertBelow);
1513
1559
  * @namespace BDD
1514
1560
  * @public
1515
1561
  */
1516
- function assertMost (n, msg) {
1562
+ function assertMost(n, msg) {
1517
1563
  if (msg) flag(this, 'message', msg);
1518
- var obj = flag(this, 'object')
1519
- , doLength = flag(this, 'doLength')
1520
- , flagMsg = flag(this, 'message')
1521
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1522
- , ssfi = flag(this, 'ssfi')
1523
- , objType = _.type(obj).toLowerCase()
1524
- , nType = _.type(n).toLowerCase()
1525
- , errorMessage
1526
- , shouldThrow = true;
1564
+ let obj = flag(this, 'object'),
1565
+ doLength = flag(this, 'doLength'),
1566
+ flagMsg = flag(this, 'message'),
1567
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1568
+ ssfi = flag(this, 'ssfi'),
1569
+ objType = _.type(obj).toLowerCase(),
1570
+ nType = _.type(n).toLowerCase(),
1571
+ errorMessage,
1572
+ shouldThrow = true;
1527
1573
 
1528
1574
  if (doLength && objType !== 'map' && objType !== 'set') {
1529
1575
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1530
1576
  }
1531
1577
 
1532
- if (!doLength && (objType === 'date' && nType !== 'date')) {
1578
+ if (!doLength && objType === 'date' && nType !== 'date') {
1533
1579
  errorMessage = msgPrefix + 'the argument to most must be a date';
1534
1580
  } else if (!_.isNumeric(n) && (doLength || _.isNumeric(obj))) {
1535
1581
  errorMessage = msgPrefix + 'the argument to most must be a number';
1536
- } else if (!doLength && (objType !== 'date' && !_.isNumeric(obj))) {
1537
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1538
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1582
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1583
+ let printObj = objType === 'string' ? "'" + obj + "'" : obj;
1584
+ errorMessage =
1585
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1539
1586
  } else {
1540
1587
  shouldThrow = false;
1541
1588
  }
@@ -1545,8 +1592,8 @@ function assertMost (n, msg) {
1545
1592
  }
1546
1593
 
1547
1594
  if (doLength) {
1548
- var descriptor = 'length'
1549
- , itemsCount;
1595
+ let descriptor = 'length',
1596
+ itemsCount;
1550
1597
  if (objType === 'map' || objType === 'set') {
1551
1598
  descriptor = 'size';
1552
1599
  itemsCount = obj.size;
@@ -1554,18 +1601,20 @@ function assertMost (n, msg) {
1554
1601
  itemsCount = obj.length;
1555
1602
  }
1556
1603
  this.assert(
1557
- itemsCount <= n
1558
- , 'expected #{this} to have a ' + descriptor + ' at most #{exp} but got #{act}'
1559
- , 'expected #{this} to have a ' + descriptor + ' above #{exp}'
1560
- , n
1561
- , itemsCount
1604
+ itemsCount <= n,
1605
+ 'expected #{this} to have a ' +
1606
+ descriptor +
1607
+ ' at most #{exp} but got #{act}',
1608
+ 'expected #{this} to have a ' + descriptor + ' above #{exp}',
1609
+ n,
1610
+ itemsCount
1562
1611
  );
1563
1612
  } else {
1564
1613
  this.assert(
1565
- obj <= n
1566
- , 'expected #{this} to be at most #{exp}'
1567
- , 'expected #{this} to be above #{exp}'
1568
- , n
1614
+ obj <= n,
1615
+ 'expected #{this} to be at most #{exp}',
1616
+ 'expected #{this} to be above #{exp}',
1617
+ n
1569
1618
  );
1570
1619
  }
1571
1620
  }
@@ -1618,17 +1667,18 @@ Assertion.addMethod('lessThanOrEqual', assertMost);
1618
1667
  */
1619
1668
  Assertion.addMethod('within', function (start, finish, msg) {
1620
1669
  if (msg) flag(this, 'message', msg);
1621
- var obj = flag(this, 'object')
1622
- , doLength = flag(this, 'doLength')
1623
- , flagMsg = flag(this, 'message')
1624
- , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1625
- , ssfi = flag(this, 'ssfi')
1626
- , objType = _.type(obj).toLowerCase()
1627
- , startType = _.type(start).toLowerCase()
1628
- , finishType = _.type(finish).toLowerCase()
1629
- , errorMessage
1630
- , shouldThrow = true
1631
- , range = (startType === 'date' && finishType === 'date')
1670
+ let obj = flag(this, 'object'),
1671
+ doLength = flag(this, 'doLength'),
1672
+ flagMsg = flag(this, 'message'),
1673
+ msgPrefix = flagMsg ? flagMsg + ': ' : '',
1674
+ ssfi = flag(this, 'ssfi'),
1675
+ objType = _.type(obj).toLowerCase(),
1676
+ startType = _.type(start).toLowerCase(),
1677
+ finishType = _.type(finish).toLowerCase(),
1678
+ errorMessage,
1679
+ shouldThrow = true,
1680
+ range =
1681
+ startType === 'date' && finishType === 'date'
1632
1682
  ? start.toISOString() + '..' + finish.toISOString()
1633
1683
  : start + '..' + finish;
1634
1684
 
@@ -1636,13 +1686,21 @@ Assertion.addMethod('within', function (start, finish, msg) {
1636
1686
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1637
1687
  }
1638
1688
 
1639
- if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {
1689
+ if (
1690
+ !doLength &&
1691
+ objType === 'date' &&
1692
+ (startType !== 'date' || finishType !== 'date')
1693
+ ) {
1640
1694
  errorMessage = msgPrefix + 'the arguments to within must be dates';
1641
- } else if ((!_.isNumeric(start) || !_.isNumeric(finish)) && (doLength || _.isNumeric(obj))) {
1695
+ } else if (
1696
+ (!_.isNumeric(start) || !_.isNumeric(finish)) &&
1697
+ (doLength || _.isNumeric(obj))
1698
+ ) {
1642
1699
  errorMessage = msgPrefix + 'the arguments to within must be numbers';
1643
- } else if (!doLength && (objType !== 'date' && !_.isNumeric(obj))) {
1644
- var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1645
- errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1700
+ } else if (!doLength && objType !== 'date' && !_.isNumeric(obj)) {
1701
+ let printObj = objType === 'string' ? "'" + obj + "'" : obj;
1702
+ errorMessage =
1703
+ msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1646
1704
  } else {
1647
1705
  shouldThrow = false;
1648
1706
  }
@@ -1652,8 +1710,8 @@ Assertion.addMethod('within', function (start, finish, msg) {
1652
1710
  }
1653
1711
 
1654
1712
  if (doLength) {
1655
- var descriptor = 'length'
1656
- , itemsCount;
1713
+ let descriptor = 'length',
1714
+ itemsCount;
1657
1715
  if (objType === 'map' || objType === 'set') {
1658
1716
  descriptor = 'size';
1659
1717
  itemsCount = obj.size;
@@ -1661,15 +1719,15 @@ Assertion.addMethod('within', function (start, finish, msg) {
1661
1719
  itemsCount = obj.length;
1662
1720
  }
1663
1721
  this.assert(
1664
- itemsCount >= start && itemsCount <= finish
1665
- , 'expected #{this} to have a ' + descriptor + ' within ' + range
1666
- , 'expected #{this} to not have a ' + descriptor + ' within ' + range
1722
+ itemsCount >= start && itemsCount <= finish,
1723
+ 'expected #{this} to have a ' + descriptor + ' within ' + range,
1724
+ 'expected #{this} to not have a ' + descriptor + ' within ' + range
1667
1725
  );
1668
1726
  } else {
1669
1727
  this.assert(
1670
- obj >= start && obj <= finish
1671
- , 'expected #{this} to be within ' + range
1672
- , 'expected #{this} to not be within ' + range
1728
+ obj >= start && obj <= finish,
1729
+ 'expected #{this} to be within ' + range,
1730
+ 'expected #{this} to not be within ' + range
1673
1731
  );
1674
1732
  }
1675
1733
  });
@@ -1712,21 +1770,24 @@ Assertion.addMethod('within', function (start, finish, msg) {
1712
1770
  * @namespace BDD
1713
1771
  * @public
1714
1772
  */
1715
- function assertInstanceOf (constructor, msg) {
1773
+ function assertInstanceOf(constructor, msg) {
1716
1774
  if (msg) flag(this, 'message', msg);
1717
1775
 
1718
- var target = flag(this, 'object')
1719
- var ssfi = flag(this, 'ssfi');
1720
- var flagMsg = flag(this, 'message');
1776
+ let target = flag(this, 'object');
1777
+ let ssfi = flag(this, 'ssfi');
1778
+ let flagMsg = flag(this, 'message');
1779
+ let isInstanceOf;
1721
1780
 
1722
1781
  try {
1723
- var isInstanceOf = target instanceof constructor;
1782
+ isInstanceOf = target instanceof constructor;
1724
1783
  } catch (err) {
1725
1784
  if (err instanceof TypeError) {
1726
1785
  flagMsg = flagMsg ? flagMsg + ': ' : '';
1727
1786
  throw new AssertionError(
1728
- flagMsg + 'The instanceof assertion needs a constructor but '
1729
- + _.type(constructor) + ' was given.',
1787
+ flagMsg +
1788
+ 'The instanceof assertion needs a constructor but ' +
1789
+ _.type(constructor) +
1790
+ ' was given.',
1730
1791
  undefined,
1731
1792
  ssfi
1732
1793
  );
@@ -1734,17 +1795,17 @@ function assertInstanceOf (constructor, msg) {
1734
1795
  throw err;
1735
1796
  }
1736
1797
 
1737
- var name = _.getName(constructor);
1798
+ let name = _.getName(constructor);
1738
1799
  if (name == null) {
1739
1800
  name = 'an unnamed constructor';
1740
1801
  }
1741
1802
 
1742
1803
  this.assert(
1743
- isInstanceOf
1744
- , 'expected #{this} to be an instance of ' + name
1745
- , '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
1746
1807
  );
1747
- };
1808
+ }
1748
1809
 
1749
1810
  Assertion.addMethod('instanceof', assertInstanceOf);
1750
1811
  Assertion.addMethod('instanceOf', assertInstanceOf);
@@ -1859,30 +1920,36 @@ Assertion.addMethod('instanceOf', assertInstanceOf);
1859
1920
  * @namespace BDD
1860
1921
  * @public
1861
1922
  */
1862
- function assertProperty (name, val, msg) {
1923
+ function assertProperty(name, val, msg) {
1863
1924
  if (msg) flag(this, 'message', msg);
1864
1925
 
1865
- var isNested = flag(this, 'nested')
1866
- , isOwn = flag(this, 'own')
1867
- , flagMsg = flag(this, 'message')
1868
- , obj = flag(this, 'object')
1869
- , ssfi = flag(this, 'ssfi')
1870
- , nameType = typeof name;
1926
+ let 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;
1871
1932
 
1872
1933
  flagMsg = flagMsg ? flagMsg + ': ' : '';
1873
1934
 
1874
1935
  if (isNested) {
1875
1936
  if (nameType !== 'string') {
1876
1937
  throw new AssertionError(
1877
- 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',
1878
1940
  undefined,
1879
1941
  ssfi
1880
1942
  );
1881
1943
  }
1882
1944
  } else {
1883
- if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') {
1945
+ if (
1946
+ nameType !== 'string' &&
1947
+ nameType !== 'number' &&
1948
+ nameType !== 'symbol'
1949
+ ) {
1884
1950
  throw new AssertionError(
1885
- 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',
1886
1953
  undefined,
1887
1954
  ssfi
1888
1955
  );
@@ -1905,19 +1972,19 @@ function assertProperty (name, val, msg) {
1905
1972
  );
1906
1973
  }
1907
1974
 
1908
- var isDeep = flag(this, 'deep')
1909
- , negate = flag(this, 'negate')
1910
- , pathInfo = isNested ? _.getPathInfo(obj, name) : null
1911
- , value = isNested ? pathInfo.value : obj[name]
1912
- , isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
1975
+ let 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;
1913
1980
 
1914
- var descriptor = '';
1981
+ let descriptor = '';
1915
1982
  if (isDeep) descriptor += 'deep ';
1916
1983
  if (isOwn) descriptor += 'own ';
1917
1984
  if (isNested) descriptor += 'nested ';
1918
1985
  descriptor += 'property ';
1919
1986
 
1920
- var hasProperty;
1987
+ let hasProperty;
1921
1988
  if (isOwn) hasProperty = Object.prototype.hasOwnProperty.call(obj, name);
1922
1989
  else if (isNested) hasProperty = pathInfo.exists;
1923
1990
  else hasProperty = _.hasProperty(obj, name);
@@ -1929,18 +1996,25 @@ function assertProperty (name, val, msg) {
1929
1996
  // favor of the next.
1930
1997
  if (!negate || arguments.length === 1) {
1931
1998
  this.assert(
1932
- hasProperty
1933
- , 'expected #{this} to have ' + descriptor + _.inspect(name)
1934
- , '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
+ );
1935
2003
  }
1936
2004
 
1937
2005
  if (arguments.length > 1) {
1938
2006
  this.assert(
1939
- hasProperty && isEql(val, value)
1940
- , 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
1941
- , 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}'
1942
- , val
1943
- , 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
1944
2018
  );
1945
2019
  }
1946
2020
 
@@ -1950,12 +2024,11 @@ function assertProperty (name, val, msg) {
1950
2024
  Assertion.addMethod('property', assertProperty);
1951
2025
 
1952
2026
  /**
1953
- *
1954
- * @param {unknown} name
1955
- * @param {unknown} value
1956
- * @param {string} msg
2027
+ * @param {unknown} _name
2028
+ * @param {unknown} _value
2029
+ * @param {string} _msg
1957
2030
  */
1958
- function assertOwnProperty (name, value, msg) {
2031
+ function assertOwnProperty(_name, _value, _msg) {
1959
2032
  flag(this, 'own', true);
1960
2033
  assertProperty.apply(this, arguments);
1961
2034
  }
@@ -2081,29 +2154,39 @@ Assertion.addMethod('haveOwnProperty', assertOwnProperty);
2081
2154
  * @namespace BDD
2082
2155
  * @public
2083
2156
  */
2084
- function assertOwnPropertyDescriptor (name, descriptor, msg) {
2157
+ function assertOwnPropertyDescriptor(name, descriptor, msg) {
2085
2158
  if (typeof descriptor === 'string') {
2086
2159
  msg = descriptor;
2087
2160
  descriptor = null;
2088
2161
  }
2089
2162
  if (msg) flag(this, 'message', msg);
2090
- var obj = flag(this, 'object');
2091
- var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
2092
- var eql = flag(this, 'eql');
2163
+ let obj = flag(this, 'object');
2164
+ let actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
2165
+ let eql = flag(this, 'eql');
2093
2166
  if (actualDescriptor && descriptor) {
2094
2167
  this.assert(
2095
- eql(descriptor, actualDescriptor)
2096
- , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)
2097
- , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)
2098
- , descriptor
2099
- , actualDescriptor
2100
- , true
2168
+ eql(descriptor, actualDescriptor),
2169
+ 'expected the own property descriptor for ' +
2170
+ _.inspect(name) +
2171
+ ' on #{this} to match ' +
2172
+ _.inspect(descriptor) +
2173
+ ', got ' +
2174
+ _.inspect(actualDescriptor),
2175
+ 'expected the own property descriptor for ' +
2176
+ _.inspect(name) +
2177
+ ' on #{this} to not match ' +
2178
+ _.inspect(descriptor),
2179
+ descriptor,
2180
+ actualDescriptor,
2181
+ true
2101
2182
  );
2102
2183
  } else {
2103
2184
  this.assert(
2104
- actualDescriptor
2105
- , 'expected #{this} to have an own property descriptor for ' + _.inspect(name)
2106
- , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name)
2185
+ actualDescriptor,
2186
+ 'expected #{this} to have an own property descriptor for ' +
2187
+ _.inspect(name),
2188
+ 'expected #{this} to not have an own property descriptor for ' +
2189
+ _.inspect(name)
2107
2190
  );
2108
2191
  }
2109
2192
  flag(this, 'object', actualDescriptor);
@@ -2112,10 +2195,8 @@ function assertOwnPropertyDescriptor (name, descriptor, msg) {
2112
2195
  Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor);
2113
2196
  Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor);
2114
2197
 
2115
- /**
2116
- *
2117
- */
2118
- function assertLengthChain () {
2198
+ /** */
2199
+ function assertLengthChain() {
2119
2200
  flag(this, 'doLength', true);
2120
2201
  }
2121
2202
 
@@ -2176,14 +2257,14 @@ function assertLengthChain () {
2176
2257
  * @namespace BDD
2177
2258
  * @public
2178
2259
  */
2179
- function assertLength (n, msg) {
2260
+ function assertLength(n, msg) {
2180
2261
  if (msg) flag(this, 'message', msg);
2181
- var obj = flag(this, 'object')
2182
- , objType = _.type(obj).toLowerCase()
2183
- , flagMsg = flag(this, 'message')
2184
- , ssfi = flag(this, 'ssfi')
2185
- , descriptor = 'length'
2186
- , itemsCount;
2262
+ let obj = flag(this, 'object'),
2263
+ objType = _.type(obj).toLowerCase(),
2264
+ flagMsg = flag(this, 'message'),
2265
+ ssfi = flag(this, 'ssfi'),
2266
+ descriptor = 'length',
2267
+ itemsCount;
2187
2268
 
2188
2269
  switch (objType) {
2189
2270
  case 'map':
@@ -2197,11 +2278,11 @@ function assertLength (n, msg) {
2197
2278
  }
2198
2279
 
2199
2280
  this.assert(
2200
- itemsCount == n
2201
- , 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}'
2202
- , 'expected #{this} to not have a ' + descriptor + ' of #{act}'
2203
- , n
2204
- , itemsCount
2281
+ itemsCount == n,
2282
+ 'expected #{this} to have a ' + descriptor + ' of #{exp} but got #{act}',
2283
+ 'expected #{this} to not have a ' + descriptor + ' of #{act}',
2284
+ n,
2285
+ itemsCount
2205
2286
  );
2206
2287
  }
2207
2288
 
@@ -2237,11 +2318,11 @@ Assertion.addChainableMethod('lengthOf', assertLength, assertLengthChain);
2237
2318
  */
2238
2319
  function assertMatch(re, msg) {
2239
2320
  if (msg) flag(this, 'message', msg);
2240
- var obj = flag(this, 'object');
2321
+ let obj = flag(this, 'object');
2241
2322
  this.assert(
2242
- re.exec(obj)
2243
- , 'expected #{this} to match ' + re
2244
- , 'expected #{this} not to match ' + re
2323
+ re.exec(obj),
2324
+ 'expected #{this} to match ' + re,
2325
+ 'expected #{this} not to match ' + re
2245
2326
  );
2246
2327
  }
2247
2328
 
@@ -2274,15 +2355,15 @@ Assertion.addMethod('matches', assertMatch);
2274
2355
  */
2275
2356
  Assertion.addMethod('string', function (str, msg) {
2276
2357
  if (msg) flag(this, 'message', msg);
2277
- var obj = flag(this, 'object')
2278
- , flagMsg = flag(this, 'message')
2279
- , ssfi = flag(this, 'ssfi');
2358
+ let obj = flag(this, 'object'),
2359
+ flagMsg = flag(this, 'message'),
2360
+ ssfi = flag(this, 'ssfi');
2280
2361
  new Assertion(obj, flagMsg, ssfi, true).is.a('string');
2281
2362
 
2282
2363
  this.assert(
2283
- ~obj.indexOf(str)
2284
- , 'expected #{this} to contain ' + _.inspect(str)
2285
- , 'expected #{this} to not contain ' + _.inspect(str)
2364
+ ~obj.indexOf(str),
2365
+ 'expected #{this} to contain ' + _.inspect(str),
2366
+ 'expected #{this} to not contain ' + _.inspect(str)
2286
2367
  );
2287
2368
  });
2288
2369
 
@@ -2389,27 +2470,31 @@ Assertion.addMethod('string', function (str, msg) {
2389
2470
  * @namespace BDD
2390
2471
  * @public
2391
2472
  */
2392
- function assertKeys (keys) {
2393
- var obj = flag(this, 'object')
2394
- , objType = _.type(obj)
2395
- , keysType = _.type(keys)
2396
- , ssfi = flag(this, 'ssfi')
2397
- , isDeep = flag(this, 'deep')
2398
- , str
2399
- , deepStr = ''
2400
- , actual
2401
- , ok = true
2402
- , flagMsg = flag(this, 'message');
2473
+ function assertKeys(keys) {
2474
+ let obj = flag(this, 'object'),
2475
+ objType = _.type(obj),
2476
+ keysType = _.type(keys),
2477
+ ssfi = flag(this, 'ssfi'),
2478
+ isDeep = flag(this, 'deep'),
2479
+ str,
2480
+ deepStr = '',
2481
+ actual,
2482
+ ok = true,
2483
+ flagMsg = flag(this, 'message');
2403
2484
 
2404
2485
  flagMsg = flagMsg ? flagMsg + ': ' : '';
2405
- 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';
2486
+ let mixedArgsMsg =
2487
+ flagMsg +
2488
+ 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments';
2406
2489
 
2407
2490
  if (objType === 'Map' || objType === 'Set') {
2408
2491
  deepStr = isDeep ? 'deeply ' : '';
2409
2492
  actual = [];
2410
2493
 
2411
2494
  // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach.
2412
- obj.forEach(function (val, key) { actual.push(key) });
2495
+ obj.forEach(function (val, key) {
2496
+ actual.push(key);
2497
+ });
2413
2498
 
2414
2499
  if (keysType !== 'Array') {
2415
2500
  keys = Array.prototype.slice.call(arguments);
@@ -2443,11 +2528,11 @@ function assertKeys (keys) {
2443
2528
  throw new AssertionError(flagMsg + 'keys required', undefined, ssfi);
2444
2529
  }
2445
2530
 
2446
- var len = keys.length
2447
- , any = flag(this, 'any')
2448
- , all = flag(this, 'all')
2449
- , expected = keys
2450
- , isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
2531
+ let len = keys.length,
2532
+ any = flag(this, 'any'),
2533
+ all = flag(this, 'all'),
2534
+ expected = keys,
2535
+ isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
2451
2536
 
2452
2537
  if (!any && !all) {
2453
2538
  all = true;
@@ -2455,8 +2540,8 @@ function assertKeys (keys) {
2455
2540
 
2456
2541
  // Has any
2457
2542
  if (any) {
2458
- ok = expected.some(function(expectedKey) {
2459
- return actual.some(function(actualKey) {
2543
+ ok = expected.some(function (expectedKey) {
2544
+ return actual.some(function (actualKey) {
2460
2545
  return isEql(expectedKey, actualKey);
2461
2546
  });
2462
2547
  });
@@ -2464,8 +2549,8 @@ function assertKeys (keys) {
2464
2549
 
2465
2550
  // Has all
2466
2551
  if (all) {
2467
- ok = expected.every(function(expectedKey) {
2468
- return actual.some(function(actualKey) {
2552
+ ok = expected.every(function (expectedKey) {
2553
+ return actual.some(function (actualKey) {
2469
2554
  return isEql(expectedKey, actualKey);
2470
2555
  });
2471
2556
  });
@@ -2477,10 +2562,10 @@ function assertKeys (keys) {
2477
2562
 
2478
2563
  // Key string
2479
2564
  if (len > 1) {
2480
- keys = keys.map(function(key) {
2565
+ keys = keys.map(function (key) {
2481
2566
  return _.inspect(key);
2482
2567
  });
2483
- var last = keys.pop();
2568
+ let last = keys.pop();
2484
2569
  if (all) {
2485
2570
  str = keys.join(', ') + ', and ' + last;
2486
2571
  }
@@ -2499,12 +2584,12 @@ function assertKeys (keys) {
2499
2584
 
2500
2585
  // Assertion
2501
2586
  this.assert(
2502
- ok
2503
- , 'expected #{this} to ' + deepStr + str
2504
- , 'expected #{this} to not ' + deepStr + str
2505
- , expected.slice(0).sort(_.compareByInspect)
2506
- , actual.sort(_.compareByInspect)
2507
- , true
2587
+ ok,
2588
+ 'expected #{this} to ' + deepStr + str,
2589
+ 'expected #{this} to not ' + deepStr + str,
2590
+ expected.slice(0).sort(_.compareByInspect),
2591
+ actual.sort(_.compareByInspect),
2592
+ true
2508
2593
  );
2509
2594
  }
2510
2595
 
@@ -2670,12 +2755,12 @@ Assertion.addMethod('key', assertKeys);
2670
2755
  * @namespace BDD
2671
2756
  * @public
2672
2757
  */
2673
- function assertThrows (errorLike, errMsgMatcher, msg) {
2758
+ function assertThrows(errorLike, errMsgMatcher, msg) {
2674
2759
  if (msg) flag(this, 'message', msg);
2675
- var obj = flag(this, 'object')
2676
- , ssfi = flag(this, 'ssfi')
2677
- , flagMsg = flag(this, 'message')
2678
- , negate = flag(this, 'negate') || false;
2760
+ let obj = flag(this, 'object'),
2761
+ ssfi = flag(this, 'ssfi'),
2762
+ flagMsg = flag(this, 'message'),
2763
+ negate = flag(this, 'negate') || false;
2679
2764
  new Assertion(obj, flagMsg, ssfi, true).is.a('function');
2680
2765
 
2681
2766
  if (_.isRegExp(errorLike) || typeof errorLike === 'string') {
@@ -2694,18 +2779,19 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2694
2779
 
2695
2780
  // If we have the negate flag enabled and at least one valid argument it means we do expect an error
2696
2781
  // but we want it to match a given set of criteria
2697
- var everyArgIsUndefined = errorLike === undefined && errMsgMatcher === undefined;
2782
+ let everyArgIsUndefined =
2783
+ errorLike === undefined && errMsgMatcher === undefined;
2698
2784
 
2699
2785
  // If we've got the negate flag enabled and both args, we should only fail if both aren't compatible
2700
2786
  // See Issue #551 and PR #683@GitHub
2701
- var everyArgIsDefined = Boolean(errorLike && errMsgMatcher);
2702
- var errorLikeFail = false;
2703
- var errMsgMatcherFail = false;
2787
+ let everyArgIsDefined = Boolean(errorLike && errMsgMatcher);
2788
+ let errorLikeFail = false;
2789
+ let errMsgMatcherFail = false;
2704
2790
 
2705
2791
  // Checking if error was thrown
2706
- if (everyArgIsUndefined || !everyArgIsUndefined && !negate) {
2792
+ if (everyArgIsUndefined || (!everyArgIsUndefined && !negate)) {
2707
2793
  // We need this to display results correctly according to their types
2708
- var errorLikeString = 'an error';
2794
+ let errorLikeString = 'an error';
2709
2795
  if (errorLike instanceof Error) {
2710
2796
  errorLikeString = '#{exp}';
2711
2797
  } else if (errorLike) {
@@ -2717,7 +2803,10 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2717
2803
  actual = caughtErr.toString();
2718
2804
  } else if (typeof caughtErr === 'string') {
2719
2805
  actual = caughtErr;
2720
- } else if (caughtErr && (typeof caughtErr === 'object' || typeof caughtErr === 'function')) {
2806
+ } else if (
2807
+ caughtErr &&
2808
+ (typeof caughtErr === 'object' || typeof caughtErr === 'function')
2809
+ ) {
2721
2810
  try {
2722
2811
  actual = _.checkError.getConstructorName(caughtErr);
2723
2812
  } catch (_err) {
@@ -2727,18 +2816,21 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2727
2816
  }
2728
2817
 
2729
2818
  this.assert(
2730
- errorWasThrown
2731
- , 'expected #{this} to throw ' + errorLikeString
2732
- , 'expected #{this} to not throw an error but #{act} was thrown'
2733
- , errorLike && errorLike.toString()
2734
- , actual
2819
+ errorWasThrown,
2820
+ 'expected #{this} to throw ' + errorLikeString,
2821
+ 'expected #{this} to not throw an error but #{act} was thrown',
2822
+ errorLike && errorLike.toString(),
2823
+ actual
2735
2824
  );
2736
2825
  }
2737
2826
 
2738
2827
  if (errorLike && caughtErr) {
2739
2828
  // We should compare instances only if `errorLike` is an instance of `Error`
2740
2829
  if (errorLike instanceof Error) {
2741
- var isCompatibleInstance = _.checkError.compatibleInstance(caughtErr, errorLike);
2830
+ let isCompatibleInstance = _.checkError.compatibleInstance(
2831
+ caughtErr,
2832
+ errorLike
2833
+ );
2742
2834
 
2743
2835
  if (isCompatibleInstance === negate) {
2744
2836
  // These checks were created to ensure we won't fail too soon when we've got both args and a negate
@@ -2747,27 +2839,36 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2747
2839
  errorLikeFail = true;
2748
2840
  } else {
2749
2841
  this.assert(
2750
- negate
2751
- , 'expected #{this} to throw #{exp} but #{act} was thrown'
2752
- , 'expected #{this} to not throw #{exp}' + (caughtErr && !negate ? ' but #{act} was thrown' : '')
2753
- , errorLike.toString()
2754
- , caughtErr.toString()
2842
+ negate,
2843
+ 'expected #{this} to throw #{exp} but #{act} was thrown',
2844
+ 'expected #{this} to not throw #{exp}' +
2845
+ (caughtErr && !negate ? ' but #{act} was thrown' : ''),
2846
+ errorLike.toString(),
2847
+ caughtErr.toString()
2755
2848
  );
2756
2849
  }
2757
2850
  }
2758
2851
  }
2759
2852
 
2760
- var isCompatibleConstructor = _.checkError.compatibleConstructor(caughtErr, errorLike);
2853
+ let isCompatibleConstructor = _.checkError.compatibleConstructor(
2854
+ caughtErr,
2855
+ errorLike
2856
+ );
2761
2857
  if (isCompatibleConstructor === negate) {
2762
2858
  if (everyArgIsDefined && negate) {
2763
- errorLikeFail = true;
2859
+ errorLikeFail = true;
2764
2860
  } else {
2765
2861
  this.assert(
2766
- negate
2767
- , 'expected #{this} to throw #{exp} but #{act} was thrown'
2768
- , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '')
2769
- , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike))
2770
- , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr))
2862
+ negate,
2863
+ 'expected #{this} to throw #{exp} but #{act} was thrown',
2864
+ 'expected #{this} to not throw #{exp}' +
2865
+ (caughtErr ? ' but #{act} was thrown' : ''),
2866
+ errorLike instanceof Error
2867
+ ? errorLike.toString()
2868
+ : errorLike && _.checkError.getConstructorName(errorLike),
2869
+ caughtErr instanceof Error
2870
+ ? caughtErr.toString()
2871
+ : caughtErr && _.checkError.getConstructorName(caughtErr)
2771
2872
  );
2772
2873
  }
2773
2874
  }
@@ -2775,22 +2876,27 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2775
2876
 
2776
2877
  if (caughtErr && errMsgMatcher !== undefined && errMsgMatcher !== null) {
2777
2878
  // Here we check compatible messages
2778
- var placeholder = 'including';
2879
+ let placeholder = 'including';
2779
2880
  if (_.isRegExp(errMsgMatcher)) {
2780
- placeholder = 'matching'
2881
+ placeholder = 'matching';
2781
2882
  }
2782
2883
 
2783
- var isCompatibleMessage = _.checkError.compatibleMessage(caughtErr, errMsgMatcher);
2884
+ let isCompatibleMessage = _.checkError.compatibleMessage(
2885
+ caughtErr,
2886
+ errMsgMatcher
2887
+ );
2784
2888
  if (isCompatibleMessage === negate) {
2785
2889
  if (everyArgIsDefined && negate) {
2786
- errMsgMatcherFail = true;
2890
+ errMsgMatcherFail = true;
2787
2891
  } else {
2788
2892
  this.assert(
2789
- negate
2790
- , 'expected #{this} to throw error ' + placeholder + ' #{exp} but got #{act}'
2791
- , 'expected #{this} to throw error not ' + placeholder + ' #{exp}'
2792
- , errMsgMatcher
2793
- , _.checkError.getMessage(caughtErr)
2893
+ negate,
2894
+ 'expected #{this} to throw error ' +
2895
+ placeholder +
2896
+ ' #{exp} but got #{act}',
2897
+ 'expected #{this} to throw error not ' + placeholder + ' #{exp}',
2898
+ errMsgMatcher,
2899
+ _.checkError.getMessage(caughtErr)
2794
2900
  );
2795
2901
  }
2796
2902
  }
@@ -2799,16 +2905,21 @@ function assertThrows (errorLike, errMsgMatcher, msg) {
2799
2905
  // If both assertions failed and both should've matched we throw an error
2800
2906
  if (errorLikeFail && errMsgMatcherFail) {
2801
2907
  this.assert(
2802
- negate
2803
- , 'expected #{this} to throw #{exp} but #{act} was thrown'
2804
- , 'expected #{this} to not throw #{exp}' + (caughtErr ? ' but #{act} was thrown' : '')
2805
- , (errorLike instanceof Error ? errorLike.toString() : errorLike && _.checkError.getConstructorName(errorLike))
2806
- , (caughtErr instanceof Error ? caughtErr.toString() : caughtErr && _.checkError.getConstructorName(caughtErr))
2908
+ negate,
2909
+ 'expected #{this} to throw #{exp} but #{act} was thrown',
2910
+ 'expected #{this} to not throw #{exp}' +
2911
+ (caughtErr ? ' but #{act} was thrown' : ''),
2912
+ errorLike instanceof Error
2913
+ ? errorLike.toString()
2914
+ : errorLike && _.checkError.getConstructorName(errorLike),
2915
+ caughtErr instanceof Error
2916
+ ? caughtErr.toString()
2917
+ : caughtErr && _.checkError.getConstructorName(caughtErr)
2807
2918
  );
2808
2919
  }
2809
2920
 
2810
2921
  flag(this, 'object', caughtErr);
2811
- };
2922
+ }
2812
2923
 
2813
2924
  Assertion.addMethod('throw', assertThrows);
2814
2925
  Assertion.addMethod('throws', assertThrows);
@@ -2878,18 +2989,19 @@ Assertion.addMethod('Throw', assertThrows);
2878
2989
  * @namespace BDD
2879
2990
  * @public
2880
2991
  */
2881
- function respondTo (method, msg) {
2992
+ function respondTo(method, msg) {
2882
2993
  if (msg) flag(this, 'message', msg);
2883
- var obj = flag(this, 'object')
2884
- , itself = flag(this, 'itself')
2885
- , context = ('function' === typeof obj && !itself)
2886
- ? obj.prototype[method]
2887
- : obj[method];
2994
+ let obj = flag(this, 'object'),
2995
+ itself = flag(this, 'itself'),
2996
+ context =
2997
+ 'function' === typeof obj && !itself
2998
+ ? obj.prototype[method]
2999
+ : obj[method];
2888
3000
 
2889
3001
  this.assert(
2890
- 'function' === typeof context
2891
- , 'expected #{this} to respond to ' + _.inspect(method)
2892
- , 'expected #{this} to not respond to ' + _.inspect(method)
3002
+ 'function' === typeof context,
3003
+ 'expected #{this} to respond to ' + _.inspect(method),
3004
+ 'expected #{this} to not respond to ' + _.inspect(method)
2893
3005
  );
2894
3006
  }
2895
3007
 
@@ -2956,16 +3068,16 @@ Assertion.addProperty('itself', function () {
2956
3068
  * @namespace BDD
2957
3069
  * @public
2958
3070
  */
2959
- function satisfy (matcher, msg) {
3071
+ function satisfy(matcher, msg) {
2960
3072
  if (msg) flag(this, 'message', msg);
2961
- var obj = flag(this, 'object');
2962
- var result = matcher(obj);
3073
+ let obj = flag(this, 'object');
3074
+ let result = matcher(obj);
2963
3075
  this.assert(
2964
- result
2965
- , 'expected #{this} to satisfy ' + _.objDisplay(matcher)
2966
- , 'expected #{this} to not satisfy' + _.objDisplay(matcher)
2967
- , flag(this, 'negate') ? false : true
2968
- , result
3076
+ result,
3077
+ 'expected #{this} to satisfy ' + _.objDisplay(matcher),
3078
+ 'expected #{this} to not satisfy' + _.objDisplay(matcher),
3079
+ flag(this, 'negate') ? false : true,
3080
+ result
2969
3081
  );
2970
3082
  }
2971
3083
 
@@ -3011,24 +3123,40 @@ Assertion.addMethod('satisfies', satisfy);
3011
3123
  */
3012
3124
  function closeTo(expected, delta, msg) {
3013
3125
  if (msg) flag(this, 'message', msg);
3014
- var obj = flag(this, 'object')
3015
- , flagMsg = flag(this, 'message')
3016
- , ssfi = flag(this, 'ssfi');
3126
+ let obj = flag(this, 'object'),
3127
+ flagMsg = flag(this, 'message'),
3128
+ ssfi = flag(this, 'ssfi');
3017
3129
 
3018
3130
  new Assertion(obj, flagMsg, ssfi, true).is.numeric;
3019
- let message = 'A `delta` value is required for `closeTo`';
3020
- if (delta == undefined) throw new AssertionError(flagMsg ? `${flagMsg}: ${message}` : message, undefined, ssfi);
3131
+ let message = 'A `delta` value is required for `closeTo`';
3132
+ if (delta == undefined) {
3133
+ throw new AssertionError(
3134
+ flagMsg ? `${flagMsg}: ${message}` : message,
3135
+ undefined,
3136
+ ssfi
3137
+ );
3138
+ }
3021
3139
  new Assertion(delta, flagMsg, ssfi, true).is.numeric;
3022
- message = 'A `expected` value is required for `closeTo`';
3023
- if (expected == undefined) throw new AssertionError(flagMsg ? `${flagMsg}: ${message}` : message, undefined, ssfi);
3140
+ message = 'A `expected` value is required for `closeTo`';
3141
+ if (expected == undefined) {
3142
+ throw new AssertionError(
3143
+ flagMsg ? `${flagMsg}: ${message}` : message,
3144
+ undefined,
3145
+ ssfi
3146
+ );
3147
+ }
3024
3148
  new Assertion(expected, flagMsg, ssfi, true).is.numeric;
3025
3149
 
3026
- const abs = (x) => x < 0n ? -x : x;
3150
+ const abs = (x) => (x < 0n ? -x : x);
3151
+
3152
+ // Used to round floating point number precision arithmetics
3153
+ // See: https://stackoverflow.com/a/3644302
3154
+ const strip = (number) => parseFloat(parseFloat(number).toPrecision(12));
3027
3155
 
3028
3156
  this.assert(
3029
- abs(obj - expected) <= delta
3030
- , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
3031
- , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
3157
+ strip(abs(obj - expected)) <= delta,
3158
+ 'expected #{this} to be close to ' + expected + ' +/- ' + delta,
3159
+ 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
3032
3160
  );
3033
3161
  }
3034
3162
 
@@ -3051,11 +3179,11 @@ function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3051
3179
  superset = superset.slice();
3052
3180
  }
3053
3181
 
3054
- return subset.every(function(elem, idx) {
3182
+ return subset.every(function (elem, idx) {
3055
3183
  if (ordered) return cmp ? cmp(elem, superset[idx]) : elem === superset[idx];
3056
3184
 
3057
3185
  if (!cmp) {
3058
- var matchIdx = superset.indexOf(elem);
3186
+ let matchIdx = superset.indexOf(elem);
3059
3187
  if (matchIdx === -1) return false;
3060
3188
 
3061
3189
  // Remove match from superset so not counted twice if duplicate in subset.
@@ -3063,7 +3191,7 @@ function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3063
3191
  return true;
3064
3192
  }
3065
3193
 
3066
- return superset.some(function(elem2, matchIdx) {
3194
+ return superset.some(function (elem2, matchIdx) {
3067
3195
  if (!cmp(elem, elem2)) return false;
3068
3196
 
3069
3197
  // Remove match from superset so not counted twice if duplicate in subset.
@@ -3143,17 +3271,17 @@ function isSubsetOf(_subset, _superset, cmp, contains, ordered) {
3143
3271
  */
3144
3272
  Assertion.addMethod('members', function (subset, msg) {
3145
3273
  if (msg) flag(this, 'message', msg);
3146
- var obj = flag(this, 'object')
3147
- , flagMsg = flag(this, 'message')
3148
- , ssfi = flag(this, 'ssfi');
3274
+ let obj = flag(this, 'object'),
3275
+ flagMsg = flag(this, 'message'),
3276
+ ssfi = flag(this, 'ssfi');
3149
3277
 
3150
3278
  new Assertion(obj, flagMsg, ssfi, true).to.be.iterable;
3151
3279
  new Assertion(subset, flagMsg, ssfi, true).to.be.iterable;
3152
3280
 
3153
- var contains = flag(this, 'contains');
3154
- var ordered = flag(this, 'ordered');
3281
+ let contains = flag(this, 'contains');
3282
+ let ordered = flag(this, 'ordered');
3155
3283
 
3156
- var subject, failMsg, failNegateMsg;
3284
+ let subject, failMsg, failNegateMsg;
3157
3285
 
3158
3286
  if (contains) {
3159
3287
  subject = ordered ? 'an ordered superset' : 'a superset';
@@ -3162,18 +3290,19 @@ Assertion.addMethod('members', function (subset, msg) {
3162
3290
  } else {
3163
3291
  subject = ordered ? 'ordered members' : 'members';
3164
3292
  failMsg = 'expected #{this} to have the same ' + subject + ' as #{exp}';
3165
- failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}';
3293
+ failNegateMsg =
3294
+ 'expected #{this} to not have the same ' + subject + ' as #{exp}';
3166
3295
  }
3167
3296
 
3168
- var cmp = flag(this, 'deep') ? flag(this, 'eql') : undefined;
3297
+ let cmp = flag(this, 'deep') ? flag(this, 'eql') : undefined;
3169
3298
 
3170
3299
  this.assert(
3171
- isSubsetOf(subset, obj, cmp, contains, ordered)
3172
- , failMsg
3173
- , failNegateMsg
3174
- , subset
3175
- , obj
3176
- , true
3300
+ isSubsetOf(subset, obj, cmp, contains, ordered),
3301
+ failMsg,
3302
+ failNegateMsg,
3303
+ subset,
3304
+ obj,
3305
+ true
3177
3306
  );
3178
3307
  });
3179
3308
 
@@ -3198,15 +3327,15 @@ Assertion.addMethod('members', function (subset, msg) {
3198
3327
  * @namespace BDD
3199
3328
  * @public
3200
3329
  */
3201
- Assertion.addProperty('iterable', function(msg) {
3330
+ Assertion.addProperty('iterable', function (msg) {
3202
3331
  if (msg) flag(this, 'message', msg);
3203
- var obj = flag(this, 'object');
3332
+ let obj = flag(this, 'object');
3204
3333
 
3205
3334
  this.assert(
3206
- obj != undefined && obj[Symbol.iterator]
3207
- , 'expected #{this} to be an iterable'
3208
- , 'expected #{this} to not be an iterable'
3209
- , obj
3335
+ obj != undefined && obj[Symbol.iterator],
3336
+ 'expected #{this} to be an iterable',
3337
+ 'expected #{this} to not be an iterable',
3338
+ obj
3210
3339
  );
3211
3340
  });
3212
3341
 
@@ -3247,40 +3376,44 @@ Assertion.addProperty('iterable', function(msg) {
3247
3376
  * @namespace BDD
3248
3377
  * @public
3249
3378
  */
3250
- function oneOf (list, msg) {
3379
+ function oneOf(list, msg) {
3251
3380
  if (msg) flag(this, 'message', msg);
3252
- var expected = flag(this, 'object')
3253
- , flagMsg = flag(this, 'message')
3254
- , ssfi = flag(this, 'ssfi')
3255
- , contains = flag(this, 'contains')
3256
- , isDeep = flag(this, 'deep')
3257
- , eql = flag(this, 'eql');
3381
+ let expected = flag(this, 'object'),
3382
+ flagMsg = flag(this, 'message'),
3383
+ ssfi = flag(this, 'ssfi'),
3384
+ contains = flag(this, 'contains'),
3385
+ isDeep = flag(this, 'deep'),
3386
+ eql = flag(this, 'eql');
3258
3387
  new Assertion(list, flagMsg, ssfi, true).to.be.an('array');
3259
3388
 
3260
3389
  if (contains) {
3261
3390
  this.assert(
3262
- list.some(function(possibility) { return expected.indexOf(possibility) > -1 })
3263
- , 'expected #{this} to contain one of #{exp}'
3264
- , 'expected #{this} to not contain one of #{exp}'
3265
- , list
3266
- , expected
3391
+ list.some(function (possibility) {
3392
+ return expected.indexOf(possibility) > -1;
3393
+ }),
3394
+ 'expected #{this} to contain one of #{exp}',
3395
+ 'expected #{this} to not contain one of #{exp}',
3396
+ list,
3397
+ expected
3267
3398
  );
3268
3399
  } else {
3269
3400
  if (isDeep) {
3270
3401
  this.assert(
3271
- list.some(function(possibility) { return eql(expected, possibility) })
3272
- , 'expected #{this} to deeply equal one of #{exp}'
3273
- , 'expected #{this} to deeply equal one of #{exp}'
3274
- , list
3275
- , expected
3402
+ list.some(function (possibility) {
3403
+ return eql(expected, possibility);
3404
+ }),
3405
+ 'expected #{this} to deeply equal one of #{exp}',
3406
+ 'expected #{this} to deeply equal one of #{exp}',
3407
+ list,
3408
+ expected
3276
3409
  );
3277
3410
  } else {
3278
3411
  this.assert(
3279
- list.indexOf(expected) > -1
3280
- , 'expected #{this} to be one of #{exp}'
3281
- , 'expected #{this} to not be one of #{exp}'
3282
- , list
3283
- , expected
3412
+ list.indexOf(expected) > -1,
3413
+ 'expected #{this} to be one of #{exp}',
3414
+ 'expected #{this} to not be one of #{exp}',
3415
+ list,
3416
+ expected
3284
3417
  );
3285
3418
  }
3286
3419
  }
@@ -3382,14 +3515,14 @@ Assertion.addMethod('oneOf', oneOf);
3382
3515
  * @namespace BDD
3383
3516
  * @public
3384
3517
  */
3385
- function assertChanges (subject, prop, msg) {
3518
+ function assertChanges(subject, prop, msg) {
3386
3519
  if (msg) flag(this, 'message', msg);
3387
- var fn = flag(this, 'object')
3388
- , flagMsg = flag(this, 'message')
3389
- , ssfi = flag(this, 'ssfi');
3520
+ let fn = flag(this, 'object'),
3521
+ flagMsg = flag(this, 'message'),
3522
+ ssfi = flag(this, 'ssfi');
3390
3523
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');
3391
3524
 
3392
- var initial;
3525
+ let initial;
3393
3526
  if (!prop) {
3394
3527
  new Assertion(subject, flagMsg, ssfi, true).is.a('function');
3395
3528
  initial = subject();
@@ -3400,8 +3533,8 @@ function assertChanges (subject, prop, msg) {
3400
3533
 
3401
3534
  fn();
3402
3535
 
3403
- var final = prop === undefined || prop === null ? subject() : subject[prop];
3404
- var msgObj = prop === undefined || prop === null ? initial : '.' + prop;
3536
+ let final = prop === undefined || prop === null ? subject() : subject[prop];
3537
+ let msgObj = prop === undefined || prop === null ? initial : '.' + prop;
3405
3538
 
3406
3539
  // This gets flagged because of the .by(delta) assertion
3407
3540
  flag(this, 'deltaMsgObj', msgObj);
@@ -3411,9 +3544,9 @@ function assertChanges (subject, prop, msg) {
3411
3544
  flag(this, 'realDelta', final !== initial);
3412
3545
 
3413
3546
  this.assert(
3414
- initial !== final
3415
- , 'expected ' + msgObj + ' to change'
3416
- , 'expected ' + msgObj + ' to not change'
3547
+ initial !== final,
3548
+ 'expected ' + msgObj + ' to change',
3549
+ 'expected ' + msgObj + ' to not change'
3417
3550
  );
3418
3551
  }
3419
3552
 
@@ -3498,14 +3631,14 @@ Assertion.addMethod('changes', assertChanges);
3498
3631
  * @namespace BDD
3499
3632
  * @public
3500
3633
  */
3501
- function assertIncreases (subject, prop, msg) {
3634
+ function assertIncreases(subject, prop, msg) {
3502
3635
  if (msg) flag(this, 'message', msg);
3503
- var fn = flag(this, 'object')
3504
- , flagMsg = flag(this, 'message')
3505
- , ssfi = flag(this, 'ssfi');
3636
+ let fn = flag(this, 'object'),
3637
+ flagMsg = flag(this, 'message'),
3638
+ ssfi = flag(this, 'ssfi');
3506
3639
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');
3507
3640
 
3508
- var initial;
3641
+ let initial;
3509
3642
  if (!prop) {
3510
3643
  new Assertion(subject, flagMsg, ssfi, true).is.a('function');
3511
3644
  initial = subject();
@@ -3519,8 +3652,8 @@ function assertIncreases (subject, prop, msg) {
3519
3652
 
3520
3653
  fn();
3521
3654
 
3522
- var final = prop === undefined || prop === null ? subject() : subject[prop];
3523
- var msgObj = prop === undefined || prop === null ? initial : '.' + prop;
3655
+ let final = prop === undefined || prop === null ? subject() : subject[prop];
3656
+ let msgObj = prop === undefined || prop === null ? initial : '.' + prop;
3524
3657
 
3525
3658
  flag(this, 'deltaMsgObj', msgObj);
3526
3659
  flag(this, 'initialDeltaValue', initial);
@@ -3529,9 +3662,9 @@ function assertIncreases (subject, prop, msg) {
3529
3662
  flag(this, 'realDelta', final - initial);
3530
3663
 
3531
3664
  this.assert(
3532
- final - initial > 0
3533
- , 'expected ' + msgObj + ' to increase'
3534
- , 'expected ' + msgObj + ' to not increase'
3665
+ final - initial > 0,
3666
+ 'expected ' + msgObj + ' to increase',
3667
+ 'expected ' + msgObj + ' to not increase'
3535
3668
  );
3536
3669
  }
3537
3670
 
@@ -3616,14 +3749,14 @@ Assertion.addMethod('increases', assertIncreases);
3616
3749
  * @namespace BDD
3617
3750
  * @public
3618
3751
  */
3619
- function assertDecreases (subject, prop, msg) {
3752
+ function assertDecreases(subject, prop, msg) {
3620
3753
  if (msg) flag(this, 'message', msg);
3621
- var fn = flag(this, 'object')
3622
- , flagMsg = flag(this, 'message')
3623
- , ssfi = flag(this, 'ssfi');
3754
+ let fn = flag(this, 'object'),
3755
+ flagMsg = flag(this, 'message'),
3756
+ ssfi = flag(this, 'ssfi');
3624
3757
  new Assertion(fn, flagMsg, ssfi, true).is.a('function');
3625
3758
 
3626
- var initial;
3759
+ let initial;
3627
3760
  if (!prop) {
3628
3761
  new Assertion(subject, flagMsg, ssfi, true).is.a('function');
3629
3762
  initial = subject();
@@ -3637,8 +3770,8 @@ function assertDecreases (subject, prop, msg) {
3637
3770
 
3638
3771
  fn();
3639
3772
 
3640
- var final = prop === undefined || prop === null ? subject() : subject[prop];
3641
- var msgObj = prop === undefined || prop === null ? initial : '.' + prop;
3773
+ let final = prop === undefined || prop === null ? subject() : subject[prop];
3774
+ let msgObj = prop === undefined || prop === null ? initial : '.' + prop;
3642
3775
 
3643
3776
  flag(this, 'deltaMsgObj', msgObj);
3644
3777
  flag(this, 'initialDeltaValue', initial);
@@ -3647,9 +3780,9 @@ function assertDecreases (subject, prop, msg) {
3647
3780
  flag(this, 'realDelta', initial - final);
3648
3781
 
3649
3782
  this.assert(
3650
- final - initial < 0
3651
- , 'expected ' + msgObj + ' to decrease'
3652
- , 'expected ' + msgObj + ' to not decrease'
3783
+ final - initial < 0,
3784
+ 'expected ' + msgObj + ' to decrease',
3785
+ 'expected ' + msgObj + ' to not decrease'
3653
3786
  );
3654
3787
  }
3655
3788
 
@@ -3724,13 +3857,13 @@ Assertion.addMethod('decreases', assertDecreases);
3724
3857
  function assertDelta(delta, msg) {
3725
3858
  if (msg) flag(this, 'message', msg);
3726
3859
 
3727
- var msgObj = flag(this, 'deltaMsgObj');
3728
- var initial = flag(this, 'initialDeltaValue');
3729
- var final = flag(this, 'finalDeltaValue');
3730
- var behavior = flag(this, 'deltaBehavior');
3731
- var realDelta = flag(this, 'realDelta');
3860
+ let msgObj = flag(this, 'deltaMsgObj');
3861
+ let initial = flag(this, 'initialDeltaValue');
3862
+ let final = flag(this, 'finalDeltaValue');
3863
+ let behavior = flag(this, 'deltaBehavior');
3864
+ let realDelta = flag(this, 'realDelta');
3732
3865
 
3733
- var expression;
3866
+ let expression;
3734
3867
  if (behavior === 'change') {
3735
3868
  expression = Math.abs(final - initial) === Math.abs(delta);
3736
3869
  } else {
@@ -3738,9 +3871,9 @@ function assertDelta(delta, msg) {
3738
3871
  }
3739
3872
 
3740
3873
  this.assert(
3741
- expression
3742
- , 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta
3743
- , 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta
3874
+ expression,
3875
+ 'expected ' + msgObj + ' to ' + behavior + ' by ' + delta,
3876
+ 'expected ' + msgObj + ' to not ' + behavior + ' by ' + delta
3744
3877
  );
3745
3878
  }
3746
3879
 
@@ -3773,20 +3906,20 @@ Assertion.addMethod('by', assertDelta);
3773
3906
  * @namespace BDD
3774
3907
  * @public
3775
3908
  */
3776
- Assertion.addProperty('extensible', function() {
3777
- var obj = flag(this, 'object');
3909
+ Assertion.addProperty('extensible', function () {
3910
+ let obj = flag(this, 'object');
3778
3911
 
3779
3912
  // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.
3780
3913
  // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false.
3781
3914
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible
3782
3915
  // The following provides ES6 behavior for ES5 environments.
3783
3916
 
3784
- var isExtensible = obj === Object(obj) && Object.isExtensible(obj);
3917
+ let isExtensible = obj === Object(obj) && Object.isExtensible(obj);
3785
3918
 
3786
3919
  this.assert(
3787
- isExtensible
3788
- , 'expected #{this} to be extensible'
3789
- , 'expected #{this} to not be extensible'
3920
+ isExtensible,
3921
+ 'expected #{this} to be extensible',
3922
+ 'expected #{this} to not be extensible'
3790
3923
  );
3791
3924
  });
3792
3925
 
@@ -3817,20 +3950,20 @@ Assertion.addProperty('extensible', function() {
3817
3950
  * @namespace BDD
3818
3951
  * @public
3819
3952
  */
3820
- Assertion.addProperty('sealed', function() {
3821
- var obj = flag(this, 'object');
3953
+ Assertion.addProperty('sealed', function () {
3954
+ let obj = flag(this, 'object');
3822
3955
 
3823
3956
  // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.
3824
3957
  // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true.
3825
3958
  // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed
3826
3959
  // The following provides ES6 behavior for ES5 environments.
3827
3960
 
3828
- var isSealed = obj === Object(obj) ? Object.isSealed(obj) : true;
3961
+ let isSealed = obj === Object(obj) ? Object.isSealed(obj) : true;
3829
3962
 
3830
3963
  this.assert(
3831
- isSealed
3832
- , 'expected #{this} to be sealed'
3833
- , 'expected #{this} to not be sealed'
3964
+ isSealed,
3965
+ 'expected #{this} to be sealed',
3966
+ 'expected #{this} to not be sealed'
3834
3967
  );
3835
3968
  });
3836
3969
 
@@ -3858,20 +3991,20 @@ Assertion.addProperty('sealed', function() {
3858
3991
  * @namespace BDD
3859
3992
  * @public
3860
3993
  */
3861
- Assertion.addProperty('frozen', function() {
3862
- var obj = flag(this, 'object');
3994
+ Assertion.addProperty('frozen', function () {
3995
+ let obj = flag(this, 'object');
3863
3996
 
3864
3997
  // In ES5, if the argument to this method is a primitive, then it will cause a TypeError.
3865
3998
  // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true.
3866
3999
  // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen
3867
4000
  // The following provides ES6 behavior for ES5 environments.
3868
4001
 
3869
- var isFrozen = obj === Object(obj) ? Object.isFrozen(obj) : true;
4002
+ let isFrozen = obj === Object(obj) ? Object.isFrozen(obj) : true;
3870
4003
 
3871
4004
  this.assert(
3872
- isFrozen
3873
- , 'expected #{this} to be frozen'
3874
- , 'expected #{this} to not be frozen'
4005
+ isFrozen,
4006
+ 'expected #{this} to be frozen',
4007
+ 'expected #{this} to not be frozen'
3875
4008
  );
3876
4009
  });
3877
4010
 
@@ -3923,12 +4056,101 @@ Assertion.addProperty('frozen', function() {
3923
4056
  * @namespace BDD
3924
4057
  * @public
3925
4058
  */
3926
- Assertion.addProperty('finite', function(msg) {
3927
- var obj = flag(this, 'object');
4059
+ Assertion.addProperty('finite', function (_msg) {
4060
+ let obj = flag(this, 'object');
4061
+
4062
+ this.assert(
4063
+ typeof obj === 'number' && isFinite(obj),
4064
+ 'expected #{this} to be a finite number',
4065
+ 'expected #{this} to not be a finite number'
4066
+ );
4067
+ });
4068
+
4069
+ /**
4070
+ * A subset-aware compare function
4071
+ *
4072
+ * @param {unknown} expected
4073
+ * @param {unknown} actual
4074
+ * @returns {boolean}
4075
+ */
4076
+ function compareSubset(expected, actual) {
4077
+ if (expected === actual) {
4078
+ return true;
4079
+ }
4080
+ if (typeof actual !== typeof expected) {
4081
+ return false;
4082
+ }
4083
+ if (typeof expected !== 'object' || expected === null) {
4084
+ return expected === actual;
4085
+ }
4086
+ if (!actual) {
4087
+ return false;
4088
+ }
4089
+
4090
+ if (Array.isArray(expected)) {
4091
+ if (!Array.isArray(actual)) {
4092
+ return false;
4093
+ }
4094
+ return expected.every(function (exp) {
4095
+ return actual.some(function (act) {
4096
+ return compareSubset(exp, act);
4097
+ });
4098
+ });
4099
+ }
4100
+
4101
+ if (expected instanceof Date) {
4102
+ if (actual instanceof Date) {
4103
+ return expected.getTime() === actual.getTime();
4104
+ } else {
4105
+ return false;
4106
+ }
4107
+ }
4108
+
4109
+ return Object.keys(expected).every(function (key) {
4110
+ let expectedValue = expected[key];
4111
+ let actualValue = actual[key];
4112
+ if (
4113
+ typeof expectedValue === 'object' &&
4114
+ expectedValue !== null &&
4115
+ actualValue !== null
4116
+ ) {
4117
+ return compareSubset(expectedValue, actualValue);
4118
+ }
4119
+ if (typeof expectedValue === 'function') {
4120
+ return expectedValue(actualValue);
4121
+ }
4122
+ return actualValue === expectedValue;
4123
+ });
4124
+ }
4125
+
4126
+ /**
4127
+ * ### .containSubset
4128
+ *
4129
+ * Asserts that the target primitive/object/array structure deeply contains all provided fields
4130
+ * at the same key/depth as the provided structure.
4131
+ *
4132
+ * When comparing arrays, the target must contain the subset of at least one of each object/value in the subset array.
4133
+ * Order does not matter.
4134
+ *
4135
+ * expect({name: {first: "John", last: "Smith"}}).to.containSubset({name: {first: "John"}});
4136
+ *
4137
+ * Add `.not` earlier in the chain to negate the assertion. This will cause the assertion to fail
4138
+ * only if the target DOES contains the provided data at the expected keys/depths.
4139
+ *
4140
+ * @name containSubset
4141
+ * @namespace BDD
4142
+ * @public
4143
+ */
4144
+ Assertion.addMethod('containSubset', function (expected) {
4145
+ const actual = _.flag(this, 'object');
4146
+ const showDiff = config.showDiff;
3928
4147
 
3929
4148
  this.assert(
3930
- typeof obj === 'number' && isFinite(obj)
3931
- , 'expected #{this} to be a finite number'
3932
- , 'expected #{this} to not be a finite number'
4149
+ compareSubset(expected, actual),
4150
+ 'expected #{act} to contain subset #{exp}',
4151
+ 'expected #{act} to not contain subset #{exp}',
4152
+ expected,
4153
+ actual,
4154
+ showDiff
3933
4155
  );
3934
4156
  });