Skip to content

Commit

Permalink
Merge pull request #757 from meeber/nested-property
Browse files Browse the repository at this point in the history
Breaking: Rename `.deep.property` to `.nested.property`
  • Loading branch information
lucasfcosta committed Aug 14, 2016
2 parents 77ba5eb + 92768fd commit d4e8a4a
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 124 deletions.
77 changes: 44 additions & 33 deletions lib/chai/core/assertions.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,26 +70,40 @@ module.exports = function (chai, _) {
/**
* ### .deep
*
* Sets the `deep` flag, later used by the `equal` and
* `property` assertions.
* Sets the `deep` flag, later used by the `equal` assertion.
*
* expect(foo).to.deep.equal({ bar: 'baz' });
*
* @name deep
* @namespace BDD
* @api public
*/

Assertion.addProperty('deep', function () {
flag(this, 'deep', true);
});

/**
* ### .nested
*
* Sets the `nested` flag, later used by the `property` assertion.
*
* expect({ foo: { bar: { baz: 'quux' } } })
* .to.have.deep.property('foo.bar.baz', 'quux');
* .to.have.nested.property('foo.bar.baz', 'quux');
*
* `.deep.property` special characters can be escaped
* by adding two slashes before the `.` or `[]`.
* `.nested.property` special characters can be escaped by adding two slashes
* before the `.` or `[]`.
*
* var deepCss = { '.link': { '[target]': 42 }};
* expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42);
* expect(deepCss).to.have.nested.property('\\.link.\\[target\\]', 42);
*
* @name deep
* @name nested
* @namespace BDD
* @api public
*/

Assertion.addProperty('deep', function () {
flag(this, 'deep', true);
Assertion.addProperty('nested', function () {
flag(this, 'nested', true);
});

/**
Expand Down Expand Up @@ -827,29 +841,27 @@ module.exports = function (chai, _) {
* ### .property(name, [value])
*
* Asserts that the target has a property `name`, optionally asserting that
* the value of that property is strictly equal to `value`.
* If the `deep` flag is set, you can use dot- and bracket-notation for deep
* references into objects and arrays.
* the value of that property is strictly equal to `value`.
*
* // simple referencing
* 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
* If the `nested` flag is set, you can use dot- and bracket-notation for
* nested references into objects and arrays.
*
* var deepObj = {
* green: { tea: 'matcha' }
* , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
* };
* expect(deepObj).to.have.nested.property('green.tea', 'matcha');
* expect(deepObj).to.have.nested.property('teas[1]', 'matcha');
* expect(deepObj).to.have.nested.property('teas[2].tea', 'konacha');
*
* expect(deepObj).to.have.deep.property('green.tea', 'matcha');
* expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
* expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
*
* You can also use an array as the starting point of a `deep.property`
* You can also use an array as the starting point of a `nested.property`
* assertion, or traverse nested arrays.
*
* var arr = [
Expand All @@ -858,9 +870,8 @@ module.exports = function (chai, _) {
* , { tea: 'matcha' }
* , { tea: 'konacha' } ]
* ];
*
* expect(arr).to.have.deep.property('[0][1]', 'matcha');
* expect(arr).to.have.deep.property('[1][2].tea', 'konacha');
* expect(arr).to.have.nested.property('[0][1]', 'matcha');
* expect(arr).to.have.nested.property('[1][2].tea', 'konacha');
*
* Furthermore, `property` changes the subject of the assertion
* to be the value of that property from the original object. This
Expand All @@ -873,23 +884,23 @@ module.exports = function (chai, _) {
* .that.deep.equals({ tea: 'matcha' });
* expect(deepObj).to.have.property('teas')
* .that.is.an('array')
* .with.deep.property('[2]')
* .with.nested.property('[2]')
* .that.deep.equals({ tea: 'konacha' });
*
* Note that dots and brackets in `name` must be backslash-escaped when
* the `deep` flag is set, while they must NOT be escaped when the `deep`
* the `nested` flag is set, while they must NOT be escaped when the `nested`
* flag is not set.
*
* // simple referencing
* // without nested referencing
* var css = { '.link[target]': 42 };
* expect(css).to.have.property('.link[target]', 42);
*
* // deep referencing
* // with nested referencing
* var deepCss = { '.link': { '[target]': 42 }};
* expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42);
* expect(deepCss).to.have.nested.property('\\.link.\\[target\\]', 42);
*
* @name property
* @alias deep.property
* @alias nested.property
* @param {String} name
* @param {Mixed} value (optional)
* @param {String} message _optional_
Expand All @@ -901,15 +912,15 @@ module.exports = function (chai, _) {
Assertion.addMethod('property', function (name, val, msg) {
if (msg) flag(this, 'message', msg);

var isDeep = !!flag(this, 'deep')
, descriptor = isDeep ? 'deep property ' : 'property '
var isNested = !!flag(this, 'nested')
, descriptor = isNested ? 'nested property ' : 'property '
, negate = flag(this, 'negate')
, obj = flag(this, 'object')
, pathInfo = isDeep ? _.getPathInfo(name, obj) : null
, hasProperty = isDeep
, pathInfo = isNested ? _.getPathInfo(name, obj) : null
, hasProperty = isNested
? pathInfo.exists
: _.hasProperty(name, obj)
, value = isDeep
, value = isNested
? pathInfo.value
: obj[name];

Expand Down
60 changes: 30 additions & 30 deletions lib/chai/interface/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -942,50 +942,50 @@ module.exports = function (chai, util) {
};

/**
* ### .deepProperty(object, property, [message])
* ### .nestedProperty(object, property, [message])
*
* Asserts that `object` has a property named by `property`, which can be a
* string using dot- and bracket-notation for deep reference.
* string using dot- and bracket-notation for nested reference.
*
* assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green');
* assert.nestedProperty({ tea: { green: 'matcha' }}, 'tea.green');
*
* @name deepProperty
* @name nestedProperty
* @param {Object} object
* @param {String} property
* @param {String} message
* @namespace Assert
* @api public
*/

assert.deepProperty = function (obj, prop, msg) {
new Assertion(obj, msg).to.have.deep.property(prop);
assert.nestedProperty = function (obj, prop, msg) {
new Assertion(obj, msg).to.have.nested.property(prop);
};

/**
* ### .notDeepProperty(object, property, [message])
* ### .notNestedProperty(object, property, [message])
*
* Asserts that `object` does _not_ have a property named by `property`, which
* can be a string using dot- and bracket-notation for deep reference.
* can be a string using dot- and bracket-notation for nested reference.
*
* assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong');
* assert.notNestedProperty({ tea: { green: 'matcha' }}, 'tea.oolong');
*
* @name notDeepProperty
* @name notNestedProperty
* @param {Object} object
* @param {String} property
* @param {String} message
* @namespace Assert
* @api public
*/

assert.notDeepProperty = function (obj, prop, msg) {
new Assertion(obj, msg).to.not.have.deep.property(prop);
assert.notNestedProperty = function (obj, prop, msg) {
new Assertion(obj, msg).to.not.have.nested.property(prop);
};

/**
* ### .propertyVal(object, property, value, [message])
*
* Asserts that `object` has a property named by `property` with value given
* by `value`.
* Asserts that `object` has a property named by `property` with a value given
* by `value`. Uses a strict equality check (===).
*
* assert.propertyVal({ tea: 'is good' }, 'tea', 'is good');
*
Expand All @@ -1006,7 +1006,7 @@ module.exports = function (chai, util) {
* ### .notPropertyVal(object, property, value, [message])
*
* Asserts that `object` does _not_ have a property named by `property` with
* value given by `value`.
* value given by `value`. Uses a strict equality check (===).
*
* assert.notPropertyVal({ tea: 'is good' }, 'tea', 'is bad');
* assert.notPropertyVal({ tea: 'is good' }, 'coffee', 'is good');
Expand All @@ -1025,15 +1025,15 @@ module.exports = function (chai, util) {
};

/**
* ### .deepPropertyVal(object, property, value, [message])
* ### .nestedPropertyVal(object, property, value, [message])
*
* Asserts that `object` has a property named by `property` with value given
* by `value`. `property` can use dot- and bracket-notation for deep
* reference.
* by `value`. `property` can use dot- and bracket-notation for nested
* reference. Uses a strict equality check (===).
*
* assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha');
* assert.nestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha');
*
* @name deepPropertyVal
* @name nestedPropertyVal
* @param {Object} object
* @param {String} property
* @param {Mixed} value
Expand All @@ -1042,21 +1042,21 @@ module.exports = function (chai, util) {
* @api public
*/

assert.deepPropertyVal = function (obj, prop, val, msg) {
new Assertion(obj, msg).to.have.deep.property(prop, val);
assert.nestedPropertyVal = function (obj, prop, val, msg) {
new Assertion(obj, msg).to.have.nested.property(prop, val);
};

/**
* ### .notDeepPropertyVal(object, property, value, [message])
* ### .notNestedPropertyVal(object, property, value, [message])
*
* 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.
* value given by `value`. `property` can use dot- and bracket-notation for
* nested reference. Uses a strict equality check (===).
*
* assert.notDeepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');
* assert.notDeepPropertyVal({ tea: { green: 'matcha' }}, 'coffee.green', 'matcha');
* assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');
* assert.notNestedPropertyVal({ tea: { green: 'matcha' }}, 'coffee.green', 'matcha');
*
* @name notDeepPropertyVal
* @name notNestedPropertyVal
* @param {Object} object
* @param {String} property
* @param {Mixed} value
Expand All @@ -1065,8 +1065,8 @@ module.exports = function (chai, util) {
* @api public
*/

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

/**
Expand Down
26 changes: 13 additions & 13 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -942,31 +942,31 @@ describe('assert', function () {
assert.property(obj, 'foo');
assert.property(undefinedKeyObj, 'foo');
assert.propertyVal(undefinedKeyObj, 'foo', undefined);
assert.deepProperty(obj, 'foo.bar');
assert.nestedProperty(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.notDeepPropertyVal(obj, 'foo.bar', 'flow');
assert.notDeepPropertyVal(obj, 'foo.flow', 'baz');
assert.notNestedProperty(obj, 'foo.baz');
assert.nestedPropertyVal(obj, 'foo.bar', 'baz');
assert.notNestedPropertyVal(obj, 'foo.bar', 'flow');
assert.notNestedPropertyVal(obj, 'foo.flow', 'baz');

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

err(function () {
assert.deepProperty(obj, 'foo.baz');
}, "expected { foo: { bar: 'baz' } } to have a deep property 'foo.baz'");
assert.nestedProperty(obj, 'foo.baz');
}, "expected { foo: { bar: 'baz' } } to have a nested property 'foo.baz'");

err(function () {
assert.notProperty(obj, 'foo');
}, "expected { foo: { bar: 'baz' } } to not have property 'foo'");

err(function () {
assert.notDeepProperty(obj, 'foo.bar');
}, "expected { foo: { bar: 'baz' } } to not have deep property 'foo.bar'");
assert.notNestedProperty(obj, 'foo.bar');
}, "expected { foo: { bar: 'baz' } } to not have nested property 'foo.bar'");

err(function () {
assert.propertyVal(simpleObj, 'foo', 'ball');
Expand All @@ -977,16 +977,16 @@ describe('assert', function () {
}, "expected { foo: 'bar' } to have a property 'foo' of undefined, but got 'bar'");

err(function () {
assert.deepPropertyVal(obj, 'foo.bar', 'ball');
}, "expected { foo: { bar: 'baz' } } to have a deep property 'foo.bar' of 'ball', but got 'baz'");
assert.nestedPropertyVal(obj, 'foo.bar', 'ball');
}, "expected { foo: { bar: 'baz' } } to have a nested property 'foo.bar' of 'ball', but got 'baz'");

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

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

it('throws / throw / Throw', function() {
Expand Down
Loading

0 comments on commit d4e8a4a

Please sign in to comment.