import { describe, expect, it, vi, beforeEach } from "vitest"; vi.mock("../lib/holiday-availability.js", () => ({ asHolidayResolverDb: vi.fn((db) => db), getResolvedCalendarHolidays: vi.fn(), })); vi.mock("../router/timeline-read-shared.js", () => ({ loadTimelineEntriesReadModel: vi.fn(), })); import { asHolidayResolverDb, getResolvedCalendarHolidays, } from "../lib/holiday-availability.js"; import { loadTimelineEntriesReadModel } from "../router/timeline-read-shared.js"; import { loadTimelineHolidayOverlays, loadTimelineHolidayOverlaysForReadModel, } from "../router/timeline-holiday-load-support.js"; const asHolidayResolverDbMock = vi.mocked(asHolidayResolverDb); const getResolvedCalendarHolidaysMock = vi.mocked(getResolvedCalendarHolidays); const loadTimelineEntriesReadModelMock = vi.mocked(loadTimelineEntriesReadModel); describe("timeline holiday load support", () => { beforeEach(() => { vi.clearAllMocks(); }); it("loads the timeline read model before building holiday overlays", async () => { const resourceFindMany = vi .fn() .mockResolvedValueOnce([ { id: "resource_1", countryId: "country_1", federalState: "BY", metroCityId: "city_1", country: { code: "DE", name: "Germany" }, metroCity: { name: "Munich" }, }, ]); const db = { resource: { findMany: resourceFindMany } } as never; const input = { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }; loadTimelineEntriesReadModelMock.mockResolvedValueOnce({ assignments: [{ resourceId: "resource_1" }], } as never); getResolvedCalendarHolidaysMock.mockResolvedValueOnce([ { date: "2026-04-03", name: "Holiday", scope: "COUNTRY", calendarName: "System", sourceType: "BUILTIN", }, ] as never); await expect(loadTimelineHolidayOverlays(db, input)).resolves.toEqual([ expect.objectContaining({ id: "calendar-holiday:resource_1:2026-04-03", resourceId: "resource_1", note: "Holiday", }), ]); expect(loadTimelineEntriesReadModelMock).toHaveBeenCalledWith(db, input); expect(asHolidayResolverDbMock).toHaveBeenCalledWith(db); }); it("returns an empty list when no resource ids can be resolved", async () => { const resourceFindMany = vi.fn(); const db = { resource: { findMany: resourceFindMany } } as never; await expect( loadTimelineHolidayOverlaysForReadModel( db, { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }, { assignments: [{ resourceId: null }], } as never, ), ).resolves.toEqual([]); expect(resourceFindMany).not.toHaveBeenCalled(); expect(getResolvedCalendarHolidaysMock).not.toHaveBeenCalled(); }); it("resolves holidays for matching resources and returns overlays sorted by resource and date", async () => { const resourceFindMany = vi .fn() .mockResolvedValueOnce([{ id: "resource_2" }]) .mockResolvedValueOnce([ { id: "resource_2", countryId: "country_2", federalState: null, metroCityId: null, country: { code: "US", name: "United States" }, metroCity: null, }, { id: "resource_1", countryId: "country_1", federalState: "BY", metroCityId: "city_1", country: { code: "DE", name: "Germany" }, metroCity: { name: "Munich" }, }, ]); const db = { resource: { findMany: resourceFindMany } } as never; getResolvedCalendarHolidaysMock .mockResolvedValueOnce([ { date: "2026-04-04", name: "Holiday B", scope: "COUNTRY", calendarName: "System", sourceType: "BUILTIN", }, ] as never) .mockResolvedValueOnce([ { date: "2026-04-03", name: "Holiday A", scope: "CITY", calendarName: "Munich", sourceType: "CUSTOM", }, ] as never); await expect( loadTimelineHolidayOverlaysForReadModel( db, { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), chapters: ["3D"], }, { assignments: [{ resourceId: "resource_1" }], } as never, ), ).resolves.toEqual([ expect.objectContaining({ id: "calendar-holiday:resource_1:2026-04-03", resourceId: "resource_1", note: "Holiday A", countryCode: "DE", }), expect.objectContaining({ id: "calendar-holiday:resource_2:2026-04-04", resourceId: "resource_2", note: "Holiday B", countryCode: "US", }), ]); expect(resourceFindMany).toHaveBeenNthCalledWith(1, { where: { chapter: { in: ["3D"] } }, select: { id: true }, }); expect(resourceFindMany).toHaveBeenNthCalledWith(2, { where: { id: { in: ["resource_1", "resource_2"] } }, select: { id: true, countryId: true, federalState: true, metroCityId: true, country: { select: { code: true, name: true } }, metroCity: { select: { name: true } }, }, }); }); });