Skip to content

Instantly share code, notes, and snippets.

@szkrd
Last active June 27, 2016 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szkrd/48a50397ff0e777770d5f581695f5630 to your computer and use it in GitHub Desktop.
Save szkrd/48a50397ff0e777770d5f581695f5630 to your computer and use it in GitHub Desktop.
deep fuzzy equality and deep sorting
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