// @vitest-environment jsdom import { act, createElement, Fragment } from "react"; import { createRoot } from "react-dom/client"; import { afterEach, describe, expect, test } from "vitest"; import { AssistantAutoApprovalProvider, createAssistantAutoApprovalTracker, useAssistantAutoApproval, useAssistantAutomaticAction, } from "./assistant-auto-approval"; (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true; type AutoApproval = ReturnType; let currentAutoApproval: AutoApproval | null = null; let automaticActionInProgress = false; const containers: HTMLDivElement[] = []; const AutoApprovalProbe = () => { currentAutoApproval = useAssistantAutoApproval(); return null; }; const AutomaticActionProbe = ({ ready, completed, confirm, }: { ready: boolean; completed: boolean; confirm: () => void; }) => { automaticActionInProgress = useAssistantAutomaticAction({ toolCallId: "configure-app-1", ready, completed, confirm, }); return null; }; afterEach(() => { currentAutoApproval = null; automaticActionInProgress = false; for (const container of containers.splice(0)) container.remove(); }); describe("assistant automatic approval tracker", () => { test("claims a tool call only once across duplicate conversation renderers", () => { const tracker = createAssistantAutoApprovalTracker(); expect(tracker.claim("app-create-1")).toBe(true); expect(tracker.claim("app-create-1")).toBe(false); expect(tracker.claim("board-save-1")).toBe(true); }); test("can retry a failed response and clears claims for another conversation", () => { const tracker = createAssistantAutoApprovalTracker(); expect(tracker.claim("app-create-1")).toBe(true); tracker.release("app-create-1"); expect(tracker.claim("app-create-1")).toBe(true); tracker.clear(); expect(tracker.claim("app-create-1")).toBe(true); }); test("keeps the setting for the same local conversation and resets it on a real switch", async () => { const container = document.createElement("div"); containers.push(container); document.body.append(container); const root = createRoot(container); const renderConversation = async (conversationId: string) => { await act(async () => { root.render(createElement(AssistantAutoApprovalProvider, { conversationId }, createElement(AutoApprovalProbe))); }); }; await renderConversation("local-thread-1"); act(() => currentAutoApproval?.setEnabled(true)); expect(currentAutoApproval?.enabled).toBe(true); await renderConversation("local-thread-1"); expect(currentAutoApproval?.enabled).toBe(true); await renderConversation("local-thread-2"); expect(currentAutoApproval?.enabled).toBe(false); await act(async () => root.unmount()); }); test("clears claimed calls when automatic approvals are turned off", async () => { const container = document.createElement("div"); containers.push(container); document.body.append(container); const root = createRoot(container); await act(async () => { root.render( createElement( AssistantAutoApprovalProvider, { conversationId: "local-thread-1" }, createElement(AutoApprovalProbe), ), ); }); act(() => currentAutoApproval?.setEnabled(true)); expect(currentAutoApproval?.requestAction("app-create-1", () => undefined)).toBe(true); expect(currentAutoApproval?.requestAction("app-create-1", () => undefined)).toBe(false); act(() => currentAutoApproval?.setEnabled(false)); act(() => currentAutoApproval?.setEnabled(true)); expect(currentAutoApproval?.requestAction("app-create-1", () => undefined)).toBe(true); await act(async () => root.unmount()); }); test("returns a failed approval to the caller and releases its claim", async () => { const container = document.createElement("div"); containers.push(container); document.body.append(container); const root = createRoot(container); await act(async () => { root.render( createElement( AssistantAutoApprovalProvider, { conversationId: "local-thread-1" }, createElement(AutoApprovalProbe), ), ); }); act(() => currentAutoApproval?.setEnabled(true)); expect( currentAutoApproval?.requestAction("app-create-1", () => { throw new Error("Approval transport failed"); }), ).toBe(false); expect(currentAutoApproval?.requestAction("app-create-1", () => undefined)).toBe(true); await act(async () => root.unmount()); }); test("confirms a ready human-tool action exactly once and clears progress on completion", async () => { const container = document.createElement("div"); containers.push(container); document.body.append(container); const root = createRoot(container); let confirmationCount = 0; const confirm = () => { confirmationCount += 1; }; const renderAction = async (ready: boolean, completed: boolean) => { await act(async () => { root.render( createElement( AssistantAutoApprovalProvider, { conversationId: "local-thread-1" }, createElement( Fragment, null, createElement(AutoApprovalProbe), createElement(AutomaticActionProbe, { ready, completed, confirm }), ), ), ); }); }; await renderAction(false, false); act(() => currentAutoApproval?.setEnabled(true)); await renderAction(true, false); expect(confirmationCount).toBe(1); expect(automaticActionInProgress).toBe(true); await renderAction(true, false); expect(confirmationCount).toBe(1); await renderAction(false, true); expect(automaticActionInProgress).toBe(false); await act(async () => root.unmount()); }); });