Skip to content

Handler and workflow test helpers #265

Closed

Description

@adenhertog

Context

Some helpers already exist: workflowContext() in bus-core and messageAttributes() in bus-messages. Missing:

  • a handlerContext() fake
  • any recording of what a handler sent
  • a workflow scenario runner
  • a way to wait for an in-memory bus to finish

The in-memory "latency" comes from the bus loop, not the queue: after every empty read, BusInstance.applicationLoop sleeps 500 ms (EMPTY_QUEUE_SLEEP_MS), on top of the queue's 1 s receive wait.

Workflow lifecycle hooks (#153) are closed. With #263 removing the emitters, the scenario runner covers that test need.

Decisions

Answered by the maintainer:

  1. The helpers live in bus-core, next to workflowContext(), and are exported from the package root. There's no @node-ts/bus-testing package, which also avoids confusion with the bus-test conformance suites.
  2. No test-framework matchers. Helpers return plain recorded arrays that any runner (jest, vitest, node:test) can assert on.
  3. Time control lives here (moved from Workflow (saga) timeouts #259): the scenario runner records delayed sends and delivers them with advanceTime.

Proposed:

  1. Keeping the fakes current. A change to HandlerContext or WorkflowContext updates the fakes in the same PR. Add this rule to CLAUDE.md.

Non-goals

  • jest or vitest matchers.
  • Workflow lifecycle emitters.
  • Fake clocks for real running buses.
  • A separate package.

Approach

  • handlerContext(overrides?) records sent and published (each with its attributes and delivery options from Delayed / deferred message delivery #258), and whether failMessage or returnMessage was called. workflowContext() gets the same recording.
  • testWorkflow(workflow) works with class workflows and defineWorkflow workflows:
    • .given(state) sets the starting state; .when(message, attributes?) returns { state, status, sent, published }.
    • It applies the registry's real merge rules ($workflowId, $version and $name are kept; complete and discard are honoured), with no transport.
    • .advanceTime(ms) delivers the recorded delayed sends that this workflow handles.
  • InMemoryQueue.idle(): Promise<void> resolves when nothing is queued, in flight or waiting to retry. Tests await it instead of an EventEmitter.
  • Idle sleep: skip BusInstance's 500 ms sleep when the transport's readNextMessage already waited.
  • Docs: /guide/testing.

Acceptance criteria

  • handlerContext() and workflowContext() record sends and publishes with their options
  • testWorkflow covers start, continue, complete, discard and a timeout delivered by advanceTime, for both workflow styles
  • InMemoryQueue.idle() replaces the EventEmitter waits in at least one existing integration test
  • An in-memory message sent to an idle bus is handled without the 500 ms delay
  • CLAUDE.md rule added; docs page with snippets; changeset

Activity

  1. changed the title [-]`@node-ts/bus-testing`: handler and workflow test helpers[/-] [+]Handler and workflow test helpers[/+] on Oct 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestroadmapPart of the project roadmap

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions