import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it } from "vitest"; import { DataTable } from "./data-table.tsx"; import { groupRows, readCollapsed, toggleCollapsed, writeCollapsed } from "./data-table-groups.ts"; type Row = { id: string; status: string; name: string }; const rows: Row[] = [ { id: "1", status: "未识别", name: "a.mkv" }, { id: "2", status: "已登记", name: "b.mkv" }, { id: "3", status: "未识别", name: "c.mkv" }, ]; describe("DataTable groupBy:分组逻辑", () => { it("按首次出现顺序分组,组内保持原顺序", () => { expect(groupRows(rows, (r) => r.status).map((g) => [g.key, g.rows.map((r) => r.id)])).toEqual([ ["未识别", ["1", "3"]], ["已登记", ["2"]], ]); }); it("给 order 时按 order 排组", () => { const g = groupRows( rows, (r) => r.status, (a, b) => a.localeCompare(b, "zh-CN"), ); expect(g.map((x) => x.key)).toEqual(["未识别", "已登记"].sort((a, b) => a.localeCompare(b, "zh-CN"))); }); it("折叠切换返回新集合", () => { const a = new Set(); const b = toggleCollapsed(a, "x"); expect([...b]).toEqual(["x"]); expect(a.size).toBe(0); expect([...toggleCollapsed(b, "x")]).toEqual([]); }); }); describe("DataTable groupBy:记住折叠态", () => { it("写入后能读回;没有 storageKey、内容损坏或存储不可用时为 null", () => { const map = new Map(); const store = () => ({ getItem: (k: string) => map.get(k) ?? null, setItem: (k: string, v: string) => void map.set(k, v), }); writeCollapsed("t", new Set(["已登记"]), store); expect([...(readCollapsed("t", store) ?? [])]).toEqual(["已登记"]); expect(readCollapsed(undefined, store)).toBeNull(); map.set("umt.table-groups:bad", "{oops"); expect(readCollapsed("bad", store)).toBeNull(); const blocked = () => ({ getItem: (): string | null => { throw new Error("blocked"); }, setItem: () => { throw new Error("blocked"); }, }); expect(readCollapsed("t", blocked)).toBeNull(); expect(() => writeCollapsed("t", new Set(), blocked)).not.toThrow(); expect(readCollapsed("t", () => undefined)).toBeNull(); }); }); describe("DataTable groupBy:渲染", () => { it("每组一个可折叠组头,带计数;首屏全部展开", () => { const html = renderToStaticMarkup( createElement(DataTable, { columns: [{ key: "name", header: "名称", cell: (r: Row) => r.name }], rows, rowKey: (r: Row) => r.id, groupBy: { key: (r: Row) => r.status }, }), ); expect(html.match(/aria-expanded="true"/g)).toHaveLength(2); expect(html).toContain("未识别"); expect(html).toMatch(/未识别<\/span>]*>2<\/span>/); expect(html).toMatch(/已登记<\/span>]*>1<\/span>/); for (const n of ["a.mkv", "b.mkv", "c.mkv"]) expect(html).toContain(n); }); it("不给 groupBy 时没有组头", () => { const html = renderToStaticMarkup( createElement(DataTable, { columns: [{ key: "name", header: "名称", cell: (r: Row) => r.name }], rows, rowKey: (r: Row) => r.id, }), ); expect(html).not.toContain("aria-expanded"); }); });