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();
});
});
});