diff --git a/apps/web/src/components/terminal/TerminalPanel.test.tsx b/apps/web/src/components/terminal/TerminalPanel.test.tsx index 3ee9d83..7fc5902 100644 --- a/apps/web/src/components/terminal/TerminalPanel.test.tsx +++ b/apps/web/src/components/terminal/TerminalPanel.test.tsx @@ -1,6 +1,6 @@ /** * @file TerminalPanel.test.tsx - * @description Unit tests for the TerminalPanel component + * @description Unit tests for the TerminalPanel component — multi-tab scenarios */ import { describe, it, expect, vi, beforeEach } from "vitest"; @@ -13,27 +13,93 @@ import type { ReactElement } from "react"; // Mock XTerminal to avoid xterm.js DOM dependencies in panel tests vi.mock("./XTerminal", () => ({ - XTerminal: vi.fn(({ token, isVisible }: { token: string; isVisible: boolean }) => ( -
- )), + XTerminal: vi.fn( + ({ + sessionId, + isVisible, + sessionStatus, + }: { + sessionId: string; + isVisible: boolean; + sessionStatus: string; + }) => ( + + ) + ), +})); + +// Mock useTerminalSessions +const mockCreateSession = vi.fn(); +const mockCloseSession = vi.fn(); +const mockRenameSession = vi.fn(); +const mockSetActiveSession = vi.fn(); +const mockSendInput = vi.fn(); +const mockResize = vi.fn(); +const mockRegisterOutputCallback = vi.fn(() => vi.fn()); + +// Mutable state for the mock — tests update these +let mockSessions = new Map< + string, + { + sessionId: string; + name: string; + status: "active" | "exited"; + exitCode?: number; + } +>(); +let mockActiveSessionId: string | null = null; +let mockIsConnected = false; +let mockConnectionError: string | null = null; + +vi.mock("@/hooks/useTerminalSessions", () => ({ + useTerminalSessions: vi.fn(() => ({ + sessions: mockSessions, + activeSessionId: mockActiveSessionId, + isConnected: mockIsConnected, + connectionError: mockConnectionError, + createSession: mockCreateSession, + closeSession: mockCloseSession, + renameSession: mockRenameSession, + setActiveSession: mockSetActiveSession, + sendInput: mockSendInput, + resize: mockResize, + registerOutputCallback: mockRegisterOutputCallback, + })), })); import { TerminalPanel } from "./TerminalPanel"; +// ========================================== +// Helpers +// ========================================== + +function setTwoSessions(): void { + mockSessions = new Map([ + ["session-1", { sessionId: "session-1", name: "Terminal 1", status: "active" }], + ["session-2", { sessionId: "session-2", name: "Terminal 2", status: "active" }], + ]); + mockActiveSessionId = "session-1"; +} + // ========================================== // Tests // ========================================== describe("TerminalPanel", () => { const onClose = vi.fn(); - const onTabChange = vi.fn(); beforeEach(() => { vi.clearAllMocks(); + mockSessions = new Map(); + mockActiveSessionId = null; + mockIsConnected = false; + mockConnectionError = null; + mockRegisterOutputCallback.mockReturnValue(vi.fn()); }); // ========================================== @@ -60,112 +126,249 @@ describe("TerminalPanel", () => { expect(panel).toHaveStyle({ height: "0px" }); }); - it("passes isVisible=true to XTerminal when open", () => { + it("renders empty state when no sessions exist", () => { render((