import { - beforeAll,
- beforeEach,
- describe,
- describe.only,
- describe.skip,
- it,
- it.only,
- it.skip,
- type SanitizeOptions
} from "@effectionx/bdd"@effectionx/bdd
A BDD (Behavior-Driven Development) testing harness for Deno that integrates
seamlessly with Effection
operations. This package provides a familiar describe/it/beforeEach API
that works natively with Effection's generator-based operations.
Features
- 🔄 Native Effection Support: Test functions can be generator functions that yield operations
- 🏗️ Familiar BDD API: Uses the standard
describe,it, andbeforeEachfunctions you know and love - 🧹 Automatic Cleanup: Proper resource management and cleanup for Effection operations
- 🎯 Skip and Only: Full support for
.skipand.onlymodifiers - 📦 Zero Configuration: Works out of the box with Deno's built-in testing framework
Installation
Add to your deno.json imports:
{
"imports": {
"@effectionx/bdd": "jsr:@effectionx/bdd"
}
}
Basic Usage
import { beforeEach, describe, it } from "@effectionx/bdd";
import { expect } from "@std/expect";
import { sleep, spawn } from "effection";
import { createSignal, is } from "@effectionx/signals";
describe("My async operations", () => {
let counter: ReturnType<typeof createSignal<number, void>>;
beforeEach(function* () {
// Setup that runs before each test
counter = yield* createSignal(0);
yield* sleep(10); // Can use Effection operations in setup
});
it("should increment counter", function* () {
// Test function is a generator that can yield operations
counter.update((n) => n + 1);
yield* is(counter, (value) => value === 1);
expect(counter.valueOf()).toBe(1);
});
});
Real-World Examples
The following packages have been migrated to use @effectionx/bdd and provide
excellent examples of testing patterns:
- stream-helpers: See
batch.test.tsfor testing stream batching with time and size limits - signals: See
array.test.tsfor testing array signal operations like push, set, and update - timebox: See
timebox.test.tsfor testing timeout scenarios with both success and timeout cases - task-buffer: See
task-buffer.test.tsfor testing task queuing and buffer management - websocket: See
websocket.test.tsfor testing bidirectional WebSocket communication and connection lifecycle - worker: See
worker.test.tsfor testing web worker communication, error handling, and lifecycle management
Common Patterns Demonstrated
These test files show how to:
- Handle async operations without
run()wrappers - Test error scenarios using try/catch blocks instead of Promise rejections
- Use
beforeEachfor test setup with Effection operations - Wait for signal changes using the
ishelper - Test resource cleanup and proper teardown
- Handle timeouts and concurrent operations
API Reference
describe(name: string, body: () => void)
Creates a test suite with the given name. Test suites can be nested.
Options:
describe.skip()- Skip this test suitedescribe.only()- Run only this test suite
it(desc: string, body?: () => Operation<void>)
Creates a test case with the given description. The body function should be a generator function that can yield Effection operations.
Options:
it.skip()- Skip this test caseit.only()- Run only this test case
Parameters:
desc- Description of what the test should dobody- Generator function containing the test logic (optional for pending tests)
beforeEach(body: () => Operation<void>)
Registers a setup function that runs before each test in the current suite. The body function should be a generator function that can yield Effection operations.
afterEach
afterEachThis package doesn't include afterEach because it's typically used for clean
up. With Effection, clean up is done in finally block of the resource.
Consider creating a resource in beforeEach if you encounter a need for
afterEach.
beforeAll
Is not implemented yet.
Migration from Standard Deno Testing
If you're migrating from standard Deno testing with Effection, the changes are minimal:
Before:
import { describe, it } from "@std/testing/bdd";
import { run } from "effection";
describe("my tests", () => {
it("should work", async () => {
await run(function* () {
const result = yield* someOperation();
expect(result).toBe("success");
});
});
});
After:
import { describe, it } from "@effectionx/bdd";
// No need to import 'run'
describe("my tests", () => {
it("should work", function* () {
const result = yield* someOperation();
expect(result).toBe("success");
});
});
Contributing
This package is part of the Effection ecosystem. Contributions are welcome!
API Reference
Sanitization options for test cases and test suites. These options control Deno's test sanitizers.
Properties
- sanitizeExitoptional: boolean
Ensure the test case does not prematurely cause the process to exit. Defaults to true.
- sanitizeOpsoptional: boolean
Check that the number of async completed ops after the test is the same as number of dispatched ops. Defaults to true.
- sanitizeResourcesoptional: boolean
Ensure the test case does not "leak" resources - ie. the resource table after the test has exactly the same contents as before the test. Defaults to true.
Type
(name: string, body: () => void, optionsoptional: SanitizeOptions) => void
Type
(desc: string, body: () => Operation<void>, optionsoptional: SanitizeOptions) => void
Parameters
desc: string
bodyoptional: () => Operation<void>
optionsoptional: SanitizeOptions
Return Type
void