function assertEqual(actual: T, expected: T, message: string): void { if (actual !== expected) throw new Error(`${message}: expected ${String(expected)}, got ${String(actual)}`); } import { renderToStaticMarkup } from "react-dom/server"; import Button from "../src/components/Button"; import DataGrid, { DataGridEmptyAction, DataGridRowActions, type DataGridColumn } from "../src/components/table/DataGrid"; import TableActionGroup, { runTableAction } from "../src/components/table/TableActionGroup"; import { dataGridRowIndices } from "../src/components/table/dataGridRowIndices"; function noop() {} const repeatedRow = { label: "same" }; const distinctRow = { label: "same" }; const identityRows = [repeatedRow, distinctRow, repeatedRow]; const identityIndex = dataGridRowIndices(identityRows); assertEqual(identityIndex(repeatedRow), 0, "repeated object references retain their first original index"); assertEqual(identityIndex(distinctRow), 1, "equal-looking objects keep distinct identities"); assertEqual(identityIndex({ label: "same" }), -1, "absent objects retain indexOf semantics"); const primitiveRows = [NaN, -0, 2, 2, 0]; const primitiveIndex = dataGridRowIndices(primitiveRows); for (const value of primitiveRows) { assertEqual(primitiveIndex(value), primitiveRows.indexOf(value), "primitive indices preserve NaN, zero and duplicate behavior"); } let linearVisits = 0; const measuredRows = Array.from({ length: 4_000 }, (_, index) => ({ index })); measuredRows.forEach = (callback) => Array.prototype.forEach.call(measuredRows, (row, index, array) => { linearVisits += 1; callback(row, index, array); }); const measuredIndex = dataGridRowIndices(measuredRows); for (let pass = 0; pass < 10; pass += 1) measuredRows.map(measuredIndex); assertEqual(linearVisits, 4_000, "index construction traverses once, independent of lookup count"); const callbackIndices: number[] = []; const stableRows = [{ id: "a", rank: 2 }, { id: "b", rank: 1 }, { id: "c", rank: 1 }]; const stableMarkup = renderToStaticMarkup( { assertEqual(stableRows[index], row, "sort callbacks receive original indices"); return row.rank; }, render: (row, index) => { callbackIndices.push(index); return row.id; } }]} getRowKey={(row, index) => { assertEqual(stableRows[index], row, "row keys receive original indices"); return row.id; }} initialSort={{ columnId: "rank", direction: "asc" }} />); assertEqual(stableMarkup.includes("stable-original-row-index"), true, "sorted grid renders"); assertEqual(callbackIndices.slice(-3).join(), "1,2,0", "equal sort values remain stable without mutating source order after the unchanged sizing pass"); assertEqual(stableRows.map((row) => row.id).join(), "a,b,c", "sorting never reorders input data"); function buttonCount(markup: string): number { return markup.match(/]*\btype="button"/g)?.length ?? 0; } const rowActions = renderToStaticMarkup(
); assertEqual(buttonCount(rowActions), 4, "row actions render the expected controls"); assertEqual(nonSubmittingButtonCount(rowActions), 4, "row actions do not submit an enclosing form"); const emptyAction = renderToStaticMarkup(
); assertEqual(buttonCount(emptyAction), 1, "empty action renders the expected control"); assertEqual(nonSubmittingButtonCount(emptyAction), 1, "empty action does not submit an enclosing form"); assertEqual((emptyAction.match(/table-action-placeholder/g) ?? []).length, 3, "empty actions reserve the remaining ordinary row positions"); const contextActions = renderToStaticMarkup( I, helpContextId: "test.row.inspect", helpModuleId: "test-module", onClick: noop }, { id: "edit", label: "Edit", icon: E, applicable: false, onClick: noop }, { id: "remove", label: "Remove", icon: R, disabledReason: "Permission denied", onClick: noop } ]} minimumSlots={4} /> ); assertEqual(buttonCount(contextActions), 3, "row-level unavailable actions remain visible"); assertEqual(nonSubmittingButtonCount(contextActions), 3, "table action groups do not submit an enclosing form"); assertEqual((contextActions.match(/disabled=""/g) ?? []).length, 2, "unavailable actions are disabled"); assertEqual((contextActions.match(/table-action-placeholder/g) ?? []).length, 1, "minimum action slots reserve trailing positions"); assertEqual(contextActions.includes("disabled-action-tooltip"), true, "disabled table actions can explain their unavailable state"); assertEqual(contextActions.includes('aria-label="Inspect"'), true, "table actions expose an accessible label"); assertEqual(contextActions.includes('title="Inspect"'), true, "table actions expose a native tooltip"); assertEqual(contextActions.includes('data-help-context-id="test.row.inspect"'), true, "table actions propagate exact contextual help"); assertEqual(contextActions.includes('data-help-module-id="test-module"'), true, "table actions propagate the documentation owner"); assertEqual(contextActions.includes('aria-hidden="true"'), true, "table action icons stay decorative"); let propagationStopped = false; let actionCalled = false; runTableAction( { stopPropagation: () => { propagationStopped = true; } }, () => { actionCalled = true; } ); assertEqual(propagationStopped, true, "table actions do not trigger clickable row handlers"); assertEqual(actionCalled, true, "table actions still invoke their handler"); const noReorderActions = renderToStaticMarkup( ); assertEqual(buttonCount(noReorderActions), 2, "row actions omit reorder controls when ordering does not apply"); const unavailableReorderActions = renderToStaticMarkup( ); assertEqual(buttonCount(unavailableReorderActions), 4, "ordered rows retain unavailable boundary controls"); assertEqual((unavailableReorderActions.match(/disabled=""/g) ?? []).length, 2, "unavailable boundary controls are disabled"); const reasonedButton = renderToStaticMarkup(); assertEqual(reasonedButton.includes("disabled=\"\""), true, "a disabled reason disables the central button"); assertEqual(reasonedButton.includes("disabled-action-tooltip"), true, "a disabled reason remains keyboard discoverable"); assertEqual(reasonedButton.includes("disabledReason"), false, "the central-only disabled reason is not passed to the DOM"); type FilterRow = { id: string; name: string }; const filterRows: FilterRow[] = [ { id: "first-non-match", name: "Ordinary row" }, { id: "second-non-match", name: "Another row" }, { id: "first-match", name: "Target alpha" }, { id: "third-non-match", name: "Unrelated row" }, { id: "second-match", name: "Target beta" }, { id: "third-match", name: "Target gamma" } ]; const filterColumns: DataGridColumn[] = [ { id: "name", header: "Name", filterable: true, value: (row) => row.name } ]; const fullResultFilterMarkup = renderToStaticMarkup( row.id} initialFilters={{ name: "target" }} pagination={{ page: 1, pageSize: 2, onPageChange: noop }} /> ); assertEqual(fullResultFilterMarkup.includes("Target alpha"), true, "client filtering finds matches beyond the unfiltered first page"); assertEqual(fullResultFilterMarkup.includes("Target beta"), true, "client filtering happens before the first page is sliced"); assertEqual(fullResultFilterMarkup.includes("Target gamma"), false, "client pagination still limits the filtered page size"); assertEqual(fullResultFilterMarkup.includes("1\u20132"), true, "pagination counts describe the filtered result set"); assertEqual(/of(?:)?\s*(?:)?3/.test(fullResultFilterMarkup), true, "the filtered total includes matches from every source row"); const clearedFilterMarkup = renderToStaticMarkup( row.id} pagination={{ page: 1, pageSize: 2, onPageChange: noop }} /> ); assertEqual(clearedFilterMarkup.includes("Ordinary row"), true, "clearing filters restores the first unfiltered row"); assertEqual(/of(?:)?\s*(?:)?6/.test(clearedFilterMarkup), true, "clearing filters restores the full pagination total"); const externalShortcutMarkup = renderToStaticMarkup( row.id} query={{ sort: null, filters: { name: "target" } }} /> ); assertEqual(externalShortcutMarkup.includes("Target alpha"), true, "an external count shortcut synchronizes the grid query"); assertEqual(externalShortcutMarkup.includes("Ordinary row"), false, "the synchronized query does not disagree with visible rows"); const fixedCoverMarkup = renderToStaticMarkup( row.first }, { id: "second", header: "Second", width: 200, value: (row) => row.second }, { id: "actions", header: "Actions", width: 72, sticky: "end", value: () => "" } ]} getRowKey={(row) => row.id} /> ); assertEqual(fixedCoverMarkup.includes('class="data-grid-scroll-region" tabindex="0" role="region"'), true, "horizontal scrolling is keyboard accessible and labelled"); const resizeMarkup = renderToStaticMarkup( row.id} />); assertEqual(resizeMarkup.includes('role="separator" aria-orientation="vertical"'), true, "resizers expose a focusable vertical separator"); assertEqual(resizeMarkup.includes('aria-valuemin="92"'), true, "resizers expose their effective accessible minimum"); assertEqual(resizeMarkup.includes('aria-description='), true, "resizers explain keyboard interaction and reset"); assertEqual( fixedCoverMarkup.includes("data-grid-buffer-cell"), false, "cover grids never render a synthetic blank column" );