diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 2980c7979..529085a06 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -71,7 +71,7 @@ module.exports = function (chai, _) { /** * ### .deep * - * Sets the `deep` flag, later used by the `equal`, `include`, `members`, and + * Sets the `deep` flag, later used by the `equal`, `include`, `members`, `keys` and * `property` assertions. * * const obj = {a: 1}; @@ -1328,6 +1328,10 @@ module.exports = function (chai, _) { * can have objects as keys, so, in this case, you can pass multiple objects as arguments if * you want to. * + * The default behavior when it comes to Maps and Sets is to use strict equality + * (===) to compare values. You can also use the `deep` flag if you want a deep comparison + * instead of a strict comparison. + * * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); @@ -1338,9 +1342,13 @@ module.exports = function (chai, _) { * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); * expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.key({objKey: 'value'}); + * expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.deep.key({objKey: 'value'}); * expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.any.keys([{objKey: 'value'}, {anotherKey: 'anotherValue'}]); + * expect(new Map([[{objKey: 'value'}, 'value'], [1, 2]])).to.contain.any.deep.keys([{objKey: 'value'}, {anotherKey: 'anotherValue'}]); * expect(new Map([['firstKey', 'firstValue'], [1, 2]])).to.contain.all.keys('firstKey', 1); + * expect(new Map([['firstKey', 'firstValue'], [1, 2]])).to.contain.all.deep.keys('firstKey', 1); * expect(new Set([['foo', 'bar'], ['example', 1]])).to.have.any.keys('foo'); + * expect(new Set([['foo', 'bar'], ['example', 1]])).to.have.any.deep.keys('foo'); * * @name keys * @alias key @@ -1351,11 +1359,13 @@ module.exports = function (chai, _) { function assertKeys (keys) { var obj = flag(this, 'object') + , isDeep = flag(this, 'deep') , str , ok = true , mixedArgsMsg = 'when testing keys against an object or an array you must give a single Array|Object|String argument or multiple String arguments'; if (_.type(obj) === 'map' || _.type(obj) === 'set') { + str = isDeep ? 'deeply ' : ''; actual = []; // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach. @@ -1402,7 +1412,11 @@ module.exports = function (chai, _) { if (any) { ok = expected.some(function(expectedKey) { return actual.some(function(actualKey) { - return expectedKey === actualKey; + if (isDeep) { + return _.eql(expectedKey, actualKey); + } else { + return expectedKey === actualKey; + } }); }); } @@ -1411,7 +1425,11 @@ module.exports = function (chai, _) { if (all) { ok = expected.every(function(expectedKey) { return actual.some(function(actualKey) { - return expectedKey === actualKey; + if (isDeep) { + return _.eql(expectedKey, actualKey); + } else { + return expectedKey === actualKey; + } }); }); diff --git a/lib/chai/interface/assert.js b/lib/chai/interface/assert.js index 0e8d97a80..7d4223437 100644 --- a/lib/chai/interface/assert.js +++ b/lib/chai/interface/assert.js @@ -1544,6 +1544,158 @@ module.exports = function (chai, util) { } /** + * ### .hasAnyDeepKeys(object, [keys], [message]) + * + * Asserts that `object` has at least one of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'}); + * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), [{one: 'one'}, {two: 'two'}]); + * assert.hasAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); + * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'}); + * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {three: 'three'}]); + * assert.hasAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); + * + * @name doesNotHaveAllKeys + * @param {Mixed} object + * @param {...String|Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAnyDeepKeys = function (obj, keys, msg) { + if (keys === undefined) { + new Assertion(obj, msg).to.have.any.deep.keys(); + } + + new Assertion(obj, msg).to.have.any.deep.keys(keys); + } + + /** + * ### .hasAllDeepKeys(object, [keys], [message]) + * + * Asserts that `object` has all and only all of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne']]), {one: 'one'}); + * assert.hasAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); + * assert.hasAllDeepKeys(new Set([{one: 'one'}]), {one: 'one'}); + * assert.hasAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); + * + * @name hasAllDeepKeys + * @param {Mixed} object + * @param {...String|Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAllDeepKeys = function (obj, keys, msg) { + if (keys === undefined) { + new Assertion(obj, msg).to.have.all.deep.keys(); + } + + new Assertion(obj, msg).to.have.all.deep.keys(keys); + } + + /** + * ### .containsAllDeepKeys(object, [keys], [message]) + * + * Asserts that `object` contains all of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {one: 'one'}); + * assert.containsAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{one: 'one'}, {two: 'two'}]); + * assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {one: 'one'}); + * assert.containsAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {two: 'two'}]); + * + * @name containsAllDeepKeys + * @param {Mixed} object + * @param {...String|Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.containsAllDeepKeys = function (obj, keys, msg) { + if (keys === undefined) { + new Assertion(obj, msg).to.contain.all.deep.keys(); + } + + new Assertion(obj, msg).to.contain.all.deep.keys(keys); + } + + /** + * ### .doesNotHaveAnyDeepKeys(object, [keys], [message]) + * + * Asserts that `object` has none of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'}); + * assert.doesNotHaveAnyDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {fifty: 'fifty'}]); + * assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'}); + * assert.doesNotHaveAnyDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{twenty: 'twenty'}, {fifty: 'fifty'}]); + * + * @name doesNotHaveAnyDeepKeys + * @param {Mixed} object + * @param {...String|Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAnyDeepKeys = function (obj, keys, msg) { + if (keys === undefined) { + new Assertion(obj, msg).to.not.have.any.deep.keys(); + } + + new Assertion(obj, msg).to.not.have.any.deep.keys(keys); + } + + /** + * ### .doesNotHaveAllDeepKeys(object, [keys], [message]) + * + * Asserts that `object` does not have at least one of the `keys` provided. + * Since Sets and Maps can have objects as keys you can use this assertion to perform + * a deep comparison. + * You can also provide a single object instead of a `keys` array and its keys + * will be used as the expected set of keys. + * + * assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [1, 2]]), {thisDoesNot: 'exist'}); + * assert.doesNotHaveAllDeepKeys(new Map([[{one: 'one'}, 'valueOne'], [{two: 'two'}, 'valueTwo']]), [{twenty: 'twenty'}, {one: 'one'}]); + * assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), {twenty: 'twenty'}); + * assert.doesNotHaveAllDeepKeys(new Set([{one: 'one'}, {two: 'two'}]), [{one: 'one'}, {fifty: 'fifty'}]); + * + * @name doesNotHaveAllDeepKeys + * @param {Mixed} object + * @param {...String|Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAllDeepKeys = function (obj, keys, msg) { + if (keys === undefined) { + new Assertion(obj, msg).to.not.have.all.deep.keys(); + } + + new Assertion(obj, msg).to.not.have.all.deep.keys(keys); + } + + /** * ### .throws(fn, [errorLike/string/regexp], [string/regexp], [message]) * * If `errorLike` is an `Error` constructor, asserts that `fn` will throw an error that is an diff --git a/test/assert.js b/test/assert.js index e8219c65b..ab19af95a 100644 --- a/test/assert.js +++ b/test/assert.js @@ -747,6 +747,22 @@ describe('assert', function () { assert.doesNotHaveAnyKeys(testMap, [ 'thisDoesNotExist', 'thisToo', {iDoNot: 'exist'} ]); assert.doesNotHaveAllKeys(testMap, [ aKey, {iDoNot: 'exist'} ]); + // Tests for the deep variations of the keys assertion + assert.hasAnyDeepKeys(testMap, {thisIs: 'anExampleObject'}); + assert.hasAnyDeepKeys(testMap, [{thisIs: 'anExampleObject'}, {three: 'three'}]); + assert.hasAnyDeepKeys(testMap, [{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + assert.hasAllDeepKeys(testMap, [{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + assert.containsAllDeepKeys(testMap, {thisIs: 'anExampleObject'}); + assert.containsAllDeepKeys(testMap, [{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + assert.doesNotHaveAnyDeepKeys(testMap, {thisDoesNot: 'exist'}); + assert.doesNotHaveAnyDeepKeys(testMap, [{twenty: 'twenty'}, {fifty: 'fifty'}]); + + assert.doesNotHaveAllDeepKeys(testMap, {thisDoesNot: 'exist'}); + assert.doesNotHaveAllDeepKeys(testMap, [{twenty: 'twenty'}, {thisIs: 'anExampleObject'}]); + var weirdMapKey1 = Object.create(null) , weirdMapKey2 = {toString: NaN} , weirdMapKey3 = [] @@ -778,7 +794,7 @@ describe('assert', function () { var errMap = new Map(); errMap.set({1: 20}, 'number'); - + err(function(){ assert.hasAllKeys(errMap); }, "keys required"); @@ -818,6 +834,16 @@ describe('assert', function () { err(function(){ assert.doesNotHaveAnyKeys(errMap, []); }, "keys required"); + + // Uncomment this after solving https://github.com/chaijs/chai/issues/662 + // This should fail because of referential equality (this is a strict comparison) + // err(function(){ + // assert.containsAllKeys(new Map([[{foo: 1}, 'bar']]), { foo: 1 }); + // }, 'expected [ [ { foo: 1 }, 'bar' ] ] to contain key { foo: 1 }'); + + // err(function(){ + // assert.containsAllDeepKeys(new Map([[{foo: 1}, 'bar']]), { iDoNotExist: 0 }) + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); } if (typeof Set !== 'undefined') { @@ -877,6 +903,22 @@ describe('assert', function () { errSet.add({1: 20}); errSet.add('number'); + // Tests for the deep variations of the keys assertion + assert.hasAnyDeepKeys(testSet, {thisIs: 'anExampleObject'}); + assert.hasAnyDeepKeys(testSet, [{thisIs: 'anExampleObject'}, {three: 'three'}]); + assert.hasAnyDeepKeys(testSet, [{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + assert.hasAllDeepKeys(testSet, [{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + assert.containsAllDeepKeys(testSet, {thisIs: 'anExampleObject'}); + assert.containsAllDeepKeys(testSet, [{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + assert.doesNotHaveAnyDeepKeys(testSet, {twenty: 'twenty'}); + assert.doesNotHaveAnyDeepKeys(testSet, [{twenty: 'twenty'}, {fifty: 'fifty'}]); + + assert.doesNotHaveAllDeepKeys(testSet, {twenty: 'twenty'}); + assert.doesNotHaveAllDeepKeys(testSet, [{thisIs: 'anExampleObject'}, {fifty: 'fifty'}]); + err(function(){ assert.hasAllKeys(errSet); }, "keys required"); @@ -916,6 +958,16 @@ describe('assert', function () { err(function(){ assert.doesNotHaveAnyKeys(errSet, []); }, "keys required"); + + // Uncomment this after solving https://github.com/chaijs/chai/issues/662 + // This should fail because of referential equality (this is a strict comparison) + // err(function(){ + // assert.containsAllKeys(new Set([{foo: 1}]), { foo: 1 }); + // }, 'expected [ [ { foo: 1 }, 'bar' ] ] to contain key { foo: 1 }'); + + // err(function(){ + // assert.containsAllDeepKeys(new Set([{foo: 1}]), { iDoNotExist: 0 }) + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); } err(function(){ @@ -1023,7 +1075,6 @@ describe('assert', function () { assert.doesNotHaveAllKeys({ foo: 1, bar: 2 }, { 'foo': 1, 'bar': 1}); }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); - err(function() { assert.hasAnyKeys({ foo: 1 }, 'baz'); }, "expected { foo: 1 } to have key 'baz'"); @@ -1035,7 +1086,6 @@ describe('assert', function () { err(function(){ assert.doesNotHaveAnyKeys({ foo: 1, bar: 2 }, { 'foo': 1, 'baz': 1}); }, "expected { foo: 1, bar: 2 } to not have keys 'foo', or 'baz'"); - }); it('lengthOf', function() { diff --git a/test/expect.js b/test/expect.js index cca20a88f..e4472483d 100644 --- a/test/expect.js +++ b/test/expect.js @@ -1205,6 +1205,27 @@ describe('expect', function () { expect(testMap).to.not.have.any.keys([20, 1, {13: 37}]); expect(testMap).to.not.have.all.keys([aKey, {'iDoNot': 'exist'}]); + // Using the same assertions as above but with `.deep` flag instead of using referential equality + var aKey = {thisIs: 'anExampleObject'} + expect(testMap).to.have.any.deep.keys({thisIs: 'anExampleObject'}); + expect(testMap).to.have.any.deep.keys('thisDoesNotExist', 'thisToo', {thisIs: 'anExampleObject'}); + + expect(testMap).to.contain.all.deep.keys({thisIs: 'anExampleObject'}); + expect(testMap).to.not.contain.all.deep.keys({thisIs: 'anExampleObject'}, 'thisDoesNotExist'); + + expect(testMap).to.not.have.any.deep.keys({iDoNot: 'exist'}); + expect(testMap).to.not.have.any.deep.keys('thisIsNotAkey', {iDoNot: 'exist'}, {33: 20}); + expect(testMap).to.not.have.all.deep.keys('thisDoesNotExist', 'thisToo', {doingThisBecauseOf: 'referential equality'}); + + expect(testMap).to.have.any.deep.keys([{thisIs: 'anExampleObject'}]); + expect(testMap).to.have.any.deep.keys([20, 1, {thisIs: 'anExampleObject'}]); + + expect(testMap).to.have.all.deep.keys({thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}); + + expect(testMap).to.not.have.any.deep.keys([{13: 37}, 'thisDoesNotExist', 'thisToo']); + expect(testMap).to.not.have.any.deep.keys([20, 1, {13: 37}]); + expect(testMap).to.not.have.all.deep.keys([{thisIs: 'anExampleObject'}, {'iDoNot': 'exist'}]); + var weirdMapKey1 = Object.create(null) , weirdMapKey2 = {toString: NaN} , weirdMapKey3 = [] @@ -1255,6 +1276,16 @@ describe('expect', function () { err(function(){ expect(errMap).to.contain.keys([]); }, "keys required"); + + // Uncomment this after solving https://github.com/chaijs/chai/issues/662 + // This should fail because of referential equality (this is a strict comparison) + // err(function(){ + // expect(new Map([[{foo: 1}, 'bar']])).to.contain.keys({ foo: 1 }); + // }, 'expected [ [ { foo: 1 }, 'bar' ] ] to contain key { foo: 1 }'); + + // err(function(){ + // expect(new Map([[{foo: 1}, 'bar']])).to.contain.deep.keys({ iDoNotExist: 0 }) + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); } if (typeof Set !== 'undefined') { @@ -1285,6 +1316,26 @@ describe('expect', function () { expect(testSet).to.not.have.any.keys([20, 1, {13: 37}]); expect(testSet).to.not.have.all.keys([aKey, {'iDoNot': 'exist'}]); + // Using the same assertions as above but with `.deep` flag instead of using referential equality + expect(testSet).to.have.any.deep.keys({thisIs: 'anExampleObject'}); + expect(testSet).to.have.any.deep.keys('thisDoesNotExist', 'thisToo', {thisIs: 'anExampleObject'}); + + expect(testSet).to.contain.all.deep.keys({thisIs: 'anExampleObject'}); + expect(testSet).to.not.contain.all.deep.keys({thisIs: 'anExampleObject'}, 'thisDoesNotExist'); + + expect(testSet).to.not.have.any.deep.keys({iDoNot: 'exist'}); + expect(testSet).to.not.have.any.deep.keys('thisIsNotAkey', {iDoNot: 'exist'}, {33: 20}); + expect(testSet).to.not.have.all.deep.keys('thisDoesNotExist', 'thisToo', {doingThisBecauseOf: 'referential equality'}); + + expect(testSet).to.have.any.deep.keys([{thisIs: 'anExampleObject'}]); + expect(testSet).to.have.any.deep.keys([20, 1, {thisIs: 'anExampleObject'}]); + + expect(testSet).to.have.all.deep.keys([{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + expect(testSet).to.not.have.any.deep.keys([{13: 37}, 'thisDoesNotExist', 'thisToo']); + expect(testSet).to.not.have.any.deep.keys([20, 1, {13: 37}]); + expect(testSet).to.not.have.all.deep.keys([{thisIs: 'anExampleObject'}, {'iDoNot': 'exist'}]); + var weirdSetKey1 = Object.create(null) , weirdSetKey2 = {toString: NaN} , weirdSetKey3 = [] @@ -1334,6 +1385,16 @@ describe('expect', function () { err(function(){ expect(errSet).to.contain.keys([]); }, "keys required"); + + // Uncomment this after solving https://github.com/chaijs/chai/issues/662 + // This should fail because of referential equality (this is a strict comparison) + // err(function(){ + // expect(new Set([{foo: 1}])).to.contain.keys({ foo: 1 }); + // }, 'expected [ { foo: 1 } ] to deeply contain key { foo: 1 }'); + + // err(function(){ + // expect(new Set([{foo: 1}])).to.contain.deep.keys({ iDoNotExist: 0 }); + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); } err(function(){ diff --git a/test/should.js b/test/should.js index c011ef197..2358fa1f9 100644 --- a/test/should.js +++ b/test/should.js @@ -1051,6 +1051,23 @@ describe('should', function() { testMap.should.not.have.any.keys([20, 1, {13: 37}]); testMap.should.not.have.all.keys([aKey, {'iDoNot': 'exist'}]); + // Using the same assertions as above but with `.deep` flag instead of using referential equality + testMap.should.have.any.deep.keys({thisIs: 'anExampleObject'}); + testMap.should.have.any.deep.keys('thisDoesNotExist', 'thisToo', {thisIs: 'anExampleObject'}); + + testMap.should.contain.all.deep.keys({thisIs: 'anExampleObject'}); + testMap.should.not.contain.all.deep.keys({thisIs: 'anExampleObject'}, 'thisDoesNotExist'); + testMap.should.not.have.any.deep.keys({iDoNot: 'exist'}); + testMap.should.not.have.all.deep.keys('thisDoesNotExist', 'thisToo', {doingThisBecauseOf: 'referential equality'}); + + testMap.should.have.any.deep.keys([{thisIs: 'anExampleObject'}]); + testMap.should.have.any.deep.keys([20, 1, {thisIs: 'anExampleObject'}]); + + testMap.should.have.all.deep.keys([{thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}]); + + testMap.should.not.have.any.deep.keys([{13: 37}, 'thisDoesNotExist', 'thisToo']); + testMap.should.not.have.any.deep.keys([20, 1, {13: 37}]); + var weirdMapKey1 = Object.create(null) , weirdMapKey2 = {toString: NaN} , weirdMapKey3 = [] @@ -1101,6 +1118,16 @@ describe('should', function() { err(function(){ errMap.should.contain.keys([]); }, "keys required"); + + // Uncomment these after solving https://github.com/chaijs/chai/issues/662 + // This should fail because of referential equality (this is a strict comparison) + // err(function(){ + // new Map([[{foo: 1}, 'bar']]).should.contain.keys({ foo: 1 }); + // }, 'expected [ [ { foo: 1 }, 'bar' ] ] to contain key { foo: 1 }'); + + // err(function(){ + // new Map([[{foo: 1}, 'bar']]).should.contain.deep.keys({ iDoNotExist: 0 }); + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); } if (typeof Set !== 'undefined') { @@ -1131,6 +1158,26 @@ describe('should', function() { testSet.should.not.have.any.keys([20, 1, {13: 37}]); testSet.should.not.have.all.keys([aKey, {'iDoNot': 'exist'}]); + // Using the same assertions as above but with `.deep` flag instead of using referential equality + testSet.should.have.any.deep.keys({thisIs: 'anExampleObject'}); + testSet.should.have.any.deep.keys('thisDoesNotExist', 'thisToo', {thisIs: 'anExampleObject'}); + + testSet.should.contain.all.deep.keys({thisIs: 'anExampleObject'}); + testSet.should.not.contain.all.deep.keys({thisIs: 'anExampleObject'}, 'thisDoesNotExist'); + + testSet.should.not.have.any.deep.keys({iDoNot: 'exist'}); + testSet.should.not.have.any.deep.keys('thisIsNotAkey', {iDoNot: 'exist'}, {33: 20}); + testSet.should.not.have.all.deep.keys('thisDoesNotExist', 'thisToo', {anotherObj: 'foo'}); + + testSet.should.have.any.deep.keys([{thisIs: 'anExampleObject'}]); + testSet.should.have.any.deep.keys([20, 1, {thisIs: 'anExampleObject'}]); + + testSet.should.have.all.deep.keys({thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'}); + + testSet.should.not.have.any.deep.keys([{13: 37}, 'thisDoesNotExist', 'thisToo']); + testSet.should.not.have.any.deep.keys([20, 1, {13: 37}]); + testSet.should.not.have.all.deep.keys([{thisIs: 'anExampleObject'}, {'iDoNot': 'exist'}]) + var weirdSetKey1 = Object.create(null) , weirdSetKey2 = {toString: NaN} , weirdSetKey3 = [] @@ -1181,6 +1228,16 @@ describe('should', function() { err(function(){ errSet.should.contain.keys([]); }, "keys required"); + + // Uncomment these after solving https://github.com/chaijs/chai/issues/662 + // This should fail because of referential equality (this is a strict comparison) + // err(function(){ + // new Set([{foo: 1}]).should.contain.keys({ foo: 1 }); + // }, 'expected [ { foo: 1 } ] to contain key { foo: 1 }'); + + // err(function(){ + // new Set([{foo: 1}]).should.contain.deep.keys({ iDoNotExist: 0 }); + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); } err(function(){