mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
Roving tabindex over the card grid: arrows move (grid-aware by measured column count), Home/End jump, Enter opens, Space selects, Delete removes with the undo toast; focus rides the virtualizer window (scroll-to-row, bounded retry focus). The container carries list semantics with a translated label, and the transient upload queue stays a polite live region. Selection state is conveyed by the per-card checkbox, which the focus ring reveals for keyboard users. Refs: document-vault plan W3-T3
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
|
|
/**
|
|
* Static-render pins for the timeline's accessibility contract: the
|
|
* virtualized container is a labelled list, and the transient upload queue
|
|
* is a polite live region. (The windowed rows themselves only mount
|
|
* client-side once the virtualizer measures the scroll container — the
|
|
* keyboard path is covered by the e2e battery.)
|
|
*/
|
|
import { I18nProvider } from "@/lib/i18n/context";
|
|
import { DocumentTimeline } from "../document-timeline";
|
|
import type { UploadQueueItem } from "../use-document-upload";
|
|
|
|
function render(uploadItems: UploadQueueItem[]) {
|
|
return renderToStaticMarkup(
|
|
<I18nProvider initialLocale="en">
|
|
<DocumentTimeline
|
|
documents={[]}
|
|
uploadItems={uploadItems}
|
|
onDismissUpload={() => {}}
|
|
hasNextPage={false}
|
|
isFetchingNextPage={false}
|
|
onLoadMore={() => {}}
|
|
selectedIds={new Set()}
|
|
onToggleSelected={() => {}}
|
|
onOpen={() => {}}
|
|
highlightId={null}
|
|
/>
|
|
</I18nProvider>,
|
|
);
|
|
}
|
|
|
|
describe("<DocumentTimeline> semantics", () => {
|
|
it("renders the virtualized container as a labelled list", () => {
|
|
const html = render([]);
|
|
expect(html).toContain('role="list"');
|
|
expect(html).toContain('aria-label="Documents timeline"');
|
|
});
|
|
|
|
it("announces the upload queue through a polite live region", () => {
|
|
const html = render([
|
|
{
|
|
localId: "l1",
|
|
fileName: "scan.pdf",
|
|
byteSize: 1024,
|
|
status: "uploading",
|
|
progress: 0.4,
|
|
},
|
|
]);
|
|
expect(html).toContain('aria-live="polite"');
|
|
expect(html).toContain("scan.pdf");
|
|
});
|
|
});
|