import { render, screen } from "@testing-library/react"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import type { AgentConfigInfo, AgentInfo } from "../api/agents"; import { agentsApi } from "../api/agents"; vi.mock("../api/agents", () => { const agentsApi = { listAgents: vi.fn(), getAgentConfig: vi.fn(), startAgent: vi.fn(), stopAgent: vi.fn(), reloadConfig: vi.fn(), }; return { agentsApi, subscribeAgentStream: vi.fn(() => () => {}) }; }); // Dynamic import so the mock is in place before the module loads const { AgentPanel } = await import("./AgentPanel"); const mockedAgents = { listAgents: vi.mocked(agentsApi.listAgents), getAgentConfig: vi.mocked(agentsApi.getAgentConfig), startAgent: vi.mocked(agentsApi.startAgent), }; const ROSTER: AgentConfigInfo[] = [ { name: "coder-1", role: "Full-stack engineer", model: "sonnet", allowed_tools: null, max_turns: 50, max_budget_usd: 5.0, }, ]; describe("AgentPanel active work list removed", () => { beforeAll(() => { Element.prototype.scrollIntoView = vi.fn(); }); beforeEach(() => { mockedAgents.getAgentConfig.mockResolvedValue(ROSTER); mockedAgents.listAgents.mockResolvedValue([]); }); it("does not render active agent entries even when agents are running", async () => { const agentList: AgentInfo[] = [ { story_id: "83_active", agent_name: "coder-1", status: "running", session_id: null, worktree_path: "/tmp/wt", base_branch: "master", }, ]; mockedAgents.listAgents.mockResolvedValue(agentList); const { container } = render(); // Roster badge should still be visible await screen.findByTestId("roster-badge-coder-1"); // No agent entry divs should exist expect( container.querySelector('[data-testid^="agent-entry-"]'), ).not.toBeInTheDocument(); }); }); describe("RosterBadge availability state", () => { beforeAll(() => { Element.prototype.scrollIntoView = vi.fn(); }); beforeEach(() => { mockedAgents.getAgentConfig.mockResolvedValue(ROSTER); mockedAgents.listAgents.mockResolvedValue([]); }); it("shows a green dot for an idle agent", async () => { render(); const dot = await screen.findByTestId("roster-dot-coder-1"); // JSDOM normalizes #3fb950 to rgb(63, 185, 80) expect(dot.style.background).toBe("rgb(63, 185, 80)"); expect(dot.style.animation).toBe(""); }); it("shows green badge styling for an idle agent", async () => { render(); const badge = await screen.findByTestId("roster-badge-coder-1"); // JSDOM normalizes #3fb95015 to rgba(63, 185, 80, 0.082) and #3fb950 to rgb(63, 185, 80) expect(badge.style.background).toBe("rgba(63, 185, 80, 0.082)"); expect(badge.style.color).toBe("rgb(63, 185, 80)"); }); it("shows a blue pulsing dot for an active agent", async () => { const agentList: AgentInfo[] = [ { story_id: "81_active", agent_name: "coder-1", status: "running", session_id: null, worktree_path: null, base_branch: null, }, ]; mockedAgents.listAgents.mockResolvedValue(agentList); render(); const dot = await screen.findByTestId("roster-dot-coder-1"); // JSDOM normalizes #58a6ff to rgb(88, 166, 255) expect(dot.style.background).toBe("rgb(88, 166, 255)"); expect(dot.style.animation).toBe("pulse 1.5s infinite"); }); it("shows blue badge styling for an active agent", async () => { const agentList: AgentInfo[] = [ { story_id: "81_active", agent_name: "coder-1", status: "running", session_id: null, worktree_path: null, base_branch: null, }, ]; mockedAgents.listAgents.mockResolvedValue(agentList); render(); const badge = await screen.findByTestId("roster-badge-coder-1"); // JSDOM normalizes #58a6ff18 to rgba(88, 166, 255, 0.094) and #58a6ff to rgb(88, 166, 255) expect(badge.style.background).toBe("rgba(88, 166, 255, 0.094)"); expect(badge.style.color).toBe("rgb(88, 166, 255)"); }); });