@siglo/testing Adapter Guide
@siglo/testing provides zero-flake testing utilities, virtual clocks, step spies, mocks, and failure replay tooling for Siglo workflows.
1. Overview & Architecture
Testing distributed workflows is notoriously difficult due to non-deterministic time delays, external network dependencies, and transient race conditions.@siglo/testing solves this with:
WorkflowHarness: Runs workflows in an isolated test sandbox with built-in step spying and assertions.FakeClock: Fast-forwards timers deterministically without real-timesetTimeoutdelays.InMemoryStorageFake: Lightweight, synchronous in-memory storage adapter capturing checkpoints and context mutations.- Execution Recording & Replay: Sanitizes production run records and replays them locally to verify deterministic parity and detect discrepancies.
2. Installation & Requirements
@siglo/core:^1.0.0
3. Basic Test with createWorkflowHarness
4. Mocking Steps & Fault Injection
Mock external APIs, database steps, or payment gateways to simulate failure scenarios:5. Virtual Clocks (FakeClock)
Control virtual timestamps for harness trace records without waiting for real wall-clock delays. Note that FakeClock only advances its own timestamp counter and tick() flushes microtasks via setImmediate; it does not override Node’s global Date.now or setTimeout:
6. Execution Recording & Deterministic Replay
Record workflow executions in production, sanitize PII, and replay them in CI/CD to detect regressions or output discrepancies:7. API Reference
WorkflowHarness
run(input?, options?): Promise<any>mockStep(stepName: string, implementation: Function): thisspyStep(stepName: string): StepSpyassertStepExecuted(stepName: string, expectedCount?: number): voidassertStepFailed(stepName: string, expectedError?: string | RegExp): voidassertStepRetried(stepName: string, expectedAttempts: number): voidexportExecutionRecord(options?: { excludeKeys?: string[] }): ExecutionRecordinjectEvent(eventName: string, correlationKey: string, payload?: any): Promise<any>
Note on Harness Scope:WorkflowHarness.run()instruments top-level workflow steps. It does not recursively replace nested branches or mapping children, andinjectEvent()resumes the workflow definition directly.
InMemoryStorageFake
saveCheckpoint(cp): Promise<void>getCheckpoint(stackId): Promise<any>clear(): void
FakeClock
now(): numberadvanceTime(ms: number): numbertick(ms?: number): Promise<void>reset(toTime?: number): void
