Testing
Unit-test octo flows with dolphin: mock what calls the world, assert what happened, and run the same file from a terminal, the editor, an agent and CI.
dolphin is octo's test runner. A test is a
debug config with assertions: the
input, mocks and spies you would pass to octo invoke by hand, plus what should have
happened. The mocks make the flow runnable anywhere (the HTTP call, the LLM, the
database write never happen); the assertions make the run mean something.

One file, four surfaces
A suite is a YAML file beside the flows it tests: orders.yaml is tested by
orders_test.yaml.
| You write it | You run it |
|---|---|
| By hand, in an editor | dolphin test in a terminal |
| In the Testing tab, as a form | Run tests, per suite or for the whole document |
| With an agent over MCP | run_tests |
| (any of the above) | CI, on every push |
All four give the same verdict because all four shell out to the same binary. The
editor runs dolphin and reads its report.
The shape of a suite
flow: orders # the flow every case calls
mocks: # stand in for the blocks that call the world
orders.charge-card:
cases:
- when: 'body.amount > 100'
error: card declined
default:
body: { id: ch_1, status: captured }
inputs: # named messages the cases share
small: { data: { amount: 10 } }
large: { data: { amount: 500 } }
cases:
- name: a small charge is captured
input: small
expect:
body: { id: ch_1, status: captured }
- name: a large charge is declined and answers 502
input: large
expect:
vars: { httpStatus: 502 }
that: ['body.error.contains("card declined")']
spies: # and prove the block was actually reached
orders.charge-card:
count: 1Start here
Your first test
Zero to a green suite in about ten minutes, on a flow that ships with octo, including making it fail on purpose.
Writing test cases
The format in full: mocks, shared inputs, spies over a foreach, and everything
expect can assert.
Testing in the editor
The Testing tab: a form over the same file, running one suite or all of them.
Testing with an agent
Writing and running suites over MCP, and which tools touch the committed file.
Running tests
dolphin test, its flags, the exit-code contract, and a CI job to copy.
Test file reference
Every key of a _test.yaml, field by field.
What dolphin is not
It is not an assertion DSL: expect.that and a mock's when are CEL,
the same language every block uses, over the same variables.
It is not an in-process harness: one case is one octo process, so cases are fully
isolated and a failing case can hand you a runnable command that reproduces it.
It is not a mock of octo: the engine under test is the real one, so a mocked block failure behaves exactly as the real failure would in production.
dolphin ships alongside octo as a second binary. See
installation, or use the standalone
editor's Docker image, which bundles both.