Skip to content

Commit f5f7b37

Browse files
committed
fix(workflow-tests): keep the error of a mock that throws
A mock that throws reaches the server as { runId, callId, error }. The reply schema tried the output branch first, and its optional `output` matched, stripping `error`: the block failed with "A mocked block must return an object" instead of the thrown message, so a workflow that branches on its error text behaved differently under test than live. The error branch is now tried first.
1 parent bec4639 commit f5f7b37

2 files changed

Lines changed: 34 additions & 1 deletion

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { testReplyArgsSchema } from '@/lib/workflow-tests/protocol'
3+
4+
describe('testReplyArgsSchema', () => {
5+
it('keeps the error of a mock that threw', () => {
6+
// The sandbox sends no `output` key for a thrown mock; an optional `output` must not claim it.
7+
expect(
8+
testReplyArgsSchema.parse({ runId: 'r', callId: 'c', error: '409 version conflict' })
9+
).toEqual({
10+
runId: 'r',
11+
callId: 'c',
12+
error: '409 version conflict',
13+
})
14+
})
15+
16+
it('keeps a mock output, including a falsy one', () => {
17+
expect(testReplyArgsSchema.parse({ runId: 'r', callId: 'c', output: { ok: true } })).toEqual({
18+
runId: 'r',
19+
callId: 'c',
20+
output: { ok: true },
21+
})
22+
expect(testReplyArgsSchema.parse({ runId: 'r', callId: 'c', output: null })).toEqual({
23+
runId: 'r',
24+
callId: 'c',
25+
output: null,
26+
})
27+
})
28+
})

‎apps/sim/lib/workflow-tests/protocol.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,14 @@ export const testStartArgsSchema = z.object({
4040
targets: z.array(testTargetSchema).max(MAX_TARGETS),
4141
})
4242

43+
/**
44+
* A mock's answer: its output, or the error it threw. The error branch is tried first, because
45+
* `output: z.unknown()` also accepts an object with no `output`, which would turn a thrown mock
46+
* into an empty output and lose its message.
47+
*/
4348
export const testReplyArgsSchema = z.union([
44-
z.object({ runId: z.string().min(1), callId: z.string().min(1), output: z.unknown() }),
4549
z.object({ runId: z.string().min(1), callId: z.string().min(1), error: z.string().max(10_000) }),
50+
z.object({ runId: z.string().min(1), callId: z.string().min(1), output: z.unknown() }),
4651
])
4752

4853
export const testNextArgsSchema = z.object({ runId: z.string().min(1) })

0 commit comments

Comments
 (0)