Cori
Guides

Test a workflow

Write vitest tests for code steps using captured fixtures, and use cori check for static validation.

Two layers of testing

Cori workflows have two testing surfaces:

  1. Static validationcori check validates the manifest, step file structure, and declared tools without executing anything.
  2. Unit tests — vitest tests for code steps, using captured input/output fixtures.

cori check — static validation

cori check ./my_workflow

Run this before every commit. It catches:

  • Missing or malformed manifest fields
  • Step files that don't export the right shape (input, output, default step)
  • Declared tools or MCP servers that can't be found
  • Type mismatches between step outputs and the next step's inputs

Unit testing code steps

code steps are pure functions — they're the easiest to test. Write a vitest test that calls the step's run function with a fixture input and asserts the output.

tests/03_check_gpsr.test.ts
import { describe, it, expect } from 'vitest';
import step, { input, output } from '../steps/03_check_gpsr';

describe('03_check_gpsr', () => {
  it('filters rows missing manufacturer', () => {
    const testInput = input.parse({
      rows: [
        { id: '1', name: 'Widget', manufacturer: 'ACME' },
        { id: '2', name: 'Gadget', manufacturer: '' },
        { id: '3', name: 'Doohickey' },
      ],
    });

    const result = output.parse(step.run({ input: testInput }));

    expect(result.valid_rows).toHaveLength(1);
    expect(result.valid_rows[0].id).toBe('1');
    expect(result.issues).toHaveLength(2);
  });
});

Run tests from inside the workflow directory:

cd ./my_workflow
npx vitest tests/

Why cli and mcp_tool steps usually don't need unit tests

cli and mcp_tool steps are thin wrappers around external tools. Their behavior is the external tool's responsibility. Testing them would be integration-testing the tool, not the step.

Focus unit tests on code steps, where your logic lives. For llm steps, unit testing the prompt is rarely valuable — test the output parsing/schema validation instead.

Captured fixtures (real inputs and outputs from a conversation) are better test inputs than invented ones. When an agent authors a workflow, it can generate test fixtures directly from the conversation artifacts.

Suggested test structure

my_workflow/
  tests/
    03_check_gpsr.test.ts      # test for each code step
    fixtures/
      03_check_gpsr_input.json  # captured real input
      03_check_gpsr_output.json # expected output

Load fixtures in tests:

import fixture from './fixtures/03_check_gpsr_input.json';
const testInput = input.parse(fixture);

On this page