Files
govoplan-core/webui/tests/people-picker.test.tsx

69 lines
3.3 KiB
TypeScript

function assert(condition: unknown, message = "assertion failed"): void {
if (!condition) throw new Error(message);
}
import { renderToStaticMarkup } from "react-dom/server";
import PeoplePicker from "../src/components/people/PeoplePicker";
import {
dedupePeoplePickerItems,
externalPeoplePickerItem,
selectionFromPeoplePickerCandidate,
type PeoplePickerSearch
} from "../src/components/people/peoplePickerTypes";
import { PlatformLanguageProvider } from "../src/i18n/LanguageContext";
const account = {
selection_key: "account:account-1",
kind: "account" as const,
reference_id: "account-1",
display_name: "Ada Lovelace",
email: "Ada@Example.Test",
source_module: "access",
source_label: "Accounts"
};
const contact = {
selection_key: "contact:contact-1:ada@example.test",
kind: "contact" as const,
reference_id: "contact-1",
display_name: "Ada Contact",
email: "ada@example.test",
source_module: "addresses",
source_label: "Contacts"
};
const deduped = dedupePeoplePickerItems([account, contact]);
assert(deduped.length === 1, "the same email is selected only once across directory sources");
assert(deduped[0].reference_id === "account-1", "selection order decides which discoverable reference is retained");
const external = externalPeoplePickerItem(" Grace Hopper ", " GRACE@EXAMPLE.TEST ");
assert(external.display_name === "Grace Hopper", "manual names are normalized");
assert(external.email === "grace@example.test", "manual email addresses are normalized");
assert(external.selection_key === "external:grace@example.test", "manual entries receive stable opaque selection keys");
const selected = selectionFromPeoplePickerCandidate({ ...contact, disabled: true, disabled_reason: "Policy" });
assert(!("disabled" in selected), "result-only disabled state is not persisted in selections");
assert(!("disabled_reason" in selected), "result-only policy wording is not persisted in selections");
let searchCalled = false;
const search: PeoplePickerSearch = async () => {
searchCalled = true;
return [];
};
const markup = renderToStaticMarkup(
<PlatformLanguageProvider>
<PeoplePicker id="reviewers" value={[account]} onChange={() => undefined} search={search} help="Choose a reviewer." />
</PlatformLanguageProvider>
);
assert(!searchCalled, "directory search is server-driven after user input, not during static rendering");
assert(markup.includes('role="combobox"'), "search exposes combobox semantics");
assert(markup.includes('aria-autocomplete="list"'), "search declares list autocomplete behavior");
assert(markup.includes('aria-controls="reviewers-results"'), "search and grouped result list are associated");
assert(markup.includes("inline-help"), "non-obvious picker fields use central inline help");
assert(markup.includes('role="table"'), "selected people are rendered through the central DataGrid");
assert(markup.includes("Ada Lovelace"), "selected structured rows retain the display name");
assert(markup.includes("Ada@Example.Test"), "selected structured rows retain the email address");
assert(markup.includes('aria-label="Add person"'), "row add uses an accessible central table action");
assert(markup.includes('aria-label="Remove person"'), "row removal uses an accessible central table action");
assert(markup.includes("Add external person"), "manual external entry remains a separate structured action");