Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow deepEqual fonction to be configured globally #1551

Merged
merged 1 commit into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 }");
})
})
});