mirror of
https://github.com/chaijs/chai
synced 2024-11-14 15:57:10 +00:00
commit
df9073cb8e
3 changed files with 205 additions and 89 deletions
290
chai.js
290
chai.js
|
@ -14,7 +14,7 @@ var used = [];
|
|||
* Chai version
|
||||
*/
|
||||
|
||||
exports.version = '4.0.2';
|
||||
exports.version = '4.1.0';
|
||||
|
||||
/*!
|
||||
* Assertion Error
|
||||
|
@ -691,6 +691,16 @@ module.exports = function (chai, _) {
|
|||
*
|
||||
* expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2});
|
||||
*
|
||||
* When the target is a Set or WeakSet, `.include` asserts that the given `val` is a
|
||||
* member of the target. SameValueZero equality algorithm is used.
|
||||
*
|
||||
* expect(new Set([1, 2])).to.include(2);
|
||||
*
|
||||
* When the target is a Map, `.include` asserts that the given `val` is one of
|
||||
* the values of the target. SameValueZero equality algorithm is used.
|
||||
*
|
||||
* expect(new Map([['a', 1], ['b', 2]])).to.include(2);
|
||||
*
|
||||
* Because `.include` does different things based on the target's type, it's
|
||||
* important to check the target's type before using `.include`. See the `.a`
|
||||
* doc for info on testing a target's type.
|
||||
|
@ -699,8 +709,8 @@ module.exports = function (chai, _) {
|
|||
*
|
||||
* By default, strict (`===`) equality is used to compare array members and
|
||||
* object properties. Add `.deep` earlier in the chain to use deep equality
|
||||
* instead. See the `deep-eql` project page for info on the deep equality
|
||||
* algorithm: https://github.com/chaijs/deep-eql.
|
||||
* instead (WeakSet targets are not supported). See the `deep-eql` project
|
||||
* page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql.
|
||||
*
|
||||
* // Target array deeply (but not strictly) includes `{a: 1}`
|
||||
* expect([{a: 1}]).to.deep.include({a: 1});
|
||||
|
@ -810,25 +820,24 @@ module.exports = function (chai, _) {
|
|||
* @api public
|
||||
*/
|
||||
|
||||
function includeChainingBehavior () {
|
||||
flag(this, 'contains', true);
|
||||
function SameValueZero(a, b) {
|
||||
return (_.isNaN(a) && _.isNaN(b)) || a === b;
|
||||
}
|
||||
|
||||
function isDeepIncluded (arr, val) {
|
||||
return arr.some(function (arrVal) {
|
||||
return _.eql(arrVal, val);
|
||||
});
|
||||
function includeChainingBehavior () {
|
||||
flag(this, 'contains', true);
|
||||
}
|
||||
|
||||
function include (val, msg) {
|
||||
if (msg) flag(this, 'message', msg);
|
||||
|
||||
_.expectTypes(this, ['array', 'object', 'string'], flag(this, 'ssfi'));
|
||||
_.expectTypes(this, [
|
||||
'array', 'object', 'string',
|
||||
'map', 'set', 'weakset',
|
||||
]);
|
||||
|
||||
var obj = flag(this, 'object')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : '';
|
||||
, objType = _.type(obj).toLowerCase();
|
||||
|
||||
// This block is for asserting a subset of properties in an object.
|
||||
if (objType === 'object') {
|
||||
|
@ -865,10 +874,62 @@ module.exports = function (chai, _) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Assert inclusion in an array or substring in a string.
|
||||
var isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : ''
|
||||
, included = false;
|
||||
|
||||
switch (objType) {
|
||||
case 'string':
|
||||
included = obj.indexOf(val) !== -1;
|
||||
break;
|
||||
|
||||
case 'weakset':
|
||||
if (isDeep) {
|
||||
var flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
|
||||
throw new AssertionError(
|
||||
flagMsg + 'unable to use .deep.include with WeakSet',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
}
|
||||
|
||||
included = obj.has(val);
|
||||
break;
|
||||
|
||||
case 'map':
|
||||
var isEql = isDeep ? _.eql : SameValueZero;
|
||||
obj.forEach(function (item) {
|
||||
included = included || isEql(item, val);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
if (isDeep) {
|
||||
obj.forEach(function (item) {
|
||||
included = included || _.eql(item, val);
|
||||
});
|
||||
} else {
|
||||
included = obj.has(val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'array':
|
||||
if (isDeep) {
|
||||
included = obj.some(function (item) {
|
||||
return _.eql(item, val);
|
||||
})
|
||||
} else {
|
||||
included = obj.indexOf(val) !== -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Assert inclusion in collection or substring in a string.
|
||||
this.assert(
|
||||
objType === 'string' || !isDeep ? ~obj.indexOf(val)
|
||||
: isDeepIncluded(obj, val)
|
||||
included
|
||||
, 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
|
||||
, 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
|
||||
}
|
||||
|
@ -1385,7 +1446,7 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .above(n[, msg])
|
||||
*
|
||||
* Asserts that the target is a number greater than the given number `n`.
|
||||
* Asserts that the target is a number or a date greater than the given number or date `n` respectively.
|
||||
* However, it's often best to assert that the target is equal to its expected
|
||||
* value.
|
||||
*
|
||||
|
@ -1430,21 +1491,29 @@ module.exports = function (chai, _) {
|
|||
var obj = flag(this, 'object')
|
||||
, doLength = flag(this, 'doLength')
|
||||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, nType = _.type(n).toLowerCase()
|
||||
, shouldThrow = true;
|
||||
|
||||
if (doLength) {
|
||||
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
||||
}
|
||||
|
||||
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
||||
errorMessage = msgPrefix + 'the argument to above must be a date';
|
||||
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
||||
errorMessage = msgPrefix + 'the argument to above must be a number';
|
||||
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
||||
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
||||
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
||||
} else {
|
||||
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
|
||||
shouldThrow = false;
|
||||
}
|
||||
|
||||
if (typeof n !== 'number') {
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
throw new AssertionError(
|
||||
flagMsg + 'the argument to above must be a number',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
if (shouldThrow) {
|
||||
throw new AssertionError(errorMessage, undefined, ssfi);
|
||||
}
|
||||
|
||||
if (doLength) {
|
||||
|
@ -1459,8 +1528,9 @@ module.exports = function (chai, _) {
|
|||
} else {
|
||||
this.assert(
|
||||
obj > n
|
||||
, 'expected #{this} to be above ' + n
|
||||
, 'expected #{this} to be at most ' + n
|
||||
, 'expected #{this} to be above #{exp}'
|
||||
, 'expected #{this} to be at most #{exp}'
|
||||
, n
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1472,8 +1542,8 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .least(n[, msg])
|
||||
*
|
||||
* Asserts that the target is a number greater than or equal to the given
|
||||
* number `n`. However, it's often best to assert that the target is equal to
|
||||
* Asserts that the target is a number or a date greater than or equal to the given
|
||||
* number or date `n` respectively. However, it's often best to assert that the target is equal to
|
||||
* its expected value.
|
||||
*
|
||||
* expect(2).to.equal(2); // Recommended
|
||||
|
@ -1517,21 +1587,29 @@ module.exports = function (chai, _) {
|
|||
var obj = flag(this, 'object')
|
||||
, doLength = flag(this, 'doLength')
|
||||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, nType = _.type(n).toLowerCase()
|
||||
, shouldThrow = true;
|
||||
|
||||
if (doLength) {
|
||||
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
||||
} else {
|
||||
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
|
||||
}
|
||||
|
||||
if (typeof n !== 'number') {
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
throw new AssertionError(
|
||||
flagMsg + 'the argument to least must be a number',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
||||
errorMessage = msgPrefix + 'the argument to least must be a date';
|
||||
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
||||
errorMessage = msgPrefix + 'the argument to least must be a number';
|
||||
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
||||
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
||||
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
||||
} else {
|
||||
shouldThrow = false;
|
||||
}
|
||||
|
||||
if (shouldThrow) {
|
||||
throw new AssertionError(errorMessage, undefined, ssfi);
|
||||
}
|
||||
|
||||
if (doLength) {
|
||||
|
@ -1546,8 +1624,9 @@ module.exports = function (chai, _) {
|
|||
} else {
|
||||
this.assert(
|
||||
obj >= n
|
||||
, 'expected #{this} to be at least ' + n
|
||||
, 'expected #{this} to be below ' + n
|
||||
, 'expected #{this} to be at least #{exp}'
|
||||
, 'expected #{this} to be below #{exp}'
|
||||
, n
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1558,7 +1637,7 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .below(n[, msg])
|
||||
*
|
||||
* Asserts that the target is a number less than the given number `n`.
|
||||
* Asserts that the target is a number or a date less than the given number or date `n` respectively.
|
||||
* However, it's often best to assert that the target is equal to its expected
|
||||
* value.
|
||||
*
|
||||
|
@ -1603,21 +1682,29 @@ module.exports = function (chai, _) {
|
|||
var obj = flag(this, 'object')
|
||||
, doLength = flag(this, 'doLength')
|
||||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, nType = _.type(n).toLowerCase()
|
||||
, shouldThrow = true;
|
||||
|
||||
if (doLength) {
|
||||
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
||||
} else {
|
||||
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
|
||||
}
|
||||
|
||||
if (typeof n !== 'number') {
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
throw new AssertionError(
|
||||
flagMsg + 'the argument to below must be a number',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
||||
errorMessage = msgPrefix + 'the argument to below must be a date';
|
||||
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
||||
errorMessage = msgPrefix + 'the argument to below must be a number';
|
||||
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
||||
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
||||
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
||||
} else {
|
||||
shouldThrow = false;
|
||||
}
|
||||
|
||||
if (shouldThrow) {
|
||||
throw new AssertionError(errorMessage, undefined, ssfi);
|
||||
}
|
||||
|
||||
if (doLength) {
|
||||
|
@ -1632,8 +1719,9 @@ module.exports = function (chai, _) {
|
|||
} else {
|
||||
this.assert(
|
||||
obj < n
|
||||
, 'expected #{this} to be below ' + n
|
||||
, 'expected #{this} to be at least ' + n
|
||||
, 'expected #{this} to be below #{exp}'
|
||||
, 'expected #{this} to be at least #{exp}'
|
||||
, n
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1645,8 +1733,8 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .most(n[, msg])
|
||||
*
|
||||
* Asserts that the target is a number less than or equal to the given number
|
||||
* `n`. However, it's often best to assert that the target is equal to its
|
||||
* Asserts that the target is a number or a date less than or equal to the given number
|
||||
* or date `n` respectively. However, it's often best to assert that the target is equal to its
|
||||
* expected value.
|
||||
*
|
||||
* expect(1).to.equal(1); // Recommended
|
||||
|
@ -1689,21 +1777,29 @@ module.exports = function (chai, _) {
|
|||
var obj = flag(this, 'object')
|
||||
, doLength = flag(this, 'doLength')
|
||||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, nType = _.type(n).toLowerCase()
|
||||
, shouldThrow = true;
|
||||
|
||||
if (doLength) {
|
||||
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
||||
}
|
||||
|
||||
if (!doLength && (objType === 'date' && nType !== 'date')) {
|
||||
errorMessage = msgPrefix + 'the argument to most must be a date';
|
||||
} else if (nType !== 'number' && (doLength || objType === 'number')) {
|
||||
errorMessage = msgPrefix + 'the argument to most must be a number';
|
||||
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
||||
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
||||
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
||||
} else {
|
||||
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
|
||||
shouldThrow = false;
|
||||
}
|
||||
|
||||
if (typeof n !== 'number') {
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
throw new AssertionError(
|
||||
flagMsg + 'the argument to most must be a number',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
if (shouldThrow) {
|
||||
throw new AssertionError(errorMessage, undefined, ssfi);
|
||||
}
|
||||
|
||||
if (doLength) {
|
||||
|
@ -1718,8 +1814,9 @@ module.exports = function (chai, _) {
|
|||
} else {
|
||||
this.assert(
|
||||
obj <= n
|
||||
, 'expected #{this} to be at most ' + n
|
||||
, 'expected #{this} to be above ' + n
|
||||
, 'expected #{this} to be at most #{exp}'
|
||||
, 'expected #{this} to be above #{exp}'
|
||||
, n
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1730,8 +1827,8 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .within(start, finish[, msg])
|
||||
*
|
||||
* Asserts that the target is a number greater than or equal to the given
|
||||
* number `start`, and less than or equal to the given number `finish`.
|
||||
* Asserts that the target is a number or a date greater than or equal to the given
|
||||
* number or date `start`, and less than or equal to the given number or date `finish` respectively.
|
||||
* However, it's often best to assert that the target is equal to its expected
|
||||
* value.
|
||||
*
|
||||
|
@ -1773,24 +1870,35 @@ module.exports = function (chai, _) {
|
|||
Assertion.addMethod('within', function (start, finish, msg) {
|
||||
if (msg) flag(this, 'message', msg);
|
||||
var obj = flag(this, 'object')
|
||||
, range = start + '..' + finish
|
||||
, doLength = flag(this, 'doLength')
|
||||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
, msgPrefix = ((flagMsg) ? flagMsg + ': ' : '')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, startType = _.type(start).toLowerCase()
|
||||
, finishType = _.type(finish).toLowerCase()
|
||||
, shouldThrow = true
|
||||
, range = (startType === 'date' && finishType === 'date')
|
||||
? start.toUTCString() + '..' + finish.toUTCString()
|
||||
: start + '..' + finish;
|
||||
|
||||
if (doLength) {
|
||||
new Assertion(obj, flagMsg, ssfi, true).to.have.property('length');
|
||||
} else {
|
||||
new Assertion(obj, flagMsg, ssfi, true).is.a('number');
|
||||
}
|
||||
|
||||
if (typeof start !== 'number' || typeof finish !== 'number') {
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
throw new AssertionError(
|
||||
flagMsg + 'the arguments to within must be numbers',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
if (!doLength && (objType === 'date' && (startType !== 'date' || finishType !== 'date'))) {
|
||||
errorMessage = msgPrefix + 'the arguments to within must be dates';
|
||||
} else if ((startType !== 'number' || finishType !== 'number') && (doLength || objType === 'number')) {
|
||||
errorMessage = msgPrefix + 'the arguments to within must be numbers';
|
||||
} else if (!doLength && (objType !== 'date' && objType !== 'number')) {
|
||||
var printObj = (objType === 'string') ? "'" + obj + "'" : obj;
|
||||
errorMessage = msgPrefix + 'expected ' + printObj + ' to be a number or a date';
|
||||
} else {
|
||||
shouldThrow = false;
|
||||
}
|
||||
|
||||
if (shouldThrow) {
|
||||
throw new AssertionError(errorMessage, undefined, ssfi);
|
||||
}
|
||||
|
||||
if (doLength) {
|
||||
|
@ -2005,6 +2113,7 @@ module.exports = function (chai, _) {
|
|||
var isNested = flag(this, 'nested')
|
||||
, isOwn = flag(this, 'own')
|
||||
, flagMsg = flag(this, 'message')
|
||||
, obj = flag(this, 'object')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
|
||||
if (isNested && isOwn) {
|
||||
|
@ -2016,9 +2125,17 @@ module.exports = function (chai, _) {
|
|||
);
|
||||
}
|
||||
|
||||
if (obj === null || obj === undefined) {
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
throw new AssertionError(
|
||||
flagMsg + 'Target cannot be null or undefined.',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
}
|
||||
|
||||
var isDeep = flag(this, 'deep')
|
||||
, negate = flag(this, 'negate')
|
||||
, obj = flag(this, 'object')
|
||||
, pathInfo = isNested ? _.getPathInfo(obj, name) : null
|
||||
, value = isNested ? pathInfo.value : obj[name];
|
||||
|
||||
|
@ -7720,8 +7837,6 @@ module.exports = function compareByInspect(a, b) {
|
|||
*
|
||||
* @param {Mixed} obj constructed Assertion
|
||||
* @param {Array} type A list of allowed types for this assertion
|
||||
* @param {Function} ssfi starting point for removing implementation frames from
|
||||
* stack trace of AssertionError
|
||||
* @namespace Utils
|
||||
* @name expectTypes
|
||||
* @api public
|
||||
|
@ -7731,8 +7846,9 @@ var AssertionError = require('assertion-error');
|
|||
var flag = require('./flag');
|
||||
var type = require('type-detect');
|
||||
|
||||
module.exports = function expectTypes(obj, types, ssfi) {
|
||||
module.exports = function expectTypes(obj, types) {
|
||||
var flagMsg = flag(obj, 'message');
|
||||
var ssfi = flag(obj, 'ssfi');
|
||||
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
|
||||
|
@ -7740,7 +7856,7 @@ module.exports = function expectTypes(obj, types, ssfi) {
|
|||
types = types.map(function (t) { return t.toLowerCase(); });
|
||||
types.sort();
|
||||
|
||||
// Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum'
|
||||
// Transforms ['lorem', 'ipsum'] into 'a lorem, or an ipsum'
|
||||
var str = types.map(function (t, index) {
|
||||
var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a';
|
||||
var or = types.length > 1 && index === types.length - 1 ? 'or ' : '';
|
||||
|
@ -8257,7 +8373,7 @@ function formatValue(ctx, value, recurseTimes) {
|
|||
var container = document.createElementNS(ns, '_');
|
||||
|
||||
container.appendChild(value.cloneNode(false));
|
||||
html = container.innerHTML
|
||||
var html = container.innerHTML
|
||||
.replace('><', '>' + value.innerHTML + '<');
|
||||
container.innerHTML = '';
|
||||
return html;
|
||||
|
|
|
@ -10,7 +10,7 @@ var used = [];
|
|||
* Chai version
|
||||
*/
|
||||
|
||||
exports.version = '4.0.2';
|
||||
exports.version = '4.1.0';
|
||||
|
||||
/*!
|
||||
* Assertion Error
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"Veselin Todorov <hi@vesln.com>",
|
||||
"John Firebaugh <john.firebaugh@gmail.com>"
|
||||
],
|
||||
"version": "4.0.2",
|
||||
"version": "4.1.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chaijs/chai"
|
||||
|
|
Loading…
Reference in a new issue