feat(calendar): expose an accessible calendar picker
This commit is contained in:
20
webui/tests/calendar-picker-structure.test.mjs
Normal file
20
webui/tests/calendar-picker-structure.test.mjs
Normal file
@@ -0,0 +1,20 @@
|
||||
import fs from "node:fs";
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) throw new Error(message);
|
||||
}
|
||||
|
||||
const picker = fs.readFileSync(new URL("../src/features/calendar/CalendarPicker.tsx", import.meta.url), "utf8");
|
||||
const moduleSource = fs.readFileSync(new URL("../src/module.ts", import.meta.url), "utf8");
|
||||
const coreTypes = fs.readFileSync(new URL("../../../govoplan-core/webui/src/types.ts", import.meta.url), "utf8");
|
||||
|
||||
assert(moduleSource.includes('"calendar.picker": calendarPicker'), "Calendar must register the named picker capability");
|
||||
assert(coreTypes.includes("export type CalendarPickerUiCapability"), "Core must expose the narrow cross-module contract");
|
||||
assert(picker.includes("listCalendars(settings)"), "Picker must use Calendar's authenticated list API");
|
||||
assert(picker.includes("hasScope(auth, CALENDAR_PICKER_READ_SCOPE)"), "Picker must avoid loading without read permission");
|
||||
assert(picker.includes("value={value}"), "Picker must remain controlled by its consumer");
|
||||
assert(picker.includes("onChange={(event) => onChange(event.target.value)}"), "Picker must return the chosen calendar id");
|
||||
assert(picker.includes("aria-busy={loading || undefined}"), "Picker must expose loading state accessibly");
|
||||
assert(picker.includes("aria-describedby={status ? statusId : undefined}"), "Picker must associate availability feedback");
|
||||
|
||||
console.log("Calendar picker capability structure checks passed.");
|
||||
37
webui/tests/calendar-picker.test.ts
Normal file
37
webui/tests/calendar-picker.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import {
|
||||
calendarPickerOptions,
|
||||
calendarPickerTenantId,
|
||||
type CalendarPickerOption
|
||||
} from "../src/features/calendar/calendarPickerLogic";
|
||||
|
||||
function assert(condition: unknown, message: string): void {
|
||||
if (!condition) throw new Error(message);
|
||||
}
|
||||
|
||||
function calendar(id: string, name: string, isDefault = false): CalendarPickerOption {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
is_default: isDefault
|
||||
};
|
||||
}
|
||||
|
||||
const input = [
|
||||
calendar("z", "Zulu"),
|
||||
calendar("b", "Bravo", true),
|
||||
calendar("a", "alpha")
|
||||
];
|
||||
const ordered = calendarPickerOptions(input);
|
||||
|
||||
assert(ordered.map((item) => item.id).join(",") === "b,a,z", "default calendar should lead, followed by names");
|
||||
assert(input.map((item) => item.id).join(",") === "z,b,a", "picker sorting must not mutate API data");
|
||||
assert(
|
||||
calendarPickerTenantId({ tenant: { id: "fallback" }, active_tenant: { id: "active" } }) === "active",
|
||||
"active tenant should partition picker requests"
|
||||
);
|
||||
assert(
|
||||
calendarPickerTenantId({ tenant: { id: "fallback" } }) === "fallback",
|
||||
"legacy tenant should remain a supported fallback"
|
||||
);
|
||||
|
||||
console.log("Calendar picker behavior checks passed.");
|
||||
Reference in New Issue
Block a user