mirror of
https://github.com/chaijs/chai
synced 2024-11-15 00:07:11 +00:00
Add .deep.include
for deep equality comparisons
This commit is contained in:
parent
38739f45fd
commit
7d1dd301c1
5 changed files with 169 additions and 6 deletions
|
@ -71,11 +71,13 @@ module.exports = function (chai, _) {
|
|||
/**
|
||||
* ### .deep
|
||||
*
|
||||
* Sets the `deep` flag, later used by the `equal`, `members`, and `property`
|
||||
* assertions.
|
||||
* Sets the `deep` flag, later used by the `equal`, `include`, `members`, and
|
||||
* `property` assertions.
|
||||
*
|
||||
* const obj = {a: 1};
|
||||
* expect(obj).to.deep.equal({a: 1});
|
||||
* expect([obj]).to.deep.include({a:1});
|
||||
* expect({foo: obj}).to.deep.include({foo: {a:1}});
|
||||
* expect([obj]).to.have.deep.members([{a: 1}]);
|
||||
* expect({foo: obj}).to.have.deep.property('foo', {a: 1});
|
||||
*
|
||||
|
@ -239,6 +241,14 @@ module.exports = function (chai, _) {
|
|||
* expect({foo: obj1, bar: obj2}).to.not.include({foo: {a: 1}});
|
||||
* expect({foo: obj1, bar: obj2}).to.not.include({foo: obj1, bar: {b: 2}});
|
||||
*
|
||||
* If the `deep` flag is set, deep equality is used instead. For instance:
|
||||
*
|
||||
* var obj1 = {a: 1}
|
||||
* , obj2 = {b: 2};
|
||||
* expect([obj1, obj2]).to.deep.include({a: 1});
|
||||
* expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}});
|
||||
* expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}, bar: {b: 2}});
|
||||
*
|
||||
* These assertions can also be used as property based language chains,
|
||||
* enabling the `contains` flag for the `keys` assertion. For instance:
|
||||
*
|
||||
|
@ -248,6 +258,10 @@ module.exports = function (chai, _) {
|
|||
* @alias contain
|
||||
* @alias includes
|
||||
* @alias contains
|
||||
* @alias deep.include
|
||||
* @alias deep.contain
|
||||
* @alias deep.includes
|
||||
* @alias deep.contains
|
||||
* @param {Object|String|Number} obj
|
||||
* @param {String} message _optional_
|
||||
* @namespace BDD
|
||||
|
@ -258,11 +272,19 @@ module.exports = function (chai, _) {
|
|||
flag(this, 'contains', true);
|
||||
}
|
||||
|
||||
function isDeepIncluded (arr, val) {
|
||||
return arr.some(function (arrVal) {
|
||||
return _.eql(arrVal, val);
|
||||
});
|
||||
}
|
||||
|
||||
function include (val, msg) {
|
||||
_.expectTypes(this, ['array', 'object', 'string']);
|
||||
|
||||
if (msg) flag(this, 'message', msg);
|
||||
var obj = flag(this, 'object');
|
||||
var obj = flag(this, 'object')
|
||||
, isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : '';
|
||||
|
||||
// This block is for asserting a subset of properties in an object.
|
||||
if (_.type(obj) === 'object') {
|
||||
|
@ -300,9 +322,10 @@ module.exports = function (chai, _) {
|
|||
|
||||
// Assert inclusion in an array or substring in a string.
|
||||
this.assert(
|
||||
typeof obj !== "undefined" && typeof obj !== "null" && ~obj.indexOf(val)
|
||||
, 'expected #{this} to include ' + _.inspect(val)
|
||||
, 'expected #{this} to not include ' + _.inspect(val));
|
||||
typeof obj === 'string' || !isDeep ? ~obj.indexOf(val)
|
||||
: isDeepIncluded(obj, val)
|
||||
, 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
|
||||
, 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
|
||||
}
|
||||
|
||||
Assertion.addChainableMethod('include', include, includeChainingBehavior);
|
||||
|
|
|
@ -894,6 +894,56 @@ module.exports = function (chai, util) {
|
|||
new Assertion(exp, msg, assert.notInclude).not.include(inc);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .deepInclude(haystack, needle, [message])
|
||||
*
|
||||
* Asserts that `haystack` includes `needle`. Can be used to assert the
|
||||
* inclusion of a value in an array or a subset of properties in an object.
|
||||
* Deep equality is used.
|
||||
*
|
||||
* var obj1 = {a: 1}
|
||||
* , obj2 = {b: 2};
|
||||
* assert.deepInclude([obj1, obj2], {a: 1});
|
||||
* assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}});
|
||||
* assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 2}});
|
||||
*
|
||||
* @name deepInclude
|
||||
* @param {Array|String} haystack
|
||||
* @param {Mixed} needle
|
||||
* @param {String} message
|
||||
* @namespace Assert
|
||||
* @api public
|
||||
*/
|
||||
|
||||
assert.deepInclude = function (exp, inc, msg) {
|
||||
new Assertion(exp, msg, assert.include).deep.include(inc);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .notDeepInclude(haystack, needle, [message])
|
||||
*
|
||||
* Asserts that `haystack` does not include `needle`. Can be used to assert
|
||||
* the absence of a value in an array or a subset of properties in an object.
|
||||
* Deep equality is used.
|
||||
*
|
||||
* var obj1 = {a: 1}
|
||||
* , obj2 = {b: 2};
|
||||
* assert.notDeepInclude([obj1, obj2], {a: 9});
|
||||
* assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 9}});
|
||||
* assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}});
|
||||
*
|
||||
* @name notDeepInclude
|
||||
* @param {Array|String} haystack
|
||||
* @param {Mixed} needle
|
||||
* @param {String} message
|
||||
* @namespace Assert
|
||||
* @api public
|
||||
*/
|
||||
|
||||
assert.notDeepInclude = function (exp, inc, msg) {
|
||||
new Assertion(exp, msg, assert.notInclude).not.deep.include(inc);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### .match(value, regexp, [message])
|
||||
*
|
||||
|
|
|
@ -551,6 +551,36 @@ describe('assert', function () {
|
|||
}, "expected \'foobar\' to not include \'bar\'");
|
||||
});
|
||||
|
||||
it('deepInclude and notDeepInclude', function () {
|
||||
var obj1 = {a: 1}
|
||||
, obj2 = {b: 2};
|
||||
assert.deepInclude([obj1, obj2], {a: 1});
|
||||
assert.notDeepInclude([obj1, obj2], {a: 9});
|
||||
assert.notDeepInclude([obj1, obj2], {z: 1});
|
||||
assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}});
|
||||
assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 2}});
|
||||
assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 9}});
|
||||
assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {z: 1}});
|
||||
assert.notDeepInclude({foo: obj1, bar: obj2}, {baz: {a: 1}});
|
||||
assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}});
|
||||
|
||||
err(function () {
|
||||
assert.deepInclude([obj1, obj2], {a: 9});
|
||||
}, "expected [ { a: 1 }, { b: 2 } ] to deep include { a: 9 }");
|
||||
|
||||
err(function () {
|
||||
assert.notDeepInclude([obj1, obj2], {a: 1});
|
||||
}, "expected [ { a: 1 }, { b: 2 } ] to not deep include { a: 1 }");
|
||||
|
||||
err(function () {
|
||||
assert.deepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}});
|
||||
}, "expected { foo: { a: 1 }, bar: { b: 2 } } to have a deep property 'bar' of { b: 9 }, but got { b: 2 }");
|
||||
|
||||
err(function () {
|
||||
assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 2}});
|
||||
}, "expected { foo: { a: 1 }, bar: { b: 2 } } to not have a deep property 'foo' of { a: 1 }");
|
||||
});
|
||||
|
||||
it('keys(array|Object|arguments)', function(){
|
||||
assert.hasAllKeys({ foo: 1 }, [ 'foo' ]);
|
||||
assert.hasAllKeys({ foo: 1, bar: 2 }, [ 'foo', 'bar' ]);
|
||||
|
|
|
@ -809,6 +809,36 @@ describe('expect', function () {
|
|||
}, "object tested must be an array, an object, or a string, but undefined given");
|
||||
});
|
||||
|
||||
it('deep.include()', function () {
|
||||
var obj1 = {a: 1}
|
||||
, obj2 = {b: 2};
|
||||
expect([obj1, obj2]).to.deep.include({a: 1});
|
||||
expect([obj1, obj2]).to.not.deep.include({a: 9});
|
||||
expect([obj1, obj2]).to.not.deep.include({z: 1});
|
||||
expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}});
|
||||
expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}, bar: {b: 2}});
|
||||
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {a: 9}});
|
||||
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {z: 1}});
|
||||
expect({foo: obj1, bar: obj2}).to.not.deep.include({baz: {a: 1}});
|
||||
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {a: 1}, bar: {b: 9}});
|
||||
|
||||
err(function () {
|
||||
expect([obj1, obj2]).to.deep.include({a: 9});
|
||||
}, "expected [ { a: 1 }, { b: 2 } ] to deep include { a: 9 }");
|
||||
|
||||
err(function () {
|
||||
expect([obj1, obj2]).to.not.deep.include({a: 1});
|
||||
}, "expected [ { a: 1 }, { b: 2 } ] to not deep include { a: 1 }");
|
||||
|
||||
err(function () {
|
||||
expect({foo: obj1, bar: obj2}).to.deep.include({foo: {a: 1}, bar: {b: 9}});
|
||||
}, "expected { foo: { a: 1 }, bar: { b: 2 } } to have a deep property 'bar' of { b: 9 }, but got { b: 2 }");
|
||||
|
||||
err(function () {
|
||||
expect({foo: obj1, bar: obj2}).to.not.deep.include({foo: {a: 1}, bar: {b: 2}});
|
||||
}, "expected { foo: { a: 1 }, bar: { b: 2 } } to not have a deep property 'foo' of { a: 1 }");
|
||||
});
|
||||
|
||||
it('keys(array|Object|arguments)', function(){
|
||||
expect({ foo: 1 }).to.have.keys(['foo']);
|
||||
expect({ foo: 1 }).have.keys({ 'foo': 6 });
|
||||
|
|
|
@ -681,6 +681,36 @@ describe('should', function() {
|
|||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
});
|
||||
|
||||
it('deep.include()', function () {
|
||||
var obj1 = {a: 1}
|
||||
, obj2 = {b: 2};
|
||||
[obj1, obj2].should.deep.include({a: 1});
|
||||
[obj1, obj2].should.not.deep.include({a: 9});
|
||||
[obj1, obj2].should.not.deep.include({z: 1});
|
||||
({foo: obj1, bar: obj2}).should.deep.include({foo: {a: 1}});
|
||||
({foo: obj1, bar: obj2}).should.deep.include({foo: {a: 1}, bar: {b: 2}});
|
||||
({foo: obj1, bar: obj2}).should.not.deep.include({foo: {a: 9}});
|
||||
({foo: obj1, bar: obj2}).should.not.deep.include({foo: {z: 1}});
|
||||
({foo: obj1, bar: obj2}).should.not.deep.include({baz: {a: 1}});
|
||||
({foo: obj1, bar: obj2}).should.not.deep.include({foo: {a: 1}, bar: {b: 9}});
|
||||
|
||||
err(function () {
|
||||
[obj1, obj2].should.deep.include({a: 9});
|
||||
}, "expected [ { a: 1 }, { b: 2 } ] to deep include { a: 9 }");
|
||||
|
||||
err(function () {
|
||||
[obj1, obj2].should.not.deep.include({a: 1});
|
||||
}, "expected [ { a: 1 }, { b: 2 } ] to not deep include { a: 1 }");
|
||||
|
||||
err(function () {
|
||||
({foo: obj1, bar: obj2}).should.deep.include({foo: {a: 1}, bar: {b: 9}});
|
||||
}, "expected { foo: { a: 1 }, bar: { b: 2 } } to have a deep property 'bar' of { b: 9 }, but got { b: 2 }");
|
||||
|
||||
err(function () {
|
||||
({foo: obj1, bar: obj2}).should.not.deep.include({foo: {a: 1}, bar: {b: 2}});
|
||||
}, "expected { foo: { a: 1 }, bar: { b: 2 } } to not have a deep property 'foo' of { a: 1 }");
|
||||
});
|
||||
|
||||
it('keys(array|Object|arguments)', function(){
|
||||
({ foo: 1 }).should.have.keys(['foo']);
|
||||
({ foo: 1 }).should.have.keys({ 'foo': 6 });
|
||||
|
|
Loading…
Reference in a new issue