refactor(api): extract timeline entry procedure support
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user