mirror of
https://github.com/chaijs/chai
synced 2024-11-15 00:07:11 +00:00
Add .deep.property
for deep equality comparisons
This commit is contained in:
parent
d4e8a4aee5
commit
6d6bf60dba
5 changed files with 239 additions and 4 deletions
|
@ -70,9 +70,13 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .deep
|
||||
*
|
||||
* Sets the `deep` flag, later used by the `equal` assertion.
|
||||
* Sets the `deep` flag, later used by the `equal`, `members`, and `property`
|
||||
* assertions.
|
||||
*
|
||||
* expect(foo).to.deep.equal({ bar: 'baz' });
|
||||
* const obj = {a: 1};
|
||||
* expect(obj).to.deep.equal({a: 1});
|
||||
* expect([obj]).to.have.deep.members([{a: 1}]);
|
||||
* expect({foo: obj}).to.have.deep.property('foo', {a: 1});
|
||||
*
|
||||
* @name deep
|
||||
* @namespace BDD
|
||||
|
@ -850,6 +854,13 @@ module.exports = function (chai, _) {
|
|||
* expect(obj).to.not.have.property('foo', 'baz');
|
||||
* expect(obj).to.not.have.property('baz', 'bar');
|
||||
*
|
||||
* If the `deep` flag is set, asserts that the value of the property is deeply
|
||||
* equal to `value`.
|
||||
*
|
||||
* var obj = { foo: { bar: 'baz' } };
|
||||
* expect(obj).to.have.deep.property('foo', { bar: 'baz' });
|
||||
* expect(obj).to.not.have.deep.property('foo', { bar: 'quux' });
|
||||
*
|
||||
* If the `nested` flag is set, you can use dot- and bracket-notation for
|
||||
* nested references into objects and arrays.
|
||||
*
|
||||
|
@ -861,6 +872,11 @@ module.exports = function (chai, _) {
|
|||
* expect(deepObj).to.have.nested.property('teas[1]', 'matcha');
|
||||
* expect(deepObj).to.have.nested.property('teas[2].tea', 'konacha');
|
||||
*
|
||||
* The `deep` and `nested` flags can be combined.
|
||||
*
|
||||
* expect({ foo: { bar: { baz: 'quux' } } })
|
||||
* .to.have.deep.nested.property('foo.bar', { baz: 'quux' });
|
||||
*
|
||||
* You can also use an array as the starting point of a `nested.property`
|
||||
* assertion, or traverse nested arrays.
|
||||
*
|
||||
|
@ -900,6 +916,7 @@ module.exports = function (chai, _) {
|
|||
* expect(deepCss).to.have.nested.property('\\.link.\\[target\\]', 42);
|
||||
*
|
||||
* @name property
|
||||
* @alias deep.property
|
||||
* @alias nested.property
|
||||
* @param {String} name
|
||||
* @param {Mixed} value (optional)
|
||||
|
@ -913,7 +930,10 @@ module.exports = function (chai, _) {
|
|||
if (msg) flag(this, 'message', msg);
|
||||
|
||||
var isNested = !!flag(this, 'nested')
|
||||
, descriptor = isNested ? 'nested property ' : 'property '
|
||||
, isDeep = !!flag(this, 'deep')
|
||||
, descriptor = (isDeep ? 'deep ' : '')
|
||||
+ (isNested ? 'nested ' : '')
|
||||
+ 'property '
|
||||
, negate = flag(this, 'negate')
|
||||
, obj = flag(this, 'object')
|
||||
, pathInfo = isNested ? _.getPathInfo(name, obj) : null
|
||||
|
@ -938,7 +958,7 @@ module.exports = function (chai, _) {
|
|||
|
||||
if (arguments.length > 1) {
|
||||
this.assert(
|
||||
hasProperty && val === value
|
||||
hasProperty && (isDeep ? _.eql(val, value) : 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
|
||||
|
|
|
@ -1024,6 +1024,50 @@ module.exports = function (chai, util) {
|
|||
new Assertion(obj, msg).to.not.have.property(prop, val);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .deepPropertyVal(object, property, value, [message])
|
||||
*
|
||||
* Asserts that `object` has a property named by `property` with a value given
|
||||
* by `value`. Uses a deep equality check.
|
||||
*
|
||||
* assert.deepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'matcha' });
|
||||
*
|
||||
* @name deepPropertyVal
|
||||
* @param {Object} object
|
||||
* @param {String} property
|
||||
* @param {Mixed} value
|
||||
* @param {String} message
|
||||
* @namespace Assert
|
||||
* @api public
|
||||
*/
|
||||
|
||||
assert.deepPropertyVal = function (obj, prop, val, msg) {
|
||||
new Assertion(obj, msg).to.have.deep.property(prop, val);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .notDeepPropertyVal(object, property, value, [message])
|
||||
*
|
||||
* Asserts that `object` does _not_ have a property named by `property` with
|
||||
* value given by `value`. Uses a deep equality check.
|
||||
*
|
||||
* assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { black: 'matcha' });
|
||||
* assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'tea', { green: 'oolong' });
|
||||
* assert.notDeepPropertyVal({ tea: { green: 'matcha' } }, 'coffee', { green: 'matcha' });
|
||||
*
|
||||
* @name notDeepPropertyVal
|
||||
* @param {Object} object
|
||||
* @param {String} property
|
||||
* @param {Mixed} value
|
||||
* @param {String} message
|
||||
* @namespace Assert
|
||||
* @api public
|
||||
*/
|
||||
|
||||
assert.notDeepPropertyVal = function (obj, prop, val, msg) {
|
||||
new Assertion(obj, msg).to.not.have.deep.property(prop, val);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .nestedPropertyVal(object, property, value, [message])
|
||||
*
|
||||
|
@ -1069,6 +1113,52 @@ module.exports = function (chai, util) {
|
|||
new Assertion(obj, msg).to.not.have.nested.property(prop, val);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .deepNestedPropertyVal(object, property, value, [message])
|
||||
*
|
||||
* Asserts that `object` has a property named by `property` with a value given
|
||||
* by `value`. `property` can use dot- and bracket-notation for nested
|
||||
* reference. Uses a deep equality check.
|
||||
*
|
||||
* assert.deepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yum' });
|
||||
*
|
||||
* @name deepNestedPropertyVal
|
||||
* @param {Object} object
|
||||
* @param {String} property
|
||||
* @param {Mixed} value
|
||||
* @param {String} message
|
||||
* @namespace Assert
|
||||
* @api public
|
||||
*/
|
||||
|
||||
assert.deepNestedPropertyVal = function (obj, prop, val, msg) {
|
||||
new Assertion(obj, msg).to.have.deep.nested.property(prop, val);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .notDeepNestedPropertyVal(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
|
||||
* nested reference. Uses a deep equality check.
|
||||
*
|
||||
* assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { oolong: 'yum' });
|
||||
* assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.green', { matcha: 'yuck' });
|
||||
* assert.notDeepNestedPropertyVal({ tea: { green: { matcha: 'yum' } } }, 'tea.black', { matcha: 'yum' });
|
||||
*
|
||||
* @name notDeepNestedPropertyVal
|
||||
* @param {Object} object
|
||||
* @param {String} property
|
||||
* @param {Mixed} value
|
||||
* @param {String} message
|
||||
* @namespace Assert
|
||||
* @api public
|
||||
*/
|
||||
|
||||
assert.notDeepNestedPropertyVal = function (obj, prop, val, msg) {
|
||||
new Assertion(obj, msg).to.not.have.deep.nested.property(prop, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* ### .lengthOf(object, length, [message])
|
||||
*
|
||||
|
|
|
@ -947,6 +947,7 @@ describe('assert', function () {
|
|||
assert.notProperty(obj, 'foo.bar');
|
||||
assert.notPropertyVal(simpleObj, 'foo', 'flow');
|
||||
assert.notPropertyVal(simpleObj, 'flow', 'bar');
|
||||
assert.notPropertyVal(obj, 'foo', {bar: 'baz'});
|
||||
assert.notNestedProperty(obj, 'foo.baz');
|
||||
assert.nestedPropertyVal(obj, 'foo.bar', 'baz');
|
||||
assert.notNestedPropertyVal(obj, 'foo.bar', 'flow');
|
||||
|
@ -989,6 +990,46 @@ describe('assert', function () {
|
|||
}, "expected { foo: { bar: 'baz' } } to not have a nested property 'foo.bar' of 'baz'");
|
||||
});
|
||||
|
||||
it('deepPropertyVal', function () {
|
||||
var obj = {a: {b: 1}};
|
||||
assert.deepPropertyVal(obj, 'a', {b: 1});
|
||||
assert.notDeepPropertyVal(obj, 'a', {b: 7});
|
||||
assert.notDeepPropertyVal(obj, 'a', {z: 1});
|
||||
assert.notDeepPropertyVal(obj, 'z', {b: 1});
|
||||
|
||||
err(function () {
|
||||
assert.deepPropertyVal(obj, 'a', {b: 7}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to have a deep property 'a' of { b: 7 }, but got { b: 1 }");
|
||||
|
||||
err(function () {
|
||||
assert.deepPropertyVal(obj, 'z', {b: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to have a deep property 'z'");
|
||||
|
||||
err(function () {
|
||||
assert.notDeepPropertyVal(obj, 'a', {b: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to not have a deep property 'a' of { b: 1 }");
|
||||
});
|
||||
|
||||
it('deepNestedPropertyVal', function () {
|
||||
var obj = {a: {b: {c: 1}}};
|
||||
assert.deepNestedPropertyVal(obj, 'a.b', {c: 1});
|
||||
assert.notDeepNestedPropertyVal(obj, 'a.b', {c: 7});
|
||||
assert.notDeepNestedPropertyVal(obj, 'a.b', {z: 1});
|
||||
assert.notDeepNestedPropertyVal(obj, 'a.z', {c: 1});
|
||||
|
||||
err(function () {
|
||||
assert.deepNestedPropertyVal(obj, 'a.b', {c: 7}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to have a deep nested property 'a.b' of { c: 7 }, but got { c: 1 }");
|
||||
|
||||
err(function () {
|
||||
assert.deepNestedPropertyVal(obj, 'a.z', {c: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to have a deep nested property 'a.z'");
|
||||
|
||||
err(function () {
|
||||
assert.notDeepNestedPropertyVal(obj, 'a.b', {c: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to not have a deep nested property 'a.b' of { c: 1 }");
|
||||
});
|
||||
|
||||
it('throws / throw / Throw', function() {
|
||||
['throws', 'throw', 'Throw'].forEach(function (throws) {
|
||||
assert[throws](function() { throw new Error('foo'); });
|
||||
|
|
|
@ -534,6 +534,7 @@ describe('expect', function () {
|
|||
expect('asd').to.have.property('constructor', String);
|
||||
expect('test').to.not.have.property('length', 3);
|
||||
expect('test').to.not.have.property('foo', 4);
|
||||
expect({a: {b: 1}}).to.not.have.property('a', {b: 1});
|
||||
|
||||
var deepObj = {
|
||||
green: { tea: 'matcha' }
|
||||
|
@ -589,6 +590,26 @@ describe('expect', function () {
|
|||
}, "blah: expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]");
|
||||
});
|
||||
|
||||
it('deep.property(name, val)', function () {
|
||||
var obj = {a: {b: 1}};
|
||||
expect(obj).to.have.deep.property('a', {b: 1});
|
||||
expect(obj).to.not.have.deep.property('a', {b: 7});
|
||||
expect(obj).to.not.have.deep.property('a', {z: 1});
|
||||
expect(obj).to.not.have.deep.property('z', {b: 1});
|
||||
|
||||
err(function () {
|
||||
expect(obj).to.have.deep.property('a', {b: 7}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to have a deep property 'a' of { b: 7 }, but got { b: 1 }");
|
||||
|
||||
err(function () {
|
||||
expect(obj).to.have.deep.property('z', {b: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to have a deep property 'z'");
|
||||
|
||||
err(function () {
|
||||
expect(obj).to.not.have.deep.property('a', {b: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to not have a deep property 'a' of { b: 1 }");
|
||||
});
|
||||
|
||||
it('nested.property(name, val)', function(){
|
||||
expect({ foo: { bar: 'baz' } })
|
||||
.to.have.nested.property('foo.bar', 'baz');
|
||||
|
@ -596,6 +617,7 @@ describe('expect', function () {
|
|||
.to.not.have.nested.property('foo.bar', 'quux');
|
||||
expect({ foo: { bar: 'baz' } })
|
||||
.to.not.have.nested.property('foo.quux', 'baz');
|
||||
expect({a: {b: {c: 1}}}).to.not.have.nested.property('a.b', {c: 1});
|
||||
|
||||
err(function(){
|
||||
expect({ foo: { bar: 'baz' } })
|
||||
|
@ -607,6 +629,26 @@ describe('expect', function () {
|
|||
}, "blah: expected { foo: { bar: 'baz' } } to not have a nested property 'foo.bar' of 'baz'");
|
||||
});
|
||||
|
||||
it('deep.nested.property(name, val)', function () {
|
||||
var obj = {a: {b: {c: 1}}};
|
||||
expect(obj).to.have.deep.nested.property('a.b', {c: 1});
|
||||
expect(obj).to.not.have.deep.nested.property('a.b', {c: 7});
|
||||
expect(obj).to.not.have.deep.nested.property('a.b', {z: 1});
|
||||
expect(obj).to.not.have.deep.nested.property('a.z', {c: 1});
|
||||
|
||||
err(function () {
|
||||
expect(obj).to.have.deep.nested.property('a.b', {c: 7}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to have a deep nested property 'a.b' of { c: 7 }, but got { c: 1 }");
|
||||
|
||||
err(function () {
|
||||
expect(obj).to.have.deep.nested.property('a.z', {c: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to have a deep nested property 'a.z'");
|
||||
|
||||
err(function () {
|
||||
expect(obj).to.not.have.deep.nested.property('a.b', {c: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to not have a deep nested property 'a.b' of { c: 1 }");
|
||||
});
|
||||
|
||||
it('ownProperty(name)', function(){
|
||||
expect('test').to.have.ownProperty('length');
|
||||
expect('test').to.haveOwnProperty('length');
|
||||
|
|
|
@ -457,6 +457,7 @@ describe('should', function() {
|
|||
({ 1: 1 }).should.have.property(1, 1);
|
||||
'test'.should.not.have.property('length', 3);
|
||||
'test'.should.not.have.property('foo', 4);
|
||||
({a: {b: 1}}).should.not.have.property('a', {b: 1});
|
||||
|
||||
err(function(){
|
||||
'asd'.should.have.property('length', 4, 'blah');
|
||||
|
@ -471,10 +472,31 @@ describe('should', function() {
|
|||
}, "blah: expected 'asd' to have a property 'constructor' of [Function: Number], but got [Function: String]");
|
||||
});
|
||||
|
||||
it('deep.property(name, val)', function () {
|
||||
var obj = {a: {b: 1}};
|
||||
obj.should.have.deep.property('a', {b: 1});
|
||||
obj.should.not.have.deep.property('a', {b: 7});
|
||||
obj.should.not.have.deep.property('a', {z: 1});
|
||||
obj.should.not.have.deep.property('z', {b: 1});
|
||||
|
||||
err(function () {
|
||||
obj.should.have.deep.property('a', {b: 7}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to have a deep property 'a' of { b: 7 }, but got { b: 1 }");
|
||||
|
||||
err(function () {
|
||||
obj.should.have.deep.property('z', {b: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to have a deep property 'z'");
|
||||
|
||||
err(function () {
|
||||
obj.should.not.have.deep.property('a', {b: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: 1 } } to not have a deep property 'a' of { b: 1 }");
|
||||
});
|
||||
|
||||
it('nested.property(name, val)', function(){
|
||||
({ foo: { bar: 'baz' } }).should.have.nested.property('foo.bar', 'baz');
|
||||
({ foo: { bar: 'baz' } }).should.not.have.nested.property('foo.bar', 'quux');
|
||||
({ foo: { bar: 'baz' } }).should.not.have.nested.property('foo.quux', 'baz');
|
||||
({a: {b: {c: 1}}}).should.not.have.nested.property('a.b', {c: 1});
|
||||
|
||||
err(function(){
|
||||
({ foo: { bar: 'baz' } }).should.have.nested.property('foo.bar', 'quux', 'blah');
|
||||
|
@ -484,6 +506,26 @@ describe('should', function() {
|
|||
}, "blah: expected { foo: { bar: 'baz' } } to not have a nested property 'foo.bar' of 'baz'");
|
||||
});
|
||||
|
||||
it('deep.nested.property(name, val)', function () {
|
||||
var obj = {a: {b: {c: 1}}};
|
||||
obj.should.have.deep.nested.property('a.b', {c: 1});
|
||||
obj.should.not.have.deep.nested.property('a.b', {c: 7});
|
||||
obj.should.not.have.deep.nested.property('a.b', {z: 1});
|
||||
obj.should.not.have.deep.nested.property('a.z', {c: 1});
|
||||
|
||||
err(function () {
|
||||
obj.should.have.deep.nested.property('a.b', {c: 7}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to have a deep nested property 'a.b' of { c: 7 }, but got { c: 1 }");
|
||||
|
||||
err(function () {
|
||||
obj.should.have.deep.nested.property('a.z', {c: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to have a deep nested property 'a.z'");
|
||||
|
||||
err(function () {
|
||||
obj.should.not.have.deep.nested.property('a.b', {c: 1}, 'blah');
|
||||
}, "blah: expected { a: { b: { c: 1 } } } to not have a deep nested property 'a.b' of { c: 1 }");
|
||||
});
|
||||
|
||||
it('ownProperty(name)', function(){
|
||||
'test'.should.have.ownProperty('length');
|
||||
'test'.should.haveOwnProperty('length');
|
||||
|
|
Loading…
Reference in a new issue