import { describe, expect, test, mock } from "bun:test"; import { createRunsRoute } from "../routes/runs.ts"; import type { Runtime, Action } from "@gizmo-ai/runtime"; function createMockRuntime(state: Record): Runtime, Action> { return { getState: () => state, dispatch: mock(() => {}), execute: mock(() => ({ included: Promise.resolve(), completed: Promise.resolve({ status: "completed" }), cancel: () => {}, })), subscribe: () => () => {}, subscribeToActions: () => () => {}, dispatchToReducer: mock(() => {}), resetState: mock(() => {}), getPluginGraph: () => ({ nodes: [], edges: [] }), getPlugins: () => [], } as Runtime, Action>; } describe("createRunsRoute", () => { test("POST /:executionId/continue injects route executionId when payload is missing it", async () => { const runtime = createMockRuntime({ execution: { id: "exec-123", state: "pending" }, }); const app = createRunsRoute({ getRunHistory: () => new Map(), runtime, }); const response = await app.request("/exec-123/continue", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "HITL_APPROVAL_GRANTED", payload: { approved: true }, }), }); expect(response.status).toBe(200); expect(runtime.dispatch).toHaveBeenCalledWith( expect.objectContaining({ type: "HITL_APPROVAL_GRANTED", payload: expect.objectContaining({ executionId: "exec-123", approved: true, }), }) ); }); test("POST /:executionId/continue rejects mismatched payload executionId", async () => { const runtime = createMockRuntime({ execution: { id: "exec-123", state: "pending" }, }); const app = createRunsRoute({ getRunHistory: () => new Map(), runtime, }); const response = await app.request("/exec-123/continue", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "HITL_APPROVAL_GRANTED", payload: { executionId: "exec-999", approved: true, }, }), }); expect(response.status).toBe(400); expect(runtime.dispatch).not.toHaveBeenCalled(); }); });