Skip to content

Commit

Permalink
Breaking: Change .not.property(name, val) behavior
Browse files Browse the repository at this point in the history
- Previously, `expect(obj).not.property(name, val)` would throw an Error
if `obj` didn't have a property named `name`. This change causes the
assertion to pass instead.
- assert.propertyNotVal renamed to assert.notPropertyVal
- assert.deepPropertyNotVal renamed to assert.notDeepPropertyVal
  • Loading branch information
meeber committed Jul 24, 2016
1 parent 43a64c4 commit 576489a
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 35 deletions.
17 changes: 10 additions & 7 deletions lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,9 @@ module.exports = function (chai, _) {
* var obj = { foo: 'bar' };
* expect(obj).to.have.property('foo');
* expect(obj).to.have.property('foo', 'bar');
* expect(obj).to.not.have.property('baz');
* expect(obj).to.not.have.property('foo', 'baz');
* expect(obj).to.not.have.property('baz', 'bar');
*
* // deep referencing
* var deepObj = {
Expand Down Expand Up @@ -910,12 +913,12 @@ module.exports = function (chai, _) {
? pathInfo.value
: obj[name];

if (negate && arguments.length > 1) {
if (undefined === value) {
msg = (msg != null) ? msg + ': ' : '';
throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));
}
} else {
// When performing a negated assertion for both name and val, merely having
// a property with the given name isn't enough to cause the assertion to
// fail. It must both have a property with the given name, and the value of
// that property must equal the given val. Therefore, skip this assertion in
// favor of the next.
if (!negate || arguments.length === 1) {
this.assert(
hasProperty
, 'expected #{this} to have a ' + descriptor + _.inspect(name)
Expand All @@ -924,7 +927,7 @@ module.exports = function (chai, _) {

if (arguments.length > 1) {
this.assert(
val === value
hasProperty && val === value
, 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
, 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'
, val
Expand Down
28 changes: 15 additions & 13 deletions lib/chai/interface/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -1003,14 +1003,15 @@ module.exports = function (chai, util) {
};

/**
* ### .propertyNotVal(object, property, value, [message])
* ### .notPropertyVal(object, property, value, [message])
*
* Asserts that `object` has a property named by `property`, but with a value
* different from that given by `value`.
* Asserts that `object` does _not_ have a property named by `property` with
* value given by `value`.
*
* assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad');
* assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad');
* assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good');
*
* @name propertyNotVal
* @name notPropertyVal
* @param {Object} object
* @param {String} property
* @param {Mixed} value
Expand All @@ -1019,7 +1020,7 @@ module.exports = function (chai, util) {
* @api public
*/

assert.propertyNotVal = function (obj, prop, val, msg) {
assert.notPropertyVal = function (obj, prop, val, msg) {
new Assertion(obj, msg).to.not.have.property(prop, val);
};

Expand All @@ -1046,15 +1047,16 @@ module.exports = function (chai, util) {
};

/**
* ### .deepPropertyNotVal(object, property, value, [message])
* ### .notDeepPropertyVal(object, property, value, [message])
*
* Asserts that `object` has a property named by `property`, but with a value
* different from that given by `value`. `property` can use dot- and
* bracket-notation for deep reference.
* Asserts that `object` does _not_ have a property named by `property` with
* value given by `value`. `property` can use dot- and bracket-notation for deep
* reference.
*
* assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');
* assert.notDeepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');
* assert.notDeepPropertyVal({ tea: { green: 'matcha' }}, 'coffee.green', 'matcha');
*
* @name deepPropertyNotVal
* @name notDeepPropertyVal
* @param {Object} object
* @param {String} property
* @param {Mixed} value
Expand All @@ -1063,7 +1065,7 @@ module.exports = function (chai, util) {
* @api public
*/

assert.deepPropertyNotVal = function (obj, prop, val, msg) {
assert.notDeepPropertyVal = function (obj, prop, val, msg) {
new Assertion(obj, msg).to.not.have.deep.property(prop, val);
};

Expand Down
9 changes: 6 additions & 3 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -945,9 +945,12 @@ describe('assert', function () {
assert.deepProperty(obj, 'foo.bar');
assert.notProperty(obj, 'baz');
assert.notProperty(obj, 'foo.bar');
assert.notPropertyVal(simpleObj, 'foo', 'flow');
assert.notPropertyVal(simpleObj, 'flow', 'bar');
assert.notDeepProperty(obj, 'foo.baz');
assert.deepPropertyVal(obj, 'foo.bar', 'baz');
assert.deepPropertyNotVal(obj, 'foo.bar', 'flow');
assert.notDeepPropertyVal(obj, 'foo.bar', 'flow');
assert.notDeepPropertyVal(obj, 'foo.flow', 'baz');

err(function () {
assert.property(obj, 'baz');
Expand Down Expand Up @@ -978,11 +981,11 @@ describe('assert', function () {
}, "expected { foo: { bar: 'baz' } } to have a deep property 'foo.bar' of 'ball', but got 'baz'");

err(function () {
assert.propertyNotVal(simpleObj, 'foo', 'bar');
assert.notPropertyVal(simpleObj, 'foo', 'bar');
}, "expected { foo: 'bar' } to not have a property 'foo' of 'bar'");

err(function () {
assert.deepPropertyNotVal(obj, 'foo.bar', 'baz');
assert.notDeepPropertyVal(obj, 'foo.bar', 'baz');
}, "expected { foo: { bar: 'baz' } } to not have a deep property 'foo.bar' of 'baz'");
});

Expand Down
14 changes: 6 additions & 8 deletions test/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ describe('expect', function () {
it('property(name, val)', function(){
expect('test').to.have.property('length', 4);
expect('asd').to.have.property('constructor', String);
expect('test').to.not.have.property('length', 3);
expect('test').to.not.have.property('foo', 4);

var deepObj = {
green: { tea: 'matcha' }
Expand Down Expand Up @@ -582,10 +584,6 @@ describe('expect', function () {
expect('asd').to.not.have.property('length', 3, 'blah');
}, "blah: expected 'asd' to not have a property 'length' of 3");

err(function(){
expect('asd').to.not.have.property('foo', 3, 'blah');
}, "blah: 'asd' has no property 'foo'");

err(function(){
expect('asd').to.have.property('constructor', Number, 'blah');
}, "blah: expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]");
Expand All @@ -594,6 +592,10 @@ describe('expect', function () {
it('deep.property(name, val)', function(){
expect({ foo: { bar: 'baz' } })
.to.have.deep.property('foo.bar', 'baz');
expect({ foo: { bar: 'baz' } })
.to.not.have.deep.property('foo.bar', 'quux');
expect({ foo: { bar: 'baz' } })
.to.not.have.deep.property('foo.quux', 'baz');

err(function(){
expect({ foo: { bar: 'baz' } })
Expand All @@ -603,10 +605,6 @@ describe('expect', function () {
expect({ foo: { bar: 'baz' } })
.to.not.have.deep.property('foo.bar', 'baz', 'blah');
}, "blah: expected { foo: { bar: 'baz' } } to not have a deep property 'foo.bar' of 'baz'");
err(function(){
expect({ foo: 5 })
.to.not.have.deep.property('foo.bar', 'baz', 'blah');
}, "blah: { foo: 5 } has no deep property 'foo.bar'");
});

it('ownProperty(name)', function(){
Expand Down
32 changes: 28 additions & 4 deletions test/should.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,10 +438,25 @@ describe('should', function() {
}, "expected 'asd' to have a property 'foo'");
});

it('deep.property(name)', function(){
({ 'foo.bar': 'baz'}).should.not.have.deep.property('foo.bar');
({ foo: { bar: 'baz' } }).should.have.deep.property('foo.bar');

({ 'foo': [1, 2, 3] }).should.have.deep.property('foo[1]');

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

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

it('property(name, val)', function(){
'test'.should.have.property('length', 4);
'asd'.should.have.property('constructor', String);
({ 1: 1 }).should.have.property(1, 1);
'test'.should.not.have.property('length', 3);
'test'.should.not.have.property('foo', 4);

err(function(){
'asd'.should.have.property('length', 4, 'blah');
Expand All @@ -451,15 +466,24 @@ describe('should', function() {
'asd'.should.not.have.property('length', 3, 'blah');
}, "blah: expected 'asd' to not have a property 'length' of 3");

err(function(){
'asd'.should.not.have.property('foo', 3, 'blah');
}, "blah: 'asd' has no property 'foo'");

err(function(){
'asd'.should.have.property('constructor', Number, 'blah');
}, "blah: expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]");
});

it('deep.property(name, val)', function(){
({ foo: { bar: 'baz' } }).should.have.deep.property('foo.bar', 'baz');
({ foo: { bar: 'baz' } }).should.not.have.deep.property('foo.bar', 'quux');
({ foo: { bar: 'baz' } }).should.not.have.deep.property('foo.quux', 'baz');

err(function(){
({ foo: { bar: 'baz' } }).should.have.deep.property('foo.bar', 'quux', 'blah');
}, "blah: expected { foo: { bar: 'baz' } } to have a deep property 'foo.bar' of 'quux', but got 'baz'");
err(function(){
({ foo: { bar: 'baz' } }).should.not.have.deep.property('foo.bar', 'baz', 'blah');
}, "blah: expected { foo: { bar: 'baz' } } to not have a deep property 'foo.bar' of 'baz'");
});

it('ownProperty(name)', function(){
'test'.should.have.ownProperty('length');
'test'.should.haveOwnProperty('length');
Expand Down

0 comments on commit 576489a

Please sign in to comment.