import { afterEach, describe, expect, it, vi } from "vitest"; import { cleanup, fireEvent, render, screen } from "@testing-library/react"; vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string) => key }), })); import { AddButton, FormFooter, ListRow, ListRowAction, ListRowFolder, PanelList, } from "@/components/list-kit"; afterEach(cleanup); describe("ListRow", () => { it("tints odd rows and marks the selected one", () => { const { container, rerender } = render(); const row = container.firstElementChild as HTMLElement; expect(row.className).toContain("bg-muted/15"); rerender(); expect(row.className).toContain("bg-accent-brand/10"); expect(row.getAttribute("data-selected")).toBe("true"); }); it("clicks and opens with Enter, but tray clicks do not reach the row", () => { const onClick = vi.fn(); const onAction = vi.fn(); render( } />, ); const row = screen.getByRole("button", { name: /web/ }); fireEvent.keyDown(row, { key: "Enter" }); expect(onClick).toHaveBeenCalledTimes(1); fireEvent.click(screen.getByLabelText("Edit")); expect(onAction).toHaveBeenCalledTimes(1); expect(onClick).toHaveBeenCalledTimes(1); }); it("keeps the tray visible while active", () => { render( } />, ); const tray = screen.getByLabelText("More").parentElement as HTMLElement; expect(tray.className).toMatch(/(^| )flex( |$)/); expect(tray.className).not.toContain("hidden"); }); }); describe("ListRowFolder", () => { it("toggles and shows the empty text when open with no items", () => { const onToggle = vi.fn(); const { rerender } = render( , ); fireEvent.click(screen.getByRole("button", { name: /Prod/ })); expect(onToggle).toHaveBeenCalled(); expect(screen.queryByText("Nothing here")).toBeNull(); rerender( , ); expect(screen.getByText("Nothing here")).toBeTruthy(); }); }); describe("PanelList", () => { it("shows the empty slot only without rows", () => { const { rerender } = render( empty}>{[false, null]}, ); expect(screen.getByText("empty")).toBeTruthy(); rerender( empty}> , ); expect(screen.queryByText("empty")).toBeNull(); }); }); describe("AddButton", () => { it("defaults its label and hides it when compact", () => { const { rerender } = render(); expect(screen.getByText("common.new")).toBeTruthy(); rerender(); expect(screen.queryByText("Add host")).toBeNull(); expect(screen.getByLabelText("Add host")).toBeTruthy(); }); }); describe("FormFooter", () => { it("shows the unsaved note, delete and a saving state", () => { const onSave = vi.fn(); const onDelete = vi.fn(); const { rerender } = render( {}} onDelete={onDelete} />, ); expect(screen.getByText("common.unsavedChanges")).toBeTruthy(); fireEvent.click(screen.getByText("common.delete")); expect(onDelete).toHaveBeenCalled(); fireEvent.click(screen.getByText("common.save")); expect(onSave).toHaveBeenCalled(); rerender(); const saving = screen.getByText("common.saving").closest("button"); expect(saving?.disabled).toBe(true); }); it("lets a status replace the unsaved note", () => { render( {}} />); expect(screen.getByText("2 errors")).toBeTruthy(); expect(screen.queryByText("common.unsavedChanges")).toBeNull(); }); });