chai-immutable
Advanced tools
Comparing version 2.0.0-alpha.1 to 2.0.0-alpha.2
'use strict'; | ||
(function (context, factory) { | ||
((context, factory) => { | ||
if (typeof require === 'function' && | ||
@@ -9,743 +9,827 @@ typeof exports === 'object' && | ||
module.exports = factory(require('immutable')); | ||
} | ||
else if (typeof define === 'function' && define.amd) { | ||
// AMD | ||
throw new Error('chai-immutable is not compatible with an AMD loader yet.'); | ||
} | ||
else { | ||
} else { | ||
// Other environments (usually <script> tag) | ||
context.chai.use(factory(context.Immutable)); | ||
} | ||
}(this, function (Immutable) { | ||
return function (chai, utils) { | ||
var Assertion = chai.Assertion; | ||
})(this, Immutable => (chai, utils) => { | ||
const Assertion = chai.Assertion; | ||
function assertIsIterable(obj) { | ||
new Assertion(obj).assert( | ||
Immutable.Iterable.isIterable(obj), | ||
'expected #{this} to be an Iterable' | ||
); | ||
} | ||
function assertIsIterable(obj) { | ||
new Assertion(obj).assert( | ||
Immutable.Iterable.isIterable(obj), | ||
'expected #{this} to be an Iterable' | ||
); | ||
} | ||
/** | ||
* ## BDD API Reference | ||
*/ | ||
/** | ||
* ## BDD API Reference | ||
*/ | ||
/** | ||
* ### .empty | ||
* | ||
* Asserts that the immutable collection is empty. | ||
* | ||
* ```js | ||
* expect(List()).to.be.empty; | ||
* expect(List.of(1, 2, 3)).to.not.be.empty; | ||
* ``` | ||
* | ||
* @name empty | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
/** | ||
* ### .empty | ||
* | ||
* Asserts that the immutable collection is empty. | ||
* | ||
* ```js | ||
* expect(List()).to.be.empty; | ||
* expect(List.of(1, 2, 3)).to.not.be.empty; | ||
* ``` | ||
* | ||
* @name empty | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
Assertion.overwriteProperty('empty', function (_super) { | ||
return function () { | ||
var obj = this._obj; | ||
Assertion.overwriteProperty('empty', _super => function () { | ||
const obj = this._obj; | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
var size = obj.size; | ||
new Assertion(size).a('number'); | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
const size = obj.size; | ||
new Assertion(size).a('number'); | ||
this.assert( | ||
size === 0, | ||
'expected #{this} to be empty but got size #{act}', | ||
'expected #{this} to not be empty' | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
}); | ||
this.assert( | ||
size === 0, | ||
'expected #{this} to be empty but got size #{act}', | ||
'expected #{this} to not be empty' | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}); | ||
/** | ||
* ### .equal(collection) | ||
* | ||
* Asserts that the values of the target are equivalent to the values of | ||
* `collection`. Aliases of Chai's original `equal` method are also supported. | ||
* | ||
* ```js | ||
* var a = List.of(1, 2, 3); | ||
* var b = List.of(1, 2, 3); | ||
* expect(a).to.equal(b); | ||
* ``` | ||
* | ||
* Immutable data structures should only contain other immutable data | ||
* structures (unlike `Array`s and `Object`s) to be considered immutable and | ||
* properly work against `.equal()`. See | ||
* [this issue](https://github.com/astorije/chai-immutable/issues/24) for | ||
* more information. | ||
* | ||
* Also, note that `deep.equal` and `eql` are synonyms of `equal` when | ||
* tested against immutable data structures, therefore they are aliases to | ||
* `equal`. | ||
* | ||
* @name equal | ||
* @alias equals | ||
* @alias eq | ||
* @alias eql | ||
* @alias eqls | ||
* @alias deep.equal | ||
* @param {Collection} value | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
/** | ||
* ### .equal(collection) | ||
* | ||
* Asserts that the values of the target are equivalent to the values of | ||
* `collection`. Aliases of Chai's original `equal` method are also supported. | ||
* | ||
* ```js | ||
* const a = List.of(1, 2, 3); | ||
* const b = List.of(1, 2, 3); | ||
* expect(a).to.equal(b); | ||
* ``` | ||
* | ||
* Immutable data structures should only contain other immutable data | ||
* structures (unlike `Array`s and `Object`s) to be considered immutable and | ||
* properly work against `.equal()`. See | ||
* [this issue](https://github.com/astorije/chai-immutable/issues/24) for | ||
* more information. | ||
* | ||
* Also, note that `deep.equal` and `eql` are synonyms of `equal` when | ||
* tested against immutable data structures, therefore they are aliases to | ||
* `equal`. | ||
* | ||
* @name equal | ||
* @alias equals | ||
* @alias eq | ||
* @alias eql | ||
* @alias eqls | ||
* @alias deep.equal | ||
* @param {Collection} value | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
function assertCollectionEqual(_super) { | ||
return function (collection) { | ||
var obj = this._obj; | ||
function assertCollectionEqual(_super) { | ||
return function (collection) { | ||
const obj = this._obj; | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
this.assert( | ||
Immutable.is(obj, collection), | ||
'expected #{act} to equal #{exp}', | ||
'expected #{act} to not equal #{exp}', | ||
collection.toString(), | ||
obj.toString(), | ||
true | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
this.assert( | ||
Immutable.is(obj, collection), | ||
'expected #{act} to equal #{exp}', | ||
'expected #{act} to not equal #{exp}', | ||
collection.toJS(), | ||
obj.toJS(), | ||
true | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
Assertion.overwriteMethod('equal', assertCollectionEqual); | ||
Assertion.overwriteMethod('equals', assertCollectionEqual); | ||
Assertion.overwriteMethod('eq', assertCollectionEqual); | ||
Assertion.overwriteMethod('eql', assertCollectionEqual); | ||
Assertion.overwriteMethod('eqls', assertCollectionEqual); | ||
Assertion.overwriteMethod('equal', assertCollectionEqual); | ||
Assertion.overwriteMethod('equals', assertCollectionEqual); | ||
Assertion.overwriteMethod('eq', assertCollectionEqual); | ||
Assertion.overwriteMethod('eql', assertCollectionEqual); | ||
Assertion.overwriteMethod('eqls', assertCollectionEqual); | ||
/** | ||
* ### .include(value) | ||
* | ||
* The `include` and `contain` assertions can be used as either property | ||
* based language chains or as methods to assert the inclusion of a value | ||
* in an immutable collection. When used as language chains, they toggle the | ||
* `contains` flag for the `keys` assertion. | ||
* | ||
* ```js | ||
* expect(new List([1, 2, 3])).to.include(2); | ||
* expect(new Map({ foo: 'bar', hello: 'universe' })).to.include.keys('foo'); | ||
* ``` | ||
* | ||
* @name include | ||
* @alias contain | ||
* @alias includes | ||
* @alias contains | ||
* @param {Mixed} val | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
/** | ||
* ### .include(value) | ||
* | ||
* The `include` and `contain` assertions can be used as either property | ||
* based language chains or as methods to assert the inclusion of a value | ||
* in an immutable collection. When used as language chains, they toggle the | ||
* `contains` flag for the `keys` assertion. | ||
* | ||
* Note that `deep.include` behaves exactly like `include` in the context of | ||
* immutable data structures. | ||
* | ||
* ```js | ||
* expect(new List([1, 2, 3])).to.include(2); | ||
* expect(new List([1, 2, 3])).to.deep.include(2); | ||
* expect(new Map({ foo: 'bar', hello: 'world' })).to.include.keys('foo'); | ||
* ``` | ||
* | ||
* @name include | ||
* @alias contain | ||
* @alias includes | ||
* @alias contains | ||
* @param {Mixed} val | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
function assertCollectionInclude(_super) { | ||
return function (val) { | ||
var obj = this._obj; | ||
function assertCollectionInclude(_super) { | ||
return function (val) { | ||
const obj = this._obj; | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
this.assert( | ||
obj.includes(val), | ||
'expected #{act} to include #{exp}', | ||
'expected #{act} to not include #{exp}', | ||
val, | ||
obj.toString() | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
function chainCollectionInclude(_super) { | ||
return function () { | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
this.assert( | ||
obj.includes(val), | ||
'expected #{act} to include #{exp}', | ||
'expected #{act} to not include #{exp}', | ||
val, | ||
obj.toString() | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
}; | ||
} | ||
} | ||
}; | ||
} | ||
['include', 'contain', 'contains', 'includes'].forEach(function (keyword) { | ||
Assertion.overwriteChainableMethod( | ||
keyword, | ||
assertCollectionInclude, | ||
chainCollectionInclude | ||
); | ||
}); | ||
function chainCollectionInclude(_super) { | ||
return function () { | ||
_super.apply(this, arguments); | ||
}; | ||
} | ||
/** | ||
* ### .keys(key1[, key2, ...[, keyN]]) | ||
* | ||
* Asserts that the keyed collection contains any or all of the passed-in | ||
* keys. Use in combination with `any`, `all`, `contains`, or `have` will | ||
* affect what will pass. | ||
* | ||
* When used in conjunction with `any`, at least one key that is passed in | ||
* must exist in the target object. This is regardless whether or not | ||
* the `have` or `contain` qualifiers are used. Note, either `any` or `all` | ||
* should be used in the assertion. If neither are used, the assertion is | ||
* defaulted to `all`. | ||
* | ||
* When both `all` and `contain` are used, the target object must have at | ||
* least all of the passed-in keys but may have more keys not listed. | ||
* | ||
* When both `all` and `have` are used, the target object must both contain | ||
* all of the passed-in keys AND the number of keys in the target object must | ||
* match the number of keys passed in (in other words, a target object must | ||
* have all and only all of the passed-in keys). | ||
* | ||
* `key` is an alias to `keys`. | ||
* | ||
* ```js | ||
* expect(new Map({ foo: 1 })).to.have.key('foo'); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys('foo', 'bar'); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new List(['bar', 'foo'])); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new Set(['bar', 'foo'])); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new Stack(['bar', 'foo'])); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys(['bar', 'foo']); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys({ 'bar': 6, 'foo': 7 }); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new Map({ 'bar': 6, 'foo': 7 })); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.any.keys('foo', 'not-foo'); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys('foo', 'bar'); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.contain.key('foo'); | ||
* ``` | ||
* | ||
* @name keys | ||
* @param {String...|Array|Object|Collection} keyN | ||
* @alias key | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
['include', 'contain', 'contains', 'includes'].forEach(keyword => { | ||
Assertion.overwriteChainableMethod( | ||
keyword, | ||
assertCollectionInclude, | ||
chainCollectionInclude | ||
); | ||
}); | ||
function assertKeyedCollectionKeys(_super) { | ||
return function (keys) { | ||
function has(key) { return obj.has(key); } | ||
/** | ||
* ### .keys(key1[, key2[, ...]]) | ||
* | ||
* Asserts that the target collection has the given keys. | ||
* | ||
* When the target is an object or array, keys can be provided as one or more | ||
* string arguments, a single array argument, a single object argument, or an | ||
* immutable collection. In the last 2 cases, only the keys in the given | ||
* object/collection matter; the values are ignored. | ||
* | ||
* ```js | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys('foo', 'bar'); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new List(['bar', 'foo'])); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Set(['bar', 'foo'])); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Stack(['bar', 'foo'])); | ||
* expect(new List(['x', 'y'])).to.have.all.keys(0, 1); | ||
* | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(['foo', 'bar']); | ||
* expect(new List(['x', 'y'])).to.have.all.keys([0, 1]); | ||
* | ||
* // Values in the passed object are ignored: | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys({ 'bar': 6, 'foo': 7 }); | ||
* expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Map({ 'bar': 6, 'foo': 7 })); | ||
* expect(new List(['x', 'y'])).to.have.all.keys({0: 4, 1: 5}); | ||
* ``` | ||
* | ||
* Note that `deep.property` behaves exactly like `property` in the context of | ||
* immutable data structures. | ||
* | ||
* By default, the target must have all of the given keys and no more. Add | ||
* `.any` earlier in the chain to only require that the target have at least | ||
* one of the given keys. Also, add `.not` earlier in the chain to negate | ||
* `.keys`. It's often best to add `.any` when negating `.keys`, and to use | ||
* `.all` when asserting `.keys` without negation. | ||
* | ||
* When negating `.keys`, `.any` is preferred because `.not.any.keys` asserts | ||
* exactly what's expected of the output, whereas `.not.all.keys` creates | ||
* uncertain expectations. | ||
* | ||
* ```js | ||
* // Recommended; asserts that target doesn't have any of the given keys | ||
* expect(new Map({a: 1, b: 2})).to.not.have.any.keys('c', 'd'); | ||
* | ||
* // Not recommended; asserts that target doesn't have all of the given | ||
* // keys but may or may not have some of them | ||
* expect(new Map({a: 1, b: 2})).to.not.have.all.keys('c', 'd'); | ||
* ``` | ||
* | ||
* When asserting `.keys` without negation, `.all` is preferred because | ||
* `.all.keys` asserts exactly what's expected of the output, whereas | ||
* `.any.keys` creates uncertain expectations. | ||
* | ||
* ```js | ||
* // Recommended; asserts that target has all the given keys | ||
* expect(new Map({a: 1, b: 2})).to.have.all.keys('a', 'b'); | ||
* | ||
* // Not recommended; asserts that target has at least one of the given | ||
* // keys but may or may not have more of them | ||
* expect(new Map({a: 1, b: 2})).to.have.any.keys('a', 'b'); | ||
* ``` | ||
* | ||
* Note that `.all` is used by default when neither `.all` nor `.any` appear | ||
* earlier in the chain. However, it's often best to add `.all` anyway because | ||
* it improves readability. | ||
* | ||
* ```js | ||
* // Both assertions are identical | ||
* expect(new Map({a: 1, b: 2})).to.have.all.keys('a', 'b'); // Recommended | ||
* expect(new Map({a: 1, b: 2})).to.have.keys('a', 'b'); // Not recommended | ||
* ``` | ||
* | ||
* Add `.include` earlier in the chain to require that the target's keys be a | ||
* superset of the expected keys, rather than identical sets. | ||
* | ||
* ```js | ||
* // Target object's keys are a superset of ['a', 'b'] but not identical | ||
* expect(new Map({a: 1, b: 2, c: 3})).to.include.all.keys('a', 'b'); | ||
* expect(new Map({a: 1, b: 2, c: 3})).to.not.have.all.keys('a', 'b'); | ||
* ``` | ||
* | ||
* However, if `.any` and `.include` are combined, only the `.any` takes | ||
* effect. The `.include` is ignored in this case. | ||
* | ||
* ```js | ||
* // Both assertions are identical | ||
* expect(new Map({a: 1})).to.have.any.keys('a', 'b'); | ||
* expect(new Map({a: 1})).to.include.any.keys('a', 'b'); | ||
* ``` | ||
* | ||
* The alias `.key` can be used interchangeably with `.keys`. | ||
* | ||
* ```js | ||
* expect(new Map({ foo: 1 })).to.have.key('foo'); | ||
* ``` | ||
* | ||
* @name keys | ||
* @alias key | ||
* @alias deep.key | ||
* @param {...String|Array|Object|Collection} keys | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
var obj = this._obj; | ||
function assertKeyedCollectionKeys(_super) { | ||
return function (keys) { | ||
const obj = this._obj; | ||
if (Immutable.Iterable.isKeyed(obj)) { | ||
switch (utils.type(keys)) { | ||
case 'Object': | ||
if (Immutable.Iterable.isIndexed(keys)) | ||
keys = keys.toJS(); | ||
else if (Immutable.Iterable.isIterable(keys)) | ||
keys = keys.keySeq().toJS(); | ||
else keys = Object.keys(keys); | ||
case 'Array': | ||
if (arguments.length > 1) throw new Error( | ||
'keys must be given single argument of ' + | ||
'Array|Object|String|Collection, ' + | ||
'or multiple String arguments' | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
const ssfi = utils.flag(this, 'ssfi'); | ||
switch (utils.type(keys)) { | ||
case 'Object': | ||
if (Immutable.Iterable.isIndexed(keys)) { | ||
keys = keys.toJS(); | ||
} else if (Immutable.Iterable.isIterable(keys)) { | ||
keys = keys.keySeq().toJS(); | ||
} else { | ||
keys = Object.keys(keys); | ||
} | ||
// `keys` is now an array so this statement safely falls through | ||
case 'Array': | ||
if (arguments.length > 1) { | ||
throw new chai.AssertionError( | ||
'when testing keys against an immutable collection, you must ' + | ||
'give a single Array|Object|String|Collection argument or ' + | ||
'multiple String arguments', | ||
null, | ||
ssfi | ||
); | ||
break; | ||
default: | ||
keys = Array.prototype.slice.call(arguments); | ||
break; | ||
} | ||
} | ||
break; | ||
default: | ||
keys = Array.prototype.slice.call(arguments); | ||
break; | ||
} | ||
if (!keys.length) throw new Error('keys required'); | ||
// Only stringify non-Symbols because Symbols would become "Symbol()" | ||
keys = keys.map(val => typeof val === 'symbol' ? val : String(val)); | ||
var any = utils.flag(this, 'any'); | ||
var contains = utils.flag(this, 'contains'); | ||
var ok; | ||
var str = (contains ? 'contain' : 'have') + ' '; | ||
if (!keys.length) { | ||
throw new chai.AssertionError('keys required', null, ssfi); | ||
} | ||
if (any) ok = keys.some(has); | ||
else { | ||
ok = keys.every(has); | ||
if (!contains) { | ||
ok = ok && keys.length === obj.count(); | ||
} | ||
} | ||
let all = utils.flag(this, 'all'); | ||
const any = utils.flag(this, 'any'); | ||
const contains = utils.flag(this, 'contains'); | ||
let ok; | ||
let str = contains ? 'contain ' : 'have '; | ||
if (keys.length > 1) { | ||
keys = keys.map(utils.inspect); | ||
var last = keys.pop(); | ||
var conjunction = any ? 'or' : 'and'; | ||
str += 'keys ' + keys.join(', ') + ', ' + conjunction + ' ' + last; | ||
if (!any && !all) { | ||
all = true; | ||
} | ||
if (any) { | ||
ok = keys.some(key => obj.has(key)); | ||
} else { | ||
ok = keys.every(key => obj.has(key)); | ||
if (!contains) { | ||
ok = ok && keys.length === obj.count(); | ||
} | ||
else str += 'key ' + utils.inspect(keys[0]); | ||
} | ||
this.assert( | ||
ok, | ||
'expected #{act} to ' + str, | ||
'expected #{act} to not ' + str, | ||
keys, | ||
obj.toString() | ||
); | ||
if (keys.length > 1) { | ||
keys = keys.map(utils.inspect); | ||
const last = keys.pop(); | ||
const conjunction = any ? 'or' : 'and'; | ||
str += `keys ${keys.join(', ')}, ${conjunction} ${last}`; | ||
} else { | ||
str += `key ${utils.inspect(keys[0])}`; | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
Assertion.overwriteMethod('keys', assertKeyedCollectionKeys); | ||
Assertion.overwriteMethod('key', assertKeyedCollectionKeys); | ||
this.assert( | ||
ok, | ||
`expected #{act} to ${str}`, | ||
`expected #{act} to not ${str}`, | ||
keys.slice(0).sort(utils.compareByInspect), | ||
obj.toString(), | ||
true | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
/*! | ||
* ## parsePath(path) | ||
* | ||
* Helper function used to parse string paths into arrays of keys and | ||
* indices. | ||
* | ||
* ```js | ||
* var parsed = parsePath('myobject.key.subkey'); | ||
* ``` | ||
* | ||
* ### Paths: | ||
* | ||
* - Can be as near infinitely deep and nested | ||
* - Arrays are also valid using the formal `myobject.document[3].key`. | ||
* - Literal dots and brackets (not delimiter) must be backslash-escaped. | ||
* | ||
* This function is inspired from Chai's original `parsePath` function: | ||
* https://github.com/chaijs/chai/blob/d664ef4/lib/chai/utils/getPathInfo.js#L46-L74 | ||
* | ||
* @param {String} path | ||
* @returns {Array} parsed | ||
* @api private | ||
*/ | ||
function parsePath(path) { // Given the following path: 'a.b[1]' | ||
// Separates keys followed by indices with a dot: 'a.b.[1]' | ||
var str = path.replace(/([^\\])\[/g, '$1.['); | ||
// Extracts all indices and keys into an array: ['a', 'b', '[1]'] | ||
var parts = str.match(/(\\\.|[^.]+?)+/g); | ||
Assertion.overwriteMethod('keys', assertKeyedCollectionKeys); | ||
Assertion.overwriteMethod('key', assertKeyedCollectionKeys); | ||
// Removes brackets and escaping backslashes, and extracts digits from | ||
// each value in the array: ['a', 'b', 1] | ||
return parts.map(function (value) { | ||
// Extracts indices wrapped in brackets | ||
var re = /^\[(\d+)\]$/; | ||
// Builds ['[<index>]', '<index>'] if value is a digit, null otherwise | ||
var mArr = re.exec(value); | ||
/*! | ||
* ## parsePath(path) | ||
* | ||
* Helper function used to parse string paths into arrays of keys and | ||
* indices. | ||
* | ||
* ```js | ||
* const parsed = parsePath('myobject.key.subkey'); | ||
* ``` | ||
* | ||
* ### Paths: | ||
* | ||
* - Can be as near infinitely deep and nested | ||
* - Arrays are also valid using the formal `myobject.document[3].key`. | ||
* - Literal dots and brackets (not delimiter) must be backslash-escaped. | ||
* | ||
* This function is inspired from Chai's original `parsePath` function: | ||
* https://github.com/chaijs/chai/blob/d664ef4/lib/chai/utils/getPathInfo.js#L46-L74 | ||
* | ||
* @param {String} path | ||
* @returns {Array} parsed | ||
* @api private | ||
*/ | ||
function parsePath(path) { // Given the following path: 'a.b[1]' | ||
// Separates keys followed by indices with a dot: 'a.b.[1]' | ||
const str = path.replace(/([^\\])\[/g, '$1.['); | ||
// Extracts all indices and keys into an array: ['a', 'b', '[1]'] | ||
const parts = str.match(/(\\\.|[^.]+?)+/g); | ||
// If the value was of form '[<index>]', returns <index> | ||
// Otherwise, returns the key without the escaping backslashes | ||
if (mArr) return parseFloat(mArr[1]); | ||
else return value.replace(/\\([.\[\]])/g, '$1'); | ||
}); | ||
} | ||
// Removes brackets and escaping backslashes, and extracts digits from | ||
// each value in the array: ['a', 'b', 1] | ||
return parts.map(value => { | ||
// Extracts indices wrapped in brackets | ||
const re = /^\[(\d+)\]$/; | ||
// Builds ['[<index>]', '<index>'] if value is a digit, null otherwise | ||
const mArr = re.exec(value); | ||
/** | ||
* ### .property(name, [value]) | ||
* | ||
* Asserts that the target has a property `name`, optionally asserting that | ||
* the value of that property is equal to `value`. `value` can be an | ||
* Immutable object. | ||
* If the `nested` flag is set, you can use dot- and bracket-notation for | ||
* nested references into objects and arrays. | ||
* | ||
* ```js | ||
* // Simple referencing | ||
* var map = new Map({ foo: 'bar' }); | ||
* expect(map).to.have.property('foo'); | ||
* expect(map).to.have.property('foo', 'bar'); | ||
* | ||
* // Deep referencing | ||
* var nestedMap = new Map({ | ||
* green: new Map({ tea: 'matcha' }), | ||
* teas: new List(['chai', 'matcha', new Map({ tea: 'konacha' })]) | ||
* }); | ||
* | ||
* expect(nestedMap).to.have.nested.property('green.tea', 'matcha'); | ||
* expect(nestedMap).to.have.nested.property(['green', 'tea'], 'matcha'); | ||
* expect(nestedMap).to.have.nested.property(new List(['green', 'tea']), 'matcha'); | ||
* expect(nestedMap).to.have.nested.property('teas[1]', 'matcha'); | ||
* expect(nestedMap).to.have.nested.property(['teas', 1], 'matcha'); | ||
* expect(nestedMap).to.have.nested.property(new List(['teas', 1]), 'matcha'); | ||
* expect(nestedMap).to.have.nested.property('teas[2].tea', 'konacha'); | ||
* expect(nestedMap).to.have.nested.property(['teas', 2, 'tea'], 'konacha'); | ||
* expect(nestedMap).to.have.nested.property(new List(['teas', 2, 'tea']), 'konacha'); | ||
* ``` | ||
* | ||
* You can also use a `List` as the starting point of a `nested.property` | ||
* assertion, or traverse nested `List`s. | ||
* | ||
* ```js | ||
* var list = new List([ | ||
* new List(['chai', 'matcha', 'konacha']), | ||
* new List([ | ||
* new Map({ tea: 'chai' }), | ||
* new Map({ tea: 'matcha' }), | ||
* new Map({ tea: 'konacha' }) | ||
* ]) | ||
* ]); | ||
* | ||
* expect(list).to.have.nested.property('[0][1]', 'matcha'); | ||
* expect(list).to.have.nested.property([0, 1], 'matcha'); | ||
* expect(list).to.have.nested.property(new List([0, 1]), 'matcha'); | ||
* expect(list).to.have.nested.property('[1][2].tea', 'konacha'); | ||
* expect(list).to.have.nested.property([1, 2, 'tea'], 'konacha'); | ||
* expect(list).to.have.nested.property(new List([1, 2, 'tea']), 'konacha'); | ||
* ``` | ||
* | ||
* Furthermore, `property` changes the subject of the assertion | ||
* to be the value of that property from the original object. This | ||
* permits for further chainable assertions on that property. | ||
* | ||
* ```js | ||
* expect(map).to.have.property('foo') | ||
* .that.is.a('string'); | ||
* expect(nestedMap).to.have.property('green') | ||
* .that.is.an.instanceof(Map) | ||
* .that.equals(new Map({ tea: 'matcha' })); | ||
* expect(nestedMap).to.have.property('teas') | ||
* .that.is.an.instanceof(List) | ||
* .with.nested.property([2]) | ||
* .that.equals(new Map({ tea: 'konacha' })); | ||
* ``` | ||
* | ||
* Note that dots and brackets in `name` must be backslash-escaped when | ||
* the `nested` flag is set, while they must NOT be escaped when the | ||
* `nested` flag is not set. | ||
* | ||
* ```js | ||
* // Simple referencing | ||
* var css = new Map({ '.link[target]': 42 }); | ||
* expect(css).to.have.property('.link[target]', 42); | ||
* | ||
* // Deep referencing | ||
* var nestedCss = new Map({ '.link': new Map({ '[target]': 42 }) }); | ||
* expect(nestedCss).to.have.nested.property('\\.link.\\[target\\]', 42); | ||
* ``` | ||
* | ||
* @name property | ||
* @param {String|Array|Iterable} name | ||
* @param {Mixed} value (optional) | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
function assertProperty(_super) { | ||
return function (path, val) { | ||
var obj = this._obj; | ||
// If the value was of form '[<index>]', returns <index> | ||
// Otherwise, returns the key without the escaping backslashes | ||
if (mArr) { | ||
return parseFloat(mArr[1]); | ||
} else { | ||
return value.replace(/\\([.[\]])/g, '$1'); | ||
} | ||
}); | ||
} | ||
if (Immutable.Iterable.isIterable(this._obj)) { | ||
var isNested = Boolean(utils.flag(this, 'nested')); | ||
var negate = Boolean(utils.flag(this, 'negate')); | ||
/** | ||
* ### .property(path[, val]) | ||
* | ||
* Asserts that the target has a property with the given `path`. | ||
* | ||
* ```js | ||
* expect(new Map({a: 1})).to.have.property('a'); | ||
* ``` | ||
* | ||
* When `val` is provided, `.property` also asserts that the property's value | ||
* is equal to the given `val`. `val` can be an immutable collection. | ||
* | ||
* ```js | ||
* expect(new Map({a: 1})).to.have.property('a', 1); | ||
* ``` | ||
* | ||
* Note that `deep.property` behaves exactly like `property` in the context of | ||
* immutable data structures. | ||
* | ||
* Add `.nested` earlier in the chain to enable dot- and bracket-notation when | ||
* referencing nested properties. An immutable `List` can also be used as the | ||
* starting point of a `nested.property`. | ||
* | ||
* ```js | ||
* expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property('a.b[1]'); | ||
* expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property('a.b[1]', 'y'); | ||
* expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property(['a', 'b', 1], 'y'); | ||
* expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property(new List(['a', 'b', 1]), 'y'); | ||
* ``` | ||
* | ||
* If `.` or `[]` are part of an actual property name, they can be escaped by | ||
* adding two backslashes before them. | ||
* | ||
* ```js | ||
* expect(Immutable.fromJS({'.a': {'[b]': 'x'}})).to.have.nested.property('\\.a.\\[b\\]'); | ||
* ``` | ||
* | ||
* Add `.not` earlier in the chain to negate `.property`. | ||
* | ||
* ```js | ||
* expect(new Map({a: 1})).to.not.have.property('b'); | ||
* ``` | ||
* | ||
* However, it's dangerous to negate `.property` when providing `val`. The | ||
* problem is that it creates uncertain expectations by asserting that the | ||
* target either doesn't have a property at the given `path`, or that it | ||
* does have a property at the given key `path` but its value isn't equal to | ||
* the given `val`. It's often best to identify the exact output that's | ||
* expected, and then write an assertion that only accepts that exact output. | ||
* | ||
* When the target isn't expected to have a property at the given | ||
* `path`, it's often best to assert exactly that. | ||
* | ||
* ```js | ||
* expect(new Map({b: 2})).to.not.have.property('a'); // Recommended | ||
* expect(new Map({b: 2})).to.not.have.property('a', 1); // Not recommended | ||
* ``` | ||
* | ||
* When the target is expected to have a property at the given key `path`, | ||
* it's often best to assert that the property has its expected value, rather | ||
* than asserting that it doesn't have one of many unexpected values. | ||
* | ||
* ```js | ||
* expect(new Map({a: 3})).to.have.property('a', 3); // Recommended | ||
* expect(new Map({a: 3})).to.not.have.property('a', 1); // Not recommended | ||
* ``` | ||
* | ||
* `.property` changes the target of any assertions that follow in the chain | ||
* to be the value of the property from the original target object. | ||
* | ||
* ```js | ||
* expect(new Map({a: 1})).to.have.property('a').that.is.a('number'); | ||
* ``` | ||
* | ||
* @name property | ||
* @alias deep.equal | ||
* @param {String|Array|Iterable} path | ||
* @param {Mixed} val (optional) | ||
* @returns value of property for chaining | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
var descriptor; | ||
var hasProperty; | ||
var value; | ||
function assertProperty(_super) { | ||
return function (path, val) { | ||
const obj = this._obj; | ||
if (isNested) { | ||
descriptor = 'nested property '; | ||
if (typeof path === 'string') { | ||
path = parsePath(path); | ||
} | ||
value = obj.getIn(path); | ||
hasProperty = obj.hasIn(path); | ||
} | ||
else { | ||
descriptor = 'property '; | ||
value = obj.get(path); | ||
hasProperty = obj.has(path); | ||
} | ||
if (Immutable.Iterable.isIterable(obj)) { | ||
const isNested = utils.flag(this, 'nested'); | ||
const negate = utils.flag(this, 'negate'); | ||
// In the negate case, we only throw if property is missing so we can | ||
// check the value later. | ||
if (negate && arguments.length > 1) { | ||
if (!hasProperty) { | ||
throw new chai.AssertionError('expected ' + utils.inspect(obj) + | ||
' to have a ' + descriptor + utils.inspect(path)); | ||
} | ||
let descriptor; | ||
let hasProperty; | ||
let value; | ||
if (isNested) { | ||
descriptor = 'nested '; | ||
if (typeof path === 'string') { | ||
path = parsePath(path); | ||
} | ||
else { | ||
this.assert( | ||
hasProperty, | ||
'expected #{this} to have a ' + descriptor + utils.inspect(path), | ||
'expected #{this} not to have ' + descriptor + utils.inspect(path) | ||
); | ||
} | ||
value = obj.getIn(path); | ||
hasProperty = obj.hasIn(path); | ||
} else { | ||
value = obj.get(path); | ||
hasProperty = obj.has(path); | ||
} | ||
if (arguments.length > 1) { | ||
var isEqual; | ||
if (Immutable.Iterable.isIterable(val)) { | ||
isEqual = Immutable.is(val, value); | ||
} | ||
else { | ||
isEqual = val === value; | ||
} | ||
// When performing a negated assertion for both name and val, merely | ||
// having a property with the given name isn't enough to cause the | ||
// assertion to fail. It must both have a property with the given name, | ||
// and the value of that property must equal the given val. Therefore, | ||
// skip this assertion in favor of the next. | ||
if (!negate || arguments.length === 1) { | ||
this.assert( | ||
hasProperty, | ||
`expected #{this} to have ${descriptor}property ` + | ||
`${utils.inspect(path)}`, | ||
`expected #{this} to not have ${descriptor}property ` + | ||
`${utils.inspect(path)}` | ||
); | ||
} | ||
this.assert( | ||
isEqual, | ||
'expected #{this} to have a ' + descriptor + utils.inspect(path) + | ||
' of #{exp}, but got #{act}', | ||
'expected #{this} not to have a ' + descriptor + utils.inspect(path) + | ||
' of #{act}', | ||
val, | ||
value | ||
); | ||
if (arguments.length > 1) { | ||
let isEqual; | ||
if (Immutable.Iterable.isIterable(val)) { | ||
isEqual = Immutable.is(val, value); | ||
} else { | ||
isEqual = val === value; | ||
} | ||
utils.flag(this, 'object', value); | ||
this.assert( | ||
hasProperty && isEqual, | ||
`expected #{this} to have ${descriptor}property ` + | ||
`${utils.inspect(path)} of #{exp}, but got #{act}`, | ||
`expected #{this} to not have ${descriptor}property ` + | ||
`${utils.inspect(path)} of #{act}`, | ||
val, | ||
value | ||
); | ||
} | ||
else return _super.apply(this, arguments); | ||
}; | ||
} | ||
Assertion.overwriteMethod('property', assertProperty); | ||
utils.flag(this, 'object', value); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
/** | ||
* ### .size(value) | ||
* | ||
* Asserts that the immutable collection has the expected size. | ||
* | ||
* ```js | ||
* expect(List.of(1, 2, 3)).to.have.size(3); | ||
* ``` | ||
* | ||
* It can also be used as a chain precursor to a value comparison for the | ||
* `size` property. | ||
* | ||
* ```js | ||
* expect(List.of(1, 2, 3)).to.have.size.least(3); | ||
* expect(List.of(1, 2, 3)).to.have.size.most(3); | ||
* expect(List.of(1, 2, 3)).to.have.size.above(2); | ||
* expect(List.of(1, 2, 3)).to.have.size.below(4); | ||
* expect(List.of(1, 2, 3)).to.have.size.within(2,4); | ||
* ``` | ||
* | ||
* Similarly to `length`/`lengthOf`, `sizeOf` is an alias of `size`: | ||
* | ||
* ```js | ||
* expect(List.of(1, 2, 3)).to.have.sizeOf(3); | ||
* ``` | ||
* | ||
* @name size | ||
* @alias sizeOf | ||
* @param {Number} size | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
Assertion.overwriteMethod('property', assertProperty); | ||
function assertCollectionSize(n) { | ||
assertIsIterable(this._obj); | ||
/** | ||
* ### .size(value) | ||
* | ||
* Asserts that the immutable collection has the expected size. | ||
* | ||
* ```js | ||
* expect(List.of(1, 2, 3)).to.have.size(3); | ||
* ``` | ||
* | ||
* It can also be used as a chain precursor to a value comparison for the | ||
* `size` property. | ||
* | ||
* ```js | ||
* expect(List.of(1, 2, 3)).to.have.size.least(3); | ||
* expect(List.of(1, 2, 3)).to.have.size.most(3); | ||
* expect(List.of(1, 2, 3)).to.have.size.above(2); | ||
* expect(List.of(1, 2, 3)).to.have.size.below(4); | ||
* expect(List.of(1, 2, 3)).to.have.size.within(2,4); | ||
* ``` | ||
* | ||
* Similarly to `length`/`lengthOf`, `sizeOf` is an alias of `size`: | ||
* | ||
* ```js | ||
* expect(List.of(1, 2, 3)).to.have.sizeOf(3); | ||
* ``` | ||
* | ||
* @name size | ||
* @alias sizeOf | ||
* @param {Number} size | ||
* @namespace BDD | ||
* @api public | ||
*/ | ||
var size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSize(n) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size === n, | ||
'expected #{this} to have size #{exp} but got #{act}', | ||
'expected #{this} to not have size #{act}', | ||
n, | ||
size | ||
); | ||
} | ||
const size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function chainCollectionSize() { | ||
utils.flag(this, 'immutable.collection.size', true); | ||
} | ||
this.assert( | ||
size === n, | ||
'expected #{this} to have size #{exp} but got #{act}', | ||
'expected #{this} to not have size #{act}', | ||
n, | ||
size | ||
); | ||
} | ||
Assertion.addChainableMethod('size', assertCollectionSize, chainCollectionSize); | ||
Assertion.addMethod('sizeOf', assertCollectionSize); | ||
function chainCollectionSize() { | ||
utils.flag(this, 'immutable.collection.size', true); | ||
} | ||
// Numerical comparator overwrites | ||
Assertion.addChainableMethod( | ||
'size', | ||
assertCollectionSize, | ||
chainCollectionSize | ||
); | ||
Assertion.addMethod('sizeOf', assertCollectionSize); | ||
function assertCollectionSizeLeast(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
// Numerical comparator overwrites | ||
var size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeLeast(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size >= n, | ||
'expected #{this} to have a size of at least #{exp} but got #{act}', | ||
'expected #{this} to not have a size of at least #{exp} but got #{act}', | ||
n, | ||
size | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
const size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeMost(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size >= n, | ||
'expected #{this} to have a size of at least #{exp} but got #{act}', | ||
'expected #{this} to not have a size of at least #{exp} but got ' + | ||
'#{act}', | ||
n, | ||
size | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
var size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeMost(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size <= n, | ||
'expected #{this} to have a size of at most #{exp} but got #{act}', | ||
'expected #{this} to not have a size of at most #{exp} but got #{act}', | ||
n, | ||
size | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
const size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeAbove(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size <= n, | ||
'expected #{this} to have a size of at most #{exp} but got #{act}', | ||
'expected #{this} to not have a size of at most #{exp} but got ' + | ||
'#{act}', | ||
n, | ||
size | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
var size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeAbove(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size > n, | ||
'expected #{this} to have a size above #{exp} but got #{act}', | ||
'expected #{this} to not have a size above #{exp} but got #{act}', | ||
n, | ||
size | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
const size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeBelow(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size > n, | ||
'expected #{this} to have a size above #{exp} but got #{act}', | ||
'expected #{this} to not have a size above #{exp} but got #{act}', | ||
n, | ||
size | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
var size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
function assertCollectionSizeBelow(_super) { | ||
return function (n) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
size < n, | ||
'expected #{this} to have a size below #{exp} but got #{act}', | ||
'expected #{this} to not have a size below #{exp} but got #{act}', | ||
n, | ||
size | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
} | ||
const size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
Assertion.overwriteMethod('least', assertCollectionSizeLeast); | ||
Assertion.overwriteMethod('gte', assertCollectionSizeLeast); | ||
this.assert( | ||
size < n, | ||
'expected #{this} to have a size below #{exp} but got #{act}', | ||
'expected #{this} to not have a size below #{exp} but got #{act}', | ||
n, | ||
size | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}; | ||
} | ||
Assertion.overwriteMethod('most', assertCollectionSizeMost); | ||
Assertion.overwriteMethod('lte', assertCollectionSizeMost); | ||
Assertion.overwriteMethod('least', assertCollectionSizeLeast); | ||
Assertion.overwriteMethod('gte', assertCollectionSizeLeast); | ||
Assertion.overwriteMethod('above', assertCollectionSizeAbove); | ||
Assertion.overwriteMethod('gt', assertCollectionSizeAbove); | ||
Assertion.overwriteMethod('greaterThan', assertCollectionSizeAbove); | ||
Assertion.overwriteMethod('most', assertCollectionSizeMost); | ||
Assertion.overwriteMethod('lte', assertCollectionSizeMost); | ||
Assertion.overwriteMethod('below', assertCollectionSizeBelow); | ||
Assertion.overwriteMethod('lt', assertCollectionSizeBelow); | ||
Assertion.overwriteMethod('lessThan', assertCollectionSizeBelow); | ||
Assertion.overwriteMethod('above', assertCollectionSizeAbove); | ||
Assertion.overwriteMethod('gt', assertCollectionSizeAbove); | ||
Assertion.overwriteMethod('greaterThan', assertCollectionSizeAbove); | ||
Assertion.overwriteMethod('within', function (_super) { | ||
return function (min, max) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
Assertion.overwriteMethod('below', assertCollectionSizeBelow); | ||
Assertion.overwriteMethod('lt', assertCollectionSizeBelow); | ||
Assertion.overwriteMethod('lessThan', assertCollectionSizeBelow); | ||
var size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
Assertion.overwriteMethod('within', _super => function (min, max) { | ||
if (utils.flag(this, 'immutable.collection.size')) { | ||
assertIsIterable(this._obj); | ||
this.assert( | ||
min <= size && size <= max, | ||
'expected #{this} to have a size within #{exp} but got #{act}', | ||
'expected #{this} to not have a size within #{exp} but got #{act}', | ||
min + '..' + max, | ||
size | ||
); | ||
} | ||
else _super.apply(this, arguments); | ||
}; | ||
}); | ||
const size = this._obj.size; | ||
new Assertion(size).a('number'); | ||
/** | ||
* ## TDD API Reference | ||
*/ | ||
this.assert( | ||
min <= size && size <= max, | ||
'expected #{this} to have a size within #{exp} but got #{act}', | ||
'expected #{this} to not have a size within #{exp} but got #{act}', | ||
`${min}..${max}`, | ||
size | ||
); | ||
} else { | ||
_super.apply(this, arguments); | ||
} | ||
}); | ||
var assert = chai.assert; | ||
var originalEqual = assert.equal; | ||
var originalNotEqual = assert.notEqual; | ||
/** | ||
* ## TDD API Reference | ||
*/ | ||
/** | ||
* ### .equal(actual, expected) | ||
* | ||
* Asserts that the values of `actual` are equivalent to the values of | ||
* `expected`. Note that `.strictEqual()` and `.deepEqual()` assert | ||
* exactly like `.equal()` in the context of Immutable data structures. | ||
* | ||
* ```js | ||
* var a = List.of(1, 2, 3); | ||
* var b = List.of(1, 2, 3); | ||
* assert.equal(a, b); | ||
* ``` | ||
* | ||
* Immutable data structures should only contain other immutable data | ||
* structures (unlike `Array`s and `Object`s) to be considered immutable and | ||
* properly work against `.equal()`, `.strictEqual()` or `.deepEqual()`. See | ||
* [this issue](https://github.com/astorije/chai-immutable/issues/24) for | ||
* more information. | ||
* | ||
* @name equal | ||
* @param {Collection} actual | ||
* @param {Collection} expected | ||
* @namespace Assert | ||
* @api public | ||
*/ | ||
const assert = chai.assert; | ||
const originalEqual = assert.equal; | ||
const originalNotEqual = assert.notEqual; | ||
assert.equal = function (actual, expected) { | ||
// It seems like we shouldn't actually need this check, however, | ||
// `assert.equal` actually behaves differently than its BDD counterpart! | ||
// Namely, the BDD version is strict while the "assert" one isn't. | ||
if (Immutable.Iterable.isIterable(actual)) { | ||
return new Assertion(actual).equal(expected); | ||
} | ||
else return originalEqual(actual, expected); | ||
}; | ||
/** | ||
* ### .equal(actual, expected) | ||
* | ||
* Asserts that the values of `actual` are equivalent to the values of | ||
* `expected`. Note that `.strictEqual()` and `.deepEqual()` assert | ||
* exactly like `.equal()` in the context of Immutable data structures. | ||
* | ||
* ```js | ||
* const a = List.of(1, 2, 3); | ||
* const b = List.of(1, 2, 3); | ||
* assert.equal(a, b); | ||
* ``` | ||
* | ||
* Immutable data structures should only contain other immutable data | ||
* structures (unlike `Array`s and `Object`s) to be considered immutable and | ||
* properly work against `.equal()`, `.strictEqual()` or `.deepEqual()`. See | ||
* [this issue](https://github.com/astorije/chai-immutable/issues/24) for | ||
* more information. | ||
* | ||
* @name equal | ||
* @param {Collection} actual | ||
* @param {Collection} expected | ||
* @namespace Assert | ||
* @api public | ||
*/ | ||
/** | ||
* ### .notEqual(actual, expected) | ||
* | ||
* Asserts that the values of `actual` are not equivalent to the values of | ||
* `expected`. Note that `.notStrictEqual()` and `.notDeepEqual()` assert | ||
* exactly like `.notEqual()` in the context of Immutable data structures. | ||
* | ||
* ```js | ||
* var a = List.of(1, 2, 3); | ||
* var b = List.of(4, 5, 6); | ||
* assert.notEqual(a, b); | ||
* ``` | ||
* | ||
* @name notEqual | ||
* @param {Collection} actual | ||
* @param {Collection} expected | ||
* @namespace Assert | ||
* @api public | ||
*/ | ||
assert.equal = (actual, expected) => { | ||
// It seems like we shouldn't actually need this check, however, | ||
// `assert.equal` actually behaves differently than its BDD counterpart! | ||
// Namely, the BDD version is strict while the "assert" one isn't. | ||
if (Immutable.Iterable.isIterable(actual)) { | ||
return new Assertion(actual).equal(expected); | ||
} else { | ||
return originalEqual(actual, expected); | ||
} | ||
}; | ||
assert.notEqual = function (actual, expected) { | ||
if (Immutable.Iterable.isIterable(actual)) { | ||
return new Assertion(actual).not.equal(expected); | ||
} | ||
else return originalNotEqual(actual, expected); | ||
}; | ||
/** | ||
* ### .notEqual(actual, expected) | ||
* | ||
* Asserts that the values of `actual` are not equivalent to the values of | ||
* `expected`. Note that `.notStrictEqual()` and `.notDeepEqual()` assert | ||
* exactly like `.notEqual()` in the context of Immutable data structures. | ||
* | ||
* ```js | ||
* const a = List.of(1, 2, 3); | ||
* const b = List.of(4, 5, 6); | ||
* assert.notEqual(a, b); | ||
* ``` | ||
* | ||
* @name notEqual | ||
* @param {Collection} actual | ||
* @param {Collection} expected | ||
* @namespace Assert | ||
* @api public | ||
*/ | ||
/** | ||
* ### .sizeOf(collection, length) | ||
* | ||
* Asserts that the immutable collection has the expected size. | ||
* | ||
* ```js | ||
* assert.sizeOf(List.of(1, 2, 3), 3); | ||
* assert.sizeOf(new List(), 0); | ||
* ``` | ||
* | ||
* @name sizeOf | ||
* @param {Collection} collection | ||
* @param {Number} size | ||
* @namespace Assert | ||
* @api public | ||
*/ | ||
assert.notEqual = (actual, expected) => { | ||
if (Immutable.Iterable.isIterable(actual)) { | ||
return new Assertion(actual).not.equal(expected); | ||
} else { | ||
return originalNotEqual(actual, expected); | ||
} | ||
}; | ||
assert.sizeOf = function (collection, expected) { | ||
new Assertion(collection).size(expected); | ||
}; | ||
/** | ||
* ### .sizeOf(collection, length) | ||
* | ||
* Asserts that the immutable collection has the expected size. | ||
* | ||
* ```js | ||
* assert.sizeOf(List.of(1, 2, 3), 3); | ||
* assert.sizeOf(new List(), 0); | ||
* ``` | ||
* | ||
* @name sizeOf | ||
* @param {Collection} collection | ||
* @param {Number} size | ||
* @namespace Assert | ||
* @api public | ||
*/ | ||
assert.sizeOf = (collection, expected) => { | ||
new Assertion(collection).size(expected); | ||
}; | ||
})); | ||
}); |
{ | ||
"name": "chai-immutable", | ||
"version": "2.0.0-alpha.1", | ||
"version": "2.0.0-alpha.2", | ||
"description": "Chai assertions for Facebook's Immutable library for JavaScript collections", | ||
"publishConfig": { | ||
"tag": "next" | ||
}, | ||
"main": "chai-immutable.js", | ||
@@ -13,9 +10,7 @@ "directories": { | ||
"scripts": { | ||
"check-style": "jscs chai-immutable.js test/test.js", | ||
"test": "npm run test-mocha; npm run test-phantomjs; npm run test-readme; npm run check-style", | ||
"test-readme": "mocha --compilers md:fulky/mocha-md-compiler README.md", | ||
"test-mocha": "mocha", | ||
"test-phantomjs": "mocha-phantomjs test/index.html", | ||
"coverage": "istanbul cover _mocha", | ||
"coveralls": "npm run coverage && cat ./coverage/lcov.info | coveralls" | ||
"lint": "eslint --ignore-path .gitignore . --report-unused-disable-directives", | ||
"test": "npm run test-mocha; npm run test-readme; npm run lint", | ||
"test-readme": "mocha --compilers md:fulky/md-compiler README.md", | ||
"test-mocha": "nyc mocha", | ||
"coveralls": "nyc report --reporter=text-lcov | coveralls" | ||
}, | ||
@@ -39,2 +34,5 @@ "repository": { | ||
"license": "MIT", | ||
"engines": { | ||
"node": ">=6" | ||
}, | ||
"bugs": { | ||
@@ -45,14 +43,17 @@ "url": "https://github.com/astorije/chai-immutable/issues" | ||
"peerDependencies": { | ||
"chai": "^4.0.0" | ||
"chai": "^4.0.0", | ||
"immutable": "^3.0.0" | ||
}, | ||
"devDependencies": { | ||
"chai": "^4.0.0", | ||
"coveralls": "^2.11.9", | ||
"fulky": "^0.1.0", | ||
"immutable": "^3.7.5", | ||
"istanbul": "^0.4.3", | ||
"jscs": "^2.5.0", | ||
"mocha": "^2.4.5", | ||
"mocha-phantomjs": "^4.1.0" | ||
"chai": "4.1.2", | ||
"coveralls": "3.0.1", | ||
"eslint": "4.19.1", | ||
"eslint-plugin-chai-expect": "1.1.1", | ||
"eslint-plugin-chai-friendly": "0.4.1", | ||
"eslint-plugin-mocha": "5.0.0", | ||
"fulky": "0.2.0", | ||
"immutable": "3.8.2", | ||
"mocha": "5.2.0", | ||
"nyc": "11.8.0" | ||
} | ||
} |
237
README.md
@@ -37,2 +37,4 @@ [![npm Version](https://img.shields.io/npm/v/chai-immutable.svg)](https://npmjs.org/package/chai-immutable) | ||
⚠️ To use `chai-immutable` with Chai v4, you need to use `npm install chai-immutable@next` instead, until I am done with the v2 release of this plugin. I apologize for the inconvenience in the meantime. | ||
You can then use this plugin as any other Chai plugins: | ||
@@ -126,132 +128,183 @@ | ||
Note that `deep.include` behaves exactly like `include` in the context of | ||
immutable data structures. | ||
```js | ||
expect(new List([1, 2, 3])).to.include(2); | ||
expect(new Map({ foo: 'bar', hello: 'universe' })).to.include.keys('foo'); | ||
expect(new List([1, 2, 3])).to.deep.include(2); | ||
expect(new Map({ foo: 'bar', hello: 'world' })).to.include.keys('foo'); | ||
``` | ||
### .keys(key1[, key2, ...[, keyN]]) | ||
### .keys(key1[, key2[, ...]]) | ||
- **@param** *{ String... | Array | Object | Collection }* key*N* | ||
Asserts that the keyed collection contains any or all of the passed-in | ||
keys. Use in combination with `any`, `all`, `contains`, or `have` will | ||
affect what will pass. | ||
Asserts that the target collection has the given keys. | ||
When used in conjunction with `any`, at least one key that is passed in | ||
must exist in the target object. This is regardless whether or not | ||
the `have` or `contain` qualifiers are used. Note, either `any` or `all` | ||
should be used in the assertion. If neither are used, the assertion is | ||
defaulted to `all`. | ||
When the target is an object or array, keys can be provided as one or more | ||
string arguments, a single array argument, a single object argument, or an | ||
immutable collection. In the last 2 cases, only the keys in the given | ||
object/collection matter; the values are ignored. | ||
When both `all` and `contain` are used, the target object must have at | ||
least all of the passed-in keys but may have more keys not listed. | ||
```js | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys('foo', 'bar'); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new List(['bar', 'foo'])); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Set(['bar', 'foo'])); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Stack(['bar', 'foo'])); | ||
expect(new List(['x', 'y'])).to.have.all.keys(0, 1); | ||
When both `all` and `have` are used, the target object must both contain | ||
all of the passed-in keys AND the number of keys in the target object must | ||
match the number of keys passed in (in other words, a target object must | ||
have all and only all of the passed-in keys). | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(['foo', 'bar']); | ||
expect(new List(['x', 'y'])).to.have.all.keys([0, 1]); | ||
`key` is an alias to `keys`. | ||
// Values in the passed object are ignored: | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys({ bar: 6, foo: 7 }); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Map({ bar: 6, foo: 7 })); | ||
expect(new List(['x', 'y'])).to.have.all.keys({ 0: 4, 1: 5 }); | ||
``` | ||
Note that `deep.property` behaves exactly like `property` in the context of | ||
immutable data structures. | ||
By default, the target must have all of the given keys and no more. Add | ||
`.any` earlier in the chain to only require that the target have at least | ||
one of the given keys. Also, add `.not` earlier in the chain to negate | ||
`.keys`. It's often best to add `.any` when negating `.keys`, and to use | ||
`.all` when asserting `.keys` without negation. | ||
When negating `.keys`, `.any` is preferred because `.not.any.keys` asserts | ||
exactly what's expected of the output, whereas `.not.all.keys` creates | ||
uncertain expectations. | ||
```js | ||
// Recommended; asserts that target doesn't have any of the given keys | ||
expect(new Map({a: 1, b: 2})).to.not.have.any.keys('c', 'd'); | ||
// Not recommended; asserts that target doesn't have all of the given | ||
// keys but may or may not have some of them | ||
expect(new Map({a: 1, b: 2})).to.not.have.all.keys('c', 'd'); | ||
``` | ||
When asserting `.keys` without negation, `.all` is preferred because | ||
`.all.keys` asserts exactly what's expected of the output, whereas | ||
`.any.keys` creates uncertain expectations. | ||
```js | ||
// Recommended; asserts that target has all the given keys | ||
expect(new Map({a: 1, b: 2})).to.have.all.keys('a', 'b'); | ||
// Not recommended; asserts that target has at least one of the given | ||
// keys but may or may not have more of them | ||
expect(new Map({a: 1, b: 2})).to.have.any.keys('a', 'b'); | ||
``` | ||
Note that `.all` is used by default when neither `.all` nor `.any` appear | ||
earlier in the chain. However, it's often best to add `.all` anyway because | ||
it improves readability. | ||
```js | ||
// Both assertions are identical | ||
expect(new Map({a: 1, b: 2})).to.have.all.keys('a', 'b'); // Recommended | ||
expect(new Map({a: 1, b: 2})).to.have.keys('a', 'b'); // Not recommended | ||
``` | ||
Add `.include` earlier in the chain to require that the target's keys be a | ||
superset of the expected keys, rather than identical sets. | ||
```js | ||
// Target object's keys are a superset of ['a', 'b'] but not identical | ||
expect(new Map({a: 1, b: 2, c: 3})).to.include.all.keys('a', 'b'); | ||
expect(new Map({a: 1, b: 2, c: 3})).to.not.have.all.keys('a', 'b'); | ||
``` | ||
However, if `.any` and `.include` are combined, only the `.any` takes | ||
effect. The `.include` is ignored in this case. | ||
```js | ||
// Both assertions are identical | ||
expect(new Map({a: 1})).to.have.any.keys('a', 'b'); | ||
expect(new Map({a: 1})).to.include.any.keys('a', 'b'); | ||
``` | ||
The alias `.key` can be used interchangeably with `.keys`. | ||
```js | ||
expect(new Map({ foo: 1 })).to.have.key('foo'); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys('foo', 'bar'); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new List(['bar', 'foo'])); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new Set(['bar', 'foo'])); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new Stack(['bar', 'foo'])); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys(['bar', 'foo']); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys({ 'bar': 6, 'foo': 7 }); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.keys(new Map({ 'bar': 6, 'foo': 7 })); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.any.keys('foo', 'not-foo'); | ||
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys('foo', 'bar'); | ||
expect(new Map({ foo: 1, bar: 2 })).to.contain.key('foo'); | ||
``` | ||
### .property(name, [value]) | ||
### .property(path[, val]) | ||
- **@param** *{ String | Array | Iterable }* name | ||
- **@param** *{ Mixed }* value (optional) | ||
- **@param** *{ String | Array | Iterable }* path | ||
- **@param** *{ Mixed }* val (optional) | ||
Asserts that the target has a property `name`, optionally asserting that | ||
the value of that property is equal to `value`. `value` can be an | ||
Immutable object. | ||
If the `nested` flag is set, you can use dot- and bracket-notation for nested | ||
references into objects and arrays. | ||
Asserts that the target has a property with the given `path`. | ||
<!-- fulky:define maps --> | ||
```js | ||
// Simple referencing | ||
var map = new Map({ foo: 'bar' }); | ||
expect(map).to.have.property('foo'); | ||
expect(map).to.have.property('foo', 'bar'); | ||
expect(new Map({a: 1})).to.have.property('a'); | ||
``` | ||
// Deep referencing | ||
var nestedMap = new Map({ | ||
green: new Map({ tea: 'matcha' }), | ||
teas: new List(['chai', 'matcha', new Map({ tea: 'konacha' })]) | ||
}); | ||
When `val` is provided, `.property` also asserts that the property's value | ||
is equal to the given `val`. `val` can be an immutable collection. | ||
expect(nestedMap).to.have.nested.property('green.tea', 'matcha'); | ||
expect(nestedMap).to.have.nested.property(['green', 'tea'], 'matcha'); | ||
expect(nestedMap).to.have.nested.property(new List(['green', 'tea']), 'matcha'); | ||
expect(nestedMap).to.have.nested.property('teas[1]', 'matcha'); | ||
expect(nestedMap).to.have.nested.property(['teas', 1], 'matcha'); | ||
expect(nestedMap).to.have.nested.property(new List(['teas', 1]), 'matcha'); | ||
expect(nestedMap).to.have.nested.property('teas[2].tea', 'konacha'); | ||
expect(nestedMap).to.have.nested.property(['teas', 2, 'tea'], 'konacha'); | ||
expect(nestedMap).to.have.nested.property(new List(['teas', 2, 'tea']), 'konacha'); | ||
```js | ||
expect(new Map({a: 1})).to.have.property('a', 1); | ||
``` | ||
You can also use a `List` as the starting point of a `nested.property` | ||
assertion, or traverse nested `List`s. | ||
Note that `deep.property` behaves exactly like `property` in the context of | ||
immutable data structures. | ||
Add `.nested` earlier in the chain to enable dot- and bracket-notation when | ||
referencing nested properties. An immutable `List` can also be used as the | ||
starting point of a `nested.property`. | ||
```js | ||
var list = new List([ | ||
new List(['chai', 'matcha', 'konacha']), | ||
new List([ | ||
new Map({ tea: 'chai' }), | ||
new Map({ tea: 'matcha' }), | ||
new Map({ tea: 'konacha' }) | ||
]) | ||
]); | ||
expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property('a.b[1]'); | ||
expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property('a.b[1]', 'y'); | ||
expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property(['a', 'b', 1], 'y'); | ||
expect(Immutable.fromJS({a: {b: ['x', 'y']}})).to.have.nested.property(new List(['a', 'b', 1]), 'y'); | ||
``` | ||
expect(list).to.have.nested.property('[0][1]', 'matcha'); | ||
expect(list).to.have.nested.property([0, 1], 'matcha'); | ||
expect(list).to.have.nested.property(new List([0, 1]), 'matcha'); | ||
expect(list).to.have.nested.property('[1][2].tea', 'konacha'); | ||
expect(list).to.have.nested.property([1, 2, 'tea'], 'konacha'); | ||
expect(list).to.have.nested.property(new List([1, 2, 'tea']), 'konacha'); | ||
If `.` or `[]` are part of an actual property name, they can be escaped by | ||
adding two backslashes before them. | ||
```js | ||
expect(Immutable.fromJS({'.a': {'[b]': 'x'}})).to.have.nested.property('\\.a.\\[b\\]'); | ||
``` | ||
Furthermore, `property` changes the subject of the assertion | ||
to be the value of that property from the original object. This | ||
permits for further chainable assertions on that property. | ||
Add `.not` earlier in the chain to negate `.property`. | ||
<!-- fulky:use maps --> | ||
```js | ||
expect(map).to.have.property('foo') | ||
.that.is.a('string'); | ||
expect(nestedMap).to.have.property('green') | ||
.that.is.an.instanceof(Map) | ||
.that.equals(new Map({ tea: 'matcha' })); | ||
expect(nestedMap).to.have.property('teas') | ||
.that.is.an.instanceof(List) | ||
.with.nested.property([2]) | ||
.that.equals(new Map({ tea: 'konacha' })); | ||
expect(new Map({a: 1})).to.not.have.property('b'); | ||
``` | ||
Note that dots and brackets in `name` must be backslash-escaped when | ||
the `nested` flag is set, while they must NOT be escaped when the `nested` | ||
flag is not set. | ||
However, it's dangerous to negate `.property` when providing `val`. The | ||
problem is that it creates uncertain expectations by asserting that the | ||
target either doesn't have a property at the given `path`, or that it | ||
does have a property at the given key `path` but its value isn't equal to | ||
the given `val`. It's often best to identify the exact output that's | ||
expected, and then write an assertion that only accepts that exact output. | ||
When the target isn't expected to have a property at the given | ||
`path`, it's often best to assert exactly that. | ||
```js | ||
// Simple referencing | ||
var css = new Map({ '.link[target]': 42 }); | ||
expect(css).to.have.property('.link[target]', 42); | ||
expect(new Map({b: 2})).to.not.have.property('a'); // Recommended | ||
expect(new Map({b: 2})).to.not.have.property('a', 1); // Not recommended | ||
``` | ||
// Deep referencing | ||
var nestedCss = new Map({ '.link': new Map({ '[target]': 42 }) }); | ||
expect(nestedCss).to.have.nested.property('\\.link.\\[target\\]', 42); | ||
When the target is expected to have a property at the given key `path`, | ||
it's often best to assert that the property has its expected value, rather | ||
than asserting that it doesn't have one of many unexpected values. | ||
```js | ||
expect(new Map({a: 3})).to.have.property('a', 3); // Recommended | ||
expect(new Map({a: 3})).to.not.have.property('a', 1); // Not recommended | ||
``` | ||
`.property` changes the target of any assertions that follow in the chain | ||
to be the value of the property from the original target object. | ||
```js | ||
expect(new Map({a: 1})).to.have.property('a').that.is.a('number'); | ||
``` | ||
### .size(value) | ||
@@ -258,0 +311,0 @@ |
942
test/test.js
@@ -5,29 +5,35 @@ 'use strict'; | ||
function clone(obj) { | ||
if (null === obj || 'object' !== typeof obj) return obj; | ||
var copy = obj.constructor(); | ||
for (var attr in obj) { | ||
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; | ||
if (obj === null || typeof obj !== 'object') { | ||
return obj; | ||
} | ||
const copy = obj.constructor(); | ||
for (const attr in obj) { | ||
if (Object.prototype.hasOwnProperty.call(obj, attr)) { | ||
copy[attr] = obj[attr]; | ||
} | ||
} | ||
return copy; | ||
} | ||
var typeEnv; | ||
// These can be global if they are coming from a browser environment, so `let` | ||
// cannot be used here. | ||
var chai; // eslint-disable-line no-var | ||
var chaiImmutable; // eslint-disable-line no-var | ||
var Immutable; // eslint-disable-line no-var | ||
if (!chai) { | ||
var chai = require('chai'); | ||
var chaiImmutable = require('../chai-immutable'); | ||
var Immutable = require('immutable'); | ||
chai = require('chai'); | ||
chaiImmutable = require('../chai-immutable'); | ||
Immutable = require('immutable'); | ||
chai.use(chaiImmutable); | ||
typeEnv = 'Node.js'; | ||
} | ||
else typeEnv = 'PhantomJS'; | ||
var clonedImmutable = clone(Immutable); | ||
const clonedImmutable = clone(Immutable); | ||
var assert = chai.assert; | ||
var expect = chai.expect; | ||
var List = Immutable.List; | ||
var Map = Immutable.Map; | ||
var Set = Immutable.Set; | ||
var Stack = Immutable.Stack; | ||
const assert = chai.assert; | ||
const expect = chai.expect; | ||
const List = Immutable.List; | ||
const Map = Immutable.Map; | ||
const Set = Immutable.Set; | ||
const Stack = Immutable.Stack; | ||
@@ -39,37 +45,27 @@ /*! | ||
function fail(fn, msg) { | ||
if (msg !== undefined) expect(fn).to.throw(chai.AssertionError, msg); | ||
else expect(fn).to.throw(chai.AssertionError); | ||
if (msg) { | ||
expect(fn).to.throw(chai.AssertionError, msg); | ||
} else { | ||
expect(fn).to.throw(chai.AssertionError); | ||
} | ||
} | ||
describe('chai-immutable (' + typeEnv + ')', function () { | ||
var list3 = List.of(1, 2, 3); | ||
describe('chai-immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
const list3 = List.of(1, 2, 3); | ||
const deepMap = new Map({ foo: 'bar', list: List.of(1, 2, 3) }); | ||
const sameDeepMap = new Map({ foo: 'bar', list: List.of(1, 2, 3) }); | ||
const differentDeepMap = new Map({ foo: 'bar', list: List.of(42) }); | ||
const clonedImmutableList = clonedImmutable.List.of(1, 2, 3); | ||
var deepMap = new Map({ | ||
foo: 'bar', | ||
list: List.of(1, 2, 3), | ||
}); | ||
var sameDeepMap = new Map({ | ||
foo: 'bar', | ||
list: List.of(1, 2, 3), | ||
}); | ||
var differentDeepMap = new Map({ | ||
foo: 'bar', | ||
list: List.of(42), | ||
}); | ||
var clonedImmutableList = clonedImmutable.List.of(1, 2, 3); | ||
describe('BDD interface', function () { | ||
describe('empty property', function () { | ||
it('should pass given an empty collection', function () { | ||
describe('BDD interface', function () { // eslint-disable-line prefer-arrow-callback | ||
describe('empty property', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given an empty collection', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new List()).to.be.empty; | ||
}); | ||
it('should pass using `not` given a non-empty collection', function () { | ||
it('should pass using `not` given a non-empty collection', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.be.empty; | ||
}); | ||
it('should not affect the original assertions', function () { | ||
it('should not affect the original assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
expect([]).to.be.empty; | ||
@@ -80,25 +76,25 @@ expect('').to.be.empty; | ||
it('should fail given a non-empty collection', function () { | ||
fail(function () { expect(list3).to.be.empty; }); | ||
it('should fail given a non-empty collection', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.be.empty); | ||
}); | ||
it('should fail using `not` given an empty collection', function () { | ||
fail(function () { expect(new List()).to.not.be.empty; }); | ||
it('should fail using `not` given an empty collection', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(new List()).to.not.be.empty); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
expect(clonedImmutable.List()).to.be.empty; | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new clonedImmutable.List()).to.be.empty; | ||
}); | ||
}); | ||
describe('equal method', function () { | ||
it('should pass given equal values', function () { | ||
describe('equal method', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.equal(List.of(1, 2, 3)); | ||
}); | ||
it('should pass using `not` given different values', function () { | ||
it('should pass using `not` given different values', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.equal(new List()); | ||
}); | ||
it('aliases of equal should also work', function () { | ||
it('aliases of equal should also work', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.equal(List.of(1, 2, 3)); | ||
@@ -118,3 +114,3 @@ expect(list3).to.not.equal(new List()); | ||
it('should not affect the original assertions', function () { | ||
it('should not affect the original assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
expect('hello').to.equal('hello'); | ||
@@ -127,3 +123,3 @@ expect(42).to.equal(42); | ||
it('should pass given deeply equal values', function () { | ||
it('should pass given deeply equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(deepMap).to.equal(sameDeepMap); | ||
@@ -137,3 +133,3 @@ expect(deepMap).to.equals(sameDeepMap); | ||
it('should pass using `not` given deeply different values', function () { | ||
it('should pass using `not` given deeply different values', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(deepMap).to.not.equal(differentDeepMap); | ||
@@ -147,46 +143,54 @@ expect(deepMap).to.not.equals(differentDeepMap); | ||
it('should pass using `not` given a non-Immutable value', function () { | ||
expect([]).to.not.equal(List()); | ||
it('should pass using `not` given a non-Immutable value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect([]).to.not.equal(new List()); | ||
}); | ||
// See https://github.com/astorije/chai-immutable/issues/7 | ||
it('should display a helpful failure output on big objects', function () { | ||
var actual = new Map({ foo: 'foo foo foo foo foo foo foo foo' }); | ||
var expected = new Map({ bar: 'bar bar bar bar bar bar bar bar' }); | ||
fail(function () { | ||
expect(actual).to.equal(expected); | ||
}, /(foo ?){8}.+(bar ?){8}/); | ||
it('should display a helpful failure output on big objects', function () { // eslint-disable-line prefer-arrow-callback | ||
const actual = new Map({ foo: 'foo foo foo foo foo foo foo foo' }); | ||
const expected = new Map({ bar: 'bar bar bar bar bar bar bar bar' }); | ||
// AssertionError: expected { Object (foo) } to equal { Object (bar) } | ||
// + expected - actual | ||
// | ||
// { | ||
// - "foo": "foo foo foo foo foo foo foo foo" | ||
// + "bar": "bar bar bar bar bar bar bar bar" | ||
// } | ||
fail( | ||
() => expect(actual).to.equal(expected), | ||
'expected { Object (foo) } to equal { Object (bar) }' | ||
); | ||
}); | ||
it('should fail given a non-Immutable value', function () { | ||
fail(function () { expect([]).to.equal(List()); }); | ||
it('should fail given a non-Immutable value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect([]).to.equal(new List())); | ||
}); | ||
it('should fail given different values', function () { | ||
fail(function () { expect(list3).to.equal(new List()); }); | ||
it('should fail given different values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.equal(new List())); | ||
}); | ||
it('should fail using `not` given equal values', function () { | ||
fail(function () { expect(list3).to.not.equal(List.of(1, 2, 3)); }); | ||
it('should fail using `not` given equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.equal(List.of(1, 2, 3))); | ||
}); | ||
it('should fail given deeply different values', function () { | ||
fail(function () { expect(deepMap).to.equal(differentDeepMap); }); | ||
fail(function () { expect(deepMap).to.equals(differentDeepMap); }); | ||
fail(function () { expect(deepMap).to.eq(differentDeepMap); }); | ||
fail(function () { expect(deepMap).to.eql(differentDeepMap); }); | ||
fail(function () { expect(deepMap).to.eqls(differentDeepMap); }); | ||
fail(function () { expect(deepMap).to.deep.equal(differentDeepMap); }); | ||
it('should fail given deeply different values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(deepMap).to.equal(differentDeepMap)); | ||
fail(() => expect(deepMap).to.equals(differentDeepMap)); | ||
fail(() => expect(deepMap).to.eq(differentDeepMap)); | ||
fail(() => expect(deepMap).to.eql(differentDeepMap)); | ||
fail(() => expect(deepMap).to.eqls(differentDeepMap)); | ||
fail(() => expect(deepMap).to.deep.equal(differentDeepMap)); | ||
}); | ||
it('should fail using `not` given deeply equal values', function () { | ||
fail(function () { expect(deepMap).to.not.equal(sameDeepMap); }); | ||
fail(function () { expect(deepMap).to.not.equals(sameDeepMap); }); | ||
fail(function () { expect(deepMap).to.not.eq(sameDeepMap); }); | ||
fail(function () { expect(deepMap).to.not.eql(sameDeepMap); }); | ||
fail(function () { expect(deepMap).to.not.eqls(sameDeepMap); }); | ||
fail(function () { expect(deepMap).to.not.deep.equal(sameDeepMap); }); | ||
it('should fail using `not` given deeply equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(deepMap).to.not.equal(sameDeepMap)); | ||
fail(() => expect(deepMap).to.not.equals(sameDeepMap)); | ||
fail(() => expect(deepMap).to.not.eq(sameDeepMap)); | ||
fail(() => expect(deepMap).to.not.eql(sameDeepMap)); | ||
fail(() => expect(deepMap).to.not.eqls(sameDeepMap)); | ||
fail(() => expect(deepMap).to.not.deep.equal(sameDeepMap)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(clonedImmutableList).to.equal(List.of(1, 2, 3)); | ||
@@ -196,26 +200,27 @@ }); | ||
describe('include method', function () { | ||
it('should pass given an existing value', function () { | ||
describe('include method', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given an existing value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new List([1, 2, 3])).to.include(2); | ||
expect(new List([1, 2, 3])).to.deep.include(2); | ||
}); | ||
it('should pass using `not` given an inexisting value', function () { | ||
it('should pass using `not` given an inexisting value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new List([1, 2, 3])).to.not.include(42); | ||
expect(new List([1, 2, 3])).to.not.deep.include(42); | ||
}); | ||
it('should chain and pass given an existing key', function () { | ||
expect(new Map({ | ||
foo: 'bar', | ||
hello: 'universe', | ||
})).to.include.keys('foo'); | ||
it('should chain and pass given an existing key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new Map({ foo: 'bar', hello: 'world' })).to.include.keys('foo'); | ||
expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.deep.include.keys('foo'); | ||
}); | ||
it('should chain and pass using `not` given an inexisting key', function () { | ||
expect(new Map({ | ||
foo: 'bar', | ||
hello: 'universe', | ||
})).to.not.include.keys('not-foo'); | ||
it('should chain and pass using `not` given an inexisting key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.not.include.keys('not-foo'); | ||
expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.not.deep.include.keys('not-foo'); | ||
}); | ||
it('aliases of include should also work', function () { | ||
it('aliases of include should also work', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new List([1, 2, 3])).contain(2); | ||
@@ -229,300 +234,390 @@ expect(new List([1, 2, 3])).not.contain(42); | ||
it('should not affect the original assertions', function () { | ||
it('should not affect the original assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
expect([1, 2, 3]).to.include(2); | ||
expect([1, 2, 3]).to.deep.include(2); | ||
expect('foobar').to.contain('foo'); | ||
expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); | ||
expect('foobar').to.deep.contain('foo'); | ||
expect({ foo: 'bar', hello: 'world' }).to.include.keys('foo'); | ||
expect({ foo: 'bar', hello: 'world' }).to.deep.include.keys('foo'); | ||
}); | ||
// See https://github.com/astorije/chai-immutable/issues/7 | ||
it('should display a helpful failure output on big objects', function () { | ||
var lengthyMap = new Map({ foo: 'foo foo foo foo foo foo foo foo ' }); | ||
fail(function () { | ||
expect(lengthyMap).to.include('not-foo'); | ||
}, /(foo ){8}/); | ||
it('should display a helpful failure output on big objects', function () { // eslint-disable-line prefer-arrow-callback | ||
const lengthyMap = new Map({ foo: 'foo foo foo foo foo foo foo foo ' }); | ||
fail( | ||
() => expect(lengthyMap).to.include('not-foo'), | ||
/(foo ){8}/ | ||
); | ||
fail( | ||
() => expect(lengthyMap).to.deep.include('not-foo'), | ||
/(foo ){8}/ | ||
); | ||
}); | ||
it('should fail given an inexisting value', function () { | ||
fail(function () { expect(new List([1, 2, 3])).to.include(42); }); | ||
it('should fail given an inexisting value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(new List([1, 2, 3])).to.include(42)); | ||
fail(() => expect(new List([1, 2, 3])).to.deep.include(42)); | ||
}); | ||
it('should fail using `not` given an existing value', function () { | ||
fail(function () { expect(new List([1, 2, 3])).not.to.include(2); }); | ||
it('should fail using `not` given an existing value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(new List([1, 2, 3])).not.to.include(2)); | ||
fail(() => expect(new List([1, 2, 3])).not.to.deep.include(2)); | ||
}); | ||
it('should chain and fail given an inexisting key', function () { | ||
fail(function () { | ||
expect(new Map({ | ||
foo: 'bar', | ||
hello: 'universe', | ||
})).to.include.keys('not-foo'); | ||
}); | ||
it('should chain and fail given an inexisting key', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.include.keys('not-foo')); | ||
fail(() => expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.deep.include.keys('not-foo')); | ||
}); | ||
it('should chain and fail using `not` given an existing key', function () { | ||
fail(function () { | ||
expect(new Map({ | ||
foo: 'bar', | ||
hello: 'universe', | ||
})).to.not.include.keys('foo'); | ||
}); | ||
it('should chain and fail using `not` given an existing key', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.not.include.keys('foo')); | ||
fail(() => expect(new Map({ foo: 'bar', hello: 'world' })) | ||
.to.not.deep.include.keys('foo')); | ||
}); | ||
}); | ||
describe('keys method', function () { | ||
var map = new Map({ x: 1, y: 2 }); | ||
var obj = { x: 1, y: 2 }; | ||
describe('keys method', function () { // eslint-disable-line prefer-arrow-callback | ||
const obj = { x: 1, y: 2 }; | ||
const map = new Map(obj); | ||
it('should pass given an existing key', function () { | ||
it('should pass given an existing key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new Map({ x: 1 })).to.have.key('x'); | ||
expect({ x: 1 }).to.have.key('x'); | ||
expect(new Map({ x: 1 })).to.have.deep.key('x'); | ||
}); | ||
it('should pass using `not` given an inexisting key', function () { | ||
it('should pass using `not` given an inexisting key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.not.have.key('z'); | ||
expect(obj).to.not.have.key('z'); | ||
expect(map).to.not.have.deep.key('z'); | ||
}); | ||
it('should pass given multiple existing keys', function () { | ||
it('should pass given multiple existing keys', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys('x', 'y'); | ||
expect(obj).to.have.keys('x', 'y'); | ||
expect(map).to.have.deep.keys('x', 'y'); | ||
}); | ||
it('should pass using `not` given multiple inexisting keys', function () { | ||
it('should pass using `not` given multiple inexisting keys', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.not.have.keys('z1', 'z2'); | ||
expect(obj).to.not.have.keys('z1', 'z2'); | ||
expect(map).to.not.have.deep.keys('z1', 'z2'); | ||
}); | ||
it('should accept an Array of keys to check against', function () { | ||
it('should accept an Array of keys to check against', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys(['x', 'y']); | ||
expect(obj).to.have.keys(['x', 'y']); | ||
expect(map).to.have.deep.keys(['x', 'y']); | ||
}); | ||
it('should accept a List of keys to check against', function () { | ||
it('should accept a List of keys to check against', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys(new List(['x', 'y'])); | ||
expect(map).to.have.deep.keys(new List(['x', 'y'])); | ||
}); | ||
it('should accept a Set of keys to check against', function () { | ||
it('should accept a Set of keys to check against', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys(new Set(['x', 'y'])); | ||
expect(map).to.have.deep.keys(new Set(['x', 'y'])); | ||
}); | ||
it('should accept a Stack of keys to check against', function () { | ||
it('should accept a Stack of keys to check against', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys(new Stack(['x', 'y'])); | ||
expect(map).to.have.deep.keys(new Stack(['x', 'y'])); | ||
}); | ||
it('should accept an Object to check against', function () { | ||
expect(map).to.have.keys({ 'x': 6, 'y': 7 }); | ||
expect(obj).to.have.keys({ 'x': 6, 'y': 7 }); | ||
it('should accept an Object to check against', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys({ x: 6, y: 7 }); | ||
expect(map).to.have.deep.keys({ x: 6, y: 7 }); | ||
expect(new List(['x', 'y'])).to.have.all.keys({ 0: 4, 1: 5 }); | ||
}); | ||
it('should accept a Map to check against', function () { | ||
expect(map).to.have.keys(new Map({ 'x': 6, 'y': 7 })); | ||
it('should accept a Map to check against', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.keys(new Map({ x: 6, y: 7 })); | ||
expect(map).to.have.deep.keys(new Map({ x: 6, y: 7 })); | ||
}); | ||
it('should pass using `any` given an existing key', function () { | ||
it('should error when given multiple non-scalar arguments', function () { // eslint-disable-line prefer-arrow-callback | ||
const msg = 'when testing keys against an immutable collection, ' + | ||
'you must give a single Array|Object|String|Collection argument or ' + | ||
'multiple String arguments'; | ||
fail(() => expect(map).to.have.all.keys(['x'], 'y'), msg); | ||
fail(() => expect(map).to.have.all.keys(new List(['x']), 'y'), msg); | ||
fail(() => expect(map).to.have.all.keys(new Set(['x']), 'y'), msg); | ||
fail(() => expect(map).to.have.all.keys(new Stack(['x']), 'y'), msg); | ||
fail(() => expect(map).to.have.all.keys({ x: 1 }, 'y'), msg); | ||
fail(() => expect(map).to.have.all.keys(new Map({ x: 1 }), 'y'), msg); | ||
}); | ||
it('should error when given no arguments', function () { // eslint-disable-line prefer-arrow-callback | ||
const msg = 'keys required'; | ||
fail(() => expect(map).to.have.all.keys([]), msg); | ||
fail(() => expect(map).to.have.all.keys(new List()), msg); | ||
fail(() => expect(map).to.have.all.keys(new Set()), msg); | ||
fail(() => expect(map).to.have.all.keys(new Stack()), msg); | ||
fail(() => expect(map).to.have.all.keys({}), msg); | ||
fail(() => expect(map).to.have.all.keys(new Map()), msg); | ||
}); | ||
it('should pass using `any` given an existing key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.any.keys('x', 'z'); | ||
expect(obj).to.have.any.keys('x', 'z'); | ||
expect(map).to.have.any.deep.keys('x', 'z'); | ||
}); | ||
it('should pass using `not` and `any` given inexisting keys', function () { | ||
it('should pass using `not` and `any` given inexisting keys', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.not.have.any.keys('z1', 'z2'); | ||
expect(obj).to.not.have.any.keys('z1', 'z2'); | ||
expect(map).to.not.have.any.deep.keys('z1', 'z2'); | ||
}); | ||
it('should pass using `all` given existing keys', function () { | ||
it('should pass using `all` given existing keys', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.have.all.keys('x', 'y'); | ||
expect(obj).to.have.all.keys('x', 'y'); | ||
expect(map).to.have.all.deep.keys('x', 'y'); | ||
}); | ||
it('should pass using `not` and `all` given inexisting keys', function () { | ||
it('should pass using `not` and `all` given inexisting keys', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.not.have.all.keys('z1', 'y'); | ||
expect(obj).to.not.have.all.keys('z1', 'y'); | ||
expect(map).to.not.have.all.deep.keys('z1', 'y'); | ||
}); | ||
it('should pass using `contain` given an existing key', function () { | ||
it('should pass using `contain` given an existing key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(map).to.contain.key('x'); | ||
expect(obj).to.contain.key('x'); | ||
expect(map).to.contain.deep.key('x'); | ||
}); | ||
it('should not affect the original assertions', function () { | ||
it('should not affect the original assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
expect({ x: 1, y: 2 }).to.have.any.keys('x', 'z'); | ||
expect({ x: 1, y: 2 }).to.have.any.deep.keys('x', 'z'); | ||
expect({ x: 1, y: 2 }).to.have.any.keys('x'); | ||
expect({ x: 1, y: 2 }).to.have.any.deep.keys('x'); | ||
expect({ x: 1, y: 2 }).to.contain.any.keys('y', 'z'); | ||
expect({ x: 1, y: 2 }).to.contain.any.deep.keys('y', 'z'); | ||
expect({ x: 1, y: 2 }).to.contain.any.keys(['x']); | ||
expect({ x: 1, y: 2 }).to.contain.any.keys({ 'x': 6 }); | ||
expect({ x: 1, y: 2 }).to.contain.any.deep.keys(['x']); | ||
expect({ x: 1, y: 2 }).to.contain.any.keys({ x: 6 }); | ||
expect({ x: 1, y: 2 }).to.contain.any.deep.keys({ x: 6 }); | ||
expect({ x: 1, y: 2 }).to.have.all.keys(['x', 'y']); | ||
expect({ x: 1, y: 2 }).to.have.all.keys({ 'x': 6, 'y': 7 }); | ||
expect({ x: 1, y: 2 }).to.have.all.deep.keys(['x', 'y']); | ||
expect({ x: 1, y: 2 }).to.have.all.keys({ x: 6, y: 7 }); | ||
expect({ x: 1, y: 2 }).to.have.all.deep.keys({ x: 6, y: 7 }); | ||
expect({ x: 1, y: 2, z: 3 }).to.contain.all.keys(['x', 'y']); | ||
expect({ x: 1, y: 2, z: 3 }).to.contain.all.keys({ 'x': 6 }); | ||
expect({ x: 1, y: 2, z: 3 }).to.contain.all.deep.keys(['x', 'y']); | ||
expect({ x: 1, y: 2, z: 3 }).to.contain.all.keys({ x: 6 }); | ||
expect({ x: 1, y: 2, z: 3 }).to.contain.all.deep.keys({ x: 6 }); | ||
}); | ||
// See https://github.com/astorije/chai-immutable/issues/7 | ||
it('should display a helpful failure output on big objects', function () { | ||
var lengthyMap = new Map({ foo: 'foo foo foo foo foo foo foo foo ' }); | ||
fail(function () { | ||
expect(lengthyMap).to.have.keys('not-foo'); | ||
}, /(foo ){8}/); | ||
it('should display a helpful failure output on big objects', function () { // eslint-disable-line prefer-arrow-callback | ||
const lengthyMap = new Map({ foo: 'foo foo foo foo foo foo foo foo ' }); | ||
fail( | ||
() => expect(lengthyMap).to.have.keys('not-foo'), | ||
/(foo ){8}/ | ||
); | ||
fail( | ||
() => expect(lengthyMap).to.have.deep.keys('not-foo'), | ||
/(foo ){8}/ | ||
); | ||
}); | ||
it('should fail given an inexisting key', function () { | ||
fail(function () { expect(new Map({ x: 1 })).to.have.key('z'); }); | ||
fail(function () { expect({ x: 1 }).to.have.key('z'); }); | ||
it('should pass against Lists', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new List(['x', 'y'])).to.have.all.keys(0, 1); | ||
expect(new List(['x', 'y'])).to.have.all.keys([0, 1]); | ||
}); | ||
it('should fail given multiple inexisting keys', function () { | ||
fail(function () { expect(map).to.have.keys('z1', 'z2'); }); | ||
fail(function () { expect(obj).to.have.keys('z1', 'z2'); }); | ||
it('should fail given an inexisting key', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(new Map({ x: 1 })).to.have.key('z')); | ||
fail(() => expect(new Map({ x: 1 })).to.have.deep.key('z')); | ||
fail(() => expect({ x: 1 }).to.have.key('z')); | ||
fail(() => expect({ x: 1 }).to.have.deep.key('z')); | ||
}); | ||
it('should fail using `not` given multiple existing keys', function () { | ||
fail(function () { expect(map).to.not.have.keys('x', 'y'); }); | ||
fail(function () { expect(obj).to.not.have.keys('x', 'y'); }); | ||
it('should fail given multiple inexisting keys', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.have.keys('z1', 'z2')); | ||
fail(() => expect(map).to.have.deep.keys('z1', 'z2')); | ||
}); | ||
it('should fail using `any` given inexisting keys', function () { | ||
fail(function () { expect(map).to.have.any.keys('z1', 'z2'); }); | ||
fail(function () { expect(obj).to.have.any.keys('z1', 'z2'); }); | ||
it('should fail using `not` given multiple existing keys', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.not.have.keys('x', 'y')); | ||
fail(() => expect(map).to.not.have.deep.keys('x', 'y')); | ||
}); | ||
it('should fail using `not` and `any` given an existing key', function () { | ||
fail(function () { expect(map).to.not.have.any.keys('x', 'z'); }); | ||
fail(function () { expect(obj).to.not.have.any.keys('x', 'z'); }); | ||
it('should fail using `any` given inexisting keys', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.have.any.keys('z1', 'z2')); | ||
fail(() => expect(map).to.have.any.deep.keys('z1', 'z2')); | ||
}); | ||
it('should fail using `all` given an inexisting key', function () { | ||
fail(function () { expect(map).to.have.all.keys('z1', 'y'); }); | ||
fail(function () { expect(obj).to.have.all.keys('z1', 'y'); }); | ||
it('should fail using `not` and `any` given an existing key', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.not.have.any.keys('x', 'z')); | ||
fail(() => expect(map).to.not.have.any.deep.keys('x', 'z')); | ||
}); | ||
it('should fail using `not` and `all` given existing keys', function () { | ||
fail(function () { expect(map).to.not.have.all.keys('x', 'y'); }); | ||
fail(function () { expect(obj).to.not.have.all.keys('x', 'y'); }); | ||
it('should fail using `all` given an inexisting key', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.have.all.keys('z1', 'y')); | ||
fail(() => expect(map).to.have.all.deep.keys('z1', 'y')); | ||
}); | ||
it('should fail using `contain` given an inexisting key', function () { | ||
fail(function () { expect(map).to.contain.key('z'); }); | ||
fail(function () { expect(obj).to.contain.key('z'); }); | ||
it('should fail using `not` and `all` given existing keys', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.not.have.all.keys('x', 'y')); | ||
fail(() => expect(map).to.not.have.all.deep.keys('x', 'y')); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
expect(clonedImmutable.Map({ x: 1 })).to.have.key('x'); | ||
it('should fail using `contain` given an inexisting key', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(map).to.contain.key('z')); | ||
fail(() => expect(map).to.contain.deep.key('z')); | ||
}); | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(new clonedImmutable.Map({ x: 1 })).to.have.key('x'); | ||
expect(new clonedImmutable.Map({ x: 1 })).to.have.deep.key('x'); | ||
}); | ||
}); | ||
describe('property property', function () { | ||
it('should not affect the original assertion', function () { | ||
describe('property property', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should not affect the original assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
expect({ x: 1 }).to.have.property('x', 1); | ||
}); | ||
it('should fail given an inexisting property', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
fail(function () { expect(obj).to.have.property('z'); }); | ||
it('should not affect the original assertion using `not`', function () { // eslint-disable-line prefer-arrow-callback | ||
expect({ x: 1 }).not.to.have.property('z'); | ||
expect({ x: 1 }).not.to.have.property('z', 42); | ||
}); | ||
it('should pass using `not` given an inexisting property', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
// All following tests assert against regular `.property` and | ||
// `.deep.property`. In the Immutable world, these are supposed to carry | ||
// the same meaning (similar to `.equal` vs. `.deep.equal`). | ||
const obj = Immutable.fromJS({ x: 1 }); | ||
const nestedObj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
it('should fail given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(obj).to.have.property('z')); | ||
fail(() => expect(obj).to.have.deep.property('z')); | ||
}); | ||
it('should pass using `not` given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(obj).not.to.have.property('z'); | ||
expect(obj).not.to.have.deep.property('z'); | ||
}); | ||
it('should pass given an existing property', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
it('should pass using `not` given an inexisting property and value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(obj).not.to.have.property('z', 42); | ||
expect(obj).not.to.have.deep.property('z', 42); | ||
}); | ||
it('should pass given an existing property', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(obj).to.have.property('x'); | ||
expect(obj).to.have.deep.property('x'); | ||
}); | ||
it('should fail using `not` given an existing property', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
fail(function () { expect(obj).not.to.have.property('x'); }); | ||
it('should fail using `not` given an existing property', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(obj).not.to.have.property('x')); | ||
fail(() => expect(obj).not.to.have.deep.property('x')); | ||
}); | ||
it('should fail given a property with a bad value', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
fail(function () { expect(obj).to.have.property('x', 'different'); }); | ||
it('should fail given a property with a bad value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(obj).to.have.property('x', 'different')); | ||
fail(() => expect(obj).to.have.deep.property('x', 'different')); | ||
}); | ||
it('should pass given a property with the good value', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
it('should pass given a property with the good value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(obj).to.have.property('x', 1); | ||
expect(obj).to.have.deep.property('x', 1); | ||
}); | ||
it('should pass given an immutable value', function () { | ||
var obj = Immutable.fromJS({ foo: { bar: 42 } }); | ||
expect(obj).to.have.property('foo', new Map({ bar: 42 })); | ||
it('should pass given an immutable value', function () { // eslint-disable-line prefer-arrow-callback | ||
const obj2 = Immutable.fromJS({ foo: { bar: 42 } }); | ||
expect(obj2).to.have.property('foo', new Map({ bar: 42 })); | ||
expect(obj2).to.have.deep.property('foo', new Map({ bar: 42 })); | ||
}); | ||
it('should change the subject to the value of that property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
var sub = obj.get('y'); | ||
expect(obj).to.have.property('y').that.equal(sub); | ||
it('should change the subject to the value of that property', function () { // eslint-disable-line prefer-arrow-callback | ||
const sub = nestedObj.get('y'); | ||
expect(nestedObj).to.have.property('y').that.equal(sub); | ||
expect(nestedObj).to.have.deep.property('y').that.equal(sub); | ||
}); | ||
describe('using the `nested` flag', function () { | ||
it('should not affect the original assertion', function () { | ||
describe('using the `nested` flag', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should not affect the original assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
expect({ x: 1, y: { x: 2, y: 3 } }).to.have.nested.property('y.x', 2); | ||
expect({ x: 1, y: { x: 2, y: 3 } }) | ||
.to.have.nested.deep.property('y.x', 2); | ||
}); | ||
it('should fail given an inexisting property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
fail(function () { expect(obj).to.have.nested.property(['y', 'z']); }); | ||
it('should not affect the original assertion using `not`', function () { // eslint-disable-line prefer-arrow-callback | ||
expect({ x: 1, y: { x: 2 } }).not.to.have.nested.property('z.z'); | ||
expect({ x: 1, y: { x: 2 } }).not.to.have.nested.deep.property('z.z'); | ||
expect({ x: 1, y: { x: 2 } }).not.to.have.nested.property('z.z', 42); | ||
expect({ x: 1, y: { x: 2 } }) | ||
.not.to.have.nested.deep.property('z.z', 42); | ||
}); | ||
it('should pass using `not` given an inexisting property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
expect(obj).not.to.have.nested.property(['y', 'z']); | ||
it('should fail given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(nestedObj).to.have.nested.property(['y', 'z'])); | ||
fail(() => expect(nestedObj) | ||
.to.have.nested.deep.property(['y', 'z'])); | ||
}); | ||
it('should pass given an existing property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
expect(obj).to.have.nested.property(['y', 'x']); | ||
it('should pass using `not` given an inexisting property', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj).not.to.have.nested.property(['y', 'z']); | ||
expect(nestedObj).not.to.have.nested.deep.property(['y', 'z']); | ||
}); | ||
it('should pass given an index', function () { | ||
var obj = Immutable.fromJS({ | ||
items: ['a', 'b', 'c'], | ||
}); | ||
expect(obj).to.have.nested.property(['items', 2], 'c'); | ||
it('should pass using `not` given an inexisting property and value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(obj).not.to.have.nested.property(['y', 'x'], 'different'); | ||
expect(obj).not.to.have.nested.deep.property(['y', 'x'], 'different'); | ||
}); | ||
it('should fail using `not` given an existing property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
fail(function () { expect(obj).not.to.have.nested.property(['y', 'x']); }); | ||
it('should pass given an existing property', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj).to.have.nested.property(['y', 'x']); | ||
expect(nestedObj).to.have.nested.deep.property(['y', 'x']); | ||
}); | ||
it('should fail given a property with a bad value', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
fail(function () { | ||
expect(obj).to.have.property(['y', 'x'], 'different'); | ||
}); | ||
it('should pass given an index', function () { // eslint-disable-line prefer-arrow-callback | ||
const obj2 = Immutable.fromJS({ items: ['a', 'b', 'c'] }); | ||
expect(obj2).to.have.nested.property(['items', 2], 'c'); | ||
expect(obj2).to.have.nested.deep.property(['items', 2], 'c'); | ||
}); | ||
it('should pass given a property with the good value', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
expect(obj).to.have.nested.property(['y', 'x'], 2); | ||
it('should fail using `not` given an existing property', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(nestedObj).not.to.have.nested.property(['y', 'x'])); | ||
fail(() => expect(nestedObj) | ||
.not.to.have.nested.deep.property(['y', 'x'])); | ||
}); | ||
it('should fail using `not` given an inexisting property', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
fail(function () { | ||
expect(obj).not.to.have.nested.property(['y', 'x'], 'different'); | ||
}); | ||
it('should fail given a property with a bad value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(nestedObj) | ||
.to.have.nested.property(['y', 'x'], 'different')); | ||
fail(() => expect(nestedObj) | ||
.to.have.nested.deep.property(['y', 'x'], 'different')); | ||
}); | ||
it('should fail using `not` given a property with good value', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2 } }); | ||
fail(function () { | ||
expect(obj).not.to.have.nested.property(['y', 'x'], 2); | ||
}); | ||
it('should pass given a property with the good value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj).to.have.nested.property(['y', 'x'], 2); | ||
expect(nestedObj).to.have.nested.deep.property(['y', 'x'], 2); | ||
}); | ||
it('should pass using `not` given a property with a bad value', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2 } }); | ||
expect(obj).not.to.have.nested.property(['y', 'x'], 'different'); | ||
it('should fail using `not` given a property with good value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(nestedObj) | ||
.not.to.have.nested.property(['y', 'x'], 2)); | ||
fail(() => expect(nestedObj) | ||
.not.to.have.nested.deep.property(['y', 'x'], 2)); | ||
}); | ||
it('should pass given an immutable value', function () { | ||
var obj = Immutable.fromJS({ foo: [{ bar: 42 }] }); | ||
expect(obj).to.have.nested.property('foo[0]', new Map({ bar: 42 })); | ||
it('should pass using `not` given a property with a bad value', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj) | ||
.not.to.have.nested.property(['y', 'x'], 'different'); | ||
expect(nestedObj) | ||
.not.to.have.nested.deep.property(['y', 'x'], 'different'); | ||
}); | ||
it('should pass given an immutable value', function () { // eslint-disable-line prefer-arrow-callback | ||
const nestedObj2 = Immutable.fromJS({ foo: [{ bar: 42 }] }); | ||
expect(nestedObj2) | ||
.to.have.nested.property('foo[0]', new Map({ bar: 42 })); | ||
expect(nestedObj2) | ||
.to.have.nested.deep.property('foo[0]', new Map({ bar: 42 })); | ||
}); | ||
}); | ||
describe('given a string-based path', function () { | ||
var obj = Immutable.fromJS({ | ||
describe('given a string-based path', function () { // eslint-disable-line prefer-arrow-callback | ||
const nestedObj2 = Immutable.fromJS({ | ||
items: [ | ||
@@ -535,9 +630,11 @@ { name: 'Jane' }, | ||
it('should pass using `nested` given a single index', function () { | ||
expect(obj.get('items')).to.have.nested.property('[1]') | ||
it('should pass using `nested` given a single index', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj2.get('items')).to.have.nested.property('[1]') | ||
.that.equals(new Map({ name: 'John' })); | ||
expect(nestedObj2.get('items')).to.have.nested.deep.property('[1]') | ||
.that.equals(new Map({ name: 'John' })); | ||
}); | ||
it('should pass using `nested` given a single key', function () { | ||
expect(obj).to.have.nested.property('items') | ||
it('should pass using `nested` given a single key', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj2).to.have.nested.property('items') | ||
.that.equals(new List([ | ||
@@ -548,25 +645,41 @@ new Map({ name: 'Jane' }), | ||
])); | ||
expect(nestedObj2).to.have.nested.deep.property('items') | ||
.that.equals(new List([ | ||
new Map({ name: 'Jane' }), | ||
new Map({ name: 'John' }), | ||
new Map({ name: 'Jim' }), | ||
])); | ||
}); | ||
it('should pass using `nested` starting with an index', function () { | ||
expect(obj.get('items')).to.have.nested.property('[0].name', 'Jane'); | ||
it('should pass using `nested` starting with an index', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj2.get('items')) | ||
.to.have.nested.property('[0].name', 'Jane'); | ||
expect(nestedObj2.get('items')) | ||
.to.have.nested.deep.property('[0].name', 'Jane'); | ||
}); | ||
it('should pass using `nested` ending with an index', function () { | ||
expect(obj).to.have.nested.property('items[1]') | ||
it('should pass using `nested` ending with an index', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj2).to.have.nested.property('items[1]') | ||
.that.equals(new Map({ name: 'John' })); | ||
expect(nestedObj2).to.have.nested.deep.property('items[1]') | ||
.that.equals(new Map({ name: 'John' })); | ||
}); | ||
it('should pass using `nested` given mix of keys and indices', function () { | ||
expect(obj).to.have.nested.property('items[2].name', 'Jim'); | ||
it('should pass using `nested` given mix of keys and indices', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(nestedObj2).to.have.nested.property('items[2].name', 'Jim'); | ||
expect(nestedObj2) | ||
.to.have.nested.deep.property('items[2].name', 'Jim'); | ||
}); | ||
it('should expect unescaped path strings', function () { | ||
var css = new Map({ '.link[target]': 42 }); | ||
it('should expect unescaped path strings', function () { // eslint-disable-line prefer-arrow-callback | ||
const css = new Map({ '.link[target]': 42 }); | ||
expect(css).to.have.property('.link[target]', 42); | ||
expect(css).to.have.deep.property('.link[target]', 42); | ||
}); | ||
it('should expect escaped path strings using `nested`', function () { | ||
var nestedCss = new Map({ '.link': new Map({ '[target]': 42 }) }); | ||
it('should expect escaped path strings using `nested`', function () { // eslint-disable-line prefer-arrow-callback | ||
const nestedCss = new Map({ '.link': new Map({ '[target]': 42 }) }); | ||
expect(nestedCss).to.have.nested.property('\\.link.\\[target\\]', 42); | ||
expect(nestedCss) | ||
.to.have.nested.deep.property('\\.link.\\[target\\]', 42); | ||
}); | ||
@@ -576,12 +689,12 @@ }); | ||
describe('size method', function () { | ||
it('should pass given the right size', function () { | ||
describe('size method', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given the right size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size(3); | ||
}); | ||
it('should pass using `not` given the wrong size', function () { | ||
it('should pass using `not` given the wrong size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.have.size(42); | ||
}); | ||
it('should also work with alias sizeOf', function () { | ||
it('should also work with alias sizeOf', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.sizeOf(3); | ||
@@ -591,11 +704,11 @@ expect(list3).to.not.have.sizeOf(42); | ||
it('should fail given the wrong size', function () { | ||
fail(function () { expect(list3).to.have.size(42); }); | ||
it('should fail given the wrong size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.have.size(42)); | ||
}); | ||
it('should fail using `not` given the right size', function () { | ||
fail(function () { expect(list3).to.not.have.size(3); }); | ||
it('should fail using `not` given the right size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.have.size(3)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(clonedImmutableList).to.have.size(3); | ||
@@ -605,12 +718,12 @@ }); | ||
describe('size property', function () { | ||
it('above should pass given a good min size', function () { | ||
describe('size property', function () { // eslint-disable-line prefer-arrow-callback | ||
it('above should pass given a good min size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.above(2); | ||
}); | ||
it('above should pass using `not` given a bad min size', function () { | ||
it('above should pass using `not` given a bad min size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.have.size.above(42); | ||
}); | ||
it('aliases of above should also work', function () { | ||
it('aliases of above should also work', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.gt(2); | ||
@@ -622,3 +735,3 @@ expect(list3).to.have.size.greaterThan(2); | ||
it('should not affect the original assertions of above', function () { | ||
it('should not affect the original assertions of above', function () { // eslint-disable-line prefer-arrow-callback | ||
expect('foo').to.have.length.above(2); | ||
@@ -628,19 +741,19 @@ expect([1, 2, 3]).to.have.length.above(2); | ||
it('above should fail given a bad min size', function () { | ||
fail(function () { expect(list3).to.have.size.above(42); }); | ||
it('above should fail given a bad min size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.have.size.above(42)); | ||
}); | ||
it('above should fail using `not` given a good min size', function () { | ||
fail(function () { expect(list3).to.not.have.size.above(2); }); | ||
it('above should fail using `not` given a good min size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.have.size.above(2)); | ||
}); | ||
it('below should pass given a good max size', function () { | ||
it('below should pass given a good max size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.below(42); | ||
}); | ||
it('below should pass using `not` given a bad max size', function () { | ||
it('below should pass using `not` given a bad max size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.have.size.below(1); | ||
}); | ||
it('aliases of below should also work', function () { | ||
it('aliases of below should also work', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.lt(4); | ||
@@ -652,3 +765,3 @@ expect(list3).to.have.size.lessThan(4); | ||
it('should not affect the original assertions of below', function () { | ||
it('should not affect the original assertions of below', function () { // eslint-disable-line prefer-arrow-callback | ||
expect('foo').to.have.length.below(4); | ||
@@ -658,19 +771,19 @@ expect([1, 2, 3]).to.have.length.below(4); | ||
it('below should fail given a bad max size', function () { | ||
fail(function () { expect(list3).to.have.size.below(1); }); | ||
it('below should fail given a bad max size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.have.size.below(1)); | ||
}); | ||
it('below should fail using `not` given a good max size', function () { | ||
fail(function () { expect(list3).to.not.have.size.below(42); }); | ||
it('below should fail using `not` given a good max size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.have.size.below(42)); | ||
}); | ||
it('within should pass given a good range', function () { | ||
it('within should pass given a good range', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.within(2, 42); | ||
}); | ||
it('within should pass using `not` given a bad range', function () { | ||
it('within should pass using `not` given a bad range', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.have.size.within(10, 20); | ||
}); | ||
it('should not affect the original assertions of within', function () { | ||
it('should not affect the original assertions of within', function () { // eslint-disable-line prefer-arrow-callback | ||
expect('foo').to.have.length.within(2, 4); | ||
@@ -680,19 +793,19 @@ expect([1, 2, 3]).to.have.length.within(2, 4); | ||
it('within should fail given a bad range', function () { | ||
fail(function () { expect(list3).to.have.size.within(10, 20); }); | ||
it('within should fail given a bad range', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.have.size.within(10, 20)); | ||
}); | ||
it('within should fail using `not` given a good range', function () { | ||
fail(function () { expect(list3).to.not.have.size.within(2, 42); }); | ||
it('within should fail using `not` given a good range', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.have.size.within(2, 42)); | ||
}); | ||
it('least should pass given a good min size', function () { | ||
it('least should pass given a good min size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.of.at.least(2); | ||
}); | ||
it('least should pass using `not` given a bad min size', function () { | ||
it('least should pass using `not` given a bad min size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.have.size.of.at.least(42); | ||
}); | ||
it('aliases of least should also work', function () { | ||
it('aliases of least should also work', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.gte(2); | ||
@@ -702,3 +815,3 @@ expect(list3).to.not.have.size.gte(42); | ||
it('should not affect the original assertions of least', function () { | ||
it('should not affect the original assertions of least', function () { // eslint-disable-line prefer-arrow-callback | ||
expect('foo').to.have.length.of.at.least(2); | ||
@@ -708,19 +821,19 @@ expect([1, 2, 3]).to.have.length.of.at.least(3); | ||
it('least should fail given a bad min size', function () { | ||
fail(function () { expect(list3).to.have.size.of.at.least(42); }); | ||
it('least should fail given a bad min size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.have.size.of.at.least(42)); | ||
}); | ||
it('least should fail using `not` given a good min size', function () { | ||
fail(function () { expect(list3).to.not.have.size.of.at.least(2); }); | ||
it('least should fail using `not` given a good min size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.have.size.of.at.least(2)); | ||
}); | ||
it('most should pass given a good max size', function () { | ||
it('most should pass given a good max size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.of.at.most(42); | ||
}); | ||
it('most should pass using `not` given a bad max size', function () { | ||
it('most should pass using `not` given a bad max size', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.not.have.size.of.at.most(2); | ||
}); | ||
it('aliases of most should also work', function () { | ||
it('aliases of most should also work', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(list3).to.have.size.lte(42); | ||
@@ -730,3 +843,3 @@ expect(list3).to.not.have.size.lte(2); | ||
it('should not affect the original assertions of most', function () { | ||
it('should not affect the original assertions of most', function () { // eslint-disable-line prefer-arrow-callback | ||
expect('foo').to.have.length.of.at.most(4); | ||
@@ -736,11 +849,11 @@ expect([1, 2, 3]).to.have.length.of.at.most(3); | ||
it('most should fail given a good max size', function () { | ||
fail(function () { expect(list3).to.have.size.of.at.most(2); }); | ||
it('most should fail given a good max size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.have.size.of.at.most(2)); | ||
}); | ||
it('most should fail using `not` given a bad max size', function () { | ||
fail(function () { expect(list3).to.not.have.size.of.at.most(42); }); | ||
it('most should fail using `not` given a bad max size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => expect(list3).to.not.have.size.of.at.most(42)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
expect(clonedImmutableList).to.have.size.above(2); | ||
@@ -751,13 +864,13 @@ }); | ||
describe('TDD interface', function () { | ||
describe('equal assertion', function () { | ||
it('should pass given equal values', function () { | ||
describe('TDD interface', function () { // eslint-disable-line prefer-arrow-callback | ||
describe('equal assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.equal(list3, List.of(1, 2, 3)); | ||
}); | ||
it('should pass given deeply equal values', function () { | ||
it('should pass given deeply equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.equal(deepMap, sameDeepMap); | ||
}); | ||
it('should not affect the original assertion', function () { | ||
it('should not affect the original assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.equal(42, 42); | ||
@@ -768,23 +881,31 @@ assert.equal(3, '3'); | ||
// See https://github.com/astorije/chai-immutable/issues/7 | ||
it('should display a helpful failure output on big objects', function () { | ||
var actual = new Map({ foo: 'foo foo foo foo foo foo foo foo ' }); | ||
var expected = new Map({ bar: 'bar bar bar bar bar bar bar bar ' }); | ||
fail(function () { | ||
assert.equal(actual, expected); | ||
}, /(foo ){8}.+(bar ){8}/); | ||
it('should display a helpful failure output on big objects', function () { // eslint-disable-line prefer-arrow-callback | ||
const actual = new Map({ foo: 'foo foo foo foo foo foo foo foo ' }); | ||
const expected = new Map({ bar: 'bar bar bar bar bar bar bar bar ' }); | ||
// AssertionError: expected { Object (foo) } to equal { Object (bar) } | ||
// + expected - actual | ||
// | ||
// { | ||
// - "foo": "foo foo foo foo foo foo foo foo" | ||
// + "bar": "bar bar bar bar bar bar bar bar" | ||
// } | ||
fail( | ||
() => assert.equal(actual, expected), | ||
'expected { Object (foo) } to equal { Object (bar) }' | ||
); | ||
}); | ||
it('should fail given a non-Immutable value', function () { | ||
fail(function () { assert.equal([], List()); }); | ||
it('should fail given a non-Immutable value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.equal([], new List())); | ||
}); | ||
it('should fail given different values', function () { | ||
fail(function () { assert.equal(list3, new List()); }); | ||
it('should fail given different values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.equal(list3, new List())); | ||
}); | ||
it('should fail given deeply different values', function () { | ||
fail(function () { assert.equal(deepMap, differentDeepMap); }); | ||
it('should fail given deeply different values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.equal(deepMap, differentDeepMap)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.equal(clonedImmutableList, List.of(1, 2, 3)); | ||
@@ -794,12 +915,12 @@ }); | ||
describe('notEqual assertion', function () { | ||
it('should pass given different values', function () { | ||
describe('notEqual assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given different values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notEqual(list3, new List()); | ||
}); | ||
it('should pass given deeply different values', function () { | ||
it('should pass given deeply different values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notEqual(deepMap, differentDeepMap); | ||
}); | ||
it('should not affect the original assertion', function () { | ||
it('should not affect the original assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notEqual('oui', 'non'); | ||
@@ -809,15 +930,15 @@ assert.notEqual({ foo: 'bar' }, { foo: 'bar' }); | ||
it('should pass given a non-Immutable value', function () { | ||
assert.notEqual([], List()); | ||
it('should pass given a non-Immutable value', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notEqual([], new List()); | ||
}); | ||
it('should fail given equal values', function () { | ||
fail(function () { assert.notEqual(list3, List.of(1, 2, 3)); }); | ||
it('should fail given equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.notEqual(list3, List.of(1, 2, 3))); | ||
}); | ||
it('should fail given deeply equal values', function () { | ||
fail(function () { assert.notEqual(deepMap, sameDeepMap); }); | ||
it('should fail given deeply equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.notEqual(deepMap, sameDeepMap)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notEqual(clonedImmutableList, List.of()); | ||
@@ -827,4 +948,4 @@ }); | ||
describe('unoverridden strictEqual and deepEqual assertions', function () { | ||
it('should pass given equal values', function () { | ||
describe('unoverridden strictEqual and deepEqual assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.strictEqual(list3, List.of(1, 2, 3)); | ||
@@ -834,3 +955,3 @@ assert.deepEqual(list3, List.of(1, 2, 3)); | ||
it('should pass given deeply equal values', function () { | ||
it('should pass given deeply equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.strictEqual(deepMap, sameDeepMap); | ||
@@ -840,13 +961,13 @@ assert.deepEqual(deepMap, sameDeepMap); | ||
it('should fail given different values', function () { | ||
fail(function () { assert.strictEqual(list3, new List()); }); | ||
fail(function () { assert.deepEqual(list3, new List()); }); | ||
it('should fail given different values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.strictEqual(list3, new List())); | ||
fail(() => assert.deepEqual(list3, new List())); | ||
}); | ||
it('should fail given deeply different values', function () { | ||
fail(function () { assert.strictEqual(deepMap, differentDeepMap); }); | ||
fail(function () { assert.deepEqual(deepMap, differentDeepMap); }); | ||
it('should fail given deeply different values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.strictEqual(deepMap, differentDeepMap)); | ||
fail(() => assert.deepEqual(deepMap, differentDeepMap)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.strictEqual(clonedImmutableList, List.of(1, 2, 3)); | ||
@@ -857,4 +978,4 @@ assert.deepEqual(clonedImmutableList, List.of(1, 2, 3)); | ||
describe('unoverridden notStrictEqual and notDeepEqual assertions', function () { | ||
it('should pass given different values', function () { | ||
describe('unoverridden notStrictEqual and notDeepEqual assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given different values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notStrictEqual(list3, new List()); | ||
@@ -864,3 +985,3 @@ assert.notDeepEqual(list3, new List()); | ||
it('should pass given deeply different values', function () { | ||
it('should pass given deeply different values', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notStrictEqual(deepMap, differentDeepMap); | ||
@@ -870,51 +991,86 @@ assert.notDeepEqual(deepMap, differentDeepMap); | ||
it('should fail given equal values', function () { | ||
fail(function () { assert.notStrictEqual(list3, List.of(1, 2, 3)); }); | ||
fail(function () { assert.notDeepEqual(list3, List.of(1, 2, 3)); }); | ||
it('should fail given equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.notStrictEqual(list3, List.of(1, 2, 3))); | ||
fail(() => assert.notDeepEqual(list3, List.of(1, 2, 3))); | ||
}); | ||
it('should fail given deeply equal values', function () { | ||
fail(function () { assert.notStrictEqual(deepMap, sameDeepMap); }); | ||
fail(function () { assert.notDeepEqual(deepMap, sameDeepMap); }); | ||
it('should fail given deeply equal values', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.notStrictEqual(deepMap, sameDeepMap)); | ||
fail(() => assert.notDeepEqual(deepMap, sameDeepMap)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
assert.notStrictEqual(clonedImmutableList, List()); | ||
assert.notDeepEqual(clonedImmutableList, List()); | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notStrictEqual(clonedImmutableList, new List()); | ||
assert.notDeepEqual(clonedImmutableList, new List()); | ||
}); | ||
}); | ||
describe('property assertions', function () { | ||
it('should fail for missing property', function () { | ||
var obj = Immutable.fromJS({ x: 1 }); | ||
fail(function () { assert.property(obj, 'z'); }); | ||
describe('property assertions', function () { // eslint-disable-line prefer-arrow-callback | ||
const obj = Immutable.fromJS({ x: 1 }); | ||
const nestedObj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
it('should pass for existing property', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.property(obj, 'x'); | ||
}); | ||
it('should succeed for equal nested property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
assert.nestedProperty(obj, ['y', 'x']); | ||
it('should fail for missing property', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.property(obj, 'z')); | ||
}); | ||
it('should fail for unequal deep property', function () { | ||
var obj = Immutable.fromJS({ x: 1, y: { x: 2, y: 3 } }); | ||
fail(function () { | ||
assert.nestedPropertyVal(obj, ['y', 'x'], 'different'); | ||
}); | ||
it('should pass for missing property using `not`', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notProperty(obj, 'z'); | ||
}); | ||
it('should fail for existing property using `not`', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.notProperty(obj, 'x')); | ||
}); | ||
it('should pass for existing property and value', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.propertyVal(obj, 'x', 1); | ||
assert.deepPropertyVal(obj, 'x', 1); | ||
}); | ||
it('should fail for wrong property or value', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.propertyVal(obj, 'z', 1)); | ||
fail(() => assert.deepPropertyVal(obj, 'z', 1)); | ||
fail(() => assert.propertyVal(obj, 'x', 42)); | ||
fail(() => assert.deepPropertyVal(obj, 'x', 42)); | ||
}); | ||
it('should pass for wrong property or value using `not`', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.notPropertyVal(obj, 'z', 1); | ||
assert.notDeepPropertyVal(obj, 'z', 1); | ||
assert.notPropertyVal(obj, 'x', 42); | ||
assert.notDeepPropertyVal(obj, 'x', 42); | ||
}); | ||
it('should fail for existing property and value using `not`', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.notPropertyVal(obj, 'x', 1)); | ||
fail(() => assert.notDeepPropertyVal(obj, 'x', 1)); | ||
}); | ||
it('should succeed for equal nested property', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.nestedProperty(nestedObj, ['y', 'x']); | ||
}); | ||
it('should fail for unequal nested property', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.nestedPropertyVal(nestedObj, ['y', 'x'], 42)); | ||
fail(() => assert.deepNestedPropertyVal(nestedObj, ['y', 'x'], 42)); | ||
}); | ||
}); | ||
describe('sizeOf assertion', function () { | ||
it('should pass given the right size', function () { | ||
describe('sizeOf assertion', function () { // eslint-disable-line prefer-arrow-callback | ||
it('should pass given the right size', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.sizeOf(list3, 3); | ||
}); | ||
it('should work with empty collections', function () { | ||
it('should work with empty collections', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.sizeOf(new List(), 0); | ||
}); | ||
it('should fail given the wrong size', function () { | ||
fail(function () { assert.sizeOf(list3, 42); }); | ||
it('should fail given the wrong size', function () { // eslint-disable-line prefer-arrow-callback | ||
fail(() => assert.sizeOf(list3, 42)); | ||
}); | ||
it('should work if using different copies of Immutable', function () { | ||
it('should work if using different copies of Immutable', function () { // eslint-disable-line prefer-arrow-callback | ||
assert.sizeOf(clonedImmutableList, 3); | ||
@@ -921,0 +1077,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
101889
12
1624
384
2
10