iterator-matcher
Easily found out if an ES6 Iterator match what you expected
Limitations
- No built-in mechanism to match on non-primitive values.
Requirements
- Node.js v16 or higher
Getting Started
This package is available in the Node Package Repository and can be easily installed with npm or yarn.
$ npm i iterator-matcher
# or
$ yarn add iterator-matcher
Usage example
import { IteratorMatcher } from "iterator-matcher";
import assert from "node:assert";
function* dummyGen() {
yield "console";
yield "trace";
yield "error";
}
const result = new IteratorMatcher()
.expect("console")
.expect(["trace", "error"], { occurence: 2 })
.execute(dummyGen());
assert.ok(result.isMatching, true);
assert.equal(result.elapsedSteps, 3);
[!NOTE] You can re-use the same IteratorMatcher multiple time.
API
constructor()
No options are required.
expect(expectedValue: T | T[] | Set< T >, options: IteratorMatcherExpectOptions): this
The options payload is described by the following TypeScript interface:
export interface IteratorMatcherExpectOptions {
/**
* When a value is not mandatory the Executor continue his job/execution.
*
* @default true
*/
mandatory?: boolean;
/**
* Number of occurences of the expected value
*
* @default 1
*/
occurence?: number;
}
In usage the expectedValue can be an Array or a ES6 Set.
new IteratorMatcher()
.expect("primitive", { mandatory: false })
.expect([1, 2, 3])
.expect(new Set(["oh", "hey", "oh"]), { occurence: 2 });
execute(iterator: IterableIterator< T >, options: IteratorMatcherExecutorOptions): IteratorMatcherExecutorResult
The options payload is described by the following TypeScript interface:
interface DefaultIteratorMatcherExecutorOptions {
/**
* Stop the executor on the first matching value.
*
* @default false
*/
stopOnFirstMatch?: boolean;
/**
* When enabled it return isMatching: true if no value has been matched (like an empty Iterator for example).
*
* @default true
*/
allowNoMatchingValues?: boolean;
}
interface DefaultUnpreservedIteratorMatcherExecutorOptions
extends DefaultIteratorMatcherExecutorOptions {
/**
* Authorize unexpected value to appear
*
* @default false
*/
allowUnexpectedValue?: boolean;
}
export type IteratorMatcherExecutorOptions = {
/**
* When enabled it preserve the order of expectation
*/
preserveExpectationOrder?: true;
} & DefaultIteratorMatcherExecutorOptions | {
/**
* When disabled it will iterate all expectations and try to match them all with no order.
*/
preserveExpectationOrder?: false;
} & DefaultUnpreservedIteratorMatcherExecutorOptions;
The response is described by the following TypeScript type:
export type IteratorMatcherExecutorResult = {
isMatching: boolean;
elapsedSteps: number;
}
EventListener
The IteratorMatcher expose an additional EventListener
helper class useful for testing purpose with Node.js EventEmitter.
Here a real world example extracted from the UT one of my package:
import assert from "node:assert";
import { test } from "node:test";
import { TimeStore } from "@openally/timestore";
import { IteratorMatcher, EventListener } from "iterator-matcher";
test("Example with TimeStore, IteratorMatcher and EventListener", () => {
const store = new TimeStore({ ttl })
.add("foo").add("bar");
const eeListener = new EventListener(store, TimeStore.Expired);
// Doing some work with store
assert.equal(eeListener.listenerCount, 2);
const { isMatching } = new IteratorMatcher()
.expect("foo")
.expect("bar")
.execute(eeListener.names(), { allowNoMatchingValues: false });
assert.ok(isMatching, true);
});
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Gentilhomme 💻 🐛 📖 🛡️ |
License
MIT