Chai assertions for Facebook's Immutable library for JavaScript collections
npm install chai-immutable






This plugin provides a set of Chai assertions for Facebook's Immutable library for JavaScript collections.
- BDD API Reference (Expect / Should)
- .empty
- .equal(collection)
- .referenceEqual(value)
- .include(value)
- [.keys(key1[, key2[, ...]])](#keyskey1-key2-)
- [.property(path[, val])](#propertypath-val)
- .size(value)
- TDD API Reference (Assert)
- .equal(actual, expected)
- .referenceEqual(actual, expected)
- .notEqual(actual, expected)
- .notReferenceEqual(actual, expected)
- .sizeOf(collection, length)
``bash`
npm install --save-dev chai-immutable
yarn add --dev chai-immutable
You can then use this plugin as any other Chai plugins:
`js
const chai = require('chai');
const chaiImmutable = require('chai-immutable');
chai.use(chaiImmutable);
`
`js
import chai from 'chai';
import chaiImmutable from 'chai-immutable';
chai.use(chaiImmutable);
`
Include this plugin after including Chai and Immutable. It will automatically
plug in to Chai and be ready for use:
`html`
If you are using this plugin with
chai-as-promised or
dirty-chai, note that
chai-immutable must be loaded before any of them. For example:
`js
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const chaiImmutable = require('chai-immutable');
const dirtyChai = require('dirty-chai');
const { expect } = chai;
chai.use(chaiImmutable);
chai.use(chaiAsPromised);
chai.use(dirtyChai);
const { List } = require('immutable');
/ ... /
expect(Promise.resolve(List.of(1, 2, 3))).to.eventually.have.size(3);
expect(true).to.be.true();
`
Asserts that the immutable collection is empty.
`js`
expect(List()).to.be.empty;
expect(List.of(1, 2, 3)).to.not.be.empty;
- @param _{ Collection }_ 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 Arrays and Objects) to be considered immutable and.equal()
properly work against . See
issue #24 for more
information.
Also, note that deep.equal and eql are synonyms of equal whenequal
tested against immutable data structures, therefore they are aliases to.
- @param _{Collection}_ value
Asserts that the reference of the target is equivalent to the reference of
collection. This method preserves the original behavior of Chai's equal.
See issue #210 for
more details.
`js`
const a = List.of(1, 2, 3);
const b = a;
const c = List.of(1, 2, 3);
expect(a).to.referenceEqual(b);
expect(a).to.not.referenceEqual(c);
- @param _{ Mixed }_ val
The include and contain assertions can be used as either propertycontains
based language chains or as methods to assert the inclusion of a value or
subset in an immutable collection. When used as language chains, they toggle
the 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('bar');
expect(new Map({ a: 1, b: 2, c: 3 })).to.include(new Map({ a: 1, b: 2 }));
expect(new Map({ foo: 'bar', hello: 'world' })).to.include.keys('foo');
- @param _{ String... | Array | Object | Collection }_ keyN
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.not
one of the given keys. Also, add 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.not.all.keys
exactly what's expected of the output, whereas 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.all
earlier in the chain. However, it's often best to add 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.include
effect. The 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');
- @param _{ String | Array | Iterable }_ path
- @param _{ Mixed }_ val (optional)
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 valueval
is equal to the given . 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 whenList
referencing nested properties. An immutable can also be used as thenested.property
starting point of a .
`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. Thepath
problem is that it creates uncertain expectations by asserting that the
target either doesn't have a property at the given , or that itpath
does have a property at the given key but its value isn't equal toval
the given . 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');
- @param _{ Number }_ size
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);
- @param _{ Collection }_ actual
- @param _{ Collection }_ expected
Asserts that the values of actual are equivalent to the values ofexpected. Note that .strictEqual() and .deepEqual() assert.equal()
exactly like 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 Arrays and Objects) to be considered immutable and.equal()
properly work against , .strictEqual() or .deepEqual(). See
issue #24 for more
information.
- @param _{Collection}_ actual
- @param _{Collection}_ expected
Asserts that the reference of actual is equivalent to the reference ofexpected. This method preserves the original behavior of Chai's equal.
See issue #210 for
more details.
`js`
const a = List.of(1, 2, 3);
const b = a;
const c = List.of(1, 2, 3);
assert.referenceEqual(a, b);
assert.throws(() => assert.referenceEqual(a, c));
- @param _{ Collection }_ actual
- @param _{ Collection }_ expected
Asserts that the values of actual are not equivalent to the values ofexpected. Note that .notStrictEqual() and .notDeepEqual() assert.notEqual()
exactly like 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);
- @param _{Collection}_ actual
- @param _{Collection}_ expected
Asserts that the reference of actual is not equivalent to the reference ofexpected. This method preserves the original behavior of Chai's notEqual.
See issue #210 for
more details.
`js`
const a = List.of(1, 2, 3);
const b = a;
const c = List.of(1, 2, 3);
assert.throws(() => assert.notReferenceEqual(a, b));
assert.notReferenceEqual(a, c);
- @param _{ Collection }_ collection
- @param _{ Number }_ size
Asserts that the immutable collection has the expected size.
`js``
assert.sizeOf(List.of(1, 2, 3), 3);
assert.sizeOf(new List(), 0);