97 lines
2.3 KiB
TypeScript
97 lines
2.3 KiB
TypeScript
import {
|
|
continuousVirtualWindow,
|
|
groupEventsByDay,
|
|
layoutTimedEventsForDay,
|
|
moveEventToDay,
|
|
rangeForMode,
|
|
resizeEventToTime,
|
|
} from "../src/features/calendar/calendarViewModel.ts";
|
|
|
|
function assert(condition: unknown, message: string): void {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
function event(
|
|
id: string,
|
|
start: Date,
|
|
end: Date,
|
|
allDay = false,
|
|
) {
|
|
return {
|
|
id,
|
|
calendar_id: "calendar-1",
|
|
summary: id,
|
|
start_at: start.toISOString(),
|
|
end_at: end.toISOString(),
|
|
all_day: allDay,
|
|
} as never;
|
|
}
|
|
|
|
const focus = new Date(2026, 6, 15, 12);
|
|
const month = rangeForMode("month", focus, {
|
|
before: 8,
|
|
after: 12,
|
|
});
|
|
assert(
|
|
(month.end.getTime() - month.start.getTime()) / 86_400_000 === 42,
|
|
"month view should retain its six-week window",
|
|
);
|
|
|
|
const virtual = continuousVirtualWindow(
|
|
100,
|
|
{ scrollTop: 20 * 92, height: 8 * 92 },
|
|
3,
|
|
);
|
|
assert(virtual.start === 17, "virtualization should retain overscan above");
|
|
assert(virtual.end === 31, "virtualization should retain overscan below");
|
|
assert(
|
|
virtual.topSpacerHeight + virtual.bottomSpacerHeight > 0,
|
|
"virtualization should preserve offscreen geometry",
|
|
);
|
|
|
|
const day = new Date(2026, 6, 7);
|
|
const parallel = [0, 1, 2, 3].map((index) =>
|
|
event(
|
|
`event-${index}`,
|
|
new Date(2026, 6, 7, 9),
|
|
new Date(2026, 6, 7, 10),
|
|
),
|
|
);
|
|
const layout = layoutTimedEventsForDay(parallel, day);
|
|
assert(
|
|
layout.items.length === 2 && layout.overflows.length === 1,
|
|
"parallel events should use bounded columns plus one overflow control",
|
|
);
|
|
assert(
|
|
layout.overflows[0].events.length === 2,
|
|
"overflow should retain every hidden event",
|
|
);
|
|
|
|
const allDay = event(
|
|
"all-day",
|
|
new Date(2026, 6, 7),
|
|
new Date(2026, 6, 9),
|
|
true,
|
|
);
|
|
const grouped = groupEventsByDay([allDay]);
|
|
assert(grouped.size === 2, "all-day end dates should remain exclusive");
|
|
const moved = moveEventToDay(allDay, new Date(2026, 6, 20));
|
|
assert(
|
|
moved.endAt?.getDate() === 22,
|
|
"moving an all-day event should preserve its duration",
|
|
);
|
|
|
|
const timed = event(
|
|
"timed",
|
|
new Date(2026, 6, 7, 10),
|
|
new Date(2026, 6, 7, 11),
|
|
);
|
|
const resized = resizeEventToTime(timed, "end", day, 9 * 60);
|
|
assert(
|
|
resized.endAt !== null &&
|
|
resized.endAt.getTime() > resized.startAt.getTime(),
|
|
"resizing must not invert an event",
|
|
);
|
|
|
|
console.log("Calendar view model interaction checks passed.");
|