Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

property assertion should only accept strings if nested, fixes #1043 #1044

Merged
merged 10 commits into from Oct 2, 2017
25 changes: 22 additions & 3 deletions lib/chai/core/assertions.js
Expand Up @@ -1763,10 +1763,30 @@ module.exports = function (chai, _) {
, isOwn = flag(this, 'own')
, flagMsg = flag(this, 'message')
, obj = flag(this, 'object')
, ssfi = flag(this, 'ssfi');
, ssfi = flag(this, 'ssfi')
, nameType = typeof name;

flagMsg = flagMsg ? flagMsg + ': ' : '';

if (isNested) {
if (nameType !== 'string') {
throw new AssertionError(
flagMsg + 'the argument to property must be a string when using nested syntax',
undefined,
ssfi
);
}
} else {
if (nameType !== 'string' && nameType !== 'number' && nameType !== 'symbol') {
throw new AssertionError(
flagMsg + 'the argument to property must be a string, number, or symbol',
undefined,
ssfi
);
}
}

if (isNested && isOwn) {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'The "nested" and "own" flags cannot be combined.',
undefined,
Expand All @@ -1775,7 +1795,6 @@ module.exports = function (chai, _) {
}

if (obj === null || obj === undefined) {
flagMsg = flagMsg ? flagMsg + ': ' : '';
throw new AssertionError(
flagMsg + 'Target cannot be null or undefined.',
undefined,
Expand Down
9 changes: 9 additions & 0 deletions test/assert.js
Expand Up @@ -1395,6 +1395,7 @@ describe('assert', function () {
var obj = { foo: { bar: 'baz' } };
var simpleObj = { foo: 'bar' };
var undefinedKeyObj = { foo: undefined };
var dummyObj = { a: '1' };
assert.property(obj, 'foo');
assert.property(obj, 'toString');
assert.propertyVal(obj, 'toString', Object.prototype.toString);
Expand Down Expand Up @@ -1454,6 +1455,14 @@ describe('assert', function () {
err(function () {
assert.property(undefined, 'a', 'blah');
}, "blah: Target cannot be null or undefined.");

err(function () {
assert.propertyVal(dummyObj, 'a', '2', 'blah');
}, "blah: expected { a: '1' } to have property 'a' of '2', but got '1'");

err(function () {
assert.nestedProperty({a:1}, {'a':'1'}, 'blah');
}, 'blah: the argument to property must be a string when using nested syntax');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more test should be added here to the assert interface tests in order to verify the error message "the argument to property must be a string, number, or symbol". This test can closely resemble the expect({a:1}).to.have.property(null); test that you added on the expect interface, except using the assert interface instead of expect. (And using the err helper function, just like you've done in the previous two tests on the assert interface).

});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are using chai.expect on line 18 too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's shouldn't be wrong to use expect in this test, because here we are actually using chai to assert, we are not calling assertions and expecting them to work, we are testing that the assertion throws.

But I agree with @meeber that we must try and be able to use own interface to test it.

You can replace the ones you added on this PR with assert.throws and assert.doesNotThrows and maybe remove the others in another PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure @vieiralucas . I have replaced them and also surely will open a seperate PR in future to replace the remaining.

it('deepPropertyVal', function () {
Expand Down
8 changes: 8 additions & 0 deletions test/expect.js
Expand Up @@ -1462,6 +1462,10 @@ describe('expect', function () {
err(function () {
expect(undefined, 'blah').to.have.property("a");
}, "blah: Target cannot be null or undefined.");

expect(function () {
expect({a:1}).to.have.property(null);
}).to.throw('the argument to property must be a string, number, or symbol');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use the err helper function, just like the test above it.

});

it('property(name, val)', function(){
Expand Down Expand Up @@ -1755,6 +1759,10 @@ describe('expect', function () {
expect({ 'foo.bar': 'baz' })
.to.have.nested.property('foo.bar');
}, "expected { 'foo.bar': 'baz' } to have nested property 'foo.bar'");

expect(function () {
expect({a:1}).to.have.nested.property({'a':'1'});
}).to.throw('the argument to property must be a string when using nested syntax');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use the err helper function.

});

it('nested.property(name, val)', function(){
Expand Down
10 changes: 10 additions & 0 deletions test/should.js
Expand Up @@ -1407,6 +1407,16 @@ describe('should', function() {

({ 'foo.bar[]': 'baz'}).should.have.nested.property('foo\\.bar\\[\\]');

({a:1}).should.have.nested.property('a');

(function () {
({a:1}).should.have.nested.property('{a:1}');
}).should.not.throw('the argument to property must be a string when using nested syntax');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this test. We already test that .nested.property works properly elsewhere in the suite. Adding this test with ".should.not.throw` doesn't add any value.


(function () {
({a:1}).should.have.nested.property({'a':'1'});
}).should.throw('the argument to property must be a string when using nested syntax');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use the err helper function, just like the test below it.


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more test should be added here to the should interface tests in order to verify the error message "the argument to property must be a string, number, or symbol". This test can closely resemble the expect({a:1}).to.have.property(null); test that you added on the expect interface, except using the should interface this time instead of expect. (And using the err helper function).

err(function(){
({ 'foo.bar': 'baz' }).should.have.nested.property('foo.bar');
}, "expected { 'foo.bar': 'baz' } to have nested property 'foo.bar'");
Expand Down