These assertions test iterables and async iterables using the iteration protocol (Symbol.iterator / Symbol.asyncIterator).
Important: These assertions are semantically different from Collection Assertions. Collection assertions use native APIs like
Array.prototype.includes()and.size. Iterable assertions usefor...of/for await...ofto consume the iterator. A subject with customSymbol.iteratorbehavior may produce different results.
These assertions work with any synchronous iterable (arrays, Sets, Maps, generators, custom iterables) via expect().
Aliases:
{Iterable} to yield {any} {Iterable} to emit {any} {Iterable} to yield value satisfying {any}
Iterates through the subject and checks if any yielded value satisfies the expected shape (partial matching semantics, like 'to satisfy').
Success:
expect([1, 2, 3], 'to yield', 2);
expect(new Set(['a', 'b']), 'to emit', 'a');
// Partial matching - extra properties are allowed
expect([{ a: 1, b: 2 }, { c: 3 }], 'to yield', { a: 1 }); // passes
function* gen() {
yield { name: 'test', extra: true };
}
expect(gen(), 'to yield value satisfying', { name: 'test' }); // passes
Failure:
expect([1, 2, 3], 'to yield', 5);
// AssertionError: Expected iterable to yield a value satisfying 5, but none matched
Negation:
expect([1, 2, 3], 'not to yield', 5);
Iterates through the subject and checks if any yielded value exhaustively matches the expected value (deep equality semantics, like 'to equal').
Success:
expect([{ a: 1 }, { b: 2 }], 'to yield value exhaustively satisfying', {
a: 1,
}); // passes
Failure:
// Extra properties cause failure with exhaustive matching
expect([{ a: 1, b: 2 }], 'to yield value exhaustively satisfying', { a: 1 });
// AssertionError: Expected iterable to yield a value exhaustively satisfying { a: 1 }, but none matched
Negation:
expect([{ a: 1, b: 2 }], 'not to yield value exhaustively satisfying', {
a: 1,
});
Asserts that ALL yielded values individually satisfy the expected shape. Uses partial matching semantics.
Success:
expect([{ a: 1 }, { a: 2, b: 3 }], 'to yield items satisfying', {
a: expect.it('to be a number'),
});
expect([1, 2, 3], 'to yield items satisfying', expect.it('to be a number'));
expect([], 'to yield items satisfying', { any: 'shape' }); // vacuous truth
Failure:
expect([{ a: 1 }, { b: 2 }], 'to yield items satisfying', {
a: expect.it('to be a number'),
});
// AssertionError: Expected all items to satisfy {...}, but item at index 1 did not match
Asserts that ALL yielded values individually match with deep equality. Extra properties cause failure.
Success:
expect([{ a: 1 }, { a: 1 }], 'to yield items exhaustively satisfying', {
a: 1,
});
Failure:
expect([{ a: 1, b: 2 }], 'to yield items exhaustively satisfying', { a: 1 });
// AssertionError: Expected all items to exhaustively satisfy { a: 1 }, but item at index 0 did not match
Aliases:
{Iterable} to yield first {any} {Iterable} to yield first satisfying {any}
Asserts that the first yielded value satisfies the expected shape. Uses partial matching semantics.
Success:
expect([{ a: 1, b: 2 }, { c: 3 }], 'to yield first', { a: 1 });
expect([1, 2, 3], 'to yield first satisfying', 1);
Failure:
expect([1, 2, 3], 'to yield first', 2);
// AssertionError: Expected first yielded value to satisfy 2, but got 1
expect([], 'to yield first', 1);
// AssertionError: Expected iterable to yield at least one value, but it was empty
Asserts that the first yielded value exhaustively matches. Extra properties cause failure.
Success:
expect([{ a: 1 }], 'to yield first exhaustively satisfying', { a: 1 });
Failure:
expect([{ a: 1, b: 2 }], 'to yield first exhaustively satisfying', { a: 1 });
// AssertionError: Expected first yielded value to exhaustively satisfy { a: 1 }, but got { a: 1, b: 2 }
Aliases:
{Iterable} to yield last {any} {Iterable} to yield last satisfying {any}
Asserts that the last yielded value satisfies the expected shape. Uses partial matching semantics.
Note: Fully consumes the iterator.
Success:
expect([{ a: 1 }, { b: 2, c: 3 }], 'to yield last', { b: 2 });
expect([1, 2, 3], 'to yield last satisfying', 3);
Failure:
expect([1, 2, 3], 'to yield last', 2);
// AssertionError: Expected last yielded value to satisfy 2, but got 3
Asserts that the last yielded value exhaustively matches. Extra properties cause failure.
Note: Fully consumes the iterator.
Success:
expect([{ a: 1 }, { b: 2 }], 'to yield last exhaustively satisfying', { b: 2 });
Failure:
expect([{ a: 1, extra: true }], 'to yield last exhaustively satisfying', {
a: 1,
});
// AssertionError: Expected last yielded value to exhaustively satisfy { a: 1 }, but got { a: 1, extra: true }
Asserts that an iterable yields exactly the specified count of values.
Success:
expect([1, 2, 3], 'to yield count', 3);
expect(new Set([1, 2]), 'to yield count', 2);
function* gen() {
yield 1;
yield 2;
yield 3;
yield 4;
}
expect(gen(), 'to yield count', 4);
Failure:
expect([1, 2, 3], 'to yield count', 5);
// AssertionError: Expected iterable to yield 5 value(s), but yielded 3
Negation:
expect([1, 2, 3], 'not to yield count', 5);
Asserts that an iterable yields at least the specified count of values.
Success:
expect([1, 2, 3], 'to yield at least', 2);
expect([1, 2, 3], 'to yield at least', 3);
Failure:
expect([1], 'to yield at least', 2);
// AssertionError: Expected iterable to yield at least 2 value(s), but yielded 1
Asserts that an iterable yields at most the specified count of values.
Success:
expect([1, 2], 'to yield at most', 3);
expect([1, 2, 3], 'to yield at most', 3);
Failure:
expect([1, 2, 3, 4], 'to yield at most', 3);
// AssertionError: Expected iterable to yield at most 3 value(s), but yielded 4
Asserts that an iterable yields nothing.
Use 'not to be an empty iterable' or 'to yield at least', 1 for non-empty assertions.
Success:
expect([], 'to be an empty iterable');
expect(new Set(), 'to be an empty iterable');
function* emptyGen() {}
expect(emptyGen(), 'to be an empty iterable');
Failure:
expect([1], 'to be an empty iterable');
// AssertionError: Expected iterable to be empty, but it yielded at least one value: 1
Negation:
expect([1, 2, 3], 'not to be an empty iterable');
Collects all yielded values and checks they match the expected array with deep equality semantics.
Success:
expect([1, 2, 3], 'to yield exactly', [1, 2, 3]);
function* gen() {
yield 'a';
yield 'b';
}
expect(gen(), 'to yield exactly', ['a', 'b']);
Failure:
expect([1, 2, 3], 'to yield exactly', [1, 2]);
// AssertionError: Expected iterable to yield exactly [1, 2]
// Extra properties also cause failure (deep equality)
expect([{ a: 1, b: 2 }], 'to yield exactly', [{ a: 1 }]);
// AssertionError: Expected iterable to yield exactly [{ a: 1 }]
Negation:
expect([1, 2], 'not to yield exactly', [1, 2, 3]);
Aliases:
{Iterable} to yield sequence satisfying {array} {Iterable} to yield array satisfying {array}
Collects all yielded values and checks they match the expected array with satisfy semantics (partial matching on objects).
Success:
expect([1, 2, 3], 'to yield sequence satisfying', [1, 2, 3]);
// Partial object matching - extra properties allowed
expect([{ a: 1, b: 2 }], 'to yield array satisfying', [{ a: 1 }]); // passes!
Failure:
expect([1, 2, 3], 'to yield sequence satisfying', [1, 2]);
// AssertionError: Expected iterable to yield sequence satisfying [1, 2]
Negation:
expect([1, 2], 'not to yield sequence satisfying', [1, 2, 3]);
These assertions work with async generators, Node.js Readable streams, Web ReadableStreams, and sync iterables via expectAsync().
Note: Sync iterables can be passed to async assertions - they are automatically wrapped as async iterators.
Aliases:
{AsyncIterable} to yield {any} {AsyncIterable} to emit {any} {AsyncIterable} to yield value satisfying {any}
Same semantics as the sync version, but for async iterables.
Success:
import { Readable } from 'node:stream';
// Async generator
async function* asyncGen() {
yield 1;
yield 2;
yield 3;
}
await expectAsync(asyncGen(), 'to yield', 2);
// Node.js Readable stream
const readable = Readable.from(['chunk1', 'chunk2', 'chunk3']);
await expectAsync(readable, 'to emit', 'chunk2');
// Web ReadableStream (Node.js v22+)
const webStream = new ReadableStream({
start(controller) {
controller.enqueue('data1');
controller.enqueue('data2');
controller.close();
},
});
await expectAsync(webStream, 'to yield', 'data2');
// Sync iterable also works
await expectAsync([1, 2, 3], 'to yield', 2);
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield value exhaustively satisfying', {
a: 1,
});
Same semantics as the sync version, but for async iterables.
import { Readable } from 'node:stream';
const readable = Readable.from(['str1', 'str2', 'str3']);
await expectAsync(
readable,
'to yield items satisfying',
expect.it('to be a string'),
);
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield items exhaustively satisfying', {
type: 'data',
});
Aliases:
{AsyncIterable} to yield first {any} {AsyncIterable} to yield first satisfying {any}
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield first', { type: 'header' });
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield first exhaustively satisfying', {
a: 1,
});
Aliases:
{AsyncIterable} to yield last {any} {AsyncIterable} to yield last satisfying {any}
Same semantics as the sync version, but for async iterables. Fully consumes the async iterator.
await expectAsync(asyncGen(), 'to yield last', { type: 'footer' });
Same semantics as the sync version, but for async iterables. Fully consumes the async iterator.
await expectAsync(asyncGen(), 'to yield last exhaustively satisfying', {
b: 2,
});
Same semantics as the sync version, but for async iterables.
import { Readable } from 'node:stream';
const readable = Readable.from(['a', 'b']);
await expectAsync(readable, 'to yield count', 2);
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield at least', 3);
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield at most', 10);
Same semantics as the sync version, but for async iterables.
async function* emptyAsyncGen() {}
await expectAsync(emptyAsyncGen(), 'to be an empty iterable');
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield exactly', [1, 2, 3]);
Aliases:
{AsyncIterable} to yield sequence satisfying {array} {AsyncIterable} to yield array satisfying {array}
Same semantics as the sync version, but for async iterables.
await expectAsync(asyncGen(), 'to yield sequence satisfying', [
{ type: 'start' },
{ type: 'end' },
]);
These assertions are specific to async iterables and check completion or error conditions.
Aliases:
{AsyncIterable} to complete {AsyncIterable} to finish
Asserts that an async iterable completes without throwing. Fully consumes the iterator.
Success:
import { Readable } from 'node:stream';
await expectAsync(asyncGen(), 'to complete');
await expectAsync(Readable.from(['a', 'b']), 'to finish');
Failure:
async function* failingGen() {
yield 1;
throw new Error('Oops!');
}
await expectAsync(failingGen(), 'to complete');
// AssertionError: Expected async iterable to complete, but it rejected with: Error: Oops!
Aliases:
{AsyncIterable} to reject {AsyncIterable} to be rejected
Asserts that an async iterable rejects (throws) during iteration.
Success:
async function* failingGen() {
yield 1;
throw new Error('Test error');
}
await expectAsync(failingGen(), 'to reject');
await expectAsync(failingGen(), 'to be rejected');
Failure:
await expectAsync(asyncGen(), 'to reject');
// AssertionError: Expected async iterable to reject, but it completed successfully
Aliases:
{AsyncIterable} to reject with a {Constructor} {AsyncIterable} to reject with an {Constructor}
Asserts that an async iterable rejects with a specific error type.
Success:
async function* typedErrorGen() {
throw new TypeError('Invalid type');
}
await expectAsync(typedErrorGen(), 'to reject with a', TypeError);
await expectAsync(typedErrorGen(), 'to reject with an', Error);
Failure:
async function* regularErrorGen() {
throw new Error('Regular error');
}
await expectAsync(regularErrorGen(), 'to reject with a', TypeError);
// AssertionError: Expected async iterable to reject with TypeError, but got Error: Regular error
await expectAsync(asyncGen(), 'to reject with an', Error);
// AssertionError: Expected async iterable to reject with Error, but it completed successfully
Aliases:
{AsyncIterable} to reject with error satisfying {any} {AsyncIterable} to be rejected with error satisfying {any}
Asserts that an async iterable rejects with an error matching a shape.
Success:
async function* connectionFailGen() {
throw new Error('Connection failed');
}
await expectAsync(connectionFailGen(), 'to reject with error satisfying', {
message: 'Connection failed',
});
const errorWithCode = Object.assign(new Error('Failed'), {
code: 'ECONNREFUSED',
});
async function* codedErrorGen() {
throw errorWithCode;
}
await expectAsync(codedErrorGen(), 'to be rejected with error satisfying', {
code: 'ECONNREFUSED',
});
Failure:
await expectAsync(connectionFailGen(), 'to reject with error satisfying', {
message: 'Wrong message',
});
// AssertionError: Expected async iterable to reject with error satisfying { message: 'Wrong message' }, but got Error: Connection failed
import { Readable } from 'node:stream';
// Create from array
const readable = Readable.from(['line1', 'line2', 'line3']);
await expectAsync(readable, 'to yield count', 3);
await expectAsync(Readable.from(['data']), 'to yield first', 'data');
// Web ReadableStream supports async iteration in Node.js v22+
const webStream = new ReadableStream({
start(controller) {
controller.enqueue('chunk1');
controller.enqueue('chunk2');
controller.close();
},
});
await expectAsync(webStream, 'to yield count', 2);
// response.body is a Web ReadableStream
const response = await fetch('https://example.com/api/stream');
await expectAsync(response.body, 'to complete');
Important: Generator functions must be called to create an iterator. The assertion library accepts iterators/iterables, not generator functions.
// Generator function - must be called
function* myGenerator() {
yield 1;
yield 2;
}
// Correct - call the generator function to create an iterator
expect(myGenerator(), 'to yield', 1);
// Incorrect - myGenerator is a Function, not an Iterable
// expect(myGenerator, 'to yield', 1); // This would fail type checking
expect([1, undefined, 3], 'to yield count', 3);
expect([undefined], 'to yield', undefined);
Strings are iterable (by character):
expect('abc', 'to yield', 'b');
expect('abc', 'to yield count', 3);
Maps yield [key, value] entries:
const map = new Map([
['a', 1],
['b', 2],
]);
expect(map, 'to yield count', 2);
expect(map, 'to yield', ['a', 1]);