refactor(api): extract timeline filter support

This commit is contained in:
2026-03-31 15:54:56 +02:00
parent 153b90cc11
commit fda6bcab74
3 changed files with 271 additions and 136 deletions
@@ -0,0 +1,122 @@
import { TRPCError } from "@trpc/server";
import { describe, expect, it, vi } from "vitest";
import {
buildSelfServiceTimelineInput,
buildTimelineEntriesDetailInput,
createTimelineDateRange,
createTimelineFilters,
} from "../router/timeline-filter-support.js";
describe("timeline filter support", () => {
it("builds date ranges and rejects inverted ranges", () => {
expect(
createTimelineDateRange({
startDate: "2026-04-01",
durationDays: 3,
}),
).toEqual({
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-03T00:00:00.000Z"),
});
expect(() =>
createTimelineDateRange({
startDate: "2026-04-03",
endDate: "2026-04-01",
}),
).toThrowError(new TRPCError({
code: "BAD_REQUEST",
message: "endDate must be on or after startDate.",
}));
});
it("normalizes timeline filters and assembles detail input", () => {
expect(
createTimelineFilters({
resourceIds: [" resource_1 ", ""],
projectIds: ["project_1"],
chapters: [" Compositing "],
}),
).toEqual({
resourceIds: ["resource_1"],
projectIds: ["project_1"],
clientIds: undefined,
chapters: ["Compositing"],
eids: undefined,
countryCodes: undefined,
});
expect(
buildTimelineEntriesDetailInput({
startDate: "2026-04-01",
durationDays: 3,
resourceIds: [" resource_1 ", ""],
projectIds: ["project_1"],
chapters: [" Compositing "],
}),
).toEqual({
period: {
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-03T00:00:00.000Z"),
},
filters: {
resourceIds: ["resource_1"],
projectIds: ["project_1"],
clientIds: undefined,
chapters: ["Compositing"],
eids: undefined,
countryCodes: undefined,
},
timelineInput: {
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-03T00:00:00.000Z"),
resourceIds: ["resource_1"],
projectIds: ["project_1"],
clientIds: undefined,
chapters: ["Compositing"],
eids: undefined,
countryCodes: undefined,
},
});
});
it("builds self-service timeline input only for owned resources", async () => {
const ctx = {
dbUser: { id: "user_1" },
db: {
resource: {
findFirst: vi.fn().mockResolvedValue({ id: "resource_1" }),
},
},
};
await expect(
buildSelfServiceTimelineInput(ctx as never, {
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-03T00:00:00.000Z"),
projectIds: [" project_1 "],
clientIds: [" client_1 "],
}),
).resolves.toEqual({
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-03T00:00:00.000Z"),
resourceIds: ["resource_1"],
projectIds: ["project_1"],
clientIds: ["client_1"],
});
await expect(
buildSelfServiceTimelineInput({
dbUser: { id: "user_2" },
db: {
resource: {
findFirst: vi.fn().mockResolvedValue(null),
},
},
} as never, {
startDate: new Date("2026-04-01T00:00:00.000Z"),
endDate: new Date("2026-04-03T00:00:00.000Z"),
}),
).resolves.toBeNull();
});
});