import { beforeEach, describe, expect, it, vi } from "vitest"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from "react"; interface MockButtonProps extends ButtonHTMLAttributes { children: ReactNode; } interface MockBadgeProps extends HTMLAttributes { children: ReactNode; } interface AuditLogEntry { id: string; userId: string; sessionId: string; provider: string; action: string; content: string | null; metadata: unknown; createdAt: string; } interface AuditLogResponse { items: AuditLogEntry[]; total: number; page: number; pages: number; } const mockApiGet = vi.fn<(endpoint: string) => Promise>(); vi.mock("@/lib/api/client", () => ({ apiGet: (endpoint: string): Promise => mockApiGet(endpoint), })); vi.mock("@/components/ui/button", () => ({ Button: ({ children, ...props }: MockButtonProps): React.JSX.Element => ( ), })); vi.mock("@/components/ui/badge", () => ({ Badge: ({ children, ...props }: MockBadgeProps): React.JSX.Element => ( {children} ), })); import { AuditLogDrawer } from "./AuditLogDrawer"; function renderWithQueryClient(ui: React.JSX.Element): ReturnType { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, }); return render({ui}); } function responseWith(items: AuditLogEntry[], page: number, pages: number): AuditLogResponse { return { items, total: items.length, page, pages, }; } describe("AuditLogDrawer", (): void => { beforeEach((): void => { vi.clearAllMocks(); mockApiGet.mockResolvedValue(responseWith([], 1, 0)); }); it("opens from trigger text and renders empty state", async (): Promise => { const user = userEvent.setup(); renderWithQueryClient(); await user.click(screen.getByRole("button", { name: "Audit" })); await waitFor((): void => { expect(screen.getByText("Audit Log")).toBeInTheDocument(); expect(screen.getByText("No audit entries found.")).toBeInTheDocument(); }); }); it("renders audit entries with action, session id, and payload", async (): Promise => { const user = userEvent.setup(); mockApiGet.mockResolvedValue( responseWith( [ { id: "entry-1", userId: "operator-1", sessionId: "1234567890abcdef", provider: "internal", action: "inject", content: "Run diagnostics", metadata: { payload: { ignored: true } }, createdAt: "2026-03-07T19:00:00.000Z", }, ], 1, 1 ) ); renderWithQueryClient(); await user.click(screen.getByRole("button", { name: "Audit" })); await waitFor((): void => { expect(screen.getByText("inject")).toBeInTheDocument(); expect(screen.getByText("12345678")).toBeInTheDocument(); expect(screen.getByText("Run diagnostics")).toBeInTheDocument(); }); }); it("supports pagination and metadata payload summary", async (): Promise => { const user = userEvent.setup(); mockApiGet.mockImplementation((endpoint: string): Promise => { const query = endpoint.split("?")[1] ?? ""; const params = new URLSearchParams(query); const page = Number(params.get("page") ?? "1"); if (page === 1) { return Promise.resolve({ items: [ { id: "entry-page-1", userId: "operator-2", sessionId: "abcdefgh12345678", provider: "internal", action: "pause", content: "", metadata: { payload: { reason: "hold" } }, createdAt: "2026-03-07T19:01:00.000Z", }, ], total: 2, page: 1, pages: 2, }); } return Promise.resolve({ items: [ { id: "entry-page-2", userId: "operator-3", sessionId: "zzzz111122223333", provider: "internal", action: "kill", content: null, metadata: { payload: { force: true } }, createdAt: "2026-03-07T19:02:00.000Z", }, ], total: 2, page: 2, pages: 2, }); }); renderWithQueryClient(); await user.click(screen.getByRole("button", { name: "Audit" })); await waitFor((): void => { expect(screen.getByText("Page 1 of 2")).toBeInTheDocument(); expect(screen.getByText("reason=hold")).toBeInTheDocument(); }); await user.click(screen.getByRole("button", { name: "Next" })); await waitFor((): void => { expect(screen.getByText("Page 2 of 2")).toBeInTheDocument(); expect(screen.getByText("force=true")).toBeInTheDocument(); }); }); it("includes sessionId filter in query string", async (): Promise => { const user = userEvent.setup(); renderWithQueryClient(); await user.click(screen.getByRole("button", { name: "Audit" })); await waitFor((): void => { expect(mockApiGet).toHaveBeenCalled(); }); const firstCall = mockApiGet.mock.calls[0]; const endpoint = firstCall?.[0] ?? ""; expect(endpoint).toContain("sessionId=session+7"); }); });