mirror of
https://github.com/chaijs/chai
synced 2024-11-12 23:07:06 +00:00
Allow deepEqual fonction to be configured globally (#1553)
This commit is contained in:
parent
744a16e1cc
commit
fb5fd85ba1
5 changed files with 117 additions and 46 deletions
72
chai.js
72
chai.js
|
@ -150,6 +150,8 @@ module.exports = function (_chai, util) {
|
|||
* from within another assertion. It's also temporarily set to `true` before
|
||||
* an overwritten assertion gets called by the overwriting assertion.
|
||||
*
|
||||
* - `eql`: This flag contains the deepEqual function to be used by the assertion.
|
||||
*
|
||||
* @param {Mixed} obj target of the assertion
|
||||
* @param {String} msg (optional) custom error message
|
||||
* @param {Function} ssfi (optional) starting point for removing stack frames
|
||||
|
@ -162,6 +164,7 @@ module.exports = function (_chai, util) {
|
|||
flag(this, 'lockSsfi', lockSsfi);
|
||||
flag(this, 'object', obj);
|
||||
flag(this, 'message', msg);
|
||||
flag(this, 'eql', config.deepEqual ?? util.eql);
|
||||
|
||||
return util.proxify(this);
|
||||
}
|
||||
|
@ -365,7 +368,33 @@ module.exports = {
|
|||
* @api public
|
||||
*/
|
||||
|
||||
proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON']
|
||||
proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON'],
|
||||
|
||||
/**
|
||||
* ### config.deepEqual
|
||||
*
|
||||
* User configurable property, defines which a custom function to use for deepEqual
|
||||
* comparisons.
|
||||
* By default, the function used is the one from the `deep-eql` package without custom comparator.
|
||||
*
|
||||
* // use a custom comparator
|
||||
* chai.config.deepEqual = (expected, actual) => {
|
||||
* return chai.util.eql(expected, actual, {
|
||||
* comparator: (expected, actual) => {
|
||||
* // for non number comparison, use the default behavior
|
||||
* if(typeof expected !== 'number') return null;
|
||||
* // allow a difference of 10 between compared numbers
|
||||
* return typeof actual === 'number' && Math.abs(actual - expected) < 10
|
||||
* }
|
||||
* })
|
||||
* };
|
||||
*
|
||||
* @param {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
deepEqual: null
|
||||
|
||||
};
|
||||
|
||||
},{}],5:[function(require,module,exports){
|
||||
|
@ -849,7 +878,8 @@ module.exports = function (chai, _) {
|
|||
, negate = flag(this, 'negate')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : '';
|
||||
, descriptor = isDeep ? 'deep ' : ''
|
||||
, isEql = isDeep ? flag(this, 'eql') : SameValueZero;
|
||||
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
|
||||
|
@ -873,7 +903,6 @@ module.exports = function (chai, _) {
|
|||
break;
|
||||
|
||||
case 'map':
|
||||
var isEql = isDeep ? _.eql : SameValueZero;
|
||||
obj.forEach(function (item) {
|
||||
included = included || isEql(item, val);
|
||||
});
|
||||
|
@ -882,7 +911,7 @@ module.exports = function (chai, _) {
|
|||
case 'set':
|
||||
if (isDeep) {
|
||||
obj.forEach(function (item) {
|
||||
included = included || _.eql(item, val);
|
||||
included = included || isEql(item, val);
|
||||
});
|
||||
} else {
|
||||
included = obj.has(val);
|
||||
|
@ -892,7 +921,7 @@ module.exports = function (chai, _) {
|
|||
case 'array':
|
||||
if (isDeep) {
|
||||
included = obj.some(function (item) {
|
||||
return _.eql(item, val);
|
||||
return isEql(item, val);
|
||||
})
|
||||
} else {
|
||||
included = obj.indexOf(val) !== -1;
|
||||
|
@ -1464,8 +1493,9 @@ module.exports = function (chai, _) {
|
|||
|
||||
function assertEql(obj, msg) {
|
||||
if (msg) flag(this, 'message', msg);
|
||||
var eql = flag(this, 'eql');
|
||||
this.assert(
|
||||
_.eql(obj, flag(this, 'object'))
|
||||
eql(obj, flag(this, 'object'))
|
||||
, 'expected #{this} to deeply equal #{exp}'
|
||||
, 'expected #{this} to not deeply equal #{exp}'
|
||||
, obj
|
||||
|
@ -2233,7 +2263,8 @@ module.exports = function (chai, _) {
|
|||
var isDeep = flag(this, 'deep')
|
||||
, negate = flag(this, 'negate')
|
||||
, pathInfo = isNested ? _.getPathInfo(obj, name) : null
|
||||
, value = isNested ? pathInfo.value : obj[name];
|
||||
, value = isNested ? pathInfo.value : obj[name]
|
||||
, isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;;
|
||||
|
||||
var descriptor = '';
|
||||
if (isDeep) descriptor += 'deep ';
|
||||
|
@ -2260,7 +2291,7 @@ module.exports = function (chai, _) {
|
|||
|
||||
if (arguments.length > 1) {
|
||||
this.assert(
|
||||
hasProperty && (isDeep ? _.eql(val, value) : val === value)
|
||||
hasProperty && isEql(val, value)
|
||||
, 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
|
||||
, 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}'
|
||||
, val
|
||||
|
@ -2408,9 +2439,10 @@ module.exports = function (chai, _) {
|
|||
if (msg) flag(this, 'message', msg);
|
||||
var obj = flag(this, 'object');
|
||||
var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
|
||||
var eql = flag(this, 'eql');
|
||||
if (actualDescriptor && descriptor) {
|
||||
this.assert(
|
||||
_.eql(descriptor, actualDescriptor)
|
||||
eql(descriptor, actualDescriptor)
|
||||
, 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)
|
||||
, 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)
|
||||
, descriptor
|
||||
|
@ -2764,7 +2796,8 @@ module.exports = function (chai, _) {
|
|||
var len = keys.length
|
||||
, any = flag(this, 'any')
|
||||
, all = flag(this, 'all')
|
||||
, expected = keys;
|
||||
, expected = keys
|
||||
, isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
|
||||
|
||||
if (!any && !all) {
|
||||
all = true;
|
||||
|
@ -2774,11 +2807,7 @@ module.exports = function (chai, _) {
|
|||
if (any) {
|
||||
ok = expected.some(function(expectedKey) {
|
||||
return actual.some(function(actualKey) {
|
||||
if (isDeep) {
|
||||
return _.eql(expectedKey, actualKey);
|
||||
} else {
|
||||
return expectedKey === actualKey;
|
||||
}
|
||||
return isEql(expectedKey, actualKey);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2787,11 +2816,7 @@ module.exports = function (chai, _) {
|
|||
if (all) {
|
||||
ok = expected.every(function(expectedKey) {
|
||||
return actual.some(function(actualKey) {
|
||||
if (isDeep) {
|
||||
return _.eql(expectedKey, actualKey);
|
||||
} else {
|
||||
return expectedKey === actualKey;
|
||||
}
|
||||
return isEql(expectedKey, actualKey);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3479,7 +3504,7 @@ module.exports = function (chai, _) {
|
|||
failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}';
|
||||
}
|
||||
|
||||
var cmp = flag(this, 'deep') ? _.eql : undefined;
|
||||
var cmp = flag(this, 'deep') ? flag(this, 'eql') : undefined;
|
||||
|
||||
this.assert(
|
||||
isSubsetOf(subset, obj, cmp, contains, ordered)
|
||||
|
@ -3535,7 +3560,8 @@ module.exports = function (chai, _) {
|
|||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, contains = flag(this, 'contains')
|
||||
, isDeep = flag(this, 'deep');
|
||||
, isDeep = flag(this, 'deep')
|
||||
, eql = flag(this, 'eql');
|
||||
new Assertion(list, flagMsg, ssfi, true).to.be.an('array');
|
||||
|
||||
if (contains) {
|
||||
|
@ -3549,7 +3575,7 @@ module.exports = function (chai, _) {
|
|||
} else {
|
||||
if (isDeep) {
|
||||
this.assert(
|
||||
list.some(function(possibility) { return _.eql(expected, possibility) })
|
||||
list.some(function(possibility) { return eql(expected, possibility) })
|
||||
, 'expected #{this} to deeply equal one of #{exp}'
|
||||
, 'expected #{this} to deeply equal one of #{exp}'
|
||||
, list
|
||||
|
|
|
@ -52,6 +52,8 @@ module.exports = function (_chai, util) {
|
|||
* from within another assertion. It's also temporarily set to `true` before
|
||||
* an overwritten assertion gets called by the overwriting assertion.
|
||||
*
|
||||
* - `eql`: This flag contains the deepEqual function to be used by the assertion.
|
||||
*
|
||||
* @param {Mixed} obj target of the assertion
|
||||
* @param {String} msg (optional) custom error message
|
||||
* @param {Function} ssfi (optional) starting point for removing stack frames
|
||||
|
@ -64,6 +66,7 @@ module.exports = function (_chai, util) {
|
|||
flag(this, 'lockSsfi', lockSsfi);
|
||||
flag(this, 'object', obj);
|
||||
flag(this, 'message', msg);
|
||||
flag(this, 'eql', config.deepEqual ?? util.eql);
|
||||
|
||||
return util.proxify(this);
|
||||
}
|
||||
|
|
|
@ -90,5 +90,31 @@ module.exports = {
|
|||
* @api public
|
||||
*/
|
||||
|
||||
proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON']
|
||||
proxyExcludedKeys: ['then', 'catch', 'inspect', 'toJSON'],
|
||||
|
||||
/**
|
||||
* ### config.deepEqual
|
||||
*
|
||||
* User configurable property, defines which a custom function to use for deepEqual
|
||||
* comparisons.
|
||||
* By default, the function used is the one from the `deep-eql` package without custom comparator.
|
||||
*
|
||||
* // use a custom comparator
|
||||
* chai.config.deepEqual = (expected, actual) => {
|
||||
* return chai.util.eql(expected, actual, {
|
||||
* comparator: (expected, actual) => {
|
||||
* // for non number comparison, use the default behavior
|
||||
* if(typeof expected !== 'number') return null;
|
||||
* // allow a difference of 10 between compared numbers
|
||||
* return typeof actual === 'number' && Math.abs(actual - expected) < 10
|
||||
* }
|
||||
* })
|
||||
* };
|
||||
*
|
||||
* @param {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
deepEqual: null
|
||||
|
||||
};
|
||||
|
|
|
@ -478,7 +478,8 @@ module.exports = function (chai, _) {
|
|||
, negate = flag(this, 'negate')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : '';
|
||||
, descriptor = isDeep ? 'deep ' : ''
|
||||
, isEql = isDeep ? flag(this, 'eql') : SameValueZero;
|
||||
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
|
||||
|
@ -502,7 +503,6 @@ module.exports = function (chai, _) {
|
|||
break;
|
||||
|
||||
case 'map':
|
||||
var isEql = isDeep ? _.eql : SameValueZero;
|
||||
obj.forEach(function (item) {
|
||||
included = included || isEql(item, val);
|
||||
});
|
||||
|
@ -511,7 +511,7 @@ module.exports = function (chai, _) {
|
|||
case 'set':
|
||||
if (isDeep) {
|
||||
obj.forEach(function (item) {
|
||||
included = included || _.eql(item, val);
|
||||
included = included || isEql(item, val);
|
||||
});
|
||||
} else {
|
||||
included = obj.has(val);
|
||||
|
@ -521,7 +521,7 @@ module.exports = function (chai, _) {
|
|||
case 'array':
|
||||
if (isDeep) {
|
||||
included = obj.some(function (item) {
|
||||
return _.eql(item, val);
|
||||
return isEql(item, val);
|
||||
})
|
||||
} else {
|
||||
included = obj.indexOf(val) !== -1;
|
||||
|
@ -1093,8 +1093,9 @@ module.exports = function (chai, _) {
|
|||
|
||||
function assertEql(obj, msg) {
|
||||
if (msg) flag(this, 'message', msg);
|
||||
var eql = flag(this, 'eql');
|
||||
this.assert(
|
||||
_.eql(obj, flag(this, 'object'))
|
||||
eql(obj, flag(this, 'object'))
|
||||
, 'expected #{this} to deeply equal #{exp}'
|
||||
, 'expected #{this} to not deeply equal #{exp}'
|
||||
, obj
|
||||
|
@ -1862,7 +1863,8 @@ module.exports = function (chai, _) {
|
|||
var isDeep = flag(this, 'deep')
|
||||
, negate = flag(this, 'negate')
|
||||
, pathInfo = isNested ? _.getPathInfo(obj, name) : null
|
||||
, value = isNested ? pathInfo.value : obj[name];
|
||||
, value = isNested ? pathInfo.value : obj[name]
|
||||
, isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;;
|
||||
|
||||
var descriptor = '';
|
||||
if (isDeep) descriptor += 'deep ';
|
||||
|
@ -1889,7 +1891,7 @@ module.exports = function (chai, _) {
|
|||
|
||||
if (arguments.length > 1) {
|
||||
this.assert(
|
||||
hasProperty && (isDeep ? _.eql(val, value) : val === value)
|
||||
hasProperty && isEql(val, value)
|
||||
, 'expected #{this} to have ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
|
||||
, 'expected #{this} to not have ' + descriptor + _.inspect(name) + ' of #{act}'
|
||||
, val
|
||||
|
@ -2037,9 +2039,10 @@ module.exports = function (chai, _) {
|
|||
if (msg) flag(this, 'message', msg);
|
||||
var obj = flag(this, 'object');
|
||||
var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name);
|
||||
var eql = flag(this, 'eql');
|
||||
if (actualDescriptor && descriptor) {
|
||||
this.assert(
|
||||
_.eql(descriptor, actualDescriptor)
|
||||
eql(descriptor, actualDescriptor)
|
||||
, 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor)
|
||||
, 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor)
|
||||
, descriptor
|
||||
|
@ -2393,7 +2396,8 @@ module.exports = function (chai, _) {
|
|||
var len = keys.length
|
||||
, any = flag(this, 'any')
|
||||
, all = flag(this, 'all')
|
||||
, expected = keys;
|
||||
, expected = keys
|
||||
, isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2;
|
||||
|
||||
if (!any && !all) {
|
||||
all = true;
|
||||
|
@ -2403,11 +2407,7 @@ module.exports = function (chai, _) {
|
|||
if (any) {
|
||||
ok = expected.some(function(expectedKey) {
|
||||
return actual.some(function(actualKey) {
|
||||
if (isDeep) {
|
||||
return _.eql(expectedKey, actualKey);
|
||||
} else {
|
||||
return expectedKey === actualKey;
|
||||
}
|
||||
return isEql(expectedKey, actualKey);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2416,11 +2416,7 @@ module.exports = function (chai, _) {
|
|||
if (all) {
|
||||
ok = expected.every(function(expectedKey) {
|
||||
return actual.some(function(actualKey) {
|
||||
if (isDeep) {
|
||||
return _.eql(expectedKey, actualKey);
|
||||
} else {
|
||||
return expectedKey === actualKey;
|
||||
}
|
||||
return isEql(expectedKey, actualKey);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3108,7 +3104,7 @@ module.exports = function (chai, _) {
|
|||
failNegateMsg = 'expected #{this} to not have the same ' + subject + ' as #{exp}';
|
||||
}
|
||||
|
||||
var cmp = flag(this, 'deep') ? _.eql : undefined;
|
||||
var cmp = flag(this, 'deep') ? flag(this, 'eql') : undefined;
|
||||
|
||||
this.assert(
|
||||
isSubsetOf(subset, obj, cmp, contains, ordered)
|
||||
|
@ -3164,7 +3160,8 @@ module.exports = function (chai, _) {
|
|||
, flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi')
|
||||
, contains = flag(this, 'contains')
|
||||
, isDeep = flag(this, 'deep');
|
||||
, isDeep = flag(this, 'deep')
|
||||
, eql = flag(this, 'eql');
|
||||
new Assertion(list, flagMsg, ssfi, true).to.be.an('array');
|
||||
|
||||
if (contains) {
|
||||
|
@ -3178,7 +3175,7 @@ module.exports = function (chai, _) {
|
|||
} else {
|
||||
if (isDeep) {
|
||||
this.assert(
|
||||
list.some(function(possibility) { return _.eql(expected, possibility) })
|
||||
list.some(function(possibility) { return eql(expected, possibility) })
|
||||
, 'expected #{this} to deeply equal one of #{exp}'
|
||||
, 'expected #{this} to deeply equal one of #{exp}'
|
||||
, list
|
||||
|
|
|
@ -810,4 +810,23 @@ describe('configuration', function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('deepEqual', function() {
|
||||
it('should use custom deepEqual function for deepEqual comparison', function(){
|
||||
chai.config.deepEqual = (expected, actual) => {
|
||||
return chai.util.eql(expected, actual, {
|
||||
comparator: (expected, actual) => {
|
||||
// for non number comparison, use the default behavior
|
||||
if(typeof expected !== 'number') return null;
|
||||
// allow a difference of 10 between compared numbers
|
||||
return typeof actual === 'number' && Math.abs(actual - expected) < 10
|
||||
}
|
||||
})
|
||||
};
|
||||
assert.deepEqual({v: 1}, {v: 10});
|
||||
err(function() {
|
||||
assert.deepEqual({v: 1}, {v: 100});
|
||||
}, "expected { v: 1 } to deeply equal { v: 100 }");
|
||||
})
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue