diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 2980c7979..98ea0e01a 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,14 @@ module.exports = function (chai, _) { function assertKeys (keys) { var obj = flag(this, 'object') + , isDeep = flag(this, 'deep') , str + , deepStr = '' , 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') { + deepStr = isDeep ? 'deeply ' : ''; actual = []; // Map and Set '.keys' aren't supported in IE 11. Therefore, use .forEach. @@ -1402,7 +1413,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 +1426,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; + } }); }); @@ -1445,8 +1464,8 @@ module.exports = function (chai, _) { // Assertion this.assert( ok - , 'expected #{this} to ' + str - , 'expected #{this} to not ' + str + , 'expected #{this} to ' + deepStr + str + , 'expected #{this} to not ' + deepStr + str , expected.slice(0).sort(_.compareByInspect) , actual.sort(_.compareByInspect) , true diff --git a/lib/chai/interface/assert.js b/lib/chai/interface/assert.js index 0e8d97a80..47395c5c2 100644 --- a/lib/chai/interface/assert.js +++ b/lib/chai/interface/assert.js @@ -1420,10 +1420,6 @@ module.exports = function (chai, util) { */ assert.hasAnyKeys = function (obj, keys, msg) { - if (keys === undefined) { - new Assertion(obj, msg).to.not.have.all.keys(); - } - new Assertion(obj, msg).to.have.any.keys(keys); } @@ -1448,10 +1444,6 @@ module.exports = function (chai, util) { */ assert.hasAllKeys = function (obj, keys, msg) { - if (keys === undefined) { - new Assertion(obj, msg).to.not.have.all.keys(); - } - new Assertion(obj, msg).to.have.all.keys(keys); } @@ -1480,10 +1472,6 @@ module.exports = function (chai, util) { */ assert.containsAllKeys = function (obj, keys, msg) { - if (keys === undefined) { - new Assertion(obj, msg).to.not.have.all.keys(); - } - new Assertion(obj, msg).to.contain.all.keys(keys); } @@ -1508,10 +1496,6 @@ module.exports = function (chai, util) { */ assert.doesNotHaveAnyKeys = function (obj, keys, msg) { - if (keys === undefined) { - new Assertion(obj, msg).to.not.have.all.keys(); - } - new Assertion(obj, msg).to.not.have.any.keys(keys); } @@ -1536,14 +1520,142 @@ module.exports = function (chai, util) { */ assert.doesNotHaveAllKeys = function (obj, keys, msg) { - if (keys === undefined) { - new Assertion(obj, msg).to.not.have.all.keys(); - } - new Assertion(obj, msg).to.not.have.all.keys(keys); } /** + * ### .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 {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAnyDeepKeys = function (obj, keys, msg) { + 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 {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.hasAllDeepKeys = function (obj, keys, msg) { + 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 {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.containsAllDeepKeys = function (obj, keys, msg) { + 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 {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAnyDeepKeys = function (obj, keys, msg) { + 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 {Array|Object} keys + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.doesNotHaveAllDeepKeys = function (obj, keys, msg) { + 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..093a4db9d 100644 --- a/test/assert.js +++ b/test/assert.js @@ -747,6 +747,38 @@ describe('assert', function () { assert.doesNotHaveAnyKeys(testMap, [ 'thisDoesNotExist', 'thisToo', {iDoNot: 'exist'} ]); assert.doesNotHaveAllKeys(testMap, [ aKey, {iDoNot: 'exist'} ]); + // Ensure the assertions above use strict equality + assert.doesNotHaveAnyKeys(testMap, {thisIs: 'anExampleObject'}); + assert.doesNotHaveAllKeys(testMap, [ {thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'} ]); + + err(function(){ + assert.hasAnyKeys(testMap, [ {thisIs: 'anExampleObject'} ]); + }); + + err(function(){ + assert.hasAllKeys(testMap, [ {thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'} ]); + }); + + err(function(){ + assert.containsAllKeys(testMap, [ {thisIs: 'anExampleObject'} ]); + }); + + // 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 = [] @@ -779,45 +811,35 @@ describe('assert', function () { errMap.set({1: 20}, 'number'); - err(function(){ - assert.hasAllKeys(errMap); - }, "keys required"); - err(function(){ assert.hasAllKeys(errMap, []); }, "keys required"); - err(function(){ - assert.containsAllKeys(errMap); - }, "keys required"); - err(function(){ assert.containsAllKeys(errMap, []); }, "keys required"); - err(function(){ - assert.doesNotHaveAllKeys(errMap); - }, "keys required"); - err(function(){ assert.doesNotHaveAllKeys(errMap, []); }, "keys required"); - err(function(){ - assert.hasAnyKeys(errMap); - }, "keys required"); - err(function(){ assert.hasAnyKeys(errMap, []); }, "keys required"); - err(function(){ - assert.doesNotHaveAnyKeys(errMap); - }, "keys required"); - 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') { @@ -844,6 +866,38 @@ describe('assert', function () { assert.doesNotHaveAnyKeys(testSet, [ 20, 1, {iDoNot: 'exist'} ]); assert.doesNotHaveAllKeys(testSet, [ 'thisDoesNotExist', 'thisToo', {iDoNot: 'exist'} ]); + // Ensure the assertions above use strict equality + assert.doesNotHaveAnyKeys(testSet, {thisIs: 'anExampleObject'}); + assert.doesNotHaveAllKeys(testSet, [ {thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'} ]); + + err(function(){ + assert.hasAnyKeys(testSet, [ {thisIs: 'anExampleObject'} ]); + }); + + err(function(){ + assert.hasAllKeys(testSet, [ {thisIs: 'anExampleObject'}, {doingThisBecauseOf: 'referential equality'} ]); + }); + + err(function(){ + assert.containsAllKeys(testSet, [ {thisIs: 'anExampleObject'} ]); + }); + + // 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'}]); + var weirdSetKey1 = Object.create(null) , weirdSetKey2 = {toString: NaN} , weirdSetKey3 = [] @@ -877,83 +931,53 @@ describe('assert', function () { errSet.add({1: 20}); errSet.add('number'); - err(function(){ - assert.hasAllKeys(errSet); - }, "keys required"); - err(function(){ assert.hasAllKeys(errSet, []); }, "keys required"); - err(function(){ - assert.containsAllKeys(errSet); - }, "keys required"); - err(function(){ assert.containsAllKeys(errSet, []); }, "keys required"); - err(function(){ - assert.doesNotHaveAllKeys(errSet); - }, "keys required"); - err(function(){ assert.doesNotHaveAllKeys(errSet, []); }, "keys required"); - err(function(){ - assert.hasAnyKeys(errSet); - }, "keys required"); - err(function(){ assert.hasAnyKeys(errSet, []); }, "keys required"); - err(function(){ - assert.doesNotHaveAnyKeys(errSet); - }, "keys required"); - err(function(){ assert.doesNotHaveAnyKeys(errSet, []); }, "keys required"); - } - err(function(){ - assert.hasAllKeys({ foo: 1 }); - }, "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.hasAllKeys({ foo: 1 }, []); - }, "keys required"); + // err(function(){ + // assert.containsAllDeepKeys(new Set([{foo: 1}]), { iDoNotExist: 0 }) + // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); + } err(function(){ - assert.containsAllKeys({ foo: 1 }); + assert.hasAllKeys({ foo: 1 }, []); }, "keys required"); err(function(){ assert.containsAllKeys({ foo: 1 }, []); }, "keys required"); - err(function(){ - assert.doesNotHaveAllKeys({ foo: 1 }); - }, "keys required"); - err(function(){ assert.doesNotHaveAllKeys({ foo: 1 }, []); }, "keys required"); - err(function(){ - assert.hasAnyKeys({ foo: 1 }); - }, "keys required"); - err(function(){ assert.hasAnyKeys({ foo: 1 }, []); }, "keys required"); - err(function(){ - assert.doesNotHaveAnyKeys({ foo: 1 }); - }, "keys required"); - err(function(){ assert.doesNotHaveAnyKeys({ foo: 1 }, []); }, "keys required"); @@ -1023,7 +1047,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 +1058,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(){