import type React from "react"; import { fireEvent, render, screen } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import type { AgentRead, BoardRead } from "@/api/generated/model"; import { AgentsTable } from "./AgentsTable"; vi.mock("next/link", () => { type LinkProps = React.PropsWithChildren<{ href: string | { pathname?: string }; }> & Omit, "href">; return { default: ({ href, children, ...props }: LinkProps) => ( {children} ), }; }); const buildAgent = (overrides: Partial = {}): AgentRead => ({ id: "agent-1", name: "Ava", gateway_id: "gateway-1", board_id: "board-1", status: "online", openclaw_session_id: "session-1234", last_seen_at: "2026-01-01T00:00:00Z", created_at: "2026-01-01T00:00:00Z", updated_at: "2026-01-01T00:00:00Z", ...overrides, }); const buildBoard = (overrides: Partial = {}): BoardRead => ({ id: "board-1", name: "Ops Board", slug: "ops-board", description: "Operations board context.", organization_id: "org-1", created_at: "2026-01-01T00:00:00Z", updated_at: "2026-01-01T00:00:00Z", ...overrides, }); describe("AgentsTable", () => { it("renders linked board name and default row actions", () => { const onDelete = vi.fn(); const agent = buildAgent(); const board = buildBoard(); render( , ); expect( screen.getByRole("link", { name: /Ava ID agent-1/i }), ).toHaveAttribute("href", "/agents/agent-1"); expect(screen.getByRole("link", { name: "Ops Board" })).toHaveAttribute( "href", "/boards/board-1", ); expect(screen.getByRole("link", { name: "Edit" })).toHaveAttribute( "href", "/agents/agent-1/edit", ); fireEvent.click(screen.getByRole("button", { name: "Delete" })); expect(onDelete).toHaveBeenCalledWith(agent); }); it("hides row actions when showActions is false", () => { render( , ); expect( screen.queryByRole("link", { name: "Edit" }), ).not.toBeInTheDocument(); expect( screen.queryByRole("button", { name: "Delete" }), ).not.toBeInTheDocument(); }); it("supports hiddenColumns and columnOrder", () => { render( , ); expect( screen.queryByRole("columnheader", { name: "Status" }), ).not.toBeInTheDocument(); expect( screen.queryByRole("columnheader", { name: "Session" }), ).not.toBeInTheDocument(); const headers = screen .getAllByRole("columnheader") .map((header) => header.textContent?.replace(/[↑↓↕]/g, "").trim()); expect(headers.slice(0, 4)).toEqual([ "Updated", "Agent", "Board", "Last seen", ]); }); it("supports disableSorting and preserves input order", () => { const zulu = buildAgent({ id: "agent-z", name: "Zulu" }); const alpha = buildAgent({ id: "agent-a", name: "Alpha" }); const { rerender } = render( , ); // Default behavior applies name sorting. expect(screen.getAllByRole("row")[1]).toHaveTextContent("Alpha"); rerender( , ); // disableSorting keeps incoming data order. expect(screen.getAllByRole("row")[1]).toHaveTextContent("Zulu"); }); });