import { fireEvent, render, screen } from "@solidjs/testing-library"; import { describe, expect, it, vi } from "vitest"; import { DataTable, DataTableColumnSchema, DataTableMeta, DataTableRootPropsSchema } from "../../../src/components/data-table/index"; const data = [ { id: 1, name: "Alice", age: 30 }, { id: 2, name: "Bob", age: 25 }, { id: 3, name: "Charlie", age: 35 }, ]; const columns = [ { id: "name", header: "Name", cell: (row: typeof data[0]) => row.name, sortable: true }, { id: "age", header: "Age", cell: (row: typeof data[0]) => String(row.age), sortable: true }, ]; function TestTable(props: { pageSize?: number; enableRowSelection?: boolean }) { return (
); } describe("DataTable — rendering", () => { it("renders all rows by default", () => { render(() => ); expect(screen.getByText("Alice")).toBeTruthy(); expect(screen.getByText("Bob")).toBeTruthy(); expect(screen.getByText("Charlie")).toBeTruthy(); }); it("renders column headers", () => { render(() => ); expect(screen.getByText("Name")).toBeTruthy(); expect(screen.getByText("Age")).toBeTruthy(); }); it("renders pagination controls", () => { render(() => ); expect(screen.getByText("Previous")).toBeTruthy(); expect(screen.getByText("Next")).toBeTruthy(); expect(screen.getByText(/Page 1 of/)).toBeTruthy(); }); }); describe("DataTable — sorting", () => { it("sorts ascending on first header click", () => { render(() => ); fireEvent.click(screen.getByText("Name")); const cells = screen.getAllByRole("cell"); const names = cells.filter((_, i) => i % 2 === 0).map((c) => c.textContent); expect(names[0]).toBe("Alice"); expect(names[1]).toBe("Bob"); expect(names[2]).toBe("Charlie"); }); it("sorts descending on second header click", () => { render(() => ); const nameHeader = screen.getByRole("columnheader", { name: /Name/ }); fireEvent.click(nameHeader); fireEvent.click(nameHeader); const cells = screen.getAllByRole("cell"); const names = cells.filter((_, i) => i % 2 === 0).map((c) => c.textContent); expect(names[0]).toBe("Charlie"); expect(names[1]).toBe("Bob"); expect(names[2]).toBe("Alice"); }); it("resets sort on third header click", () => { render(() => ); const nameHeader = screen.getByRole("columnheader", { name: /Name/ }); fireEvent.click(nameHeader); fireEvent.click(nameHeader); fireEvent.click(nameHeader); expect(nameHeader.getAttribute("aria-sort")).toBe("none"); }); it("header has aria-sort=ascending when sorted asc", () => { render(() => ); const nameHeader = screen.getByRole("columnheader", { name: /Name/ }); fireEvent.click(nameHeader); expect(nameHeader.getAttribute("aria-sort")).toBe("ascending"); }); }); describe("DataTable — pagination", () => { it("shows only pageSize rows per page", () => { render(() => ); const cells = screen.getAllByRole("cell"); expect(cells.length).toBe(4); }); it("next page shows remaining rows", () => { render(() => ); fireEvent.click(screen.getByText("Next")); expect(screen.getByText("Charlie")).toBeTruthy(); }); it("previous button is disabled on first page", () => { render(() => ); const prev = screen.getByText("Previous") as HTMLButtonElement; expect(prev.disabled).toBe(true); }); it("next button is disabled on last page", () => { render(() => ); fireEvent.click(screen.getByText("Next")); const next = screen.getByText("Next") as HTMLButtonElement; expect(next.disabled).toBe(true); }); it("shows correct page label", () => { render(() => ); expect(screen.getByText("Page 1 of 2")).toBeTruthy(); }); }); describe("DataTable — row selection", () => { it("clicking a row marks it selected", () => { render(() => ); const rows = screen.getAllByRole("row"); fireEvent.click(rows[1]); expect(rows[1].getAttribute("aria-selected")).toBe("true"); }); it("clicking selected row deselects it", () => { render(() => ); const rows = screen.getAllByRole("row"); fireEvent.click(rows[1]); fireEvent.click(rows[1]); expect(rows[1].getAttribute("aria-selected")).toBe("false"); }); it("onSelectionChange is called", () => { const onChange = vi.fn(); render(() => (
)); const rows = screen.getAllByRole("row"); fireEvent.click(rows[1]); expect(onChange).toHaveBeenCalledWith(expect.any(Set)); }); }); describe("DataTable — schema and meta", () => { it("DataTableColumnSchema validates a valid column", () => { const result = DataTableColumnSchema.safeParse({ id: "name", header: "Name", sortable: true }); expect(result.success).toBe(true); }); it("DataTableRootPropsSchema validates pageSize", () => { const result = DataTableRootPropsSchema.safeParse({ pageSize: 20 }); expect(result.success).toBe(true); }); it("DataTableMeta has correct name", () => { expect(DataTableMeta.name).toBe("DataTable"); }); it("DataTableMeta lists required parts", () => { expect(DataTableMeta.requiredParts).toContain("Root"); expect(DataTableMeta.requiredParts).toContain("Body"); }); });