@aws-solutions-constructs/core
Version:
Core CDK Construct for patterns library
760 lines (623 loc) • 22.5 kB
JavaScript
(function (root, factory) {
if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef
define(['deep-diff', 'expect.js'], factory);// eslint-disable-line no-undef
} else if (typeof module === 'object' && module.exports) {
module.exports = factory(require('../'), require('expect.js'));
} else {
root.returnExports = factory(root.DeepDiff, root.expect);
}
// eslint-disable-next-line no-undef
}(typeof self !== 'undefined' ? self : this, function (deep, expect) {
describe('deep-diff', function () {
var empty = {};
describe('A target that has no properties', function () {
it('shows no differences when compared to another empty object', function () {
expect(deep.diff(empty, {})).to.be.an('undefined');
});
describe('when compared to a different type of keyless object', function () {
var comparandTuples = [
['an array', {
key: []
}],
['an object', {
key: {}
}],
['a date', {
key: new Date()
}],
['a null', {
key: null
}],
['a regexp literal', {
key: /a/
}],
['Math', {
key: Math
}]
];
comparandTuples.forEach(function (lhsTuple) {
comparandTuples.forEach(function (rhsTuple) {
if (lhsTuple[0] === rhsTuple[0]) {
return;
}
it('shows differences when comparing ' + lhsTuple[0] + ' to ' + rhsTuple[0], function () {
var diff = deep.diff(lhsTuple[1], rhsTuple[1]);
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
});
});
});
describe('when compared with an object having other properties', function () {
var comparand = {
other: 'property',
another: 13.13
};
var diff = deep.diff(empty, comparand);
it('the differences are reported', function () {
expect(diff).to.be.ok();
expect(diff.length).to.be(2);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('N');
expect(diff[0]).to.have.property('path');
expect(diff[0].path).to.be.an(Array);
expect(diff[0].path[0]).to.eql('other');
expect(diff[0]).to.have.property('rhs');
expect(diff[0].rhs).to.be('property');
expect(diff[1]).to.have.property('kind');
expect(diff[1].kind).to.be('N');
expect(diff[1]).to.have.property('path');
expect(diff[1].path).to.be.an(Array);
expect(diff[1].path[0]).to.eql('another');
expect(diff[1]).to.have.property('rhs');
expect(diff[1].rhs).to.be(13.13);
});
});
});
describe('A target that has one property', function () {
var lhs = {
one: 'property'
};
it('shows no differences when compared to itself', function () {
expect(deep.diff(lhs, lhs)).to.be.an('undefined');
});
it('shows the property as removed when compared to an empty object', function () {
var diff = deep.diff(lhs, empty);
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('D');
});
it('shows the property as edited when compared to an object with null', function () {
var diff = deep.diff(lhs, {
one: null
});
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
it('shows the property as edited when compared to an array', function () {
var diff = deep.diff(lhs, ['one']);
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
});
describe('A target that has null value', function () {
var lhs = {
key: null
};
it('shows no differences when compared to itself', function () {
expect(deep.diff(lhs, lhs)).to.be.an('undefined');
});
it('shows the property as removed when compared to an empty object', function () {
var diff = deep.diff(lhs, empty);
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('D');
});
it('shows the property is changed when compared to an object that has value', function () {
var diff = deep.diff(lhs, {
key: 'value'
});
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
it('shows that an object property is changed when it is set to null', function () {
lhs.key = {
nested: 'value'
};
var diff = deep.diff(lhs, {
key: null
});
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
});
describe('A target that has a date value', function () {
var lhs = {
key: new Date(555555555555)
};
it('shows the property is changed with a new date value', function () {
var diff = deep.diff(lhs, {
key: new Date(777777777777)
});
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
});
describe('A target that has a NaN', function () {
var lhs = {
key: NaN
};
it('shows the property is changed when compared to another number', function () {
var diff = deep.diff(lhs, {
key: 0
});
expect(diff).to.be.ok();
expect(diff.length).to.be(1);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
});
it('shows no differences when compared to another NaN', function () {
var diff = deep.diff(lhs, {
key: NaN
});
expect(diff).to.be.an('undefined');
});
});
describe('can revert namespace using noConflict', function () {
if (deep.noConflict) {
deep = deep.noConflict();
it('conflict is restored (when applicable)', function () {
// In node there is no global conflict.
if (typeof globalConflict !== 'undefined') {
expect(DeepDiff).to.be(deep); // eslint-disable-line no-undef
}
});
it('DeepDiff functionality available through result of noConflict()', function () {
expect(deep.applyDiff).to.be.a('function');
});
}
});
describe('When filtering keys', function () {
var lhs = {
enhancement: 'Filter/Ignore Keys?',
numero: 11,
submittedBy: 'ericclemmons',
supportedBy: ['ericclemmons'],
status: 'open'
};
var rhs = {
enhancement: 'Filter/Ignore Keys?',
numero: 11,
submittedBy: 'ericclemmons',
supportedBy: [
'ericclemmons',
'TylerGarlick',
'flitbit',
'ergdev'
],
status: 'closed',
fixedBy: 'flitbit'
};
describe('if the filtered property is an array', function () {
it('changes to the array do not appear as a difference', function () {
var prefilter = function (path, key) {
return key === 'supportedBy';
};
var diff = deep(lhs, rhs, prefilter);
expect(diff).to.be.ok();
expect(diff.length).to.be(2);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('E');
expect(diff[1]).to.have.property('kind');
expect(diff[1].kind).to.be('N');
});
});
describe('if the filtered property is not an array', function () {
it('changes do not appear as a difference', function () {
var prefilter = function (path, key) {
return key === 'fixedBy';
};
var diff = deep(lhs, rhs, prefilter);
expect(diff).to.be.ok();
expect(diff.length).to.be(4);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('A');
expect(diff[1]).to.have.property('kind');
expect(diff[1].kind).to.be('A');
expect(diff[2]).to.have.property('kind');
expect(diff[2].kind).to.be('A');
expect(diff[3]).to.have.property('kind');
expect(diff[3].kind).to.be('E');
});
});
});
describe('A target that has nested values', function () {
var nestedOne = {
noChange: 'same',
levelOne: {
levelTwo: 'value'
},
arrayOne: [{
objValue: 'value'
}]
};
var nestedTwo = {
noChange: 'same',
levelOne: {
levelTwo: 'another value'
},
arrayOne: [{
objValue: 'new value'
}, {
objValue: 'more value'
}]
};
it('shows no differences when compared to itself', function () {
expect(deep.diff(nestedOne, nestedOne)).to.be.an('undefined');
});
it('shows the property as removed when compared to an empty object', function () {
var diff = deep(nestedOne, empty);
expect(diff).to.be.ok();
expect(diff.length).to.be(3);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('D');
expect(diff[1]).to.have.property('kind');
expect(diff[1].kind).to.be('D');
});
it('shows the property is changed when compared to an object that has value', function () {
var diff = deep.diff(nestedOne, nestedTwo);
expect(diff).to.be.ok();
expect(diff.length).to.be(3);
});
it('shows the property as added when compared to an empty object on left', function () {
var diff = deep.diff(empty, nestedOne);
expect(diff).to.be.ok();
expect(diff.length).to.be(3);
expect(diff[0]).to.have.property('kind');
expect(diff[0].kind).to.be('N');
});
describe('when diff is applied to a different empty object', function () {
var diff = deep.diff(nestedOne, nestedTwo);
it('has result with nested values', function () {
var result = {};
deep.applyChange(result, nestedTwo, diff[0]);
expect(result.levelOne).to.be.ok();
expect(result.levelOne).to.be.an('object');
expect(result.levelOne.levelTwo).to.be.ok();
expect(result.levelOne.levelTwo).to.eql('another value');
});
it('has result with array object values', function () {
var result = {};
deep.applyChange(result, nestedTwo, diff[2]);
expect(result.arrayOne).to.be.ok();
expect(result.arrayOne).to.be.an('array');
expect(result.arrayOne[0]).to.be.ok();
expect(result.arrayOne[0].objValue).to.be.ok();
expect(result.arrayOne[0].objValue).to.equal('new value');
});
it('has result with added array objects', function () {
var result = {};
deep.applyChange(result, nestedTwo, diff[1]);
expect(result.arrayOne).to.be.ok();
expect(result.arrayOne).to.be.an('array');
expect(result.arrayOne[1]).to.be.ok();
expect(result.arrayOne[1].objValue).to.be.ok();
expect(result.arrayOne[1].objValue).to.equal('more value');
});
});
});
describe('regression test for bug #10, ', function () {
var lhs = {
id: 'Release',
phases: [{
id: 'Phase1',
tasks: [{
id: 'Task1'
}, {
id: 'Task2'
}]
}, {
id: 'Phase2',
tasks: [{
id: 'Task3'
}]
}]
};
var rhs = {
id: 'Release',
phases: [{
// E: Phase1 -> Phase2
id: 'Phase2',
tasks: [{
id: 'Task3'
}]
}, {
id: 'Phase1',
tasks: [{
id: 'Task1'
}, {
id: 'Task2'
}]
}]
};
describe('differences in nested arrays are detected', function () {
var diff = deep.diff(lhs, rhs);
// there should be differences
expect(diff).to.be.ok();
expect(diff.length).to.be(6);
it('differences can be applied', function () {
var applied = deep.applyDiff(lhs, rhs);
it('and the result equals the rhs', function () {
expect(applied).to.eql(rhs);
});
});
});
});
describe('regression test for bug #35', function () {
var lhs = ['a', 'a', 'a'];
var rhs = ['a'];
it('can apply diffs between two top level arrays', function () {
var differences = deep.diff(lhs, rhs);
differences.forEach(function (it) {
deep.applyChange(lhs, true, it);
});
expect(lhs).to.eql(['a']);
});
});
describe('Objects from different frames', function () {
if (typeof globalConflict === 'undefined') { return; }
// eslint-disable-next-line no-undef
var frame = document.createElement('iframe');
// eslint-disable-next-line no-undef
document.body.appendChild(frame);
var lhs = new frame.contentWindow.Date(2010, 1, 1);
var rhs = new frame.contentWindow.Date(2010, 1, 1);
it('can compare date instances from a different frame', function () {
var differences = deep.diff(lhs, rhs);
expect(differences).to.be(undefined);
});
});
describe('Comparing regexes should work', function () {
var lhs = /foo/;
var rhs = /foo/i;
it('can compare regex instances', function () {
var diff = deep.diff(lhs, rhs);
expect(diff.length).to.be(1);
expect(diff[0].kind).to.be('E');
expect(diff[0].path).to.not.be.ok();
expect(diff[0].lhs).to.be('/foo/');
expect(diff[0].rhs).to.be('/foo/i');
});
});
describe('subject.toString is not a function', function () {
var lhs = {
left: 'yes',
right: 'no',
};
var rhs = {
left: {
toString: true,
},
right: 'no',
};
it('should not throw a TypeError', function () {
var diff = deep.diff(lhs, rhs);
expect(diff.length).to.be(1);
});
});
describe('regression test for issue #83', function () {
var lhs = {
date: null
};
var rhs = {
date: null
};
it('should not detect a difference', function () {
expect(deep.diff(lhs, rhs)).to.be(undefined);
});
});
describe('regression test for issue #70', function () {
it('should detect a difference with undefined property on lhs', function () {
var diff = deep.diff({ foo: undefined }, {});
expect(diff).to.be.an(Array);
expect(diff.length).to.be(1);
expect(diff[0].kind).to.be('D');
expect(diff[0].path).to.be.an('array');
expect(diff[0].path).to.have.length(1);
expect(diff[0].path[0]).to.be('foo');
expect(diff[0].lhs).to.be(undefined);
});
it('should detect a difference with undefined property on rhs', function () {
var diff = deep.diff({}, { foo: undefined });
expect(diff).to.be.an(Array);
expect(diff.length).to.be(1);
expect(diff[0].kind).to.be('N');
expect(diff[0].path).to.be.an('array');
expect(diff[0].path).to.have.length(1);
expect(diff[0].path[0]).to.be('foo');
expect(diff[0].rhs).to.be(undefined);
});
});
describe('regression test for issue #98', function () {
var lhs = { foo: undefined };
var rhs = { foo: undefined };
it('should not detect a difference with two undefined property values', function () {
var diff = deep.diff(lhs, rhs);
expect(diff).to.be(undefined);
});
});
describe('regression tests for issue #102', function () {
it('should not throw a TypeError', function () {
var diff = deep.diff(null, undefined);
expect(diff).to.be.an(Array);
expect(diff.length).to.be(1);
expect(diff[0].kind).to.be('D');
expect(diff[0].lhs).to.be(null);
});
it('should not throw a TypeError', function () {
var diff = deep.diff(Object.create(null), { foo: undefined });
expect(diff).to.be.an(Array);
expect(diff.length).to.be(1);
expect(diff[0].kind).to.be('N');
expect(diff[0].rhs).to.be(undefined);
});
});
describe('Order independent hash testing', function () {
function sameHash(a, b) {
expect(deep.orderIndepHash(a)).to.equal(deep.orderIndepHash(b));
}
function differentHash(a, b) {
expect(deep.orderIndepHash(a)).to.not.equal(deep.orderIndepHash(b));
}
describe('Order indepdendent hash function should give different values for different objects', function () {
it('should give different values for different "simple" types', function () {
differentHash(1, -20);
differentHash('foo', 45);
differentHash('pie', 'something else');
differentHash(1.3332, 1);
differentHash(1, null);
differentHash('this is kind of a long string, don\'t you think?', 'the quick brown fox jumped over the lazy doge');
differentHash(true, 2);
differentHash(false, 'flooog');
});
it('should give different values for string and object with string', function () {
differentHash('some string', { key: 'some string' });
});
it('should give different values for number and array', function () {
differentHash(1, [1]);
});
it('should give different values for string and array of string', function () {
differentHash('string', ['string']);
});
it('should give different values for boolean and object with boolean', function () {
differentHash(true, { key: true });
});
it('should give different values for different arrays', function () {
differentHash([1, 2, 3], [1, 2]);
differentHash([1, 4, 5, 6], ['foo', 1, true, undefined]);
differentHash([1, 4, 6], [1, 4, 7]);
differentHash([1, 3, 5], ['1', '3', '5']);
});
it('should give different values for different objects', function () {
differentHash({ key: 'value' }, { other: 'value' });
differentHash({ a: { b: 'c' } }, { a: 'b' });
});
it('should differentiate between arrays and objects', function () {
differentHash([1, true, '1'], { a: 1, b: true, c: '1' });
});
});
describe('Order independent hash function should work in pathological cases', function () {
it('should work in funky javascript cases', function () {
differentHash(undefined, null);
differentHash(0, undefined);
differentHash(0, null);
differentHash(0, false);
differentHash(0, []);
differentHash('', []);
differentHash(3.22, '3.22');
differentHash(true, 'true');
differentHash(false, 0);
});
it('should work on empty array and object', function () {
differentHash([], {});
});
it('should work on empty object and undefined', function () {
differentHash({}, undefined);
});
it('should work on empty array and array with 0', function () {
differentHash([], [0]);
});
});
describe('Order independent hash function should be order independent', function () {
it('should not care about array order', function () {
sameHash([1, 2, 3], [3, 2, 1]);
sameHash(['hi', true, 9.4], [true, 'hi', 9.4]);
});
it('should not care about key order in an object', function () {
sameHash({ foo: 'bar', foz: 'baz' }, { foz: 'baz', foo: 'bar' });
});
it('should work with complicated objects', function () {
var obj1 = {
foo: 'bar',
faz: [
1,
'pie',
{
food: 'yum'
}
]
};
var obj2 = {
faz: [
'pie',
{
food: 'yum'
},
1
],
foo: 'bar'
};
sameHash(obj1, obj2);
});
});
});
describe('Order indepedent array comparison should work', function () {
it('can compare simple arrays in an order independent fashion', function () {
var lhs = [1, 2, 3];
var rhs = [1, 3, 2];
var diff = deep.orderIndependentDiff(lhs, rhs);
expect(diff).to.be(undefined);
});
it('still works with repeated elements', function () {
var lhs = [1, 1, 2];
var rhs = [1, 2, 1];
var diff = deep.orderIndependentDiff(lhs, rhs);
expect(diff).to.be(undefined);
});
it('works on complex objects', function () {
var obj1 = {
foo: 'bar',
faz: [
1,
'pie',
{
food: 'yum'
}
]
};
var obj2 = {
faz: [
'pie',
{
food: 'yum'
},
1
],
foo: 'bar'
};
var diff = deep.orderIndependentDiff(obj1, obj2);
expect(diff).to.be(undefined);
});
it('should report some difference in non-equal arrays', function () {
var lhs = [1, 2, 3];
var rhs = [2, 2, 3];
var diff = deep.orderIndependentDiff(lhs, rhs);
expect(diff.length).to.be.ok();
});
});
});
}));