Testing your flows
Because Rungs takes its time, IDs and approvers from you, a flow is easy to test: use the memory store, a clock you move, and predictable IDs.
// Your flow, on the memory store, with a clock the test moves. No database, no waiting.async function setup() { let now = new Date("2026-03-02T09:00:00.000Z"); const rungs = createRungs({ store: memoryStore(), clock: () => now, ids: (() => { let n = 0; return () => `r${++n}`; // predictable ids })(), events: "discard", }); await rungs.flows.register(expenseFlow); return { rungs, advance: (hours: number) => (now = new Date(+now + hours * 3_600_000)) };}
// Inside your test runner's it(...):const { rungs, advance } = await setup();const request = await rungs.submit({ flow: "expense", requesterId: "u_req", subject: { type: "expense", id: "EXP-1" }, payload: { amount: 10 },});advance(49);await rungs.tick();const { tasks } = await rungs.inbox({ userId: "u_dir" });assert.deepEqual( tasks.map((t) => t.requestId), [request.id],);Runs in CI:examples/docs-snippets/src/guides/testing.ts
The playground
Section titled “The playground”To explore a flow by hand, write a scenario for the playground. It prints every step, approver and decision as a readable timeline:
pnpm playground scenarios/02-manager-on-leave.tsTesting a store adapter
Section titled “Testing a store adapter”If you write your own RungsStore, the repository’s @rungsjs/store-contract suites check it
against the same behavior the memory and PostgreSQL stores pass; see the
store contract.