import { beforeEach, describe, expect, it, vi } from "vitest"; vi.mock("../lib/anonymization.js", () => ({ getAnonymizationDirectory: vi.fn(), })); vi.mock("../router/timeline-read-shared.js", () => ({ buildSelfServiceTimelineInput: vi.fn(), buildTimelineEntriesDetailInput: vi.fn(), createEmptyTimelineEntriesView: vi.fn(), loadTimelineEntriesReadModel: vi.fn(), })); vi.mock("../router/timeline-entry-response-support.js", () => ({ buildTimelineEntriesDetailResponse: vi.fn(), buildTimelineEntriesViewResponse: vi.fn(), })); vi.mock("../router/timeline-holiday-read.js", () => ({ formatHolidayOverlays: vi.fn(), loadTimelineHolidayOverlaysForReadModel: vi.fn(), summarizeHolidayOverlays: vi.fn(), })); import { getAnonymizationDirectory } from "../lib/anonymization.js"; import { buildSelfServiceTimelineInput, buildTimelineEntriesDetailInput, createEmptyTimelineEntriesView, loadTimelineEntriesReadModel, } from "../router/timeline-read-shared.js"; import { buildTimelineEntriesDetailResponse, buildTimelineEntriesViewResponse, } from "../router/timeline-entry-response-support.js"; import { formatHolidayOverlays, loadTimelineHolidayOverlaysForReadModel, summarizeHolidayOverlays, } from "../router/timeline-holiday-read.js"; import { readMyTimelineEntriesView, readTimelineEntries, readTimelineEntriesDetail, readTimelineEntriesView, } from "../router/timeline-entry-procedure-support.js"; const getAnonymizationDirectoryMock = vi.mocked(getAnonymizationDirectory); const buildSelfServiceTimelineInputMock = vi.mocked(buildSelfServiceTimelineInput); const buildTimelineEntriesDetailInputMock = vi.mocked(buildTimelineEntriesDetailInput); const createEmptyTimelineEntriesViewMock = vi.mocked(createEmptyTimelineEntriesView); const loadTimelineEntriesReadModelMock = vi.mocked(loadTimelineEntriesReadModel); const buildTimelineEntriesDetailResponseMock = vi.mocked(buildTimelineEntriesDetailResponse); const buildTimelineEntriesViewResponseMock = vi.mocked(buildTimelineEntriesViewResponse); const formatHolidayOverlaysMock = vi.mocked(formatHolidayOverlays); const loadTimelineHolidayOverlaysForReadModelMock = vi.mocked(loadTimelineHolidayOverlaysForReadModel); const summarizeHolidayOverlaysMock = vi.mocked(summarizeHolidayOverlays); describe("timeline entry procedure support", () => { beforeEach(() => { vi.clearAllMocks(); }); it("returns anonymized allocations for entry list reads", async () => { const readModel = { allocations: [{ id: "allocation_1" }], assignments: [] }; const directory = { enabled: true }; const response = { allocations: [{ id: "allocation_1", anonymized: true }], assignments: [] }; loadTimelineEntriesReadModelMock.mockResolvedValueOnce(readModel as never); getAnonymizationDirectoryMock.mockResolvedValueOnce(directory as never); buildTimelineEntriesViewResponseMock.mockReturnValueOnce(response as never); await expect( readTimelineEntries({} as never, { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }), ).resolves.toEqual([{ id: "allocation_1", anonymized: true }]); expect(loadTimelineEntriesReadModelMock).toHaveBeenCalledWith({}, { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }); expect(getAnonymizationDirectoryMock).toHaveBeenCalledWith({}); expect(buildTimelineEntriesViewResponseMock).toHaveBeenCalledWith(readModel, directory); }); it("returns an empty entries view when self-service scope cannot be resolved", async () => { buildSelfServiceTimelineInputMock.mockResolvedValueOnce(null); createEmptyTimelineEntriesViewMock.mockReturnValueOnce({ allocations: [], assignments: [], demands: [], } as never); await expect( readMyTimelineEntriesView( { db: {}, dbUser: { id: "user_1" } } as never, { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }, ), ).resolves.toEqual({ allocations: [], assignments: [], demands: [], }); expect(createEmptyTimelineEntriesViewMock).toHaveBeenCalledTimes(1); expect(loadTimelineEntriesReadModelMock).not.toHaveBeenCalled(); }); it("builds entry detail responses with formatted holiday overlays", async () => { const period = { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }; const filters = { countryCodes: ["DE"] }; const timelineInput = { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), countryCodes: ["DE"], }; const readModel = { allocations: [{ id: "allocation_1" }], demands: [{ id: "demand_1" }], assignments: [{ id: "assignment_1" }], }; buildTimelineEntriesDetailInputMock.mockReturnValueOnce({ period, filters, timelineInput, } as never); loadTimelineEntriesReadModelMock.mockResolvedValueOnce(readModel as never); getAnonymizationDirectoryMock.mockResolvedValueOnce({ enabled: true } as never); loadTimelineHolidayOverlaysForReadModelMock.mockResolvedValueOnce([{ id: "overlay_1" }] as never); formatHolidayOverlaysMock.mockReturnValueOnce([{ id: "formatted_1" }] as never); summarizeHolidayOverlaysMock.mockReturnValueOnce({ overlayCount: 1, holidayResourceCount: 1, byScope: [{ scope: "COUNTRY", count: 1 }], } as never); buildTimelineEntriesDetailResponseMock.mockReturnValueOnce({ detail: true } as never); await expect( readTimelineEntriesDetail({} as never, { startDate: "2026-04-01", endDate: "2026-04-07", countryCodes: ["DE"], }), ).resolves.toEqual({ detail: true }); expect(loadTimelineHolidayOverlaysForReadModelMock).toHaveBeenCalledWith( {}, timelineInput, readModel, ); expect(formatHolidayOverlaysMock).toHaveBeenCalledWith([{ id: "overlay_1" }]); expect(summarizeHolidayOverlaysMock).toHaveBeenCalledWith([{ id: "formatted_1" }]); expect(buildTimelineEntriesDetailResponseMock).toHaveBeenCalledWith({ period, filters, readModel, directory: { enabled: true }, holidayOverlays: [{ id: "formatted_1" }], holidaySummary: { overlayCount: 1, holidayResourceCount: 1, byScope: [{ scope: "COUNTRY", count: 1 }], }, }); }); it("builds full entries views from loaded read models", async () => { const readModel = { allocations: [{ id: "allocation_1" }], assignments: [{ id: "assignment_1" }] }; const directory = { enabled: true }; const response = { allocations: [{ id: "allocation_1", anonymized: true }], assignments: [{ id: "assignment_1", anonymized: true }], }; loadTimelineEntriesReadModelMock.mockResolvedValueOnce(readModel as never); getAnonymizationDirectoryMock.mockResolvedValueOnce(directory as never); buildTimelineEntriesViewResponseMock.mockReturnValueOnce(response as never); await expect( readTimelineEntriesView({} as never, { startDate: new Date("2026-04-01T00:00:00.000Z"), endDate: new Date("2026-04-07T00:00:00.000Z"), }), ).resolves.toEqual(response); }); });