diff --git a/index.js b/index.js index 6d2afac..552f0d2 100644 --- a/index.js +++ b/index.js @@ -357,6 +357,20 @@ function getGeneratorEntries(generator) { return accumulator; } +/*! + * Gets all own and inherited enumerable keys from a target. + * + * @param {Object} target + * @returns {Array} an array of own and inherited enumerable keys from the target. + */ +function getEnumerableKeys(target) { + var keys = []; + for (var key in target) { + keys.push(key); + } + return keys; +} + /*! * Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of * each key. If any value of the given key is not equal, the function will return false (early). @@ -391,12 +405,8 @@ function keysEqual(leftHandOperand, rightHandOperand, keys, options) { */ function objectEqual(leftHandOperand, rightHandOperand, options) { - if (Object.getPrototypeOf(leftHandOperand) !== Object.getPrototypeOf(rightHandOperand)) { - return false; - } - - var leftHandKeys = Object.keys(leftHandOperand); - var rightHandKeys = Object.keys(rightHandOperand); + var leftHandKeys = getEnumerableKeys(leftHandOperand); + var rightHandKeys = getEnumerableKeys(rightHandOperand); if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) { leftHandKeys.sort(); rightHandKeys.sort(); diff --git a/test/index.js b/test/index.js index 22c5de6..0fd8e8a 100644 --- a/test/index.js +++ b/test/index.js @@ -192,6 +192,15 @@ describe('Generic', function () { assert(eql(new BaseA(1), new BaseA(1)), 'eql(new BaseA(1), new BaseA(1))'); }); + it('returns true given two class instances with deeply equal bases', function () { + function BaseA() {} + function BaseB() {} + BaseA.prototype.foo = { a: 1 }; + BaseB.prototype.foo = { a: 1 }; + assert(eql(new BaseA(), new BaseB()) === true, + 'eql(new , new ) === true'); + }); + it('returns false given two class instances with different properties', function () { function BaseA(prop) { this.prop = prop; @@ -199,10 +208,13 @@ describe('Generic', function () { assert(eql(new BaseA(1), new BaseA(2)) === false, 'eql(new BaseA(1), new BaseA(2)) === false'); }); - it('returns false given two different empty class instances', function () { + it('returns false given two class instances with deeply unequal bases', function () { function BaseA() {} function BaseB() {} - assert(eql(new BaseA(), new BaseB()) === false, 'eql(new BaseA(), new BaseB()) === false'); + BaseA.prototype.foo = { a: 1 }; + BaseB.prototype.foo = { a: 2 }; + assert(eql(new BaseA(), new BaseB()) === false, + 'eql(new , new ) === false'); }); }); @@ -283,6 +295,13 @@ describe('Generic', function () { 'eql({ foo: 1, bar: objectC }, { foo: 1, bar: objectC }) === true'); }); + it('returns true with objects with deeply equal prototypes', function () { + var objectA = Object.create({ foo: { a: 1 } }); + var objectB = Object.create({ foo: { a: 1 } }); + assert(eql(objectA, objectB) === true, + 'eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 1 } })) === true'); + }); + it('returns false with objects containing different literals', function () { assert(eql({ foo: 1, bar: 1 }, { foo: 1, bar: 2 }) === false, 'eql({ foo: 1, bar: 2 }, { foo: 1, bar: 2 }) === false'); @@ -306,6 +325,13 @@ describe('Generic', function () { 'eql({ foo: 1, bar: -> }, { foo: 1, bar: <- }) === true'); }); + it('returns false with objects with deeply unequal prototypes', function () { + var objectA = Object.create({ foo: { a: 1 } }); + var objectB = Object.create({ foo: { a: 2 } }); + assert(eql(objectA, objectB) === false, + 'eql(Object.create({ foo: { a: 1 } }), Object.create({ foo: { a: 2 } })) === false'); + }); + }); describe('functions', function () {