diff --git a/src/diff/index.js b/src/diff/index.js index b681591..a44e255 100644 --- a/src/diff/index.js +++ b/src/diff/index.js @@ -1,23 +1,26 @@ -import { isDate, isEmpty, isObject } from '../utils'; +import { isDate, isEmpty, isObject, properObject } from '../utils'; const diff = (lhs, rhs) => { if (lhs === rhs) return {}; // equal return no diff if (!isObject(lhs) || !isObject(rhs)) return rhs; // return updated rhs - const deletedValues = Object.keys(lhs).reduce((acc, key) => { - return rhs.hasOwnProperty(key) ? acc : { ...acc, [key]: undefined }; + const l = properObject(lhs); + const r = properObject(rhs); + + const deletedValues = Object.keys(l).reduce((acc, key) => { + return r.hasOwnProperty(key) ? acc : { ...acc, [key]: undefined }; }, {}); - if (isDate(lhs) || isDate(rhs)) { - if (lhs.toString() == rhs.toString()) return {}; - return rhs; + if (isDate(l) || isDate(r)) { + if (l.toString() == r.toString()) return {}; + return r; } - return Object.keys(rhs).reduce((acc, key) => { - if (!lhs.hasOwnProperty(key)) return { ...acc, [key]: rhs[key] }; // return added rhs key + return Object.keys(r).reduce((acc, key) => { + if (!l.hasOwnProperty(key)) return { ...acc, [key]: r[key] }; // return added r key - const difference = diff(lhs[key], rhs[key]); + const difference = diff(l[key], r[key]); if (isObject(difference) && isEmpty(difference) && !isDate(difference)) return acc; // return no diff diff --git a/src/diff/index.test.js b/src/diff/index.test.js index 0032256..47bf3a4 100644 --- a/src/diff/index.test.js +++ b/src/diff/index.test.js @@ -117,5 +117,61 @@ describe('.diff', () => { expect(diff([], [rhs])).toEqual({ 0: rhs }); }); }); + + describe('object create null', () => { + test('returns right hand side value when given objects are different', () => { + const lhs = Object.create(null); + lhs.a = 1; + const rhs = Object.create(null); + rhs.a = 2; + expect(diff(lhs, rhs)).toEqual({ a: 2 }); + }); + + test('returns subset of right hand side value when sibling objects differ', () => { + const lhs = Object.create(null); + lhs.a = { b: 1 }; + lhs.c = 2; + const rhs = Object.create(null); + rhs.a = { b: 1 }; + rhs.c = 3; + expect(diff(lhs, rhs)).toEqual({ c: 3 }); + }); + + test('returns subset of right hand side value when nested values differ', () => { + const lhs = Object.create(null); + lhs.a = { b: 1, c: 2}; + const rhs = Object.create(null); + rhs.a = { b: 1, c: 3 }; + expect(diff(lhs, rhs)).toEqual({ a: { c: 3 } }); + }); + + test('returns subset of right hand side value when nested values differ at multiple paths', () => { + const lhs = Object.create(null); + lhs.a = { b: 1 }; + lhs.c = 2; + const rhs = Object.create(null); + rhs.a = { b: 99 }; + rhs.c = 3; + expect(diff(lhs, rhs)).toEqual({ a: { b: 99 }, c: 3 }); + }); + + test('returns subset of right hand side value when a key value has been deleted', () => { + const lhs = Object.create(null); + lhs.a = { b: 1 }; + lhs.c = 2; + const rhs = Object.create(null); + rhs.a = { b: 1 }; + expect(diff(lhs, rhs)).toEqual({ c: undefined }); + }); + + test('returns subset of right hand side value when a key value has been added', () => { + const lhs = Object.create(null); + lhs.a = 1; + const rhs = Object.create(null); + rhs.a = 1; + rhs.b = 2; + expect(diff(lhs, rhs)).toEqual({ b: 2 }); + }); + }); }); });