import { render, fireEvent, screen } from "@testing-library/react" import { useExtensionState } from "../../../context/ExtensionStateContext" import AutoApproveMenu from "../AutoApproveMenu" import { defaultModeSlug, defaultPrompts } from "../../../../../src/shared/modes" // Mock the ExtensionStateContext hook jest.mock("../../../context/ExtensionStateContext") const mockUseExtensionState = useExtensionState as jest.MockedFunction describe("AutoApproveMenu", () => { const defaultMockState = { // Required state properties version: "1.0.0", clineMessages: [], taskHistory: [], shouldShowAnnouncement: false, allowedCommands: [], soundEnabled: false, soundVolume: 0.5, diffEnabled: false, fuzzyMatchThreshold: 1.0, preferredLanguage: "English", writeDelayMs: 1000, browserViewportSize: "900x600", screenshotQuality: 75, terminalOutputLineLimit: 500, mcpEnabled: true, requestDelaySeconds: 5, currentApiConfigName: "default", listApiConfigMeta: [], mode: defaultModeSlug, customModePrompts: defaultPrompts, customSupportPrompts: {}, enhancementApiConfigId: "", didHydrateState: true, showWelcome: false, theme: {}, glamaModels: {}, openRouterModels: {}, openAiModels: [], mcpServers: [], filePaths: [], // Auto-approve specific properties alwaysAllowReadOnly: false, alwaysAllowWrite: false, alwaysAllowExecute: false, alwaysAllowBrowser: false, alwaysAllowMcp: false, alwaysApproveResubmit: false, autoApprovalEnabled: false, // Required setter functions setApiConfiguration: jest.fn(), setCustomInstructions: jest.fn(), setAlwaysAllowReadOnly: jest.fn(), setAlwaysAllowWrite: jest.fn(), setAlwaysAllowExecute: jest.fn(), setAlwaysAllowBrowser: jest.fn(), setAlwaysAllowMcp: jest.fn(), setShowAnnouncement: jest.fn(), setAllowedCommands: jest.fn(), setSoundEnabled: jest.fn(), setSoundVolume: jest.fn(), setDiffEnabled: jest.fn(), setBrowserViewportSize: jest.fn(), setFuzzyMatchThreshold: jest.fn(), setPreferredLanguage: jest.fn(), setWriteDelayMs: jest.fn(), setScreenshotQuality: jest.fn(), setTerminalOutputLineLimit: jest.fn(), setMcpEnabled: jest.fn(), setAlwaysApproveResubmit: jest.fn(), setRequestDelaySeconds: jest.fn(), setCurrentApiConfigName: jest.fn(), setListApiConfigMeta: jest.fn(), onUpdateApiConfig: jest.fn(), setMode: jest.fn(), setCustomPrompts: jest.fn(), setEnhancementApiConfigId: jest.fn(), setAutoApprovalEnabled: jest.fn(), } beforeEach(() => { mockUseExtensionState.mockReturnValue(defaultMockState) }) afterEach(() => { jest.clearAllMocks() }) it("renders with initial collapsed state", () => { render() // Check for main checkbox and label expect(screen.getByText("Auto-approve:")).toBeInTheDocument() expect(screen.getByText("None")).toBeInTheDocument() // Verify the menu is collapsed (actions not visible) expect(screen.queryByText("Read files and directories")).not.toBeInTheDocument() }) it("expands menu when clicked", () => { render() // Click to expand fireEvent.click(screen.getByText("Auto-approve:")) // Verify menu items are visible expect(screen.getByText("Read files and directories")).toBeInTheDocument() expect(screen.getByText("Edit files")).toBeInTheDocument() expect(screen.getByText("Execute approved commands")).toBeInTheDocument() expect(screen.getByText("Use the browser")).toBeInTheDocument() expect(screen.getByText("Use MCP servers")).toBeInTheDocument() expect(screen.getByText("Retry failed requests")).toBeInTheDocument() }) it("toggles main auto-approval checkbox", () => { render() const mainCheckbox = screen.getByRole("checkbox") fireEvent.click(mainCheckbox) expect(defaultMockState.setAutoApprovalEnabled).toHaveBeenCalledWith(true) }) it("toggles individual permissions", () => { render() // Expand menu fireEvent.click(screen.getByText("Auto-approve:")) // Click read files checkbox fireEvent.click(screen.getByText("Read files and directories")) expect(defaultMockState.setAlwaysAllowReadOnly).toHaveBeenCalledWith(true) // Click edit files checkbox fireEvent.click(screen.getByText("Edit files")) expect(defaultMockState.setAlwaysAllowWrite).toHaveBeenCalledWith(true) // Click execute commands checkbox fireEvent.click(screen.getByText("Execute approved commands")) expect(defaultMockState.setAlwaysAllowExecute).toHaveBeenCalledWith(true) }) it("displays enabled actions in summary", () => { mockUseExtensionState.mockReturnValue({ ...defaultMockState, alwaysAllowReadOnly: true, alwaysAllowWrite: true, autoApprovalEnabled: true, }) render() // Check that enabled actions are shown in summary expect(screen.getByText("Read, Edit")).toBeInTheDocument() }) it("preserves checkbox states", () => { // Mock state with some permissions enabled const mockState = { ...defaultMockState, alwaysAllowReadOnly: true, alwaysAllowWrite: true, } // Update mock to return our state mockUseExtensionState.mockReturnValue(mockState) render() // Expand menu fireEvent.click(screen.getByText("Auto-approve:")) // Verify read and edit checkboxes are checked expect(screen.getByLabelText("Read files and directories")).toBeInTheDocument() expect(screen.getByLabelText("Edit files")).toBeInTheDocument() // Verify the setters haven't been called yet expect(mockState.setAlwaysAllowReadOnly).not.toHaveBeenCalled() expect(mockState.setAlwaysAllowWrite).not.toHaveBeenCalled() // Collapse menu fireEvent.click(screen.getByText("Auto-approve:")) // Expand again fireEvent.click(screen.getByText("Auto-approve:")) // Verify checkboxes are still present expect(screen.getByLabelText("Read files and directories")).toBeInTheDocument() expect(screen.getByLabelText("Edit files")).toBeInTheDocument() // Verify the setters still haven't been called expect(mockState.setAlwaysAllowReadOnly).not.toHaveBeenCalled() expect(mockState.setAlwaysAllowWrite).not.toHaveBeenCalled() }) })