Skip to content

Commit

Permalink
Merge pull request #641 from lucasfcosta/ownProperty-changes-target
Browse files Browse the repository at this point in the history
[WIP] Assertion subject (obj) changes when using ownProperty assertion
  • Loading branch information
keithamus committed Mar 15, 2016
2 parents ec8d99f + 728e04e commit 6b11cc5
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 12 deletions.
48 changes: 40 additions & 8 deletions lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -880,27 +880,59 @@ module.exports = function (chai, _) {


/**
* ### .ownProperty(name)
* ### .ownProperty(name, [value])
*
* Asserts that the target has an own property `name`.
* Asserts that the target has an own property `name` and, optionally, if it has
* (or not, if using `.not`) the desired `value`.
*
* expect('test').to.have.ownProperty('length');
* expect('test').to.haveOwnProperty('length');
* expect('test').to.not.have.ownProperty('foo');
* expect('test').to.not.haveOwnProperty('foo');
* expect({ length: 12 }).to.have.ownProperty('length', 12);
* expect({ length: 1337 }).to.not.have.ownProperty('length', 20);
* expect({ length: 12 }).to.haveOwnProperty('length', 12);
* expect({ length: 1337 }).to.not.haveOwnProperty('length', 20);
*
* @name ownProperty
* @alias haveOwnProperty
* @param {String} name
* @param {Mixed} value (optional)
* @param {String} message _optional_
* @namespace BDD
* @api public
*/

function assertOwnProperty (name, msg) {
function assertOwnProperty (name, value, msg) {
if (msg) flag(this, 'message', msg);
var obj = flag(this, 'object');
this.assert(
obj.hasOwnProperty(name)
, 'expected #{this} to have own property ' + _.inspect(name)
, 'expected #{this} to not have own property ' + _.inspect(name)
);
var negate = flag(this, 'negate');
var objHasProperty = obj.hasOwnProperty(name);
var actualValue = obj[name];

if (negate && value !== undefined) {
if (actualValue === undefined) {
throw new Error(_.inspect(obj) + ' does not have own property ' + _.inspect(name));
}
} else {
this.assert(
objHasProperty
, 'expected #{this} to have own property ' + _.inspect(name)
, 'expected #{this} to not have own property ' + _.inspect(name)
);
}

if (value !== undefined) {
this.assert(
actualValue === value
, 'expected #{this} to have own property ' + _.inspect(name) + ' of #{exp}, but got #{act}'
, 'expected #{this} to not have own property ' + _.inspect(name) + ' of #{act}'
, value
, actualValue
);
}

flag(this, 'object', actualValue);
}

Assertion.addMethod('ownProperty', assertOwnProperty);
Expand Down
76 changes: 76 additions & 0 deletions lib/chai/interface/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,82 @@ module.exports = function (chai, util) {
new Assertion(obj, msg).to.not.have.deep.property(prop, val);
};

/**
* ### .ownProperty(object, property, [message])
*
* Asserts that `object` has an own property named by `property`.
*
* assert.ownProperty({ tea: { green: 'matcha' }}, 'tea');
*
* @name ownProperty
* @param {Object} object
* @param {String} property
* @param {String} message
* @api public
*/

assert.ownProperty = function (obj, prop, msg) {
new Assertion(obj, msg).to.have.ownProperty(prop);
};

/**
* ### .notOwnProperty(object, property, [message])
*
* Asserts that `object` does not have an own property named by `property`.
*
* assert.notOwnProperty({ tea: { green: 'matcha' }}, 'coffee');
*
* @name notOwnProperty
* @param {Object} object
* @param {String} property
* @param {String} message
* @api public
*/

assert.notOwnProperty = function (obj, prop, msg) {
new Assertion(obj, msg).to.not.have.ownProperty(prop);
};

/**
* ### .ownPropertyVal(object, property, value, [message])
*
* Asserts that `object` has an own property named by `property` and a value
* equal to the provided `value`.
*
* assert.ownPropertyVal({ coffee: 'is good'}, 'coffee', 'is good');
*
* @name ownPropertyVal
* @param {Object} object
* @param {String} property
* @param {Mixed} value
* @param {String} message
* @api public
*/

assert.ownPropertyVal = function (obj, prop, value, msg) {
new Assertion(obj, msg).to.have.ownProperty(prop, value);
};

/**
* ### .notOwnPropertyVal(object, property, value, [message])
*
* Asserts that `object` has an own property named by `property`, but with a value
* different from that given by `value`.
*
* assert.notOwnPropertyVal({ tea: 'is better'}, 'tea', 'is worse');
*
* @name notOwnPropertyVal
* @param {Object} object
* @param {String} property
* @param {Mixed} value
* @param {String} message
* @api public
*/

assert.notOwnPropertyVal = function (obj, prop, value, msg) {
new Assertion(obj, msg).to.not.have.ownProperty(prop, value);
};

/**
* ### .lengthOf(object, length, [message])
*
Expand Down
47 changes: 47 additions & 0 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,53 @@ describe('assert', function () {
}, "expected { foo: { bar: 'baz' } } to not have a deep property 'foo.bar' of 'baz'");
});

it('ownProperty', function() {
var coffeeObj = { coffee: 'is good' };

// This has length = 17
var teaObj = 'but tea is better';

assert.ownProperty(coffeeObj, 'coffee');
assert.ownProperty(teaObj, 'length');

assert.ownPropertyVal(coffeeObj, 'coffee', 'is good');
assert.ownPropertyVal(teaObj, 'length', 17);

assert.notOwnProperty(coffeeObj, 'length');
assert.notOwnProperty(teaObj, 'calories');

assert.notOwnPropertyVal(coffeeObj, 'coffee', 'is bad');
assert.notOwnPropertyVal(teaObj, 'length', 1);

err(function () {
assert.ownProperty(coffeeObj, 'calories');
}, "expected { coffee: 'is good' } to have own property 'calories'");

err(function () {
assert.notOwnProperty(coffeeObj, 'coffee');
}, "expected { coffee: 'is good' } to not have own property 'coffee'");

err(function () {
assert.ownPropertyVal(teaObj, 'length', 1);
}, "expected 'but tea is better' to have own property 'length' of 1, but got 17");

err(function () {
assert.notOwnPropertyVal(teaObj, 'length', 17);
}, "expected 'but tea is better' to not have own property 'length' of 17");

err(function () {
assert.ownPropertyVal(teaObj, 'calories', 17);
}, "expected 'but tea is better' to have own property 'calories'");

err(function () {
assert.ownPropertyVal(teaObj, 'calories', 17);
}, "expected 'but tea is better' to have own property 'calories'");

err(function () {
assert.notOwnPropertyVal(coffeeObj, 'sugar', 1337);
}, "{ coffee: 'is good' } does not have own property 'sugar'");
});

it('throws / throw / Throw', function() {
['throws', 'throw', 'Throw'].forEach(function (throws) {
assert[throws](function() { throw new Error('foo'); });
Expand Down
74 changes: 72 additions & 2 deletions test/expect.js
Original file line number Diff line number Diff line change
Expand Up @@ -593,11 +593,81 @@ describe('expect', function () {
it('ownProperty(name)', function(){
expect('test').to.have.ownProperty('length');
expect('test').to.haveOwnProperty('length');
expect('test').to.not.have.ownProperty('iDontExist');
expect('test').to.not.haveOwnProperty('iDontExist');

expect({ length: 12 }).to.have.ownProperty('length');
expect({ length: 12 }).to.haveOwnProperty('length');
expect({ length: 12 }).to.not.have.ownProperty('iDontExist');
expect({ length: 12 }).to.not.haveOwnProperty('iDontExist');

// Chaining property's value
expect('test').to.have.ownProperty('length').that.is.a('number');
expect('test').to.haveOwnProperty('length').that.is.a('number');

err(function(){
expect({ length: 12 }).to.have.ownProperty('iDontExist');
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function(){
expect({ length: 12 }).to.not.have.ownProperty('length');
}, "expected { length: 12 } to not have own property 'length'");

err(function(){
expect({ length: 12 }).to.haveOwnProperty('iDontExist');
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function(){
expect({ length: 12 }).to.not.haveOwnProperty('length');
}, "expected { length: 12 } to not have own property 'length'");
});

it('ownProperty(name, value)', function(){
expect('test').to.have.ownProperty('length', 4);
expect('test').to.haveOwnProperty('length', 4);
expect('test').to.not.have.ownProperty('length', 1337);
expect('test').to.not.haveOwnProperty('length', 1337);

expect({ length: 12 }).to.have.ownProperty('length', 12);
expect({ length: 12 }).to.haveOwnProperty('length', 12);
expect({ length: 12 }).to.not.have.ownProperty('length', 15);
expect({ length: 12 }).to.not.haveOwnProperty('length', 15);

// Chaining property's value
expect('test').to.have.ownProperty('length', 4).that.is.a('number');
expect('test').to.haveOwnProperty('length', 4).that.is.a('number');

err(function(){
expect({ length: 12 }).to.not.have.ownProperty('length', 'blah');
}, "blah: expected { length: 12 } to not have own property 'length'");
expect({ length: 12 }).to.have.ownProperty('iDontExist', 12);
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function() {
expect({ length: 12 }).to.not.have.ownProperty('length', 12);
}, "expected { length: 12 } to not have own property 'length' of 12");

err(function() {
expect({ length: 12 }).to.have.ownProperty('length', 15);
}, "expected { length: 12 } to have own property 'length' of 15, but got 12");

err(function() {
expect({ length: 12 }).to.not.have.ownProperty('iDontExist', 15);
}, "{ length: 12 } does not have own property 'iDontExist'");

err(function(){
expect({ length: 12 }).to.haveOwnProperty('iDontExist', 12);
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function() {
expect({ length: 12 }).to.not.haveOwnProperty('length', 12);
}, "expected { length: 12 } to not have own property 'length' of 12");

err(function() {
expect({ length: 12 }).to.haveOwnProperty('length', 15);
}, "expected { length: 12 } to have own property 'length' of 15, but got 12");

err(function() {
expect({ length: 12 }).to.not.haveOwnProperty('iDontExist', 15);
}, "{ length: 12 } does not have own property 'iDontExist'");
});

it('ownPropertyDescriptor(name)', function(){
Expand Down
74 changes: 72 additions & 2 deletions test/should.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,81 @@ describe('should', function() {
it('ownProperty(name)', function(){
'test'.should.have.ownProperty('length');
'test'.should.haveOwnProperty('length');
'test'.should.not.have.ownProperty('iDontExist');
'test'.should.not.haveOwnProperty('iDontExist');

({ length: 12 }).should.have.ownProperty('length');
({ length: 12 }).should.haveOwnProperty('length');
({ length: 12 }).should.not.have.ownProperty('iDontExist');
({ length: 12 }).should.not.haveOwnProperty('iDontExist');

// Chaining property's value
'test'.should.have.ownProperty('length').that.is.a('number');
'test'.should.haveOwnProperty('length').that.is.a('number');

err(function(){
({ length: 12 }).should.have.ownProperty('iDontExist');
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function(){
({ length: 12 }).should.not.have.ownProperty('length');
}, "expected { length: 12 } to not have own property 'length'");

err(function(){
({ length: 12 }).should.haveOwnProperty('iDontExist');
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function(){
({ length: 12 }).should.not.haveOwnProperty('length');
}, "expected { length: 12 } to not have own property 'length'");
});

it('ownProperty(name, value)', function(){
'test'.should.have.ownProperty('length', 4);
'test'.should.haveOwnProperty('length', 4);
'test'.should.not.have.ownProperty('length', 1337);
'test'.should.not.haveOwnProperty('length', 1337);

({ length: 12 }).should.have.ownProperty('length', 12);
({ length: 12 }).should.haveOwnProperty('length', 12);
({ length: 12 }).should.not.have.ownProperty('length', 15);
({ length: 12 }).should.not.haveOwnProperty('length', 15);

// Chaining property's value
'test'.should.have.ownProperty('length', 4).that.is.a('number');
'test'.should.haveOwnProperty('length', 4).that.is.a('number');

err(function(){
({ length: 12 }).should.not.have.ownProperty('length', 'blah');
}, "blah: expected { length: 12 } to not have own property 'length'");
({ length: 12 }).should.have.ownProperty('iDontExist', 12);
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function() {
({ length: 12 }).should.not.have.ownProperty('length', 12);
}, "expected { length: 12 } to not have own property 'length' of 12");

err(function() {
({ length: 12 }).should.have.ownProperty('length', 15);
}, "expected { length: 12 } to have own property 'length' of 15, but got 12");

err(function() {
({ length: 12 }).should.not.have.ownProperty('iDontExist', 15);
}, "{ length: 12 } does not have own property 'iDontExist'");

err(function(){
({ length: 12 }).should.haveOwnProperty('iDontExist', 12);
}, "expected { length: 12 } to have own property 'iDontExist'");

err(function() {
({ length: 12 }).should.not.haveOwnProperty('length', 12);
}, "expected { length: 12 } to not have own property 'length' of 12");

err(function() {
({ length: 12 }).should.haveOwnProperty('length', 15);
}, "expected { length: 12 } to have own property 'length' of 15, but got 12");

err(function() {
({ length: 12 }).should.not.haveOwnProperty('iDontExist', 15);
}, "{ length: 12 } does not have own property 'iDontExist'");
});

it('ownPropertyDescriptor(name)', function(){
Expand Down

0 comments on commit 6b11cc5

Please sign in to comment.