Skip to content

Commit

Permalink
Allow deepEqual fonction to be configured globally
Browse files Browse the repository at this point in the history
  • Loading branch information
forty committed Nov 10, 2023
1 parent 84bd1f8 commit cf3dd4a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 23 deletions.
3 changes: 3 additions & 0 deletions lib/chai/assertion.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import * as util from './utils/index.js';
* 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
Expand All @@ -52,6 +54,7 @@ export function Assertion (obj, msg, ssfi, lockSsfi) {
util.flag(this, 'lockSsfi', lockSsfi);
util.flag(this, 'object', obj);
util.flag(this, 'message', msg);
util.flag(this, 'eql', config.deepEqual ?? util.eql);

return util.proxify(this);
}
Expand Down
28 changes: 27 additions & 1 deletion lib/chai/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,31 @@ export const config = {
* @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

};
41 changes: 19 additions & 22 deletions lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,8 @@ function include (val, msg) {
, 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 + ': ' : '';

Expand All @@ -503,7 +504,6 @@ function include (val, msg) {
break;

case 'map':
var isEql = isDeep ? _.eql : SameValueZero;
obj.forEach(function (item) {
included = included || isEql(item, val);
});
Expand All @@ -512,7 +512,7 @@ function include (val, msg) {
case 'set':
if (isDeep) {
obj.forEach(function (item) {
included = included || _.eql(item, val);
included = included || isEql(item, val);
});
} else {
included = obj.has(val);
Expand All @@ -522,7 +522,7 @@ function include (val, msg) {
case 'array':
if (isDeep) {
included = obj.some(function (item) {
return _.eql(item, val);
return isEql(item, val);
})
} else {
included = obj.indexOf(val) !== -1;
Expand Down Expand Up @@ -1094,8 +1094,9 @@ Assertion.addMethod('eq', assertEqual);

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
Expand Down Expand Up @@ -1863,7 +1864,8 @@ function assertProperty (name, val, msg) {
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 ';
Expand All @@ -1890,7 +1892,7 @@ function assertProperty (name, val, msg) {

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
Expand Down Expand Up @@ -2038,9 +2040,10 @@ function assertOwnPropertyDescriptor (name, descriptor, msg) {
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
Expand Down Expand Up @@ -2394,7 +2397,8 @@ function assertKeys (keys) {
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;
Expand All @@ -2404,11 +2408,7 @@ function assertKeys (keys) {
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);
});
});
}
Expand All @@ -2417,11 +2417,7 @@ function assertKeys (keys) {
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);
});
});

Expand Down Expand Up @@ -3109,7 +3105,7 @@ Assertion.addMethod('members', function (subset, msg) {
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)
Expand Down Expand Up @@ -3165,7 +3161,8 @@ function oneOf (list, msg) {
, 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) {
Expand All @@ -3179,7 +3176,7 @@ function oneOf (list, msg) {
} 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
Expand Down
19 changes: 19 additions & 0 deletions test/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -815,4 +815,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 }");
})
})
});

0 comments on commit cf3dd4a

Please sign in to comment.