78 lines
2.8 KiB
TypeScript
78 lines
2.8 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import type { DataTableModel } from "@toolctrl/view-models";
|
|
|
|
import { renderDataTable } from "./index.js";
|
|
|
|
const model: DataTableModel = {
|
|
captionKey: "ui.data-table.caption",
|
|
columns: [
|
|
{ key: "name", labelKey: "ui.data-table.column.name", align: "left" },
|
|
{ key: "amount", labelKey: "ui.data-table.column.amount", align: "right" },
|
|
],
|
|
rows: [
|
|
{ id: "row-1", cells: { name: "Alpha", amount: "10" } },
|
|
{ id: "row-2", cells: { name: "Beta", amount: "20" } },
|
|
],
|
|
emptyLabelKey: "ui.data-table.empty",
|
|
rowCount: 2,
|
|
};
|
|
|
|
const emptyModel: DataTableModel = {
|
|
columns: [{ key: "name", labelKey: "ui.data-table.column.name", align: "left" }],
|
|
rows: [],
|
|
emptyLabelKey: "ui.data-table.empty",
|
|
rowCount: 0,
|
|
};
|
|
|
|
describe("renderDataTable (subframe impl)", () => {
|
|
test("renders a semantic table with the subframe implementation markers", () => {
|
|
const html = renderDataTable(model);
|
|
expect(html).toContain('<table data-ui-impl="subframe" data-ui-id="ui.data-table"');
|
|
expect(html).toContain("</table>");
|
|
expect(html).toContain("<thead>");
|
|
expect(html).toContain("<tbody>");
|
|
});
|
|
|
|
test("emits header cells with i18n keys and align attributes", () => {
|
|
const html = renderDataTable(model);
|
|
expect(html).toContain('data-i18n-key="ui.data-table.column.name"');
|
|
expect(html).toContain('data-i18n-key="ui.data-table.column.amount"');
|
|
expect(html).toContain('data-align="left"');
|
|
expect(html).toContain('data-align="right"');
|
|
});
|
|
|
|
test("renders a caption with its i18n key when captionKey is present", () => {
|
|
const html = renderDataTable(model);
|
|
expect(html).toContain('<caption data-i18n-key="ui.data-table.caption"></caption>');
|
|
});
|
|
|
|
test("renders rows with row ids and escaped cell data", () => {
|
|
const html = renderDataTable(model);
|
|
expect(html).toContain('data-row-id="row-1"');
|
|
expect(html).toContain('data-row-id="row-2"');
|
|
expect(html).toContain(">Alpha<");
|
|
expect(html).toContain(">20<");
|
|
});
|
|
|
|
test("renders an empty row with the empty i18n key when there are no rows", () => {
|
|
const html = renderDataTable(emptyModel);
|
|
expect(html).toContain('data-empty="true"');
|
|
expect(html).toContain('data-i18n-key="ui.data-table.empty"');
|
|
expect(html).not.toContain("data-row-id=");
|
|
});
|
|
|
|
test("escapes hostile cell content", () => {
|
|
const html = renderDataTable({
|
|
...model,
|
|
rows: [{ id: "row-x", cells: { name: '<script>"&"</script>', amount: "" } }],
|
|
rowCount: 1,
|
|
});
|
|
expect(html).not.toContain("<script>");
|
|
expect(html).toContain("<script>");
|
|
});
|
|
|
|
test("is visually stable: identical input renders identical output (M016)", () => {
|
|
expect(renderDataTable(model)).toBe(renderDataTable(model));
|
|
});
|
|
});
|