Last active
June 27, 2016 15:38
-
-
Save szkrd/48a50397ff0e777770d5f581695f5630 to your computer and use it in GitHub Desktop.
deep fuzzy equality and deep sorting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function _selectProp (obj, props) { | |
if (typeof props === 'string') { | |
return props | |
} | |
if (_.isArray(obj) && obj.length) { | |
obj = obj[0] | |
} | |
for (let i = 0, l = props.length; i < l; i++) { | |
if (_.keys(obj).indexOf(props[i]) > -1) { | |
return props[i] | |
} | |
} | |
} | |
/** | |
* deep version of _.sortBy, accepts a string for the key or | |
* an array of strings (sorts by the first available key) | |
*/ | |
function deepSort (array, properties) { | |
if (!_.isArray(array)) { | |
throw new ParameterError('array', 'deepSort', arguments, 'deepSort works with arrays') | |
} | |
_.forEach(array, (item) => { | |
_.forEach(_.keys(item), (key) => { | |
if (_.isArray(item[key])) { | |
item[key] = deepSort(item[key], properties) | |
} | |
}) | |
}) | |
return _.sortBy(array, _selectProp(array, properties)) | |
} | |
/** | |
* kinda like isEqualWith, but for certain properties it only compares | |
* their internal type, not the value itself | |
* | |
* ({id: 1}, {id: 2}, ['id']) === true | |
* ({id: 1, name: 'John'}, {id: 2, name: 'Jill'}, ['id']) === false | |
*/ | |
function deepFuzzyEqual (source, target, fuzzies) { | |
fuzzies = fuzzies || [] | |
const testTypes = (a, b) => Object.prototype.toString.call(a) === Object.prototype.toString.call(b) | |
const comparator = (objValue, otherValue, indexOrKey, obj, other, stack) => { | |
// if we're inside an object and the key is part of the fuzzy list, | |
// then just compare the types | |
if (typeof indexOrKey === 'string' && fuzzies.indexOf(indexOrKey) > -1) { | |
return testTypes(objValue, otherValue) | |
} | |
} | |
return _.isEqualWith(source, target, comparator) // though without chai readable errors it's not very helpful | |
} | |
/** | |
* Preps source and target (with clone): replaces certain | |
* values with their internal type (as a string), then | |
* compares the the two resulting objects with chai | |
* (this way we still get nice chai error messages). | |
* | |
* Example: | |
* fuzzyEql({id: 1, b: 2}, {id: 99, b: 2}, ['id']) === true | |
* fuzzyEql({id: 1, b: 2}, {id: '1', b: 2}, ['id']) === false | |
*/ | |
function fuzzyEql (source, target, keys) { | |
keys = keys || [] | |
const customizer = (objValue, indexOrKey, obj, other, stack) => { | |
if (typeof indexOrKey === 'string' && keys.indexOf(indexOrKey) > -1) { | |
return Object.prototype.toString.call(objValue) | |
} | |
} | |
const result = { | |
source: _.cloneDeepWith(source, customizer), | |
target: _.cloneDeepWith(target, customizer) | |
} | |
expect(result.source).to.eql(result.target) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment