import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import "@testing-library/jest-dom"; import { AgentDetailView } from "../AgentDetailView"; import type { AgentCapability, AgentDetail } from "../../api"; // Mock the API functions vi.mock("../../api", () => ({ fetchAgent: vi.fn(), updateAgentState: vi.fn(), deleteAgent: vi.fn(), fetchAgentLogs: vi.fn(), })); import { fetchAgent, updateAgentState } from "../../api"; const mockFetchAgent = vi.mocked(fetchAgent); const mockUpdateAgentState = vi.mocked(updateAgentState); describe("AgentDetailView", () => { const createMockAgent = (overrides: Partial<{ id: string; name: string; role: AgentCapability; state: "idle" | "active" | "paused" | "terminated"; taskId?: string; }> = {}): AgentDetail => ({ id: "agent-001", name: "Test Agent", role: "executor" as AgentCapability, state: "active", taskId: "FN-001", createdAt: "2024-01-01T00:00:00.000Z", updatedAt: "2024-01-01T00:00:00.000Z", lastHeartbeatAt: "2024-01-01T00:05:00.000Z", metadata: {}, heartbeatHistory: [], activeRun: { id: "run-001", agentId: "agent-001", startedAt: "2024-01-01T00:00:00.000Z", endedAt: null, status: "active", }, completedRuns: [ { id: "run-002", agentId: "agent-001", startedAt: "2023-12-31T00:00:00.000Z", endedAt: "2023-12-31T00:05:00.000Z", status: "completed", }, ], ...overrides, } as AgentDetail); beforeEach(() => { vi.clearAllMocks(); mockFetchAgent.mockResolvedValue(createMockAgent()); mockUpdateAgentState.mockResolvedValue(createMockAgent({ state: "paused" })); }); it("shows loading state initially", () => { render( ); expect(screen.getByText(/Loading agent/i)).toBeInTheDocument(); }); it("displays agent name in header after loading", async () => { render( ); // Wait for the h2 element specifically (the header title) await waitFor(() => { const headings = screen.getAllByRole("heading", { level: 2 }); expect(headings.some(h => h.textContent === "Test Agent")).toBe(true); }); }); it("fetches the agent using the active project context", async () => { render( ); await waitFor(() => { expect(mockFetchAgent).toHaveBeenCalledWith("agent-001", "proj_123"); }); }); it("displays role badge", async () => { render( ); await waitFor(() => { expect(screen.getByText("executor")).toBeInTheDocument(); }); }); it("displays state badge", async () => { render( ); await waitFor(() => { // There should be at least one element with "active" (could be in badge or inline-badge) expect(screen.getAllByText("active").length).toBeGreaterThan(0); }); }); it("shows all tabs", async () => { render( ); await waitFor(() => { expect(screen.getByText("Dashboard")).toBeInTheDocument(); expect(screen.getByText("Logs")).toBeInTheDocument(); expect(screen.getByText("Runs")).toBeInTheDocument(); expect(screen.getByText("Settings")).toBeInTheDocument(); }); }); it("shows Pause button for active agent", async () => { render( ); await waitFor(() => { expect(screen.getByText("Pause")).toBeInTheDocument(); }); }); it("shows Resume button for paused agent", async () => { mockFetchAgent.mockResolvedValue(createMockAgent({ state: "paused" })); render( ); await waitFor(() => { expect(screen.getByText("Resume")).toBeInTheDocument(); }); }); it("shows Delete button for terminated agent", async () => { mockFetchAgent.mockResolvedValue(createMockAgent({ state: "terminated" })); render( ); await waitFor(() => { expect(screen.getByText("Delete")).toBeInTheDocument(); }); }); it("shows statistics section on dashboard", async () => { render( ); await waitFor(() => { expect(screen.getByText("Total Runs")).toBeInTheDocument(); }); }); it("displays agent ID in footer", async () => { render( ); await waitFor(() => { expect(screen.getByText("agent-001")).toBeInTheDocument(); }); }); it("calls API with correct agentId", async () => { render( ); await waitFor(() => { expect(mockFetchAgent).toHaveBeenCalledWith("agent-001", undefined); }); }); it("displays health status indicator", async () => { render( ); await waitFor(() => { // Health status should be either Healthy, Unresponsive, or Idle const healthTexts = ["Healthy", "Unresponsive", "Idle"]; const hasHealthStatus = healthTexts.some(text => document.body.textContent?.includes(text) ); expect(hasHealthStatus).toBe(true); }); }); it("shows Live Run on runs tab when agent has active run", async () => { const user = userEvent.setup(); render( ); await waitFor(() => { expect(screen.getByText("Dashboard")).toBeInTheDocument(); }); await user.click(screen.getByText("Runs")); await waitFor(() => { expect(screen.getByText("Live Run")).toBeInTheDocument(); }); }); });