// @vitest-environment jsdom import { act } from "react"; import type { ReactNode } from "react"; import { createRoot } from "react-dom/client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { Agent } from "@paperclipai/shared"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { Agents } from "./Agents"; const mockAgentsApi = vi.hoisted(() => ({ list: vi.fn(), org: vi.fn(), })); const mockHeartbeatsApi = vi.hoisted(() => ({ liveRunsForCompany: vi.fn(), })); const mockOpenNewAgent = vi.hoisted(() => vi.fn()); const mockSetBreadcrumbs = vi.hoisted(() => vi.fn()); vi.mock("@/lib/router", () => ({ Link: ({ children, to, ...props }: { children: ReactNode; to: string }) => ( {children} ), useLocation: () => ({ pathname: "/agents/all", search: "", hash: "", state: null }), useNavigate: () => vi.fn(), })); vi.mock("../context/CompanyContext", () => ({ useCompany: () => ({ selectedCompanyId: "company-1" }), })); vi.mock("../context/DialogContext", () => ({ useDialogActions: () => ({ openNewAgent: mockOpenNewAgent }), })); vi.mock("../context/BreadcrumbContext", () => ({ useBreadcrumbs: () => ({ setBreadcrumbs: mockSetBreadcrumbs }), })); vi.mock("../context/SidebarContext", () => ({ useSidebar: () => ({ isMobile: false }), })); vi.mock("../api/agents", () => ({ agentsApi: mockAgentsApi, })); vi.mock("../api/heartbeats", () => ({ heartbeatsApi: mockHeartbeatsApi, })); vi.mock("../adapters/adapter-display-registry", () => ({ getAdapterLabel: (type: string) => type, })); // eslint-disable-next-line @typescript-eslint/no-explicit-any (globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; function makeAgent(overrides: Partial): Agent { return { id: "agent-1", companyId: "company-1", name: "Alpha", urlKey: "alpha", role: "engineer", title: null, icon: null, status: "active", reportsTo: null, capabilities: null, adapterType: "codex_local", adapterConfig: {}, runtimeConfig: {}, budgetMonthlyCents: 0, spentMonthlyCents: 0, pauseReason: null, pausedAt: null, permissions: { canCreateAgents: false }, lastHeartbeatAt: null, metadata: null, createdAt: new Date("2026-01-01T00:00:00Z"), updatedAt: new Date("2026-01-01T00:00:00Z"), ...overrides, }; } async function flushReact() { await act(async () => { await Promise.resolve(); await new Promise((resolve) => window.setTimeout(resolve, 0)); }); } describe("Agents", () => { let container: HTMLDivElement; let root: ReturnType | null; let queryClient: QueryClient; beforeEach(() => { container = document.createElement("div"); document.body.appendChild(container); root = null; queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }); mockAgentsApi.list.mockResolvedValue([ makeAgent({ adapterConfig: { model: "gpt-5.4" } }), ]); mockAgentsApi.org.mockResolvedValue([ { id: "agent-1", name: "Alpha", role: "engineer", status: "active", reports: [], }, ]); mockHeartbeatsApi.liveRunsForCompany.mockResolvedValue([]); }); afterEach(async () => { const currentRoot = root; if (currentRoot) { await act(async () => { currentRoot.unmount(); }); } queryClient.clear(); container.remove(); document.body.innerHTML = ""; vi.clearAllMocks(); }); it("shows the configured model beside the adapter on the all agents page", async () => { root = createRoot(container); await act(async () => { root!.render( , ); }); await flushReact(); await flushReact(); expect(container.textContent).toContain("codex_local"); expect(container.textContent).toContain("gpt-5.4"); }); });