:exclamation: :exclamation: :exclamation: :exclamation: :exclamation: :exclamation:
Install this fork by running
:exclamation: :exclamation: :exclamation: :exclamation: :exclamation: :exclamation:
Let's not limit ourselves to Arrays; we can test any iterable object.
And we can pass any iterable as our expected values too.
The sequence generated by
Just don't go trying to use
Be careful though. Iterators can't go back in time. Once a value has been yielded, it is lost forever. And so the following assertions pass.
It usually makes more sense to construct a new
The Babel polyfillbabel-polyfill is one option for environments that do not natively support
In the compiler optionscompiler-options, set
Asserts that the target is an iterable object, i.e., that it has an
Asserts that the target iterates over a given sequence of values. Set the
| Param | Type | Description | | :-------- | :------- | :------------------ | | expected |
Asserts that the target begins iterating over a given sequence of values. Set
the
| Param | Type | Description | | :-------- | :------- | :------------------ | | expected |
Asserts that the target ends iteration with a given sequence of values. Set the
| Param | Type | Description | | :-------- | :------- | :------------------ | | expected |
Asserts that the target yields exactly n values.
| Param | Type | Description | | :----- | :------- | :------------------ | | n |
Asserts that the target yields more than n values.
| Param | Type | Description | | :----- | :------- | :------------------ | | n |
Asserts that the target yields fewer than n values.
| Param | Type | Description | | :----- | :------- | :------------------ | | n |
Asserts that the target yields at least n values.
| Param | Type | Description | | :----- | :------- | :------------------ | | n |
Asserts that the target yields at most n values.
| Param | Type | Description | | :----- | :------- | :------------------ | | n |
Asserts that the target yields between min and max values, inclusive.
| Param | Type | Description | | :----- | :------- | :------------------- | | min |
| Param | Type | Description | | :------- | :------- | :--------------------------------------- | | value |
Asserts that a value is an iterable object, i.e., that it is an object with
an
Asserts that a value is not an iterable object, i.e., that it lacks an
Asserts that a value iterates exactly over a given sequence of values.
Asserts that a value does not iterate exactly over a given sequence of values.
Asserts that a value iterates exactly over a given sequence of values, using
deep equality.
Asserts that a value does not iterate exactly over a given sequence of values,
using deep equality.
Asserts that a value begins iteration with a given sequence of values.
Asserts that a value does not begin iteration with a given sequence of values.
Asserts that a value begins iteration with a given sequence of values, using
deep equality.
Asserts that a value does not begin iteration with a given sequence of values,
using deep equality.
Asserts that a value ends iteration with a given sequence of values.
Asserts that a value does not end iteration with a given sequence of values.
Asserts that a value ends iteration with a given sequence of values, using
deep equality.
Asserts that a value does not end iteration with a given sequence of values,
using deep equality.
Asserts that an iterable yields a given number of values. If value is not an
iterable object, or if it has a
Fork of chai-iterator.
chai-iterator is currently not maintained and is incompatible with chai@4.Install this fork by running
npm install --save chai @harrysarson/chai-iterator
:exclamation: :exclamation: :exclamation: :exclamation: :exclamation: :exclamation:
Chai Iterator: Assertions for iterable objects
!Versionversion-badgenpm
!Licenselicense-badgelicense
!Buildbuild-badgetravis
!Coveragecoverage-badgecoveralls
!Dependenciesdependencies-badgegemnasiumContents
Overview
Chai Iterator extends the Chaichai assertion library with methods for testing iterableiterable objects. Introduced in the ES2015 specificationecma-iterable, iterable objects have an@@iterator
iterator-method method, which allows us to iterate over them with
a for...of
for-of loop. A number of built-inbuilt-in-iterable types are
iterable by default, while custom iterable objectscustom-iterable may also
be defined. Chai Iterator makes it easy to test all such objects.Basic usage
Here is a fairly exhaustive sample of the assertions we can make using Chai Iterator. While we could just as easily useexpect
or assert
, we'll use
Chai's should()
assertion styleassertion-style, just to be different.[2, 3, 5].should.be.iterable;
[2, 3, 5].should.iterate.over([2, 3, 5]);
[2, 3, 5].should.iterate.from([2, 3]);
[2, 3, 5].should.iterate.until([3, 5]);
[2, 3, 5].should.iterate.for.lengthOf(3);
[2, 3, 5].should.iterate.for.length.above(2);
[2, 3, 5].should.iterate.for.length.below(4);
[2, 3, 5].should.iterate.for.length.of.at.least(3);
[2, 3, 5].should.iterate.for.length.of.at.most(3);
[2, 3, 5].should.iterate.for.length.within(2, 4);
[2, 3, 5].should.not.iterate.over([1, 2, 3]);
[{n: 2}, {n: 3}].should.deep.iterate.from([{n: 2}]);
Let's not limit ourselves to Arrays; we can test any iterable object.
'abcde'.should.iterate.until(['c', 'd', 'e']);
And we can pass any iterable as our expected values too.
'abcde'.should.iterate.until('cde');
User-defined iterable objects
That's enough fiddling around with built-in objects whose iteration behavior is well-known. Chai Iterator is best used to test user-defined iterable objectscustom-iterable, like the one constructed by the following classclass.class Count {
constructor(start=0, step=1) {
this.start = start;
this.step = step;
}
*[Symbol.iterator]() {
for (let n = this.start; true; n += this.step) {
yield n;
}
}
}
The sequence generated by
Count.prototype[@@iterator]()
is infinite;
it continues to yield values indefinitely. Still, we can safely
use the from()
assertion with it, since it will
terminate as soon as our expected iterable is done.let tens = new Count(10, 10);
tens.should.be.iterable;
tens.should.iterate.from([10, 20, 30]);
tens.should.iterate.from([10, 20, 30, 40, 50]);
Just don't go trying to use
over()
or
until()
on infinite sequences. The former will always
fail; the latter will never stop.Generators and iterators
Let's generate the fibonacci sequencefibonacci-sequence. A generator functiongenerator-function is just a function that returns aGenerator
generator object — an iteratoriterator that is also
iterableiterable. We can test a Generator
just as we would any other
iterable.function* fibonacci() {
for (let [x, y] = [1, 1]; true; [x, y] = [y, x + y]) {
yield x;
}
}
fibonacci().should.iterate.from([1, 1, 2, 3, 5]);
Be careful though. Iterators can't go back in time. Once a value has been yielded, it is lost forever. And so the following assertions pass.
let fiborator = fibonacci();
fiborator.should.iterate.from([1, 1, 2, 3, 5]);
fiborator.should.iterate.from([8, 13, 21, 34]);
It usually makes more sense to construct a new
Generator
for each assertion.fibonacci().should.iterate.from([1, 1, 2, 3, 5]);
fibonacci().should.iterate.from([1, 1, 2, 3, 5, 8, 13]);
Compatibility
Chai Iterator requires thatSymbol.iterator
iterator-method be
available in the environment. In Nodenode, this means the version must be
v4.0 or greater. While the latest versions of most browsersbrowser-list are
compatible, web-facing projects should almost certainly use a polyfill.The Babel polyfillbabel-polyfill is one option for environments that do not natively support
Symbol.iterator
. More minimally, we can get away with just
two sub-modules from the core-jscore-js library, like so.require('core-js/es6/symbol');
require('core-js/fn/symbol/iterator');
Installation
Install Chai Iterator using npmnpm. And be sure, of course, to install Chaichai-npm.npm install --save chai chai-iterator
Setup
Chai Iterator can be imported as a Nodenode module, an AMDamd module, or included in an HTML<script>
script-tag tag. For
TypeScripttypescript users, declarations are installed with the package.Node
To set up Chai Iterator for Nodenode, make sure the version is v4.0 or higher, as prior versions lack support for the@@iterator
iterator-method
method.const chai = require('chai');
const chaiIterator = require('chai-iterator');
chai.use(chaiIterator);
AMD
Chai Iterator can be set up inside of an AMDamd module like so.define((require, exports, module) => {
let chai = require('chai');
let chaiIterator = require('chai-iterator');
chai.use(chaiIterator);
});
HTML script tag
Chai Iterator can be included via a<script>
script-tag tag. If it is
loaded after chai.js
, Chai will use it automatically.<script src="chai.js"></script>
<script src="chai-iterator.js"></script>
TypeScript
TypeScripttypescript declarations are included in the package. To use them, ensure Chai Iterator is installed with npmnpm, then install the declarations and their dependencies via typingstypings. And be sure to install the declarations for chaichai-typings.typings install --save-dev npm~chai npm:chai-iterator
In the compiler optionscompiler-options, set
"target"
to "es6"
, or at
least include a reference to lib.es6.d.ts
es6-lib. Now the following will
just work.import chai = require("chai");
import chaiIterator = require("chai-iterator");
chai.use(chaiIterator);
[2, 3, 5].should.iterate.over([2, 3, 5]);
Expect/Should API
Assertions
iterable
iterate.over()
iterate.from()
iterate.until()
iterate.for.lengthOf()
iterate.for.length.above()
iterate.for.length.below()
iterate.for.length.of.at.least()
iterate.for.length.of.at.most()
iterate.for.length.within()
iterable
Asserts that the target is an iterable object, i.e., that it has an
@@iterator
iterator-method method.expect([2, 3, 5]).to.be.iterable;
expect('abcdefg').to.be.iterable;
expect(12345).not.to.be.iterable;
iterate.over(expected)
Asserts that the target iterates over a given sequence of values. Set the
deep
deep flag to use deep equality to compare values.| Param | Type | Description | | :-------- | :------- | :------------------ | | expected |
object
| An iterable object. |expect([2, 3, 5]).to.iterate.over([2, 3, 5]);
expect('abcdefg').to.itetate.over('abcdefg');
expect([2, 3, 5]).not.to.iterate.over([2, 3]);
expect([{n: 2}, {n: 3}]).to.deep.iterate.over([{n: 2}, {n: 3}]);
iterate.from(expected)
Asserts that the target begins iterating over a given sequence of values. Set
the deep
deep flag to use deep equality to compare values.| Param | Type | Description | | :-------- | :------- | :------------------ | | expected |
object
| An iterable object. |expect([2, 3, 5]).to.iterate.from([2, 3]);
expect('abcdefg').to.iterate.from('abc');
expect([2, 3, 5]).not.to.iterate.from([3, 5]);
expect([{n: 2}, {n: 3}]).to.deep.iterate.from([{n: 2}]);
iterate.until(expected)
Asserts that the target ends iteration with a given sequence of values. Set the
deep
deep flag to use deep equality to compare values.| Param | Type | Description | | :-------- | :------- | :------------------ | | expected |
object
| An iterable object. |expect([2, 3, 5]).to.iterate.until([3, 5]);
expect('abcdefg').to.iterate.until('efg');
expect([2, 3, 5]).not.to.iterate.until([2, 3]);
expect([{n: 2}, {n: 3}]).to.deep.iterate.until([{n: 3}]);
iterate.for.lengthOf(n)
Asserts that the target yields exactly n values.| Param | Type | Description | | :----- | :------- | :------------------ | | n |
number
| A positive integer |expect([2, 3, 5]).to.iterate.for.lengthOf(3);
expect('abcdefg').to.iterate.for.lengthOf(7);
expect([2, 3, 5]).not.to.iterate.for.lengthOf(7);
iterate.for.length.above(n)
Asserts that the target yields more than n values.| Param | Type | Description | | :----- | :------- | :------------------ | | n |
number
| A positive integer |expect([2, 3, 5]).to.iterate.for.length.above(2);
expect('abcdefg').to.iterate.for.length.above(5);
expect([2, 3, 5]).not.to.iterate.for.length.above(3);
iterate.for.length.below(n)
Asserts that the target yields fewer than n values.| Param | Type | Description | | :----- | :------- | :------------------ | | n |
number
| A positive integer |expect([2, 3, 5]).to.iterate.for.length.below(4);
expect('abcdefg').to.iterate.for.length.below(10);
expect([2, 3, 5]).not.to.iterate.for.length.below(3);
iterate.for.length.of.at.least(n)
Asserts that the target yields at least n values.| Param | Type | Description | | :----- | :------- | :------------------ | | n |
number
| A positive integer |expect([2, 3, 5]).to.iterate.for.length.of.at.least(2);
expect([2, 3, 5]).to.iterate.for.length.of.at.least(3);
expect([2, 3, 5]).not.to.iterate.for.length.of.at.least(4);
iterate.for.length.of.at.most(n)
Asserts that the target yields at most n values.| Param | Type | Description | | :----- | :------- | :------------------ | | n |
number
| A positive integer |expect([2, 3, 5]).to.iterate.for.length.of.at.most(4);
expect([2, 3, 5]).to.iterate.for.length.of.at.most(3);
expect([2, 3, 5]).not.to.iterate.for.length.of.at.most(2);
iterate.for.length.within(min, max)
Asserts that the target yields between min and max values, inclusive.| Param | Type | Description | | :----- | :------- | :------------------- | | min |
number
| A positive integer |
| max | number
| A positive integer |expect([2, 3, 5]).to.iterate.for.length.within(2, 4);
expect([2, 3, 5]).to.iterate.for.length.within(3, 3);
expect([2, 3, 5]).not.to.iterate.for.length.within(4, 7);
Assert API
Assertions
isIterable()
isNotIterable()
iteratesOver()
doesNotIterateOver()
deepIteratesOver()
doesNotDeepIterateOver()
iteratesFrom()
doesNotIterateFrom()
deepIteratesFrom()
doesNotDeepIterateFrom()
iteratesUntil()
doesNotIterateUntil()
deepIteratesUntil()
doesNotDeepIterateUntil()
lengthOf()
Parameters
The parameters for the assert methods are as follows.| Param | Type | Description | | :------- | :------- | :--------------------------------------- | | value |
any
| Any value. |
| expected | object
| An iterable object. |
| n | number
| A positive integer. |
| message? | string
| An optional message to display on error. |isIterable(value, [message])
Asserts that a value is an iterable object, i.e., that it is an object with
an @@iterator
iterator-method method.assert.isIterable([2, 3, 5]);
assert.isIterable('abcdefg');
isNotIterable(value, [message])
Asserts that a value is not an iterable object, i.e., that it lacks an
@@iterator
iterator-method method.assert.isNotIterable(235);
assert.isNotIterable(true);
iteratesOver(value, expected, [message])
Asserts that a value iterates exactly over a given sequence of values.assert.iteratesOver([2, 3, 5], [2, 3, 5]);
assert.iteratesOver('abcdefg', 'abcdefg');
doesNotIterateOver(value, expected, [message])
Asserts that a value does not iterate exactly over a given sequence of values.assert.doesNotIterateOver([2, 3, 5], [1, 2, 3]);
assert.doesNotIterateOver('abcdefg', 'abc');
deepIteratesOver(value, expected, [message])
Asserts that a value iterates exactly over a given sequence of values, using
deep equality.assert.deepIteratesOver([{n: 2}, {n: 3}], [{n: 2}, {n: 3}]);
assert.deepIteratesOver([[0, 2], [1, 3]], [[0, 2], [1, 3]]);
doesNotDeepIterateOver(value, expected, [message])
Asserts that a value does not iterate exactly over a given sequence of values,
using deep equality.assert.doesNotDeepIterateOver([{n: 2}, {n: 3}], [{n: 5}, {n: 7}]);
assert.doesNotDeepIterateOver([[0, 2], [1, 3]], [[1, 3], [0, 2]]);
iteratesFrom(value, expected, [message])
Asserts that a value begins iteration with a given sequence of values.assert.iteratesFrom([2, 3, 5], [2, 3, 5]);
assert.iteratesFrom([2, 3, 5], [2, 3]);
assert.iteratesFrom('abcdefg', 'abc');
assert.iteratesFrom('abcdefg', '');
doesNotIterateFrom(value, expected, [message])
Asserts that a value does not begin iteration with a given sequence of values.assert.doesNotIterateFrom([2, 3, 5], [3, 5]);
assert.doesNotIterateFrom('abcdefg', 'cdef');
deepIteratesFrom(value, expected, [message])
Asserts that a value begins iteration with a given sequence of values, using
deep equality.assert.deepIteratesFrom([{n: 2}, {n: 3}], [{n: 2}]);
assert.deepIteratesFrom([[0, 2], [1, 3]], [[0, 2]]);
doesNotDeepIterateFrom(value, expected, [message])
Asserts that a value does not begin iteration with a given sequence of values,
using deep equality.assert.doesNotDeepIterateFrom([{n: 2}, {n: 3}], [{n: 5}]);
assert.doesNotDeepIterateFrom([[0, 2], [1, 3]], [[1, 3]]);
iteratesUntil(value, expected, [message])
Asserts that a value ends iteration with a given sequence of values.assert.iteratesUntil([2, 3, 5], [2, 3, 5]);
assert.iteratesUntil([2, 3, 5], [3, 5]);
assert.iteratesUntil('abcdefg', 'efg');
assert.iteratesUntil('abcdefg', '');
doesNotIterateUntil(value, expected, [message])
Asserts that a value does not end iteration with a given sequence of values.assert.doesNotIterateUntil([2, 3, 5], [2, 3]);
assert.doesNotIterateUntil('abcdefg', 'cdef');
deepIteratesUntil(value, expected, [message])
Asserts that a value ends iteration with a given sequence of values, using
deep equality.assert.deepIteratesUntil([{n: 2}, {n: 3}], [{n: 3}]);
assert.deepIteratesUntil([[0, 2], [1, 3]], [[1, 3]]);
doesNotDeepIterateUntil(value, expected, [message])
Asserts that a value does not end iteration with a given sequence of values,
using deep equality.assert.doesNotDeepIterateUntil([{n: 2}, {n: 3}], [{n: 5}]);
assert.doesNotDeepIterateUntil([[0, 2], [1, 3]], [[0, 2]]);
lengthOf(value, n, [message])
Asserts that an iterable yields a given number of values. If value is not an
iterable object, or if it has a 'length'
property, Chai's built-in
assert.lengthOf()
chai-assert-lengthof will be used.function* range(min=0, max=Infinity, step=1) {
for (let n = min; n < max; n += step) {
yield n;
}
}
assert.lengthOf(range(0, 10), 10);
assert.lengthOf(range(6, 42), 36);