diff --git a/src/infra/exec-approval-channel-runtime.test.ts b/src/infra/exec-approval-channel-runtime.test.ts index ae7fab6af0c..668308eeea7 100644 --- a/src/infra/exec-approval-channel-runtime.test.ts +++ b/src/infra/exec-approval-channel-runtime.test.ts @@ -98,6 +98,53 @@ function mockReplayLists(params: { }); } +function expectStartGatewayClientCall(preauthHandshakeTimeoutMs?: number) { + expect(mockStartGatewayClientWhenEventLoopReady).toHaveBeenCalledTimes(1); + const [client, options] = mockStartGatewayClientWhenEventLoopReady.mock.calls[0] ?? []; + expect(typeof (client as { start?: unknown } | undefined)?.start).toBe("function"); + expect(options).toEqual({ + clientOptions: { preauthHandshakeTimeoutMs }, + }); +} + +function expectFinalizedExpired( + finalizedExpired: ReturnType, + params: { id: string; entries: Array<{ id: string }> }, +) { + expect(finalizedExpired).toHaveBeenCalledTimes(1); + const payload = finalizedExpired.mock.calls[0]?.[0] as + | { request?: { id?: string }; entries?: Array<{ id: string }> } + | undefined; + expect(payload?.request?.id).toBe(params.id); + expect(payload?.entries).toEqual(params.entries); +} + +function expectFinalizedResolved( + finalizedResolved: ReturnType, + params: { id: string; decision: string; entries: Array<{ id: string }> }, +) { + expect(finalizedResolved).toHaveBeenCalledTimes(1); + const payload = finalizedResolved.mock.calls[0]?.[0] as + | { + request?: { id?: string }; + resolved?: { id?: string; decision?: string }; + entries?: Array<{ id: string }>; + } + | undefined; + expect(payload?.request?.id).toBe(params.id); + expect(payload?.resolved?.id).toBe(params.id); + expect(payload?.resolved?.decision).toBe(params.decision); + expect(payload?.entries).toEqual(params.entries); +} + +function expectDeliveredRequestId(deliverRequested: ReturnType, id: string) { + expect( + deliverRequested.mock.calls.some( + ([request]) => (request as { id?: unknown } | undefined)?.id === id, + ), + ).toBe(true); +} + beforeEach(() => { mockGatewayClientStarts.mockReset(); mockGatewayClientStops.mockReset(); @@ -185,11 +232,7 @@ describe("createExecApprovalChannelRuntime", () => { await runtime.handleExpired("abc"); - expect(finalizedExpired).toHaveBeenCalledTimes(1); - expect(finalizedExpired).toHaveBeenCalledWith({ - request: expect.objectContaining({ id: "abc" }), - entries: [{ id: "abc" }], - }); + expectFinalizedExpired(finalizedExpired, { id: "abc", entries: [{ id: "abc" }] }); expect(finalizedResolved).not.toHaveBeenCalled(); await runtime.handleResolved({ @@ -198,10 +241,9 @@ describe("createExecApprovalChannelRuntime", () => { ts: 1500, }); - expect(finalizedResolved).toHaveBeenCalledTimes(1); - expect(finalizedResolved).toHaveBeenCalledWith({ - request: expect.objectContaining({ id: "xyz" }), - resolved: expect.objectContaining({ id: "xyz", decision: "allow-once" }), + expectFinalizedResolved(finalizedResolved, { + id: "xyz", + decision: "allow-once", entries: [{ id: "xyz" }], }); }); @@ -242,9 +284,9 @@ describe("createExecApprovalChannelRuntime", () => { pendingDelivery.resolve([{ id: "plugin:abc" }]); await requestPromise; - expect(finalizeResolved).toHaveBeenCalledWith({ - request: expect.objectContaining({ id: "plugin:abc" }), - resolved: expect.objectContaining({ id: "plugin:abc", decision: "allow-once" }), + expectFinalizedResolved(finalizeResolved, { + id: "plugin:abc", + decision: "allow-once", entries: [{ id: "plugin:abc" }], }); }); @@ -264,12 +306,7 @@ describe("createExecApprovalChannelRuntime", () => { await runtime.request("exec.approval.resolve", { id: "abc", decision: "deny" }); expect(mockGatewayClientStarts).toHaveBeenCalledTimes(1); - expect(mockStartGatewayClientWhenEventLoopReady).toHaveBeenCalledWith( - expect.objectContaining({ start: expect.any(Function) }), - { - clientOptions: { preauthHandshakeTimeoutMs: undefined }, - }, - ); + expectStartGatewayClientCall(); expect(mockGatewayClientRequests).toHaveBeenCalledWith("exec.approval.resolve", { id: "abc", decision: "deny", @@ -300,12 +337,7 @@ describe("createExecApprovalChannelRuntime", () => { expect(mockGatewayClientStarts).not.toHaveBeenCalled(); expect(mockGatewayClientStops).toHaveBeenCalledTimes(1); - expect(mockStartGatewayClientWhenEventLoopReady).toHaveBeenCalledWith( - expect.objectContaining({ start: expect.any(Function) }), - { - clientOptions: { preauthHandshakeTimeoutMs: 30_000 }, - }, - ); + expectStartGatewayClientCall(30_000); }); it("can retry start after gateway client creation fails", async () => { @@ -409,9 +441,7 @@ describe("createExecApprovalChannelRuntime", () => { }); expect(caught).toBeInstanceOf(ExecApprovalChannelRuntimeTerminalStartError); - expect(caught).toMatchObject({ - detailCode: "PAIRING_REQUIRED", - }); + expect((caught as { detailCode?: string }).detailCode).toBe("PAIRING_REQUIRED"); expect(mockGatewayClientStarts).toHaveBeenCalledTimes(1); expect(mockGatewayClientStops).toHaveBeenCalledTimes(1); @@ -536,11 +566,7 @@ describe("createExecApprovalChannelRuntime", () => { emitPluginApprovalRequested(clientParams); await vi.waitFor(() => { - expect(deliverRequested).toHaveBeenCalledWith( - expect.objectContaining({ - id: "plugin:abc", - }), - ); + expectDeliveredRequestId(deliverRequested, "plugin:abc"); }); clientParams?.onEvent?.({ @@ -552,9 +578,9 @@ describe("createExecApprovalChannelRuntime", () => { }, }); await vi.waitFor(() => { - expect(finalizeResolved).toHaveBeenCalledWith({ - request: expect.objectContaining({ id: "plugin:abc" }), - resolved: expect.objectContaining({ id: "plugin:abc", decision: "allow-once" }), + expectFinalizedResolved(finalizeResolved, { + id: "plugin:abc", + decision: "allow-once", entries: [{ id: "plugin:abc" }], }); }); @@ -577,11 +603,7 @@ describe("createExecApprovalChannelRuntime", () => { await vi.waitFor(() => { expect(mockGatewayClientRequests).toHaveBeenCalledWith("exec.approval.list", {}); - expect(deliverRequested).toHaveBeenCalledWith( - expect.objectContaining({ - id: "abc", - }), - ); + expectDeliveredRequestId(deliverRequested, "abc"); }); }); @@ -603,11 +625,7 @@ describe("createExecApprovalChannelRuntime", () => { await runtime.start(); await vi.waitFor(() => { - expect(deliverRequested).toHaveBeenCalledWith( - expect.objectContaining({ - id: "abc", - }), - ); + expectDeliveredRequestId(deliverRequested, "abc"); }); pendingDelivery.resolve([{ id: "abc" }]); await runtime.stop(); @@ -839,9 +857,9 @@ describe("createExecApprovalChannelRuntime", () => { ts: 1500, }); - expect(finalizeResolved).toHaveBeenCalledWith({ - request: expect.objectContaining({ id: "abc" }), - resolved: expect.objectContaining({ id: "abc", decision: "allow-once" }), + expectFinalizedResolved(finalizeResolved, { + id: "abc", + decision: "allow-once", entries: [{ id: "abc" }], }); });