import { beforeAll, describe, expect, it, vi, afterEach } from "vitest"; import { useTerminal } from "#/hooks/use-terminal"; import { Command, useCommandStore } from "#/stores/command-store"; import { renderWithProviders } from "../../test-utils"; // Mock the WsClient context vi.mock("#/context/ws-client-provider", () => ({ useWsClient: () => ({ send: vi.fn(), status: "CONNECTED", isLoadingMessages: false, events: [], }), })); // Mock useActiveConversation vi.mock("#/hooks/query/use-active-conversation", () => ({ useActiveConversation: () => ({ data: { id: "test-conversation-id", conversation_version: "V0", }, isFetched: true, }), })); // Mock useConversationWebSocket (returns null for V0 conversations) vi.mock("#/contexts/conversation-websocket-context", () => ({ useConversationWebSocket: () => null, })); function TestTerminalComponent() { const ref = useTerminal(); return
; } describe("useTerminal", () => { // Terminal is read-only - no longer tests user input functionality const mockTerminal = vi.hoisted(() => ({ loadAddon: vi.fn(), open: vi.fn(), write: vi.fn(), writeln: vi.fn(), dispose: vi.fn(), element: document.createElement("div"), })); const mockFitAddon = vi.hoisted(() => ({ fit: vi.fn(), })); beforeAll(() => { // mock ResizeObserver - use class for Vitest 4 constructor support window.ResizeObserver = class { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); } as unknown as typeof ResizeObserver; // mock Terminal - use class for Vitest 4 constructor support vi.mock("@xterm/xterm", async (importOriginal) => ({ ...(await importOriginal()), Terminal: class { loadAddon = mockTerminal.loadAddon; open = mockTerminal.open; write = mockTerminal.write; writeln = mockTerminal.writeln; dispose = mockTerminal.dispose; element = mockTerminal.element; }, })); // mock FitAddon vi.mock("@xterm/addon-fit", () => ({ FitAddon: class { fit = mockFitAddon.fit; }, })); }); afterEach(() => { vi.clearAllMocks(); // Reset command store between tests useCommandStore.setState({ commands: [] }); }); it("should render", () => { renderWithProviders(); }); it("should render the commands in the terminal", () => { const commands: Command[] = [ { content: "echo hello", type: "input" }, { content: "hello", type: "output" }, ]; // Set commands in store before rendering to ensure they're picked up during initialization useCommandStore.setState({ commands }); renderWithProviders(); expect(mockTerminal.writeln).toHaveBeenNthCalledWith(1, "echo hello"); expect(mockTerminal.writeln).toHaveBeenNthCalledWith(2, "hello"); }); it("should not call fit() when terminal.element is null", () => { // Temporarily set element to null to simulate terminal not being opened const originalElement = mockTerminal.element; mockTerminal.element = null as unknown as HTMLDivElement; renderWithProviders(); // fit() should not be called because terminal.element is null expect(mockFitAddon.fit).not.toHaveBeenCalled(); // Restore original element mockTerminal.element = originalElement; }); });