chai 4.0.0 → 4.1.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.
@@ -330,6 +330,16 @@ module.exports = function (chai, _) {
330
330
  *
331
331
  * expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2});
332
332
  *
333
+ * When the target is a Set or WeakSet, `.include` asserts that the given `val` is a
334
+ * member of the target. SameValueZero equality algorithm is used.
335
+ *
336
+ * expect(new Set([1, 2])).to.include(2);
337
+ *
338
+ * When the target is a Map, `.include` asserts that the given `val` is one of
339
+ * the values of the target. SameValueZero equality algorithm is used.
340
+ *
341
+ * expect(new Map([['a', 1], ['b', 2]])).to.include(2);
342
+ *
333
343
  * Because `.include` does different things based on the target's type, it's
334
344
  * important to check the target's type before using `.include`. See the `.a`
335
345
  * doc for info on testing a target's type.
@@ -338,8 +348,8 @@ module.exports = function (chai, _) {
338
348
  *
339
349
  * By default, strict (`===`) equality is used to compare array members and
340
350
  * object properties. Add `.deep` earlier in the chain to use deep equality
341
- * instead. See the `deep-eql` project page for info on the deep equality
342
- * algorithm: https://github.com/chaijs/deep-eql.
351
+ * instead (WeakSet targets are not supported). See the `deep-eql` project
352
+ * page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql.
343
353
  *
344
354
  * // Target array deeply (but not strictly) includes `{a: 1}`
345
355
  * expect([{a: 1}]).to.deep.include({a: 1});
@@ -449,65 +459,124 @@ module.exports = function (chai, _) {
449
459
  * @api public
450
460
  */
451
461
 
452
- function includeChainingBehavior () {
453
- flag(this, 'contains', true);
462
+ function SameValueZero(a, b) {
463
+ return (_.isNaN(a) && _.isNaN(b)) || a === b;
454
464
  }
455
465
 
456
- function isDeepIncluded (arr, val) {
457
- return arr.some(function (arrVal) {
458
- return _.eql(arrVal, val);
459
- });
466
+ function includeChainingBehavior () {
467
+ flag(this, 'contains', true);
460
468
  }
461
469
 
462
470
  function include (val, msg) {
463
471
  if (msg) flag(this, 'message', msg);
464
-
465
- _.expectTypes(this, ['array', 'object', 'string'], flag(this, 'ssfi'));
466
-
472
+
467
473
  var obj = flag(this, 'object')
468
474
  , objType = _.type(obj).toLowerCase()
475
+ , flagMsg = flag(this, 'message')
476
+ , negate = flag(this, 'negate')
477
+ , ssfi = flag(this, 'ssfi')
469
478
  , isDeep = flag(this, 'deep')
470
479
  , descriptor = isDeep ? 'deep ' : '';
471
480
 
472
- // This block is for asserting a subset of properties in an object.
473
- if (objType === 'object') {
474
- var props = Object.keys(val)
475
- , negate = flag(this, 'negate')
476
- , firstErr = null
477
- , numErrs = 0;
478
-
479
- props.forEach(function (prop) {
480
- var propAssertion = new Assertion(obj);
481
- _.transferFlags(this, propAssertion, true);
482
- flag(propAssertion, 'lockSsfi', true);
483
-
484
- if (!negate || props.length === 1) {
485
- propAssertion.property(prop, val[prop]);
486
- return;
481
+ flagMsg = flagMsg ? flagMsg + ': ' : '';
482
+
483
+ var included = false;
484
+
485
+ switch (objType) {
486
+ case 'string':
487
+ included = obj.indexOf(val) !== -1;
488
+ break;
489
+
490
+ case 'weakset':
491
+ if (isDeep) {
492
+ throw new AssertionError(
493
+ flagMsg + 'unable to use .deep.include with WeakSet',
494
+ undefined,
495
+ ssfi
496
+ );
497
+ }
498
+
499
+ included = obj.has(val);
500
+ break;
501
+
502
+ case 'map':
503
+ var isEql = isDeep ? _.eql : SameValueZero;
504
+ obj.forEach(function (item) {
505
+ included = included || isEql(item, val);
506
+ });
507
+ break;
508
+
509
+ case 'set':
510
+ if (isDeep) {
511
+ obj.forEach(function (item) {
512
+ included = included || _.eql(item, val);
513
+ });
514
+ } else {
515
+ included = obj.has(val);
487
516
  }
517
+ break;
488
518
 
489
- try {
490
- propAssertion.property(prop, val[prop]);
491
- } catch (err) {
492
- if (!_.checkError.compatibleConstructor(err, AssertionError)) throw err;
493
- if (firstErr === null) firstErr = err;
494
- numErrs++;
519
+ case 'array':
520
+ if (isDeep) {
521
+ included = obj.some(function (item) {
522
+ return _.eql(item, val);
523
+ })
524
+ } else {
525
+ included = obj.indexOf(val) !== -1;
495
526
  }
496
- }, this);
527
+ break;
497
528
 
498
- // When validating .not.include with multiple properties, we only want
499
- // to throw an assertion error if all of the properties are included,
500
- // in which case we throw the first property assertion error that we
501
- // encountered.
502
- if (negate && props.length > 1 && numErrs === props.length) throw firstErr;
529
+ default:
530
+ // This block is for asserting a subset of properties in an object.
531
+ // `_.expectTypes` isn't used here because `.include` should work with
532
+ // objects with a custom `@@toStringTag`.
533
+ if (val !== Object(val)) {
534
+ throw new AssertionError(
535
+ flagMsg + 'object tested must be an array, a map, an object,'
536
+ + ' a set, a string, or a weakset, but ' + objType + ' given',
537
+ undefined,
538
+ ssfi
539
+ );
540
+ }
503
541
 
504
- return;
542
+ var props = Object.keys(val)
543
+ , firstErr = null
544
+ , numErrs = 0;
545
+
546
+ props.forEach(function (prop) {
547
+ var propAssertion = new Assertion(obj);
548
+ _.transferFlags(this, propAssertion, true);
549
+ flag(propAssertion, 'lockSsfi', true);
550
+
551
+ if (!negate || props.length === 1) {
552
+ propAssertion.property(prop, val[prop]);
553
+ return;
554
+ }
555
+
556
+ try {
557
+ propAssertion.property(prop, val[prop]);
558
+ } catch (err) {
559
+ if (!_.checkError.compatibleConstructor(err, AssertionError)) {
560
+ throw err;
561
+ }
562
+ if (firstErr === null) firstErr = err;
563
+ numErrs++;
564
+ }
565
+ }, this);
566
+
567
+ // When validating .not.include with multiple properties, we only want
568
+ // to throw an assertion error if all of the properties are included,
569
+ // in which case we throw the first property assertion error that we
570
+ // encountered.
571
+ if (negate && props.length > 1 && numErrs === props.length) {
572
+ throw firstErr;
573
+ }
574
+ return;
505
575
  }
506
576
 
507
- // Assert inclusion in an array or substring in a string.
577
+ // Assert inclusion in collection or substring in a string.
508
578
  this.assert(
509
- objType === 'string' || !isDeep ? ~obj.indexOf(val)
510
- : isDeepIncluded(obj, val)
579
+ included
511
580
  , 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
512
581
  , 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
513
582
  }
@@ -1024,7 +1093,7 @@ module.exports = function (chai, _) {
1024
1093
  /**
1025
1094
  * ### .above(n[, msg])
1026
1095
  *
1027
- * Asserts that the target is a number greater than the given number `n`.
1096
+ * Asserts that the target is a number or a date greater than the given number or date `n` respectively.
1028
1097
  * However, it's often best to assert that the target is equal to its expected
1029
1098
  * value.
1030
1099
  *
@@ -1069,21 +1138,29 @@ module.exports = function (chai, _) {
1069
1138
  var obj = flag(this, 'object')
1070
1139
  , doLength = flag(this, 'doLength')
1071
1140
  , flagMsg = flag(this, 'message')
1072
- , ssfi = flag(this, 'ssfi');
1141
+ , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1142
+ , ssfi = flag(this, 'ssfi')
1143
+ , objType = _.type(obj).toLowerCase()
1144
+ , nType = _.type(n).toLowerCase()
1145
+ , shouldThrow = true;
1073
1146
 
1074
1147
  if (doLength) {
1075
1148
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1149
+ }
1150
+
1151
+ if (!doLength && (objType === 'date' && nType !== 'date')) {
1152
+ errorMessage = msgPrefix + 'the argument to above must be a date';
1153
+ } else if (nType !== 'number' && (doLength || objType === 'number')) {
1154
+ errorMessage = msgPrefix + 'the argument to above must be a number';
1155
+ } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1156
+ var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1157
+ errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1076
1158
  } else {
1077
- new Assertion(obj, flagMsg, ssfi, true).is.a('number');
1159
+ shouldThrow = false;
1078
1160
  }
1079
1161
 
1080
- if (typeof n !== 'number') {
1081
- flagMsg = flagMsg ? flagMsg + ': ' : '';
1082
- throw new AssertionError(
1083
- flagMsg + 'the argument to above must be a number',
1084
- undefined,
1085
- ssfi
1086
- );
1162
+ if (shouldThrow) {
1163
+ throw new AssertionError(errorMessage, undefined, ssfi);
1087
1164
  }
1088
1165
 
1089
1166
  if (doLength) {
@@ -1098,8 +1175,9 @@ module.exports = function (chai, _) {
1098
1175
  } else {
1099
1176
  this.assert(
1100
1177
  obj > n
1101
- , 'expected #{this} to be above ' + n
1102
- , 'expected #{this} to be at most ' + n
1178
+ , 'expected #{this} to be above #{exp}'
1179
+ , 'expected #{this} to be at most #{exp}'
1180
+ , n
1103
1181
  );
1104
1182
  }
1105
1183
  }
@@ -1111,8 +1189,8 @@ module.exports = function (chai, _) {
1111
1189
  /**
1112
1190
  * ### .least(n[, msg])
1113
1191
  *
1114
- * Asserts that the target is a number greater than or equal to the given
1115
- * number `n`. However, it's often best to assert that the target is equal to
1192
+ * Asserts that the target is a number or a date greater than or equal to the given
1193
+ * number or date `n` respectively. However, it's often best to assert that the target is equal to
1116
1194
  * its expected value.
1117
1195
  *
1118
1196
  * expect(2).to.equal(2); // Recommended
@@ -1156,21 +1234,29 @@ module.exports = function (chai, _) {
1156
1234
  var obj = flag(this, 'object')
1157
1235
  , doLength = flag(this, 'doLength')
1158
1236
  , flagMsg = flag(this, 'message')
1159
- , ssfi = flag(this, 'ssfi');
1237
+ , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1238
+ , ssfi = flag(this, 'ssfi')
1239
+ , objType = _.type(obj).toLowerCase()
1240
+ , nType = _.type(n).toLowerCase()
1241
+ , shouldThrow = true;
1160
1242
 
1161
1243
  if (doLength) {
1162
1244
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1245
+ }
1246
+
1247
+ if (!doLength && (objType === 'date' && nType !== 'date')) {
1248
+ errorMessage = msgPrefix + 'the argument to least must be a date';
1249
+ } else if (nType !== 'number' && (doLength || objType === 'number')) {
1250
+ errorMessage = msgPrefix + 'the argument to least must be a number';
1251
+ } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1252
+ var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1253
+ errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1163
1254
  } else {
1164
- new Assertion(obj, flagMsg, ssfi, true).is.a('number');
1255
+ shouldThrow = false;
1165
1256
  }
1166
1257
 
1167
- if (typeof n !== 'number') {
1168
- flagMsg = flagMsg ? flagMsg + ': ' : '';
1169
- throw new AssertionError(
1170
- flagMsg + 'the argument to least must be a number',
1171
- undefined,
1172
- ssfi
1173
- );
1258
+ if (shouldThrow) {
1259
+ throw new AssertionError(errorMessage, undefined, ssfi);
1174
1260
  }
1175
1261
 
1176
1262
  if (doLength) {
@@ -1185,8 +1271,9 @@ module.exports = function (chai, _) {
1185
1271
  } else {
1186
1272
  this.assert(
1187
1273
  obj >= n
1188
- , 'expected #{this} to be at least ' + n
1189
- , 'expected #{this} to be below ' + n
1274
+ , 'expected #{this} to be at least #{exp}'
1275
+ , 'expected #{this} to be below #{exp}'
1276
+ , n
1190
1277
  );
1191
1278
  }
1192
1279
  }
@@ -1197,7 +1284,7 @@ module.exports = function (chai, _) {
1197
1284
  /**
1198
1285
  * ### .below(n[, msg])
1199
1286
  *
1200
- * Asserts that the target is a number less than the given number `n`.
1287
+ * Asserts that the target is a number or a date less than the given number or date `n` respectively.
1201
1288
  * However, it's often best to assert that the target is equal to its expected
1202
1289
  * value.
1203
1290
  *
@@ -1242,21 +1329,29 @@ module.exports = function (chai, _) {
1242
1329
  var obj = flag(this, 'object')
1243
1330
  , doLength = flag(this, 'doLength')
1244
1331
  , flagMsg = flag(this, 'message')
1245
- , ssfi = flag(this, 'ssfi');
1332
+ , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1333
+ , ssfi = flag(this, 'ssfi')
1334
+ , objType = _.type(obj).toLowerCase()
1335
+ , nType = _.type(n).toLowerCase()
1336
+ , shouldThrow = true;
1246
1337
 
1247
1338
  if (doLength) {
1248
1339
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1340
+ }
1341
+
1342
+ if (!doLength && (objType === 'date' && nType !== 'date')) {
1343
+ errorMessage = msgPrefix + 'the argument to below must be a date';
1344
+ } else if (nType !== 'number' && (doLength || objType === 'number')) {
1345
+ errorMessage = msgPrefix + 'the argument to below must be a number';
1346
+ } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1347
+ var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1348
+ errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1249
1349
  } else {
1250
- new Assertion(obj, flagMsg, ssfi, true).is.a('number');
1350
+ shouldThrow = false;
1251
1351
  }
1252
1352
 
1253
- if (typeof n !== 'number') {
1254
- flagMsg = flagMsg ? flagMsg + ': ' : '';
1255
- throw new AssertionError(
1256
- flagMsg + 'the argument to below must be a number',
1257
- undefined,
1258
- ssfi
1259
- );
1353
+ if (shouldThrow) {
1354
+ throw new AssertionError(errorMessage, undefined, ssfi);
1260
1355
  }
1261
1356
 
1262
1357
  if (doLength) {
@@ -1271,8 +1366,9 @@ module.exports = function (chai, _) {
1271
1366
  } else {
1272
1367
  this.assert(
1273
1368
  obj < n
1274
- , 'expected #{this} to be below ' + n
1275
- , 'expected #{this} to be at least ' + n
1369
+ , 'expected #{this} to be below #{exp}'
1370
+ , 'expected #{this} to be at least #{exp}'
1371
+ , n
1276
1372
  );
1277
1373
  }
1278
1374
  }
@@ -1284,8 +1380,8 @@ module.exports = function (chai, _) {
1284
1380
  /**
1285
1381
  * ### .most(n[, msg])
1286
1382
  *
1287
- * Asserts that the target is a number less than or equal to the given number
1288
- * `n`. However, it's often best to assert that the target is equal to its
1383
+ * Asserts that the target is a number or a date less than or equal to the given number
1384
+ * or date `n` respectively. However, it's often best to assert that the target is equal to its
1289
1385
  * expected value.
1290
1386
  *
1291
1387
  * expect(1).to.equal(1); // Recommended
@@ -1328,21 +1424,29 @@ module.exports = function (chai, _) {
1328
1424
  var obj = flag(this, 'object')
1329
1425
  , doLength = flag(this, 'doLength')
1330
1426
  , flagMsg = flag(this, 'message')
1331
- , ssfi = flag(this, 'ssfi');
1427
+ , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1428
+ , ssfi = flag(this, 'ssfi')
1429
+ , objType = _.type(obj).toLowerCase()
1430
+ , nType = _.type(n).toLowerCase()
1431
+ , shouldThrow = true;
1332
1432
 
1333
1433
  if (doLength) {
1334
1434
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1435
+ }
1436
+
1437
+ if (!doLength && (objType === 'date' && nType !== 'date')) {
1438
+ errorMessage = msgPrefix + 'the argument to most must be a date';
1439
+ } else if (nType !== 'number' && (doLength || objType === 'number')) {
1440
+ errorMessage = msgPrefix + 'the argument to most must be a number';
1441
+ } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1442
+ var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1443
+ errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1335
1444
  } else {
1336
- new Assertion(obj, flagMsg, ssfi, true).is.a('number');
1445
+ shouldThrow = false;
1337
1446
  }
1338
1447
 
1339
- if (typeof n !== 'number') {
1340
- flagMsg = flagMsg ? flagMsg + ': ' : '';
1341
- throw new AssertionError(
1342
- flagMsg + 'the argument to most must be a number',
1343
- undefined,
1344
- ssfi
1345
- );
1448
+ if (shouldThrow) {
1449
+ throw new AssertionError(errorMessage, undefined, ssfi);
1346
1450
  }
1347
1451
 
1348
1452
  if (doLength) {
@@ -1357,8 +1461,9 @@ module.exports = function (chai, _) {
1357
1461
  } else {
1358
1462
  this.assert(
1359
1463
  obj <= n
1360
- , 'expected #{this} to be at most ' + n
1361
- , 'expected #{this} to be above ' + n
1464
+ , 'expected #{this} to be at most #{exp}'
1465
+ , 'expected #{this} to be above #{exp}'
1466
+ , n
1362
1467
  );
1363
1468
  }
1364
1469
  }
@@ -1369,8 +1474,8 @@ module.exports = function (chai, _) {
1369
1474
  /**
1370
1475
  * ### .within(start, finish[, msg])
1371
1476
  *
1372
- * Asserts that the target is a number greater than or equal to the given
1373
- * number `start`, and less than or equal to the given number `finish`.
1477
+ * Asserts that the target is a number or a date greater than or equal to the given
1478
+ * number or date `start`, and less than or equal to the given number or date `finish` respectively.
1374
1479
  * However, it's often best to assert that the target is equal to its expected
1375
1480
  * value.
1376
1481
  *
@@ -1412,24 +1517,35 @@ module.exports = function (chai, _) {
1412
1517
  Assertion.addMethod('within', function (start, finish, msg) {
1413
1518
  if (msg) flag(this, 'message', msg);
1414
1519
  var obj = flag(this, 'object')
1415
- , range = start + '..' + finish
1416
1520
  , doLength = flag(this, 'doLength')
1417
1521
  , flagMsg = flag(this, 'message')
1418
- , ssfi = flag(this, 'ssfi');
1522
+ , msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
1523
+ , ssfi = flag(this, 'ssfi')
1524
+ , objType = _.type(obj).toLowerCase()
1525
+ , startType = _.type(start).toLowerCase()
1526
+ , finishType = _.type(finish).toLowerCase()
1527
+ , shouldThrow = true
1528
+ , range = (startType === 'date' && finishType === 'date')
1529
+ ? start.toUTCString() + '..' + finish.toUTCString()
1530
+ : start + '..' + finish;
1419
1531
 
1420
1532
  if (doLength) {
1421
1533
  new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
1534
+ }
1535
+
1536
+ if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {
1537
+ errorMessage = msgPrefix + 'the arguments to within must be dates';
1538
+ } else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) {
1539
+ errorMessage = msgPrefix + 'the arguments to within must be numbers';
1540
+ } else if (!doLength && (objType !== 'date' && objType !== 'number')) {
1541
+ var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
1542
+ errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
1422
1543
  } else {
1423
- new Assertion(obj, flagMsg, ssfi, true).is.a('number');
1544
+ shouldThrow = false;
1424
1545
  }
1425
1546
 
1426
- if (typeof start !== 'number' || typeof finish !== 'number') {
1427
- flagMsg = flagMsg ? flagMsg + ': ' : '';
1428
- throw new AssertionError(
1429
- flagMsg + 'the arguments to within must be numbers',
1430
- undefined,
1431
- ssfi
1432
- );
1547
+ if (shouldThrow) {
1548
+ throw new AssertionError(errorMessage, undefined, ssfi);
1433
1549
  }
1434
1550
 
1435
1551
  if (doLength) {
@@ -1493,28 +1609,25 @@ module.exports = function (chai, _) {
1493
1609
  var target = flag(this, 'object')
1494
1610
  var ssfi = flag(this, 'ssfi');
1495
1611
  var flagMsg = flag(this, 'message');
1496
- var validInstanceOfTarget = constructor === Object(constructor) && (
1497
- typeof constructor === 'function' ||
1498
- (typeof Symbol !== 'undefined' &&
1499
- typeof Symbol.hasInstance !== 'undefined' &&
1500
- Symbol.hasInstance in constructor)
1501
- );
1502
1612
 
1503
- if (!validInstanceOfTarget) {
1504
- flagMsg = flagMsg ? flagMsg + ': ' : '';
1505
- var constructorType = constructor === null ? 'null' : typeof constructor;
1506
- throw new AssertionError(
1507
- flagMsg + 'The instanceof assertion needs a constructor but ' + constructorType + ' was given.',
1508
- undefined,
1509
- ssfi
1510
- );
1613
+ try {
1614
+ var isInstanceOf = target instanceof constructor;
1615
+ } catch (err) {
1616
+ if (err instanceof TypeError) {
1617
+ flagMsg = flagMsg ? flagMsg + ': ' : '';
1618
+ throw new AssertionError(
1619
+ flagMsg + 'The instanceof assertion needs a constructor but '
1620
+ + _.type(constructor) + ' was given.',
1621
+ undefined,
1622
+ ssfi
1623
+ );
1624
+ }
1625
+ throw err;
1511
1626
  }
1512
1627
 
1513
- var isInstanceOf = target instanceof constructor
1514
-
1515
1628
  var name = _.getName(constructor);
1516
1629
  if (name === null) {
1517
- name = 'an unnamed constructor';
1630
+ name = 'an unnamed constructor';
1518
1631
  }
1519
1632
 
1520
1633
  this.assert(
@@ -1644,6 +1757,7 @@ module.exports = function (chai, _) {
1644
1757
  var isNested = flag(this, 'nested')
1645
1758
  , isOwn = flag(this, 'own')
1646
1759
  , flagMsg = flag(this, 'message')
1760
+ , obj = flag(this, 'object')
1647
1761
  , ssfi = flag(this, 'ssfi');
1648
1762
 
1649
1763
  if (isNested && isOwn) {
@@ -1655,9 +1769,17 @@ module.exports = function (chai, _) {
1655
1769
  );
1656
1770
  }
1657
1771
 
1772
+ if (obj === null || obj === undefined) {
1773
+ flagMsg = flagMsg ? flagMsg + ': ' : '';
1774
+ throw new AssertionError(
1775
+ flagMsg + 'Target cannot be null or undefined.',
1776
+ undefined,
1777
+ ssfi
1778
+ );
1779
+ }
1780
+
1658
1781
  var isDeep = flag(this, 'deep')
1659
1782
  , negate = flag(this, 'negate')
1660
- , obj = flag(this, 'object')
1661
1783
  , pathInfo = isNested ? _.getPathInfo(obj, name) : null
1662
1784
  , value = isNested ? pathInfo.value : obj[name];
1663
1785
 
@@ -1675,10 +1675,10 @@ module.exports = function (chai, util) {
1675
1675
  * You can also provide a single object instead of a `keys` array and its keys
1676
1676
  * will be used as the expected set of keys.
1677
1677
  *
1678
- * assert.hasAnyKey({foo: 1, bar: 2, baz: 3}, ['foo', 'iDontExist', 'baz']);
1679
- * assert.hasAnyKey({foo: 1, bar: 2, baz: 3}, {foo: 30, iDontExist: 99, baz: 1337]);
1680
- * assert.hasAnyKey(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'thisKeyDoesNotExist']);
1681
- * assert.hasAnyKey(new Set([{foo: 'bar'}, 'anotherKey'], [{foo: 'bar'}, 'thisKeyDoesNotExist']);
1678
+ * assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, ['foo', 'iDontExist', 'baz']);
1679
+ * assert.hasAnyKeys({foo: 1, bar: 2, baz: 3}, {foo: 30, iDontExist: 99, baz: 1337});
1680
+ * assert.hasAnyKeys(new Map([[{foo: 1}, 'bar'], ['key', 'value']]), [{foo: 1}, 'key']);
1681
+ * assert.hasAnyKeys(new Set([{foo: 'bar'}, 'anotherKey']), [{foo: 'bar'}, 'anotherKey']);
1682
1682
  *
1683
1683
  * @name hasAnyKeys
1684
1684
  * @param {Mixed} object
@@ -13,8 +13,6 @@
13
13
  *
14
14
  * @param {Mixed} obj constructed Assertion
15
15
  * @param {Array} type A list of allowed types for this assertion
16
- * @param {Function} ssfi starting point for removing implementation frames from
17
- * stack trace of AssertionError
18
16
  * @namespace Utils
19
17
  * @name expectTypes
20
18
  * @api public
@@ -24,8 +22,9 @@ var AssertionError = require('assertion-error');
24
22
  var flag = require('./flag');
25
23
  var type = require('type-detect');
26
24
 
27
- module.exports = function expectTypes(obj, types, ssfi) {
25
+ module.exports = function expectTypes(obj, types) {
28
26
  var flagMsg = flag(obj, 'message');
27
+ var ssfi = flag(obj, 'ssfi');
29
28
 
30
29
  flagMsg = flagMsg ? flagMsg + ': ' : '';
31
30
 
@@ -33,7 +32,7 @@ module.exports = function expectTypes(obj, types, ssfi) {
33
32
  types = types.map(function (t) { return t.toLowerCase(); });
34
33
  types.sort();
35
34
 
36
- // Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum'
35
+ // Transforms ['lorem', 'ipsum'] into 'a lorem, or an ipsum'
37
36
  var str = types.map(function (t, index) {
38
37
  var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a';
39
38
  var or = types.length > 1 && index === types.length - 1 ? 'or ' : '';
@@ -86,7 +86,7 @@ function formatValue(ctx, value, recurseTimes) {
86
86
  var container = document.createElementNS(ns, '_');
87
87
 
88
88
  container.appendChild(value.cloneNode(false));
89
- html = container.innerHTML
89
+ var html = container.innerHTML
90
90
  .replace('><', '>' + value.innerHTML + '<');
91
91
  container.innerHTML = '';
92
92
  return html;
package/lib/chai.js CHANGED
@@ -10,7 +10,7 @@ var used = [];
10
10
  * Chai version
11
11
  */
12
12
 
13
- exports.version = require('../package').version;
13
+ exports.version = '4.1.1';
14
14
 
15
15
  /*!
16
16
  * Assertion Error
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "Veselin Todorov <hi@vesln.com>",
18
18
  "John Firebaugh <john.firebaugh@gmail.com>"
19
19
  ],
20
- "version": "4.0.0",
20
+ "version": "4.1.1",
21
21
  "repository": {
22
22
  "type": "git",
23
23
  "url": "https://github.com/chaijs/chai"
@@ -26,7 +26,6 @@
26
26
  "url": "https://github.com/chaijs/chai/issues"
27
27
  },
28
28
  "main": "./index",
29
- "browser": "./chai.js",
30
29
  "scripts": {
31
30
  "test": "make test"
32
31
  },
@@ -42,7 +41,7 @@
42
41
  "type-detect": "^4.0.0"
43
42
  },
44
43
  "devDependencies": {
45
- "browserify": "^13.0.1",
44
+ "browserify": "^14.4.0",
46
45
  "bump-cli": "^1.1.3",
47
46
  "istanbul": "^0.4.3",
48
47
  "karma": "^1.0.0",