refactor(api): extract holiday calendar write support
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
assertHolidayCalendarEntryDateAvailable,
|
||||
assertHolidayCalendarScopeConsistency,
|
||||
clampHolidayCalendarDate,
|
||||
normalizeHolidayCalendarScopeInput,
|
||||
normalizeHolidayCalendarStateCode,
|
||||
resolveHolidayCalendarUpdateScope,
|
||||
} from "../router/holiday-calendar-write-support.js";
|
||||
|
||||
describe("holiday calendar write support", () => {
|
||||
it("normalizes state codes and optional scope fields", () => {
|
||||
expect(normalizeHolidayCalendarStateCode(" by ")).toBe("BY");
|
||||
expect(normalizeHolidayCalendarStateCode(undefined)).toBeNull();
|
||||
expect(normalizeHolidayCalendarScopeInput({
|
||||
stateCode: " ny ",
|
||||
metroCityId: undefined,
|
||||
})).toEqual({
|
||||
stateCode: "NY",
|
||||
metroCityId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("reuses existing scope values for partial updates", () => {
|
||||
expect(resolveHolidayCalendarUpdateScope({
|
||||
existing: {
|
||||
stateCode: "BY",
|
||||
metroCityId: "city_1",
|
||||
},
|
||||
data: {
|
||||
stateCode: undefined,
|
||||
metroCityId: null,
|
||||
},
|
||||
})).toEqual({
|
||||
stateCode: "BY",
|
||||
metroCityId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("clamps dates to UTC midnight", () => {
|
||||
expect(clampHolidayCalendarDate(new Date("2026-12-24T18:45:00.000Z")).toISOString())
|
||||
.toBe("2026-12-24T00:00:00.000Z");
|
||||
});
|
||||
|
||||
it("rejects invalid state and city scope combinations before hitting uniqueness checks", async () => {
|
||||
const db = {
|
||||
metroCity: { findUnique: vi.fn() },
|
||||
holidayCalendar: { findFirst: vi.fn() },
|
||||
} as never;
|
||||
|
||||
await expect(assertHolidayCalendarScopeConsistency(db, {
|
||||
scopeType: "STATE",
|
||||
countryId: "country_de",
|
||||
stateCode: null,
|
||||
metroCityId: null,
|
||||
})).rejects.toMatchObject({
|
||||
code: "BAD_REQUEST",
|
||||
message: "State calendars require a state code",
|
||||
});
|
||||
|
||||
await expect(assertHolidayCalendarScopeConsistency(db, {
|
||||
scopeType: "CITY",
|
||||
countryId: "country_de",
|
||||
stateCode: null,
|
||||
metroCityId: null,
|
||||
})).rejects.toMatchObject({
|
||||
code: "BAD_REQUEST",
|
||||
message: "City calendars require a metro city",
|
||||
});
|
||||
|
||||
expect(db.holidayCalendar.findFirst).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects city scopes whose metro city belongs to a different country", async () => {
|
||||
const db = {
|
||||
metroCity: {
|
||||
findUnique: vi.fn().mockResolvedValue({
|
||||
id: "city_augsburg",
|
||||
countryId: "country_us",
|
||||
}),
|
||||
},
|
||||
holidayCalendar: { findFirst: vi.fn() },
|
||||
} as never;
|
||||
|
||||
await expect(assertHolidayCalendarScopeConsistency(db, {
|
||||
scopeType: "CITY",
|
||||
countryId: "country_de",
|
||||
stateCode: null,
|
||||
metroCityId: "city_augsburg",
|
||||
})).rejects.toMatchObject({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Metro city must belong to the selected country",
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects duplicate holiday entry dates using the clamped date", async () => {
|
||||
const db = {
|
||||
holidayCalendarEntry: {
|
||||
findFirst: vi.fn().mockResolvedValue({ id: "entry_existing" }),
|
||||
},
|
||||
} as never;
|
||||
|
||||
await expect(assertHolidayCalendarEntryDateAvailable(db, {
|
||||
holidayCalendarId: "cal_1",
|
||||
date: new Date("2026-12-24T18:45:00.000Z"),
|
||||
})).rejects.toMatchObject({
|
||||
code: "CONFLICT",
|
||||
message: "A holiday entry for this calendar and date already exists",
|
||||
});
|
||||
|
||||
expect(db.holidayCalendarEntry.findFirst).toHaveBeenCalledWith({
|
||||
where: {
|
||||
holidayCalendarId: "cal_1",
|
||||
date: new Date("2026-12-24T00:00:00.000Z"),
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user