test(api): cover assistant vacation read tools

This commit is contained in:
2026-03-31 23:55:28 +02:00
parent fd2c6b6203
commit c03436945e
3 changed files with 384 additions and 0 deletions
@@ -0,0 +1,214 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { VacationType } from "@capakraken/db";
import { SystemRole } from "@capakraken/shared";
vi.mock("@capakraken/application", async (importOriginal) => {
const actual = await importOriginal<typeof import("@capakraken/application")>();
return {
...actual,
approveEstimateVersion: vi.fn(),
cloneEstimate: vi.fn(),
commitDispoImportBatch: vi.fn(),
countPlanningEntries: vi.fn().mockResolvedValue({ countsByRoleId: new Map() }),
createEstimateExport: vi.fn(),
createEstimatePlanningHandoff: vi.fn(),
createEstimateRevision: vi.fn(),
assessDispoImportReadiness: vi.fn(),
loadResourceDailyAvailabilityContexts: vi.fn().mockResolvedValue(new Map()),
getDashboardDemand: vi.fn().mockResolvedValue([]),
getDashboardBudgetForecast: vi.fn().mockResolvedValue([]),
getDashboardOverview: vi.fn(),
getDashboardSkillGapSummary: vi.fn().mockResolvedValue({
roleGaps: [],
totalOpenPositions: 0,
skillSupplyTop10: [],
resourcesByRole: [],
}),
getDashboardProjectHealth: vi.fn().mockResolvedValue([]),
getDashboardPeakTimes: vi.fn().mockResolvedValue([]),
getDashboardTopValueResources: vi.fn().mockResolvedValue([]),
getEstimateById: vi.fn(),
listAssignmentBookings: vi.fn().mockResolvedValue([]),
stageDispoImportBatch: vi.fn(),
submitEstimateVersion: vi.fn(),
updateEstimateDraft: vi.fn(),
};
});
import { executeTool } from "../router/assistant-tools.js";
import { createToolContext } from "./assistant-tools-vacation-entitlement-test-helpers.js";
describe("assistant vacation balance tools", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("routes vacation balance through the real vacation workflow", async () => {
const vacationFindMany = vi.fn().mockImplementation(async (args?: any) => {
if (args?.where?.type === VacationType.PUBLIC_HOLIDAY) {
return [];
}
if (args?.where?.type?.in) {
return [
{
type: VacationType.ANNUAL,
startDate: new Date("2026-01-05T00:00:00.000Z"),
endDate: new Date("2026-01-06T00:00:00.000Z"),
status: "APPROVED",
isHalfDay: false,
},
{
type: VacationType.ANNUAL,
startDate: new Date("2026-02-03T00:00:00.000Z"),
endDate: new Date("2026-02-03T00:00:00.000Z"),
status: "PENDING",
isHalfDay: true,
},
];
}
if (args?.where?.type === VacationType.SICK) {
return [
{
startDate: new Date("2026-03-10T00:00:00.000Z"),
endDate: new Date("2026-03-10T00:00:00.000Z"),
isHalfDay: false,
},
];
}
return [];
});
const ctx = createToolContext({
resource: {
findUnique: vi.fn().mockResolvedValue({
id: "res_1",
eid: "EMP-001",
displayName: "Alice Example",
userId: "user_1",
chapter: "Delivery",
federalState: "BY",
countryId: "country_de",
metroCityId: null,
country: { code: "DE", name: "Germany" },
metroCity: null,
}),
},
holidayCalendar: {
findMany: vi.fn().mockResolvedValue([]),
},
systemSettings: {
findUnique: vi.fn().mockResolvedValue({ vacationDefaultDays: 30 }),
},
vacationEntitlement: {
findUnique: vi.fn().mockResolvedValue(null),
create: vi.fn().mockResolvedValue({
id: "ent_2026",
resourceId: "res_1",
year: 2026,
entitledDays: 30,
carryoverDays: 0,
usedDays: 0,
pendingDays: 0,
}),
update: vi.fn().mockImplementation(async (args?: any) => ({
id: "ent_2026",
resourceId: "res_1",
year: 2026,
entitledDays: 30,
carryoverDays: 0,
usedDays: args?.data?.usedDays ?? 0,
pendingDays: args?.data?.pendingDays ?? 0,
})),
},
vacation: {
findMany: vacationFindMany,
},
}, { userRole: SystemRole.ADMIN });
const result = await executeTool(
"get_vacation_balance",
JSON.stringify({ resourceId: "res_1", year: 2026 }),
ctx,
);
expect(JSON.parse(result.content)).toEqual(expect.objectContaining({
resource: "Alice Example",
eid: "EMP-001",
year: 2026,
entitlement: 30,
carryOver: 0,
taken: 1,
pending: 0.5,
remaining: 28.5,
sickDays: 1,
deductionSummary: {
formula: "remaining = entitlement - taken - pending",
approvedVacationCount: 1,
pendingVacationCount: 1,
approvedRequestedDays: 2,
pendingRequestedDays: 0.5,
approvedDeductedDays: 1,
pendingDeductedDays: 0.5,
excludedHolidayDates: ["2026-01-06"],
holidayBasisVariants: ["Germany / BY"],
sources: {
hasCalendarHolidays: true,
hasLegacyPublicHolidayEntries: false,
},
},
vacations: [
expect.objectContaining({
type: "ANNUAL",
status: "APPROVED",
startDate: "2026-01-05",
endDate: "2026-01-06",
isHalfDay: false,
requestedDays: 2,
deductedDays: 1,
holidayCountryCode: "DE",
holidayCountryName: "Germany",
holidayFederalState: "BY",
holidayMetroCityName: null,
holidayCalendarDates: ["2026-01-06"],
holidayLegacyPublicHolidayDates: [],
holidayDetails: [{ date: "2026-01-06", source: "CALENDAR" }],
holidayContext: {
countryCode: "DE",
countryName: "Germany",
federalState: "BY",
metroCityName: null,
sources: {
hasCalendarHolidays: true,
hasLegacyPublicHolidayEntries: false,
},
},
}),
expect.objectContaining({
type: "ANNUAL",
status: "PENDING",
startDate: "2026-02-03",
endDate: "2026-02-03",
isHalfDay: true,
requestedDays: 0.5,
deductedDays: 0.5,
holidayCountryCode: "DE",
holidayCountryName: "Germany",
holidayFederalState: "BY",
holidayMetroCityName: null,
holidayCalendarDates: [],
holidayLegacyPublicHolidayDates: [],
holidayDetails: [],
holidayContext: {
countryCode: "DE",
countryName: "Germany",
federalState: "BY",
metroCityName: null,
sources: {
hasCalendarHolidays: false,
hasLegacyPublicHolidayEntries: false,
},
},
}),
],
}));
});
});