Rensei docs

Testing

Test-run mode, auto-mock, and coverage.

Test-run mode lets you execute a workflow without triggering real side effects - no Linear comments are posted, no GitHub PRs are opened, no agents are dispatched. Every node is automatically mocked unless you explicitly opt specific nodes into real execution.

Starting a test run

From the editor: Switch to Execution mode in the toolbar, then click Test Run. The editor runs the current draft definition (not the published version).

Via API:

POST /api/workflows/{workflowId}/test-run
Content-Type: application/json
Authorization: Bearer rsk_live_...

{
  "triggerData": {
    "issueId": "ENG-123",
    "title": "Fix login bug",
    "teamId": "team_abc"
  },
  "unmockNodeIds": ["analyze-issue"]   # optional: run these nodes for real
}

The test run creates a workflow instance with runMode: 'test'. The instance ID is returned immediately; execution proceeds asynchronously.

Auto-mocking

In test mode, every node that would normally call an external service is automatically replaced with a mock that:

  1. Returns a plausible stub output matching the node's declared outputSchema
  2. Does not make any network calls or database writes outside the platform
  3. Emits <test:expr> placeholders for expression fields that reference upstream outputs that haven't been populated (lenient mode)

Node categories and their mock behaviour:

CategoryMock behaviour
TriggerReal - the trigger data you supply in triggerData is used verbatim
Action (provider)Mocked - no external API calls; stub output returned
ConditionEvaluated normally (conditions are pure logic, not side-effect nodes)
GateAuto-approved with signal: 'approved' unless the gate is in unmockNodeIds
ParallelExecuted normally (structural, no side effects)
FoundationalConfig resolved normally; no external calls
LLM (llm.inference)Mocked - returns a configurable stub response

unmockNodeIds - real execution

Pass node IDs in unmockNodeIds to run specific nodes against their real services. This is useful when you want to validate a particular action node (e.g. a specific API call) while keeping everything else mocked:

{
  "triggerData": { "issueId": "ENG-123", ... },
  "unmockNodeIds": [
    "read-issue",        # linear.issue.read - real Linear API call
    "analyze-content"    # llm.inference - real LLM call
  ]
}

Nodes in unmockNodeIds run for real. If you include a linear.comment.create node or an agent.dispatch node, those will post real comments and dispatch real agents.

Mock output toggle

The node config panel has a Mock output toggle (under the node's config panel in the editor). When enabled for a node, it lets you provide custom static JSON for that node's output, overriding the auto-generated stub. This is the primary mechanism for exercising specific branches during a test run.

The mock payload is validated against the node's declared outputSchema - invalid keys are flagged as errors in the config panel before you run. The mock data is stored on node.data.mock and is serialised with the workflow draft (it persists across sessions).

Testing a specific branch

To test the rejected path of an approval gate:

Select the gate node on the canvas and open its config panel.

Enable Mock output and set the outputs JSON:

{ "signal": "rejected" }

Click Test Run. The gate resolves to rejected immediately - no approval request is created, and execution follows the rejected branch.

Inspect the execution detail panel. The rejected branch nodes should show as completed; the approved and timeout branches should show as skipped.

Use the same technique to drive any condition node to a specific output: enable Mock output, supply the JSON matching the output shape you want, and run.

Test coverage

After a test run completes, you can inspect how many nodes were actually exercised versus mocked:

GET /api/workflows/{workflowId}/test-coverage
Authorization: Bearer rsk_live_...

Response:

{
  "totalNodes": 12,
  "executedNodes": 5,
  "mockedNodes": 7,
  "coveragePercent": 41.7,
  "unmockedNodeIds": ["read-issue"],
  "uncoveredNodeIds": ["notify-on-failure", "qa-gate"]
}

uncoveredNodeIds lists nodes that were not reached in this test run - they may be on branches that did not activate. Run multiple test scenarios with different triggerData values to increase branch coverage.

Expression lenient mode

In test mode, the expression evaluator runs in lenient mode. If an expression references a node output that is absent (because the node was mocked with an empty stub), the evaluator returns <test:$nodes.nodeId.output.field> instead of throwing. This prevents test runs from aborting prematurely due to mock data gaps.

After the test run, check the execution detail panel for any <test:...> values in node config - those indicate fields where real data would have been different.

Live SSE updates

Test runs produce the same real-time execution events as live runs. The canvas overlays step status (pending / running / completed / failed / mocked) on each node as the test progresses. Connect to the SSE stream:

GET /api/workflows/{workflowId}/instances/{instanceId}/stream
Authorization: Bearer rsk_live_...
Accept: text/event-stream

On this page