From 4a3144526c99b45f15d37bcfe6d5776a6cb1adc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Tue, 31 Mar 2026 23:59:17 +0200 Subject: [PATCH] test(api): cover assistant holiday resolution reads --- ...oliday-resolution-calendar-preview.test.ts | 162 ++++++++++++++++++ ...liday-resolution-regional-resource.test.ts | 106 ++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 packages/api/src/__tests__/assistant-tools-holiday-resolution-calendar-preview.test.ts create mode 100644 packages/api/src/__tests__/assistant-tools-holiday-resolution-regional-resource.test.ts diff --git a/packages/api/src/__tests__/assistant-tools-holiday-resolution-calendar-preview.test.ts b/packages/api/src/__tests__/assistant-tools-holiday-resolution-calendar-preview.test.ts new file mode 100644 index 0000000..4177de2 --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-holiday-resolution-calendar-preview.test.ts @@ -0,0 +1,162 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { SystemRole } from "@capakraken/shared"; + +import { + createToolContext, + executeTool, +} from "./assistant-tools-holiday-read-test-helpers.js"; + +describe("assistant holiday resolution calendar preview tools", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("previews resolved holiday calendars for a scope and shows the source calendar", async () => { + const ctx = createToolContext({ + country: { + findUnique: vi.fn().mockResolvedValue({ + id: "country_de", + code: "DE", + name: "Deutschland", + }), + }, + metroCity: { + findUnique: vi.fn().mockResolvedValue({ + id: "city_augsburg", + name: "Augsburg", + countryId: "country_de", + }), + }, + holidayCalendar: { + findMany: vi.fn().mockResolvedValue([ + { + id: "cal_city", + name: "Augsburg lokal", + scopeType: "CITY", + priority: 5, + createdAt: new Date("2026-01-01T00:00:00.000Z"), + entries: [ + { + id: "entry_1", + date: new Date("2020-08-08T00:00:00.000Z"), + name: "Friedensfest lokal", + isRecurringAnnual: true, + source: "manual", + }, + ], + }, + ]), + }, + }); + + const result = await executeTool( + "preview_resolved_holiday_calendar", + JSON.stringify({ countryId: "country_de", metroCityId: "city_augsburg", year: 2026 }), + ctx, + ); + + const parsed = JSON.parse(result.content) as { + count: number; + locationContext: { countryCode: string; metroCity: string | null; year: number }; + holidays: Array<{ name: string; calendarName: string; scope: string; date: string }>; + }; + + expect(parsed.count).toBeGreaterThan(0); + expect(parsed.locationContext).toEqual( + expect.objectContaining({ + countryCode: "DE", + metroCity: "Augsburg", + year: 2026, + }), + ); + expect(parsed.holidays).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + name: "Friedensfest lokal", + calendarName: "Augsburg lokal", + scope: "CITY", + date: "2026-08-08", + }), + ]), + ); + expect(ctx.db.country.findUnique).toHaveBeenCalledWith({ + where: { id: "country_de" }, + select: { id: true, code: true, name: true }, + }); + expect(ctx.db.metroCity.findUnique).toHaveBeenCalledWith({ + where: { id: "city_augsburg" }, + select: { id: true, name: true, countryId: true }, + }); + }); + + it("previews resolved holiday calendars through the real holiday router path", async () => { + const holidayCallerDb = { + country: { + findUnique: vi.fn().mockResolvedValue({ id: "country_de", code: "DE", name: "Germany" }), + }, + metroCity: { + findUnique: vi + .fn() + .mockResolvedValue({ id: "city_muc", name: "Munich", countryId: "country_de" }), + }, + holidayCalendar: { + findMany: vi.fn().mockResolvedValue([]), + }, + }; + const ctx = createToolContext(holidayCallerDb, [], SystemRole.USER); + + const result = await executeTool( + "preview_resolved_holiday_calendar", + JSON.stringify({ + countryId: "country_de", + stateCode: "BY", + metroCityId: "city_muc", + year: 2026, + }), + ctx, + ); + + expect(holidayCallerDb.country.findUnique).toHaveBeenCalledWith({ + where: { id: "country_de" }, + select: { id: true, code: true, name: true }, + }); + expect(holidayCallerDb.metroCity.findUnique).toHaveBeenCalledWith({ + where: { id: "city_muc" }, + select: { id: true, name: true, countryId: true }, + }); + expect(JSON.parse(result.content)).toEqual( + expect.objectContaining({ + count: expect.any(Number), + locationContext: { + countryId: "country_de", + countryCode: "DE", + stateCode: "BY", + metroCityId: "city_muc", + metroCity: "Munich", + year: 2026, + }, + summary: expect.objectContaining({ + byCalendar: expect.any(Array), + byScope: expect.any(Array), + bySourceType: expect.arrayContaining([ + expect.objectContaining({ sourceType: "BUILTIN" }), + ]), + }), + holidays: expect.arrayContaining([ + expect.objectContaining({ + date: "2026-01-01", + name: "Neujahr", + scope: "COUNTRY", + sourceType: "BUILTIN", + }), + expect.objectContaining({ + date: "2026-01-06", + name: "Heilige Drei Könige", + scope: "STATE", + sourceType: "BUILTIN", + }), + ]), + }), + ); + }); +}); diff --git a/packages/api/src/__tests__/assistant-tools-holiday-resolution-regional-resource.test.ts b/packages/api/src/__tests__/assistant-tools-holiday-resolution-regional-resource.test.ts new file mode 100644 index 0000000..67cd711 --- /dev/null +++ b/packages/api/src/__tests__/assistant-tools-holiday-resolution-regional-resource.test.ts @@ -0,0 +1,106 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +import { + createToolContext, + executeTool, +} from "./assistant-tools-holiday-read-test-helpers.js"; + +describe("assistant holiday resolution regional and resource tools", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("lists regional holidays and distinguishes Bavaria from Hamburg", async () => { + const ctx = createToolContext({}); + + const bavaria = await executeTool( + "list_holidays_by_region", + JSON.stringify({ countryCode: "DE", federalState: "BY", year: 2026 }), + ctx, + ); + const hamburg = await executeTool( + "list_holidays_by_region", + JSON.stringify({ countryCode: "DE", federalState: "HH", year: 2026 }), + ctx, + ); + + const bavariaResult = JSON.parse(bavaria.content) as { + count: number; + locationContext: { federalState: string | null }; + summary: { byScope: Array<{ scope: string; count: number }> }; + holidays: Array<{ name: string; date: string }>; + }; + const hamburgResult = JSON.parse(hamburg.content) as { + count: number; + locationContext: { federalState: string | null }; + holidays: Array<{ name: string; date: string }>; + }; + + expect(bavariaResult.count).toBeGreaterThan(hamburgResult.count); + expect(bavariaResult.locationContext.federalState).toBe("BY"); + expect(bavariaResult.summary.byScope).toEqual( + expect.arrayContaining([expect.objectContaining({ scope: "STATE" })]), + ); + expect(bavariaResult.holidays).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "Heilige Drei Könige", date: "2026-01-06" }), + ]), + ); + expect(hamburgResult.holidays).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "Heilige Drei Könige", date: "2026-01-06" }), + ]), + ); + }); + + it("resolves resource-specific holidays including city-local dates", async () => { + const db = { + resource: { + findUnique: vi + .fn() + .mockResolvedValueOnce(null) + .mockResolvedValueOnce({ id: "res_1", eid: "bruce.banner", displayName: "Bruce Banner" }) + .mockResolvedValueOnce({ + id: "res_1", + eid: "bruce.banner", + displayName: "Bruce Banner", + federalState: "BY", + countryId: "country_de", + metroCityId: "city_augsburg", + country: { code: "DE", name: "Deutschland" }, + metroCity: { name: "Augsburg" }, + }), + findFirst: vi.fn(), + }, + }; + const ctx = createToolContext(db); + + const result = await executeTool( + "get_resource_holidays", + JSON.stringify({ identifier: "bruce.banner", year: 2026 }), + ctx, + ); + + const parsed = JSON.parse(result.content) as { + resource: { eid: string; federalState: string | null; metroCity: string | null }; + summary: { byScope: Array<{ scope: string; count: number }> }; + holidays: Array<{ name: string; date: string }>; + }; + + expect(parsed.resource).toEqual( + expect.objectContaining({ + eid: "bruce.banner", + federalState: "BY", + metroCity: "Augsburg", + }), + ); + expect(parsed.holidays).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "Augsburger Friedensfest", date: "2026-08-08" }), + ]), + ); + expect(parsed.summary.byScope).toEqual( + expect.arrayContaining([expect.objectContaining({ scope: "CITY" })]), + ); + }); +});