Skip to content
Changelog

Report a bug

Test Automations

Test a managed agent automation before you use it for recurring work. The test is different for each kind of automation.

Instruction automationCode automation
How you testSelect Test or Test automation in the editor.Write fixtures in fixtures.json.
What runsThe managed agent follows the saved instructions in a private thread.Your code runs with a fixed event and fixed responses.
When it runsWhen you select the button.During each deploy.

A private test runs the automation in a private thread in its channel. Only you can see the thread. The thread has the name of the automation, and it links back to the automation editor. Read the response, then change the instructions in the editor.

  1. For a scheduled automation, open the automation from Automations in the sidebar.
  2. Save your changes. The test uses the saved instructions and model settings, so save first.
  3. Select Test.

For an event automation, open the event automation editor and select Test automation.

  • A private test does not wait for a real schedule, webhook, Slack event, or RSS item. Use it to examine the instructions and the behavior of the managed agent before you use live events.
  • The test runs as the person who selects Test. A scheduled run uses the execution identity, model provider credentials, and model billing context of the automation creator.
  • Each test makes a new preview in its private thread. This also occurs if the automation already delivered a result that day.
  • A test ignores delivery checkpoints and duplicate-delivery checks.
  • A test keeps the access requirements of the source.
  • A test does not change external delivery, delivery checkpoints, or recorded automation data.
  • A test can save authorized account choices. When new account choices are on for your workspace, another member’s private test can save a shared Team connection. That member must have access in the test Space, and the automation creator must have access in every destination Space. See Choose a connected account.

Use this checklist when you test with a real trigger event:

  1. Make sure that the Space has the connections that it needs.
  2. Send a typical trigger event, or wait for one.
  3. Open the thread that the run made.
  4. Examine the response and the tool calls of the managed agent.
  5. Change the automation instructions if it is necessary.
  6. Make sure that the correct people get a notification.

You can run fixtures in two ways:

  • At deploy. type-cli automations deploy runs every fixture in fixtures.json. If one fails, the deploy fails.
  • On saved code. type-cli automations test-code runs one fixture against the saved code of an automation. Pause the automation first, and sign in as its creator. The command does not enable the automation and does not use a real event.
Terminal window
type-cli automations test-code <automation-id> --space <space> --arguments-file ./fixture.json --json

For test-code, the fixture has subscriptionId and payload, and can have checkpoint, matcher, toolResponses, and integrationResponses. It cannot have name, expectedOutput, or expectedError. Read the result in the command output.

A fixture is a test case. It gives your method a fixed event and fixed responses for each call. Type runs all fixtures during each deploy. If a fixture fails, the deploy fails and the active code does not change.

Put a fixtures.json file in the project root:

fixtures.json
[
{
"name": "records the scheduled time",
"subscriptionId": "hourly",
"payload": { "scheduledAt": "2026-10-07T12:00:00.000Z" },
"toolResponses": [],
"expectedOutput": { "checkedAt": "2026-10-07T12:00:00.000Z" }
}
]
  • subscriptionId is the method to run.
  • payload is the event, in the same shape as a live event.
  • expectedOutput is the exact value that the method gives to ctx.setOutput.

For all fields, see Project Files.

Fixtures can answer two kinds of calls: integration tool calls and Custom API requests. Each of these calls needs a response in the fixture. Use the real request and the real response envelope:

{
"name": "command output uses the text envelope",
"subscriptionId": "check",
"payload": { "scheduledAt": "2026-10-07T00:00:00.000Z" },
"toolResponses": [
{
"request": {
"service": "managed-sandbox",
"name": "exec_command",
"arguments": { "command": "printf automation-ready" }
},
"response": { "content": [{ "type": "text", "text": "automation-ready" }] }
}
],
"expectedOutput": { "text": "automation-ready" }
}
Your code callsPut the response inResponse shape
ctx.tools.call, ctx.read.call, ctx.write.calltoolResponses{ content, structuredContent?, isError? }
ctx.read.request, ctx.write.requestintegrationResponses{ connection, data, headers, status, statusText, success, truncated }

Rules:

  • The request must match the call exactly: service, name, arguments, and organizationIntegrationId.
  • Type uses each response one time.
  • A call with no matching response fails the fixture.
  • A response that your code does not use fails the fixture.
  • For ctx.read.call and ctx.write.call, the response must have structuredContent. JSON in content[].text does not count.
  • If your method makes no calls, set "toolResponses": [].

In a fixture, Type rejects calls to other Type APIs. The run fails with “Unexpected fixture API request; only declared tool or integration calls are available”.

CallIn a fixture
ctx.tools.call, ctx.read.call, ctx.write.callSupported. Give the response in toolResponses.
replyInSlackThreadSupported. It is a ctx.write.call to slack_post_message.
ctx.read.request, ctx.write.requestSupported. Give the response in integrationResponses.
ctx.action, ctx.mutativeActionSupported. Type records the steps in the test result.
ctx.agent.run, ctx.agent.evaluateSupported. Type stages the handoff but does not start the managed agent.
ctx.write.sendMessageNot supported.
ctx.read.dataNot supported.
ctx.read.searchNot supported.
ctx.tools.find, ctx.tools.servicesNot supported.
Sandbox toolsSupported only as recorded toolResponses. A test never starts the sandbox.

For code that uses an unsupported call:

  • Write fixtures for the paths that end before the call. For example, test a filtered event or an error for bad data.
  • Test the path with the call in a live run. Use a test repository, a test channel, or a narrow filter. Then read the run with type-cli automations history --run <run-id> --include-activity.
  • To post in Slack instead of the Space, use replyInSlackThread or a Slack tool through ctx.write.call. Fixtures can answer those calls.

Use expectedError to make sure that a bad response fails the run:

{
"name": "provider error is a failed operation",
"subscriptionId": "check",
"payload": { "scheduledAt": "2026-10-07T00:00:00.000Z" },
"toolResponses": [
{
"request": { "service": "managed-sandbox", "name": "exec_command", "arguments": { "command": "printf automation-ready" } },
"response": { "content": [{ "type": "text", "text": "Workspace unavailable" }], "isError": true }
}
],
"expectedError": "Workspace check failed"
}

expectedError passes if the error message contains the text. Do not set both expectedOutput and expectedError in one fixture.

For an event that a matcher skips, omit both expectedOutput and expectedError. The method does not run, so there is no output. No output is not the same as null.

For AI questions, give the result in matcher. Type does not call the model in a fixture:

{ "matcher": { "decision": "skip" } }

Set checkpoint to the value that ctx.checkpoint.value has at the start of the case:

{ "name": "stays quiet when nothing changed", "subscriptionId": "check", "checkpoint": "open", "payload": { "scheduledAt": "2026-10-07T00:00:00.000Z" } }

Write one fixture for each different path in your code:

  • the normal case, with extra provider fields and null optional fields,
  • a filtered event,
  • a provider error or a response that does not match your schema,
  • a missing or wrong required ID.

Do not write many fixtures for the same path.

  • 20 fixtures in each fixtures.json file.
  • 128 tool responses and 128 integration responses in each fixture.
  • All fixtures in a deploy share a 4-minute limit. Type runs 4 fixtures at a time.

A test that passes does not prove that a live run will succeed.

Private tests of an instruction automation

Section titled “Private tests of an instruction automation”
  • A private test does not prove that real events arrive. It does not verify a webhook signature, an email address, or feed availability. Test real event delivery separately.
  • A successful test by another person does not prove that the automation creator has the same credentials or permissions.

After you enable the automation, examine the next run in Run history.

  • Fixtures do not call real APIs. They do not prove that your credentials work, or that the provider sends the response that you wrote.
  • Fixtures do not start the sandbox, and they do not start handoffs to the managed agent.
  • Fixtures do not call the model for AI questions in a matcher. To examine the answers of the model, send real example events.
  • Fixtures do not prove that events reach Type.

After the deploy, watch the first live runs with type-cli automations history.