mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:20:43 +00:00
test(agents): share approval abort helper
This commit is contained in:
@@ -365,6 +365,28 @@ describe("before_tool_call requireApproval handling", () => {
|
||||
mockCallGateway.mockReset();
|
||||
});
|
||||
|
||||
async function runAbortDuringApprovalWait(options?: { onResolution?: ReturnType<typeof vi.fn> }) {
|
||||
hookRunner.runBeforeToolCall.mockResolvedValue({
|
||||
requireApproval: {
|
||||
title: "Abortable",
|
||||
description: "Will be aborted",
|
||||
onResolution: options?.onResolution,
|
||||
},
|
||||
});
|
||||
|
||||
const controller = new AbortController();
|
||||
mockCallGateway.mockResolvedValueOnce({ id: "server-id-abort", status: "accepted" });
|
||||
mockCallGateway.mockImplementationOnce(() => new Promise(() => {}));
|
||||
setTimeout(() => controller.abort(new Error("run cancelled")), 10);
|
||||
|
||||
return await runBeforeToolCallHook({
|
||||
toolName: "bash",
|
||||
params: {},
|
||||
ctx: { agentId: "main", sessionKey: "main" },
|
||||
signal: controller.signal,
|
||||
});
|
||||
}
|
||||
|
||||
it("blocks without triggering approval when both block and requireApproval are set", async () => {
|
||||
hookRunner.runBeforeToolCall.mockResolvedValue({
|
||||
block: true,
|
||||
@@ -574,31 +596,7 @@ describe("before_tool_call requireApproval handling", () => {
|
||||
});
|
||||
|
||||
it("unblocks immediately when abort signal fires during waitDecision", async () => {
|
||||
hookRunner.runBeforeToolCall.mockResolvedValue({
|
||||
requireApproval: {
|
||||
title: "Abortable",
|
||||
description: "Will be aborted",
|
||||
},
|
||||
});
|
||||
|
||||
const controller = new AbortController();
|
||||
|
||||
// First call: plugin.approval.request → accepted
|
||||
mockCallGateway.mockResolvedValueOnce({ id: "server-id-abort", status: "accepted" });
|
||||
// Second call: plugin.approval.waitDecision → never resolves (simulates long wait)
|
||||
mockCallGateway.mockImplementationOnce(
|
||||
() => new Promise(() => {}), // hangs forever
|
||||
);
|
||||
|
||||
// Abort after a short delay
|
||||
setTimeout(() => controller.abort(new Error("run cancelled")), 10);
|
||||
|
||||
const result = await runBeforeToolCallHook({
|
||||
toolName: "bash",
|
||||
params: {},
|
||||
ctx: { agentId: "main", sessionKey: "main" },
|
||||
signal: controller.signal,
|
||||
});
|
||||
const result = await runAbortDuringApprovalWait();
|
||||
|
||||
expect(result.blocked).toBe(true);
|
||||
expect(result).toHaveProperty("reason", "Approval cancelled (run aborted)");
|
||||
@@ -767,30 +765,7 @@ describe("before_tool_call requireApproval handling", () => {
|
||||
|
||||
it("calls onResolution with cancelled when abort signal fires", async () => {
|
||||
const onResolution = vi.fn();
|
||||
|
||||
hookRunner.runBeforeToolCall.mockResolvedValue({
|
||||
requireApproval: {
|
||||
title: "Abortable with callback",
|
||||
description: "Will be aborted",
|
||||
onResolution,
|
||||
},
|
||||
});
|
||||
|
||||
const controller = new AbortController();
|
||||
|
||||
mockCallGateway.mockResolvedValueOnce({ id: "server-id-r5", status: "accepted" });
|
||||
mockCallGateway.mockImplementationOnce(
|
||||
() => new Promise(() => {}), // hangs forever
|
||||
);
|
||||
|
||||
setTimeout(() => controller.abort(new Error("run cancelled")), 10);
|
||||
|
||||
const result = await runBeforeToolCallHook({
|
||||
toolName: "bash",
|
||||
params: {},
|
||||
ctx: { agentId: "main", sessionKey: "main" },
|
||||
signal: controller.signal,
|
||||
});
|
||||
const result = await runAbortDuringApprovalWait({ onResolution });
|
||||
|
||||
expect(result.blocked).toBe(true);
|
||||
expect(result).toHaveProperty("reason", "Approval cancelled (run aborted)");
|
||||
|
||||
Reference in New Issue
Block a user