Skip to content

Instantly share code, notes, and snippets.

@davidnormo
Last active September 1, 2017 11:18
Show Gist options
  • Save davidnormo/77918a46d40c4008de33 to your computer and use it in GitHub Desktop.
Save davidnormo/77918a46d40c4008de33 to your computer and use it in GitHub Desktop.
Deep equality jasmine 2.3 matcher
"use strict";
var observableDiff = require("deep-diff").observableDiff,
lodash = require("lodash");
function valueToString(target) {
return JSON.stringify(target, function(key, value) {
var type = Object.prototype.toString.call(value);
if (value instanceof jasmine.Any) {
return value.jasmineToString();
} if (/Function/.test(type)) {
return "Function";
}
return value;
}, 4);
}
function jasmineAnyInPath(actual, expected, path) {
var accumulatedPath = [],
expectedValue,
actualValue;
return lodash.some(path, function(step) {
accumulatedPath.push(step);
expectedValue = lodash.get(expected, accumulatedPath);
if (expectedValue instanceof jasmine.Any) {
actualValue = lodash.get(actual, accumulatedPath);
return expectedValue.asymmetricMatch(actualValue);
}
});
}
/**
* Assert two objects are deep equal
* @param {Object} expected
* @return {Boolean}
*/
var deepCompare = function(actual, expected) {
var result = [],
getPath,
getErrorMessage,
messages;
/**
* Return the string representation of an object path
* @param {Array} path
* @return {String}
*/
getPath = function(path) {
return lodash.reduce(path, function(path, next) {
if (typeof next === "number") {
path += "[" + next + "]";
} else if (path) {
path += "." + next;
} else {
path = next;
}
return path;
}, "");
};
getErrorMessage = function(error) {
switch (error.kind) {
// Indicates a newly added property/element
case "N":
return "Property has been added: " +
getPath(error.path) +
" (New value: " + valueToString(error.rhs) + ")";
// Indicates a property/element was deleted
case "D":
return "Property has been deleted: " +
getPath(error.path) +
" (Actual value: " + valueToString(error.lhs) + ")";
// Indicates a property/element was edited
case "E":
return "Property has been edited: " +
getPath(error.path) +
"\n\tActual:\t\t" + valueToString(error.lhs) +
"\n\tExpected:\t" + valueToString(error.rhs) + "\n";
// Indicates a change occurred within an array
case "A":
var path = error.path || [];
path.push(error.index);
path = getPath(path) + " (" + getErrorMessage(error.item) + ")";
return "Array has been changed: (path: " + path + ")";
}
};
observableDiff(actual, expected, function(diff) {
if (diff.kind === "E" && diff.rhs instanceof jasmine.Any) {
if (!diff.rhs.asymmetricMatch(diff.lhs)) {
result.push(diff);
}
} else if (!jasmineAnyInPath(actual, expected, diff.path)) {
result.push(diff);
}
});
if (result.length === 0) {
return true;
}
// Loop through errors
messages = lodash.map(result, getErrorMessage);
return messages.join("\n");
};
module.exports = {
"toDeepEqual": function() {
return {
"compare": function(actual, expected) {
var result = deepCompare(actual, expected);
if (result === true) {
return {
"pass": true
};
}
return {
"pass": false,
"message": "\n" + result
};
}
};
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment