diff --git a/lib/chai/core/assertions.js b/lib/chai/core/assertions.js index 6d897dcb..dce28e31 100644 --- a/lib/chai/core/assertions.js +++ b/lib/chai/core/assertions.js @@ -2524,21 +2524,23 @@ function assertKeys(keys) { }); } - if (!keys.length) { - throw new AssertionError(flagMsg + 'keys required', undefined, ssfi); - } - let len = keys.length, any = flag(this, 'any'), all = flag(this, 'all'), expected = keys, - isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2; + isEql = isDeep ? flag(this, 'eql') : (val1, val2) => val1 === val2, + contains = flag(this, 'contains'); if (!any && !all) { all = true; } const uniqueExpected = [...new Set(expected)]; + const canHaveEmptyKeys = all && !contains && keysType !== 'undefined'; + + if (!keys.length && !canHaveEmptyKeys) { + throw new AssertionError(flagMsg + 'keys required', undefined, ssfi); + } // Has any if (any) { @@ -2557,7 +2559,7 @@ function assertKeys(keys) { }); }); - if (!flag(this, 'contains')) { + if (!contains) { ok = ok && uniqueExpected.length == actual.length; } } diff --git a/test/assert.js b/test/assert.js index 1755429f..108d8054 100644 --- a/test/assert.js +++ b/test/assert.js @@ -1195,18 +1195,10 @@ describe('assert', function () { errMap.set({1: 20}, 'number'); - err(function(){ - assert.hasAllKeys(errMap, [], 'blah'); - }, "blah: keys required"); - err(function(){ assert.containsAllKeys(errMap, [], 'blah'); }, "blah: keys required"); - err(function(){ - assert.doesNotHaveAllKeys(errMap, [], 'blah'); - }, "blah: keys required"); - err(function(){ assert.hasAnyKeys(errMap, [], 'blah'); }, "blah: keys required"); @@ -1310,18 +1302,10 @@ describe('assert', function () { errSet.add({1: 20}); errSet.add('number'); - err(function(){ - assert.hasAllKeys(errSet, [], 'blah'); - }, "blah: keys required"); - err(function(){ assert.containsAllKeys(errSet, [], 'blah'); }, "blah: keys required"); - err(function(){ - assert.doesNotHaveAllKeys(errSet, [], 'blah'); - }, "blah: keys required"); - err(function(){ assert.hasAnyKeys(errSet, [], 'blah'); }, "blah: keys required"); @@ -1340,18 +1324,10 @@ describe('assert', function () { // assert.containsAllDeepKeys(new Set([{foo: 1}]), { iDoNotExist: 0 }) // }, 'expected [ { foo: 1 } ] to deeply contain key { iDoNotExist: 0 }'); - err(function(){ - assert.hasAllKeys({ foo: 1 }, [], 'blah'); - }, "blah: keys required"); - err(function(){ assert.containsAllKeys({ foo: 1 }, [], 'blah'); }, "blah: keys required"); - err(function(){ - assert.doesNotHaveAllKeys({ foo: 1 }, [], 'blah'); - }, "blah: keys required"); - err(function(){ assert.hasAnyKeys({ foo: 1 }, [], 'blah'); }, "blah: keys required"); @@ -1438,6 +1414,10 @@ describe('assert', function () { }, "blah: expected { foo: 1, bar: 2 } to not have keys 'foo', or 'baz'"); }); + it('keys() with empty keys and non-contains', () => { + assert.hasAllKeys({}, []); + }); + it('lengthOf', function() { assert.lengthOf([1,2,3], 3); assert.lengthOf('foobar', 6); diff --git a/test/expect.js b/test/expect.js index 4f1a4335..beb84b18 100644 --- a/test/expect.js +++ b/test/expect.js @@ -2750,10 +2750,6 @@ describe('expect', function () { expect(errMap, 'blah').to.have.keys(); }, "blah: keys required"); - err(function(){ - expect(errMap).to.have.keys([]); - }, "keys required"); - err(function(){ expect(errMap).to.contain.keys(); }, "keys required"); @@ -2876,10 +2872,6 @@ describe('expect', function () { expect(errSet, 'blah').to.have.keys(); }, "blah: keys required"); - err(function(){ - expect(errSet).to.have.keys([]); - }, "keys required"); - err(function(){ expect(errSet).to.contain.keys(); }, "keys required"); @@ -2902,14 +2894,6 @@ describe('expect', function () { expect({ foo: 1 }, 'blah').to.have.keys(); }, "blah: keys required"); - err(function(){ - expect({ foo: 1 }).to.have.keys([]); - }, "keys required"); - - err(function(){ - expect({ foo: 1 }).to.not.have.keys([]); - }, "keys required"); - err(function(){ expect({ foo: 1 }).to.contain.keys([]); }, "keys required"); @@ -3019,6 +3003,23 @@ describe('expect', function () { }); + it('should accept empty keys if all and not contains', function () { + expect({}).to.have.all.keys([]); + err(() => { + expect({ a: 1 }).to.have.all.keys([]); + }); + }); + + it('should throw if empty keys with any or contains', function () { + err(() => { + expect({}).to.have.any.keys([]); + }, 'keys required'); + + err(() => { + expect({}).to.contain.keys([]); + }, 'keys required'); + }); + it('keys(array) will not mutate array (#359)', function () { var expected = [ 'b', 'a' ]; var original_order = [ 'b', 'a' ]; diff --git a/test/should.js b/test/should.js index 44aba076..f835dea7 100644 --- a/test/should.js +++ b/test/should.js @@ -2247,10 +2247,6 @@ describe('should', function() { errMap.should.have.keys(); }, "keys required"); - err(function(){ - errMap.should.have.keys([]); - }, "keys required"); - err(function(){ errMap.should.contain.keys(); }, "keys required"); @@ -2374,10 +2370,6 @@ describe('should', function() { errSet.should.have.keys(); }, "keys required"); - err(function(){ - errSet.should.have.keys([]); - }, "keys required"); - err(function(){ errSet.should.contain.keys(); }, "keys required"); @@ -2398,14 +2390,6 @@ describe('should', function() { ({ foo: 1 }).should.have.keys(); }, "keys required"); - err(function(){ - ({ foo: 1 }).should.have.keys([]); - }, "keys required"); - - err(function(){ - ({ foo: 1 }).should.not.have.keys([]); - }, "keys required"); - err(function(){ ({ foo: 1 }).should.contain.keys([]); }, "keys required"); @@ -2511,6 +2495,10 @@ describe('should', function() { }); + it('keys() with empty keys and non-contains', () => { + ({}).should.have.keys([]); + }); + it('keys(array) will not mutate array (#359)', function () { var expected = [ 'b', 'a' ]; var original_order = [ 'b', 'a' ];