From 4f40b3735694cca01264879d98b5f8af65dbf02b Mon Sep 17 00:00:00 2001 From: Gregg Lind Date: Sat, 7 Feb 2015 15:57:03 -0600 Subject: [PATCH] fix #359. Add `.keys(object) - `.keys(object)n => .keys(Object.keys(Object)` - added exceptions for 'if first arg is non-string, then it must be only arg. => `.keys(Array|Object, ...)` Warning: `Object.keys` must exist on systems to use this functionality. --- lib/chai/core/assertions.js | 25 +++++++++---- test/expect.js | 69 ++++++++++++++++++++++++++++++++++-- test/should.js | 70 ++++++++++++++++++++++++++++++++++++- 3 files changed, 155 insertions(+), 9 deletions(-) diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 4a4d2d28f..f2b72ac89 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -992,23 +992,36 @@ module.exports = function (chai, _) { * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo', 7}); * 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}}]); + * * * @name keys * @alias key - * @param {String...|Array} keys + * @param {String...|Array|Object} keys * @api public */ function assertKeys (keys) { var obj = flag(this, 'object') , str - , ok = true; - - keys = keys instanceof Array - ? keys - : Array.prototype.slice.call(arguments); + , ok = true + , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; + + switch (_.type(keys)) { + case "array": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + break; + case "object": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + keys = Object.keys(keys); + break; + default: + keys = Array.prototype.slice.call(arguments); + } if (!keys.length) throw new Error('keys required'); diff --git a/test/expect.js b/test/expect.js index acb02dd07..e1e2f4d8f 100644 --- a/test/expect.js +++ b/test/expect.js @@ -568,13 +568,18 @@ describe('expect', function () { }, "expected [ { a: 1 }, { b: 2 } ] to not include { b: 2 }"); }); - it('keys(array)', function(){ + it('keys(array|Object|arguments)', function(){ expect({ foo: 1 }).to.have.keys(['foo']); + expect({ foo: 1 }).have.keys({ 'foo': 6 }); expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']); expect({ foo: 1, bar: 2 }).to.have.keys('foo', 'bar'); + expect({ foo: 1, bar: 2 }).have.keys({ 'foo': 6, 'bar': 7 }); expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar'); expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('bar', 'foo'); expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('baz'); + expect({ foo: 1, bar: 2 }).contain.keys({ 'foo': 6 }); + expect({ foo: 1, bar: 2 }).contain.keys({ 'bar': 7 }); + expect({ foo: 1, bar: 2 }).contain.keys({ 'foo': 6 }); expect({ foo: 1, bar: 2 }).to.contain.keys('foo'); expect({ foo: 1, bar: 2 }).to.contain.keys('bar', 'foo'); @@ -595,12 +600,17 @@ describe('expect', function () { expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); expect({ foo: 1, bar: 2 }).to.contain.all.keys(['bar', 'foo']); + expect({ foo: 1, bar: 2 }).contain.any.keys({ 'foo': 6 }); + expect({ foo: 1, bar: 2 }).have.all.keys({ 'foo': 6, 'bar': 7 }); + expect({ foo: 1, bar: 2 }).contain.all.keys({ 'bar': 7, 'foo': 6 }); expect({ foo: 1, bar: 2 }).to.not.have.any.keys('baz', 'abc', 'def'); expect({ foo: 1, bar: 2 }).to.not.have.any.keys('baz'); expect({ foo: 1, bar: 2 }).to.not.contain.any.keys('baz'); expect({ foo: 1, bar: 2 }).to.not.have.all.keys(['baz', 'foo']); expect({ foo: 1, bar: 2 }).to.not.contain.all.keys(['baz', 'foo']); + expect({ foo: 1, bar: 2 }).not.have.all.keys({ 'baz': 8, 'foo': 7 }); + expect({ foo: 1, bar: 2 }).not.contain.all.keys({ 'baz': 8, 'foo': 7 }); err(function(){ expect({ foo: 1 }).to.have.keys(); @@ -618,6 +628,16 @@ describe('expect', function () { expect({ foo: 1 }).to.contain.keys([]); }, "keys required"); + var mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments' + + err(function(){ + expect({}).contain.keys(['a'], "b"); + }, mixedArgsMsg); + + err(function(){ + expect({}).contain.keys({ 'a': 1 }, "b"); + }, mixedArgsMsg); + err(function(){ expect({ foo: 1 }).to.have.keys(['bar']); }, "expected { foo: 1 } to have key 'bar'"); @@ -641,7 +661,7 @@ describe('expect', function () { err(function(){ expect({ foo: 1, bar: 2 }).to.not.have.keys(['foo', 'bar']); }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); - + err(function(){ expect({ foo: 1, bar: 2 }).to.have.all.keys('foo'); }, "expected { foo: 1, bar: 2 } to have key 'foo'"); @@ -666,6 +686,51 @@ describe('expect', function () { expect({ foo: 1, bar: 2 }).to.not.have.any.keys(['foo', 'baz']); }, "expected { foo: 1, bar: 2 } to not have keys 'foo', or 'baz'"); + // repeat previous tests with Object as arg. + err(function(){ + expect({ foo: 1 }).have.keys({ 'bar': 1 }); + }, "expected { foo: 1 } to have key 'bar'"); + + err(function(){ + expect({ foo: 1 }).have.keys({ 'bar': 1, 'baz': 1}); + }, "expected { foo: 1 } to have keys 'bar', and 'baz'"); + + err(function(){ + expect({ foo: 1 }).have.keys({ 'foo': 1, 'bar': 1, 'baz': 1}); + }, "expected { foo: 1 } to have keys 'foo', 'bar', and 'baz'"); + + err(function(){ + expect({ foo: 1 }).not.have.keys({ 'foo': 1 }); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + expect({ foo: 1 }).not.have.keys({ 'foo': 1 }); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + expect({ foo: 1, bar: 2 }).not.have.keys({ 'foo': 1, 'bar': 1}); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); + + err(function(){ + expect({ foo: 1 }).not.contain.keys({ 'foo': 1 }); + }, "expected { foo: 1 } to not contain key 'foo'"); + + err(function(){ + expect({ foo: 1 }).contain.keys('foo', 'bar'); + }, "expected { foo: 1 } to contain keys 'foo', and 'bar'"); + + err(function() { + expect({ foo: 1 }).have.any.keys('baz'); + }, "expected { foo: 1 } to have key 'baz'"); + + err(function(){ + expect({ foo: 1, bar: 2 }).not.have.all.keys({ 'foo': 1, 'bar': 1}); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); + + err(function(){ + expect({ foo: 1, bar: 2 }).not.have.any.keys({ 'foo': 1, 'baz': 1}); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', or 'baz'"); + }); it('keys(array) will not mutate array (#359)', function () { diff --git a/test/should.js b/test/should.js index d28861f06..7d96f828b 100644 --- a/test/should.js +++ b/test/should.js @@ -431,10 +431,14 @@ describe('should', function() { }, "expected { a: 1 } to have a property 'b'") }); - it('keys(array)', function(){ + it('keys(array|Object|arguments)', function(){ ({ foo: 1 }).should.have.keys(['foo']); + ({ foo: 1 }).should.have.keys({ 'foo': 6 }); + ({ foo: 1, bar: 2 }).should.have.keys(['foo', 'bar']); ({ foo: 1, bar: 2 }).should.have.keys('foo', 'bar'); + ({ foo: 1, bar: 2 }).should.have.keys({ 'foo': 6, 'bar': 7 }); + ({ foo: 1, bar: 2, baz: 3 }).should.include.keys('foo', 'bar'); ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('bar', 'foo'); ({ foo: 1, bar: 2, baz: 3 }).should.contain.keys('baz'); @@ -444,6 +448,9 @@ describe('should', function() { ({ foo: 1, bar: 2 }).should.contain.keys(['foo']); ({ foo: 1, bar: 2 }).should.contain.keys(['bar']); ({ foo: 1, bar: 2 }).should.contain.keys(['bar', 'foo']); + ({ foo: 1, bar: 2 }).should.contain.keys({ 'foo': 6 }); + ({ foo: 1, bar: 2 }).should.contain.keys({ 'bar': 7 }); + ({ foo: 1, bar: 2 }).should.contain.keys({ 'foo': 6 }); ({ foo: 1, bar: 2 }).should.not.have.keys('baz'); ({ foo: 1, bar: 2 }).should.not.have.keys('foo', 'baz'); @@ -457,12 +464,17 @@ describe('should', function() { ({ foo: 1, bar: 2 }).should.contain.any.keys(['foo']); ({ foo: 1, bar: 2 }).should.have.all.keys(['bar', 'foo']); ({ foo: 1, bar: 2 }).should.contain.all.keys(['bar', 'foo']); + ({ foo: 1, bar: 2 }).should.contain.any.keys({ 'foo': 6 }); + ({ foo: 1, bar: 2 }).should.have.all.keys({ 'foo': 6, 'bar': 7 }); + ({ foo: 1, bar: 2 }).should.contain.all.keys({ 'bar': 7, 'foo': 6 }); ({ foo: 1, bar: 2 }).should.not.have.any.keys('baz', 'abc', 'def'); ({ foo: 1, bar: 2 }).should.not.have.any.keys('baz'); ({ foo: 1, bar: 2 }).should.not.contain.any.keys('baz'); ({ foo: 1, bar: 2 }).should.not.have.all.keys(['baz', 'foo']); ({ foo: 1, bar: 2 }).should.not.contain.all.keys(['baz', 'foo']); + ({ foo: 1, bar: 2 }).should.not.have.all.keys({ 'baz': 8, 'foo': 7 }); + ({ foo: 1, bar: 2 }).should.not.contain.all.keys({ 'baz': 8, 'foo': 7 }); err(function(){ ({ foo: 1 }).should.have.keys(); @@ -480,6 +492,16 @@ describe('should', function() { ({ foo: 1 }).should.contain.keys([]); }, "keys required"); + var mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments' + + err(function(){ + ({}).should.contain.keys(['a'], "b"); + }, mixedArgsMsg); + + err(function(){ + ({}).should.contain.keys({ 'a': 1 }, "b"); + }, mixedArgsMsg); + err(function(){ ({ foo: 1 }).should.have.keys(['bar']); }, "expected { foo: 1 } to have key 'bar'"); @@ -523,6 +545,52 @@ describe('should', function() { err(function(){ ({ foo: 1, bar: 2 }).should.not.have.any.keys(['foo', 'baz']); }, "expected { foo: 1, bar: 2 } to not have keys 'foo', or 'baz'"); + + // repeat previous tests with Object as arg. + err(function(){ + ({ foo: 1 }).should.have.keys({ 'bar': 1 }); + }, "expected { foo: 1 } to have key 'bar'"); + + err(function(){ + ({ foo: 1 }).should.have.keys({ 'bar': 1, 'baz': 1}); + }, "expected { foo: 1 } to have keys 'bar', and 'baz'"); + + err(function(){ + ({ foo: 1 }).should.have.keys({ 'foo': 1, 'bar': 1, 'baz': 1}); + }, "expected { foo: 1 } to have keys 'foo', 'bar', and 'baz'"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys({ 'foo': 1 }); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + ({ foo: 1 }).should.not.have.keys({ 'foo': 1 }); + }, "expected { foo: 1 } to not have key 'foo'"); + + err(function(){ + ({ foo: 1, bar: 2 }).should.not.have.keys({ 'foo': 1, 'bar': 1}); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); + + err(function(){ + ({ foo: 1 }).should.not.contain.keys({ 'foo': 1 }); + }, "expected { foo: 1 } to not contain key 'foo'"); + + err(function(){ + ({ foo: 1 }).should.contain.keys('foo', 'bar'); + }, "expected { foo: 1 } to contain keys 'foo', and 'bar'"); + + err(function() { + ({ foo: 1 }).should.have.any.keys('baz'); + }, "expected { foo: 1 } to have key 'baz'"); + + err(function(){ + ({ foo: 1, bar: 2 }).should.not.have.all.keys({ 'foo': 1, 'bar': 1}); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', and 'bar'"); + + err(function(){ + ({ foo: 1, bar: 2 }).should.not.have.any.keys({ 'foo': 1, 'baz': 1}); + }, "expected { foo: 1, bar: 2 } to not have keys 'foo', or 'baz'"); + }); it('keys(array) will not mutate array (#359)', function () {