Files
NetMesh/components/vault/VirtualizedHostCollection.test.tsx

179 lines
5.5 KiB
TypeScript
Raw Permalink Normal View History

import assert from "node:assert/strict";
import test from "node:test";
import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import {
getNextRaggedRowPosition,
getNextVirtualHostIndex,
resolveVirtualFocusRequest,
shouldApplyVirtualHostDomFocus,
VirtualizedGroupedHostCollection,
VirtualizedHostCollection,
} from "./VirtualizedHostCollection.tsx";
import { getVaultHostGridColumnCount } from "./vaultHostGridLayout.ts";
test("virtual focus retries when an active item enters a collection", () => {
assert.deepEqual(resolveVirtualFocusRequest({
activeItemKey: "host-1",
lastRequestedKey: "host-1",
itemIndexByKey: new Map(),
}), { status: "missing" });
assert.deepEqual(resolveVirtualFocusRequest({
activeItemKey: "host-1",
lastRequestedKey: null,
itemIndexByKey: new Map([["host-1", 3]]),
}), { status: "request", key: "host-1", index: 3 });
});
test("virtual host DOM focus does not steal from outside controls", () => {
const inside = { tagName: "BUTTON" } as unknown as Element;
const searchInput = { tagName: "INPUT" } as unknown as Element;
const body = { tagName: "BODY" } as unknown as Element;
const collectionRoot = {
contains(node: Node) {
return node === inside;
},
};
assert.equal(shouldApplyVirtualHostDomFocus({
collectionRoot,
activeElement: inside,
}), true);
assert.equal(shouldApplyVirtualHostDomFocus({
collectionRoot,
activeElement: searchInput,
}), false);
assert.equal(shouldApplyVirtualHostDomFocus({
collectionRoot,
activeElement: body,
}), true);
assert.equal(shouldApplyVirtualHostDomFocus({
collectionRoot: null,
activeElement: inside,
}), false);
});
test("host grids use the same fixed card-width column calculation", () => {
assert.equal(getVaultHostGridColumnCount(219), 1);
assert.equal(getVaultHostGridColumnCount(452), 2);
assert.equal(getVaultHostGridColumnCount(684), 3);
assert.equal(getVaultHostGridColumnCount(916), 4);
assert.equal(getVaultHostGridColumnCount(1600), 4);
});
test("virtualized host keyboard navigation crosses rows and collection edges", () => {
assert.equal(getNextVirtualHostIndex({
currentIndex: 1,
itemCount: 20,
columns: 4,
viewMode: "grid",
key: "ArrowDown",
}), 5);
assert.equal(getNextVirtualHostIndex({
currentIndex: 5,
itemCount: 20,
columns: 4,
viewMode: "grid",
key: "ArrowLeft",
}), 4);
assert.equal(getNextVirtualHostIndex({
currentIndex: 18,
itemCount: 20,
columns: 4,
viewMode: "list",
key: "End",
}), 19);
assert.equal(getNextVirtualHostIndex({
currentIndex: 0,
itemCount: 20,
columns: 1,
viewMode: "list",
key: "ArrowUp",
}), 0);
});
test("grouped grid navigation preserves the actual column across ragged rows", () => {
assert.deepEqual(getNextRaggedRowPosition({
rowLengths: [1, 3, 3],
currentRow: 0,
currentColumn: 0,
direction: 1,
}), { row: 1, column: 0 });
assert.deepEqual(getNextRaggedRowPosition({
rowLengths: [3, 1, 3],
currentRow: 0,
currentColumn: 2,
direction: 1,
}), { row: 1, column: 0 });
});
test("virtualized host grid renders only the viewport window for a large collection", () => {
const items = Array.from({ length: 8000 }, (_, index) => ({ id: `host-${index}` }));
const html = renderToStaticMarkup(
<VirtualizedHostCollection
items={items}
itemKey={(item) => item.id}
scrollRef={React.createRef<HTMLDivElement>()}
viewMode="grid"
ariaLabel="Hosts"
renderItem={(item) => <div data-host-id={item.id} />}
/>,
);
const renderedHosts = (html.match(/data-host-id=/g) ?? []).length;
assert.ok(renderedHosts > 0);
assert.ok(renderedHosts < 100);
assert.match(html, /data-vault-virtual-row=/);
assert.match(html, /role="grid"/);
assert.match(html, /aria-rowcount="2000"/);
assert.match(html, /role="gridcell"/);
});
test("virtualized host list keeps one fixed-height item per row", () => {
const items = Array.from({ length: 8000 }, (_, index) => ({ id: `host-${index}` }));
const html = renderToStaticMarkup(
<VirtualizedHostCollection
items={items}
itemKey={(item) => item.id}
scrollRef={React.createRef<HTMLDivElement>()}
viewMode="list"
ariaLabel="Hosts"
renderItem={(item) => <div data-host-id={item.id} />}
/>,
);
const renderedHosts = (html.match(/data-host-id=/g) ?? []).length;
assert.ok(renderedHosts > 0);
assert.ok(renderedHosts < 40);
assert.match(html, /grid-template-columns:repeat\(1, minmax\(0, 1fr\)\)/);
assert.match(html, /role="list"/);
assert.match(html, /aria-setsize="8000"/);
});
test("grouped host grid uses one virtual window across every group", () => {
const groups = Array.from({ length: 80 }, (_, groupIndex) => ({
name: `group-${groupIndex}`,
hosts: Array.from({ length: 100 }, (_, hostIndex) => ({
id: `host-${groupIndex}-${hostIndex}`,
})),
}));
const html = renderToStaticMarkup(
<VirtualizedGroupedHostCollection
groups={groups}
itemKey={(item) => item.id}
scrollRef={React.createRef<HTMLDivElement>()}
viewMode="grid"
ariaLabel="Hosts"
renderGroupHeader={(group) => <div data-group-name={group.name} />}
renderItem={(item) => <div data-host-id={item.id} />}
/>,
);
const renderedHosts = (html.match(/data-host-id=/g) ?? []).length;
assert.ok(renderedHosts > 0);
assert.ok(renderedHosts < 100);
assert.equal((html.match(/data-vault-virtual-grouped-collection=/g) ?? []).length, 1);
});