Files
siftlode/frontend/src/components/ui/DataTable.fixedLayout.dom.test.tsx
T
peter 5bfcf5d83a refactor(e10): move the platform components into components/ui/ and enforce the boundary
The app HAS a platform layer -- AnchoredPopover (22 importers, with
arrows/typeahead/Escape/anchor-flip), QueryState (21), Modal (17),
PageShell, DataTable, Tabs, Tooltip and ~26 more -- but it sat flat among
~160 feature components with nothing marking it as one. Several of those
files describe themselves as 'the one place' or 'canonical' and were
still bypassed by hand-rolled markup, because a layer nobody can see is a
layer nobody uses; three separate inventory passes of this codebase
misread it the same way.

Moves the 33 domain-free modules into components/ui/, rewrites the
imports in 89 files, and makes the boundary a lint rule rather than a
convention: inside ui/ a one-level-up import (a feature component) and
any lib/api slice are errors. The rule was verified to fire on both and
to leave generic lib/ helpers alone. README.md states which side of the
line a component belongs on and why.

No behaviour change: 3x tsc, eslint, knip, prettier and 687 vitest tests
all green; no backend file touched.
2026-09-05 16:58:29 +02:00

45 lines
2.0 KiB
TypeScript

// @vitest-environment jsdom
//
// The R14 zoom-fit foundation: DataTable's opt-in `fixedLayout` renders a <colgroup> and puts the
// table into `table-layout: fixed`, so columns with a width keep it and the rest (fluid text columns)
// split the remainder + truncate instead of pushing the table wider than its container. Off by
// default so existing content-sized tables are untouched.
import { describe, it, expect, afterEach, vi } from "vitest";
import { render, cleanup } from "@testing-library/react";
import DataTable, { type Column } from "./DataTable";
vi.mock("react-i18next", async (importOriginal) => {
const actual = await importOriginal<typeof import("react-i18next")>();
return { ...actual, useTranslation: () => ({ t: (key: string) => key }) };
});
afterEach(cleanup);
type Row = { a: string; b: string };
const columns: Column<Row>[] = [
{ key: "a", header: "A", width: "5rem", render: (r) => r.a },
{ key: "b", header: "B", render: (r) => r.b }, // fluid — no width
];
const rows: Row[] = [{ a: "1", b: "hello" }];
describe("DataTable fixedLayout", () => {
it("renders a width-bearing colgroup and table-fixed only when fixedLayout is set", () => {
const { container } = render(
<DataTable rows={rows} columns={columns} rowKey={(r) => r.a} fixedLayout />,
);
const table = container.querySelector("table");
expect(table?.className).toContain("table-fixed");
const cols = container.querySelectorAll("colgroup col");
expect(cols).toHaveLength(2);
expect((cols[0] as HTMLElement).style.width).toBe("5rem"); // fixed column keeps its width
expect((cols[1] as HTMLElement).style.width).toBe(""); // fluid column: no width, splits remainder
});
it("omits the colgroup and stays auto-layout by default", () => {
const { container } = render(<DataTable rows={rows} columns={columns} rowKey={(r) => r.a} />);
expect(container.querySelector("colgroup")).toBeNull();
expect(container.querySelector("table")?.className).not.toContain("table-fixed");
});
});