Kefir Testing Utilities
Kefir-test-utils is a dedicated, framework-agnostic library providing a set of utilities specifically designed for testing Kefir.js observables. It enables developers to write robust unit tests for reactive streams by offering tools to control time, watch observable emissions, and assert their behavior over virtual timelines. The current stable version is 2.0.0, released in late 2023, following a period of maintenance and dependency upgrades. While its release cadence appears measured, recent updates indicate active development, focusing on modern JavaScript environments and dependency health. Key differentiators include its tight integration and specialization for the Kefir.js ecosystem, having been extracted from `chai-kefir` to offer a standalone, reusable set of testing primitives without tying to a specific assertion library or test framework. It is crucial for anyone building complex reactive applications with Kefir.js who needs precise control over testing asynchronous stream logic, offering a structured approach to virtual time testing that is typically more challenging with general-purpose testing tools.
Common errors
-
Error: Cannot find module 'kefir'
cause The peer dependency 'kefir' is not installed in the project, which is required by `kefir-test-utils`.fixInstall the 'kefir' package: `npm install kefir` or `yarn add kefir`. -
TypeError: (0, _kefirTestUtils.withTime) is not a function
cause This error typically indicates incorrect CommonJS `require` syntax when trying to access a named export, or attempting to use a default import for a named export in an ESM context.fixFor CommonJS environments, ensure you use `const { withTime } = require('kefir-test-utils');`. For ESM (recommended since v2.0.0), use `import { withTime } from 'kefir-test-utils';`.
Warnings
- breaking Version 2.0.0 includes an internal upgrade to its fake timers dependency, which might subtly alter timing behavior or test interaction patterns if previous versions relied on specific internal timer implementations. This could necessitate minor adjustments to tests with very precise timing assertions.
- breaking Support for Node.js v10 has been dropped in version 2.0.0, aligning the library with more modern Node.js runtimes. Running on Node.js v10 or earlier will result in compatibility errors.
- gotcha The `kefir` package is a peer dependency of `kefir-test-utils`. It must be installed separately in your project alongside `kefir-test-utils` for the library to function correctly, as it provides the core observable primitives being tested.
Install
-
npm install kefir-test-utils -
yarn add kefir-test-utils -
pnpm add kefir-test-utils
Imports
- withTime
const withTime = require('kefir-test-utils').withTimeimport { withTime } from 'kefir-test-utils' - watch
const watch = require('kefir-test-utils').watchimport { watch } from 'kefir-test-utils' - watchWithTime
import watchWithTime from 'kefir-test-utils'
import { watchWithTime } from 'kefir-test-utils'
Quickstart
import * as Kefir from 'kefir';
import { withTime, watch } from 'kefir-test-utils';
describe('Kefir-test-utils example', () => {
it('should test a simple observable with virtual time', () => {
withTime((tick) => {
// Create a Kefir stream that emits 1, 2, 3 sequentially with 100ms intervals
const stream = Kefir.sequentially(100, [1, 2, 3]);
// Use `watch` to collect events from the stream
const watcher = watch(stream);
// Assert initial state
expect(watcher.next).toEqual([]);
// Advance virtual time
tick(50); // 50ms passed
expect(watcher.next).toEqual([]); // No emissions yet
tick(50); // Total 100ms passed
expect(watcher.next).toEqual([1]); // First emission received
tick(100); // Total 200ms passed
expect(watcher.next).toEqual([1, 2]); // Second emission received
tick(100); // Total 300ms passed
expect(watcher.next).toEqual([1, 2, 3]); // All emissions received
expect(watcher.complete).toEqual(true); // Stream completed
});
});
it('should handle errors in a stream gracefully', () => {
withTime((tick) => {
// Create a stream that emits 1, then an error, which is caught and mapped to a message
const errorStream = Kefir.sequentially(50, [1])
.concat(Kefir.later(50, new Error('Simulated Error')))
.flatMapErrors(e => Kefir.constant(e.message)); // Catch error and emit message
const watcher = watch(errorStream);
tick(50);
expect(watcher.next).toEqual([1]);
tick(50);
// The error was caught and its message was emitted as a 'next' event
expect(watcher.next).toEqual([1, 'Simulated Error']);
expect(watcher.error).toEqual([]); // No actual error was propagated by `flatMapErrors`
expect(watcher.complete).toEqual(true);
});
});
});