mirror of
https://github.com/chaijs/chai
synced 2024-11-14 15:57:10 +00:00
Add ES6 collection support to include() (#994)
* fix error messages tests * add tests * add implementation * performance tweaks * add tests for SameValueZero * drop weakmap support * update docs
This commit is contained in:
parent
3c932e21e6
commit
2eddd79002
4 changed files with 309 additions and 36 deletions
|
@ -330,6 +330,16 @@ module.exports = function (chai, _) {
|
|||
*
|
||||
* expect({a: 1, b: 2, c: 3}).to.include({a: 1, b: 2});
|
||||
*
|
||||
* When the target is a Set or WeakSet, `.include` asserts that the given `val` is a
|
||||
* member of the target. SameValueZero equality algorithm is used.
|
||||
*
|
||||
* expect(new Set([1, 2])).to.include(2);
|
||||
*
|
||||
* When the target is a Map, `.include` asserts that the given `val` is one of
|
||||
* the values of the target. SameValueZero equality algorithm is used.
|
||||
*
|
||||
* expect(new Map([['a', 1], ['b', 2]])).to.include(2);
|
||||
*
|
||||
* Because `.include` does different things based on the target's type, it's
|
||||
* important to check the target's type before using `.include`. See the `.a`
|
||||
* doc for info on testing a target's type.
|
||||
|
@ -338,8 +348,8 @@ module.exports = function (chai, _) {
|
|||
*
|
||||
* By default, strict (`===`) equality is used to compare array members and
|
||||
* object properties. Add `.deep` earlier in the chain to use deep equality
|
||||
* instead. See the `deep-eql` project page for info on the deep equality
|
||||
* algorithm: https://github.com/chaijs/deep-eql.
|
||||
* instead (WeakSet targets are not supported). See the `deep-eql` project
|
||||
* page for info on the deep equality algorithm: https://github.com/chaijs/deep-eql.
|
||||
*
|
||||
* // Target array deeply (but not strictly) includes `{a: 1}`
|
||||
* expect([{a: 1}]).to.deep.include({a: 1});
|
||||
|
@ -449,25 +459,24 @@ module.exports = function (chai, _) {
|
|||
* @api public
|
||||
*/
|
||||
|
||||
function includeChainingBehavior () {
|
||||
flag(this, 'contains', true);
|
||||
function SameValueZero(a, b) {
|
||||
return (_.isNaN(a) && _.isNaN(b)) || a === b;
|
||||
}
|
||||
|
||||
function isDeepIncluded (arr, val) {
|
||||
return arr.some(function (arrVal) {
|
||||
return _.eql(arrVal, val);
|
||||
});
|
||||
function includeChainingBehavior () {
|
||||
flag(this, 'contains', true);
|
||||
}
|
||||
|
||||
function include (val, msg) {
|
||||
if (msg) flag(this, 'message', msg);
|
||||
|
||||
_.expectTypes(this, ['array', 'object', 'string']);
|
||||
_.expectTypes(this, [
|
||||
'array', 'object', 'string',
|
||||
'map', 'set', 'weakset',
|
||||
]);
|
||||
|
||||
var obj = flag(this, 'object')
|
||||
, objType = _.type(obj).toLowerCase()
|
||||
, isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : '';
|
||||
, objType = _.type(obj).toLowerCase();
|
||||
|
||||
// This block is for asserting a subset of properties in an object.
|
||||
if (objType === 'object') {
|
||||
|
@ -504,10 +513,62 @@ module.exports = function (chai, _) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Assert inclusion in an array or substring in a string.
|
||||
var isDeep = flag(this, 'deep')
|
||||
, descriptor = isDeep ? 'deep ' : ''
|
||||
, included = false;
|
||||
|
||||
switch (objType) {
|
||||
case 'string':
|
||||
included = obj.indexOf(val) !== -1;
|
||||
break;
|
||||
|
||||
case 'weakset':
|
||||
if (isDeep) {
|
||||
var flagMsg = flag(this, 'message')
|
||||
, ssfi = flag(this, 'ssfi');
|
||||
flagMsg = flagMsg ? flagMsg + ': ' : '';
|
||||
|
||||
throw new AssertionError(
|
||||
flagMsg + 'unable to use .deep.include with WeakSet',
|
||||
undefined,
|
||||
ssfi
|
||||
);
|
||||
}
|
||||
|
||||
included = obj.has(val);
|
||||
break;
|
||||
|
||||
case 'map':
|
||||
var isEql = isDeep ? _.eql : SameValueZero;
|
||||
obj.forEach(function (item) {
|
||||
included = included || isEql(item, val);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'set':
|
||||
if (isDeep) {
|
||||
obj.forEach(function (item) {
|
||||
included = included || _.eql(item, val);
|
||||
});
|
||||
} else {
|
||||
included = obj.has(val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'array':
|
||||
if (isDeep) {
|
||||
included = obj.some(function (item) {
|
||||
return _.eql(item, val);
|
||||
})
|
||||
} else {
|
||||
included = obj.indexOf(val) !== -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Assert inclusion in collection or substring in a string.
|
||||
this.assert(
|
||||
objType === 'string' || !isDeep ? ~obj.indexOf(val)
|
||||
: isDeepIncluded(obj, val)
|
||||
included
|
||||
, 'expected #{this} to ' + descriptor + 'include ' + _.inspect(val)
|
||||
, 'expected #{this} to not ' + descriptor + 'include ' + _.inspect(val));
|
||||
}
|
||||
|
|
104
test/assert.js
104
test/assert.js
|
@ -633,6 +633,42 @@ describe('assert', function () {
|
|||
assert.include({foo: obj1, bar: obj2}, {foo: obj1});
|
||||
assert.include({foo: obj1, bar: obj2}, {foo: obj1, bar: obj2});
|
||||
|
||||
if (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
var val = [{a: 1}];
|
||||
map.set('a', val);
|
||||
map.set('b', 2);
|
||||
map.set('c', -0);
|
||||
map.set('d', NaN);
|
||||
|
||||
assert.include(map, val);
|
||||
assert.include(map, 2);
|
||||
assert.include(map, 0);
|
||||
assert.include(map, NaN);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
var val = [{a: 1}];
|
||||
set.add(val);
|
||||
set.add(2);
|
||||
set.add(-0);
|
||||
set.add(NaN);
|
||||
|
||||
assert.include(set, val);
|
||||
assert.include(set, 2);
|
||||
assert.include(set, 0);
|
||||
assert.include(set, NaN);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
var ws = new WeakSet();
|
||||
var val = [{a: 1}];
|
||||
ws.add(val);
|
||||
|
||||
assert.include(ws, val);
|
||||
}
|
||||
|
||||
if (typeof Symbol === 'function') {
|
||||
var sym1 = Symbol()
|
||||
, sym2 = Symbol();
|
||||
|
@ -653,19 +689,19 @@ describe('assert', function () {
|
|||
|
||||
err(function(){
|
||||
assert.include(true, true, 'blah');
|
||||
}, "blah: object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "blah: object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function () {
|
||||
assert.include(42, 'bar');
|
||||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but number given");
|
||||
|
||||
err(function(){
|
||||
assert.include(null, 42);
|
||||
}, "object tested must be an array, an object, or a string, but null given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but null given");
|
||||
|
||||
err(function () {
|
||||
assert.include(undefined, 'bar');
|
||||
}, "object tested must be an array, an object, or a string, but undefined given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but undefined given");
|
||||
});
|
||||
|
||||
it('notInclude', function () {
|
||||
|
@ -678,6 +714,38 @@ describe('assert', function () {
|
|||
assert.notInclude({foo: obj1, bar: obj2}, {foo: {a: 1}});
|
||||
assert.notInclude({foo: obj1, bar: obj2}, {foo: obj1, bar: {b: 2}});
|
||||
|
||||
if (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
var val = [{a: 1}];
|
||||
map.set('a', val);
|
||||
map.set('b', 2);
|
||||
|
||||
assert.notInclude(map, [{a: 1}]);
|
||||
assert.notInclude(map, 3);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
var val = [{a: 1}];
|
||||
set.add(val);
|
||||
set.add(2);
|
||||
|
||||
assert.include(set, val);
|
||||
assert.include(set, 2);
|
||||
|
||||
assert.notInclude(set, [{a: 1}]);
|
||||
assert.notInclude(set, 3);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
var ws = new WeakSet();
|
||||
var val = [{a: 1}];
|
||||
ws.add(val);
|
||||
|
||||
assert.notInclude(ws, [{a: 1}]);
|
||||
assert.notInclude(ws, {});
|
||||
}
|
||||
|
||||
if (typeof Symbol === 'function') {
|
||||
var sym1 = Symbol()
|
||||
, sym2 = Symbol()
|
||||
|
@ -699,19 +767,19 @@ describe('assert', function () {
|
|||
|
||||
err(function(){
|
||||
assert.notInclude(true, true, 'blah');
|
||||
}, "blah: object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "blah: object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function () {
|
||||
assert.notInclude(42, 'bar');
|
||||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but number given");
|
||||
|
||||
err(function(){
|
||||
assert.notInclude(null, 42);
|
||||
}, "object tested must be an array, an object, or a string, but null given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but null given");
|
||||
|
||||
err(function () {
|
||||
assert.notInclude(undefined, 'bar');
|
||||
}, "object tested must be an array, an object, or a string, but undefined given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but undefined given");
|
||||
|
||||
err(function () {
|
||||
assert.notInclude('foobar', 'bar');
|
||||
|
@ -731,6 +799,26 @@ describe('assert', function () {
|
|||
assert.notDeepInclude({foo: obj1, bar: obj2}, {baz: {a: 1}});
|
||||
assert.notDeepInclude({foo: obj1, bar: obj2}, {foo: {a: 1}, bar: {b: 9}});
|
||||
|
||||
if (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
map.set(1, [{a: 1}]);
|
||||
|
||||
assert.deepInclude(map, [{a: 1}]);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
set.add([{a: 1}]);
|
||||
|
||||
assert.deepInclude(set, [{a: 1}]);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
err(function() {
|
||||
assert.deepInclude(new WeakSet(), {}, 'foo');
|
||||
}, 'foo: unable to use .deep.include with WeakSet');
|
||||
}
|
||||
|
||||
err(function () {
|
||||
assert.deepInclude([obj1, obj2], {a: 9}, 'blah');
|
||||
}, "blah: expected [ { a: 1 }, { b: 2 } ] to deep include { a: 9 }");
|
||||
|
|
|
@ -1882,6 +1882,48 @@ describe('expect', function () {
|
|||
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 (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
var val = [{a: 1}];
|
||||
map.set('a', val);
|
||||
map.set('b', 2);
|
||||
map.set('c', -0);
|
||||
map.set('d', NaN);
|
||||
|
||||
expect(map).to.include(val);
|
||||
expect(map).to.not.include([{a: 1}]);
|
||||
expect(map).to.include(2);
|
||||
expect(map).to.not.include(3);
|
||||
expect(map).to.include(0);
|
||||
expect(map).to.include(NaN);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
var val = [{a: 1}];
|
||||
set.add(val);
|
||||
set.add(2);
|
||||
set.add(-0);
|
||||
set.add(NaN);
|
||||
|
||||
expect(set).to.include(val);
|
||||
expect(set).to.not.include([{a: 1}]);
|
||||
expect(set).to.include(2);
|
||||
expect(set).to.not.include(3);
|
||||
expect(set).to.include(0);
|
||||
expect(set).to.include(NaN);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
var ws = new WeakSet();
|
||||
var val = [{a: 1}];
|
||||
ws.add(val);
|
||||
|
||||
expect(ws).to.include(val);
|
||||
expect(ws).to.not.include([{a: 1}]);
|
||||
expect(ws).to.not.include({});
|
||||
}
|
||||
|
||||
if (typeof Symbol === 'function') {
|
||||
var sym1 = Symbol()
|
||||
, sym2 = Symbol()
|
||||
|
@ -1936,39 +1978,39 @@ describe('expect', function () {
|
|||
|
||||
err(function(){
|
||||
expect(true).to.include(true, 'blah');
|
||||
}, "blah: object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "blah: object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function(){
|
||||
expect(true, 'blah').to.include(true);
|
||||
}, "blah: object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "blah: object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function(){
|
||||
expect(42.0).to.include(42);
|
||||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but number given");
|
||||
|
||||
err(function(){
|
||||
expect(null).to.include(42);
|
||||
}, "object tested must be an array, an object, or a string, but null given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but null given");
|
||||
|
||||
err(function(){
|
||||
expect(undefined).to.include(42);
|
||||
}, "object tested must be an array, an object, or a string, but undefined given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but undefined given");
|
||||
|
||||
err(function(){
|
||||
expect(true).to.not.include(true);
|
||||
}, "object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function(){
|
||||
expect(42.0).to.not.include(42);
|
||||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but number given");
|
||||
|
||||
err(function(){
|
||||
expect(null).to.not.include(42);
|
||||
}, "object tested must be an array, an object, or a string, but null given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but null given");
|
||||
|
||||
err(function(){
|
||||
expect(undefined).to.not.include(42);
|
||||
}, "object tested must be an array, an object, or a string, but undefined given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but undefined given");
|
||||
});
|
||||
|
||||
it('deep.include()', function () {
|
||||
|
@ -1984,6 +2026,26 @@ describe('expect', function () {
|
|||
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}});
|
||||
|
||||
if (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
map.set(1, [{a: 1}]);
|
||||
|
||||
expect(map).to.deep.include([{a: 1}]);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
set.add([{a: 1}]);
|
||||
|
||||
expect(set).to.deep.include([{a: 1}]);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
err(function() {
|
||||
expect(new WeakSet()).to.deep.include({}, 'foo');
|
||||
}, 'foo: unable to use .deep.include with WeakSet');
|
||||
}
|
||||
|
||||
err(function () {
|
||||
expect([obj1, obj2]).to.deep.include({a: 9}, 'blah');
|
||||
}, "blah: expected [ { a: 1 }, { b: 2 } ] to deep include { a: 9 }");
|
||||
|
|
|
@ -1540,6 +1540,48 @@ describe('should', function() {
|
|||
({foo: obj1, bar: obj2}).should.not.include({foo: {a: 1}});
|
||||
({foo: obj1, bar: obj2}).should.not.include({foo: obj1, bar: {b: 2}});
|
||||
|
||||
if (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
var val = [{a: 1}];
|
||||
map.set('a', val);
|
||||
map.set('b', 2);
|
||||
map.set('c', -0);
|
||||
map.set('d', NaN);
|
||||
|
||||
map.should.include(val);
|
||||
map.should.not.include([{a: 1}]);
|
||||
map.should.include(2);
|
||||
map.should.not.include(3);
|
||||
map.should.include(0);
|
||||
map.should.include(NaN);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
var val = [{a: 1}];
|
||||
set.add(val);
|
||||
set.add(2);
|
||||
set.add(-0);
|
||||
set.add(NaN);
|
||||
|
||||
set.should.include(val);
|
||||
set.should.not.include([{a: 1}]);
|
||||
set.should.include(2);
|
||||
set.should.not.include(3);
|
||||
set.should.include(0);
|
||||
set.should.include(NaN);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
var ws = new WeakSet();
|
||||
var val = [{a: 1}];
|
||||
ws.add(val);
|
||||
|
||||
ws.should.include(val);
|
||||
ws.should.not.include([{a: 1}]);
|
||||
ws.should.not.include({});
|
||||
}
|
||||
|
||||
if (typeof Symbol === 'function') {
|
||||
var sym1 = Symbol()
|
||||
, sym2 = Symbol()
|
||||
|
@ -1582,19 +1624,19 @@ describe('should', function() {
|
|||
|
||||
err(function(){
|
||||
(true).should.include(true, 'blah');
|
||||
}, "blah: object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "blah: object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function(){
|
||||
(42).should.include(4);
|
||||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but number given");
|
||||
|
||||
err(function(){
|
||||
(true).should.not.include(true);
|
||||
}, "object tested must be an array, an object, or a string, but boolean given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but boolean given");
|
||||
|
||||
err(function(){
|
||||
(42).should.not.include(4);
|
||||
}, "object tested must be an array, an object, or a string, but number given");
|
||||
}, "object tested must be an array, a map, an object, a set, a string, or a weakset, but number given");
|
||||
});
|
||||
|
||||
it('deep.include()', function () {
|
||||
|
@ -1610,6 +1652,26 @@ describe('should', function() {
|
|||
({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}});
|
||||
|
||||
if (typeof Map === 'function') {
|
||||
var map = new Map();
|
||||
|
||||
map.set(1, [{a: 1}]);
|
||||
map.should.deep.include([{a: 1}]);
|
||||
}
|
||||
|
||||
if (typeof Set === 'function') {
|
||||
var set = new Set();
|
||||
|
||||
set.add([{a: 1}]);
|
||||
set.should.deep.include([{a: 1}]);
|
||||
}
|
||||
|
||||
if (typeof WeakSet === 'function') {
|
||||
err(function() {
|
||||
new WeakSet().should.deep.include({}, 'foo');
|
||||
}, 'foo: unable to use .deep.include with WeakSet');
|
||||
}
|
||||
|
||||
err(function () {
|
||||
[obj1, obj2].should.deep.include({a: 9}, 'blah');
|
||||
}, "blah: expected [ { a: 1 }, { b: 2 } ] to deep include { a: 9 }");
|
||||
|
|
Loading…
Reference in a new issue