import { beforeEach, describe, expect, it, vi } from "vitest"; const mocks = vi.hoisted(() => ({ db: { availabilityRule: { findMany: vi.fn() }, availabilityException: { findMany: vi.fn() }, appointment: { findMany: vi.fn() }, calendarEvent: { findMany: vi.fn() }, }, computeSlots: vi.fn(), })); vi.mock("~/utils/db.server", () => ({ db: mocks.db })); vi.mock("./slotEngine", () => ({ computeSlots: mocks.computeSlots })); import { loadSlotsForDate } from "./SlotQueryService.server"; describe("SlotQueryService.server", () => { beforeEach(() => { vi.clearAllMocks(); mocks.db.availabilityRule.findMany.mockResolvedValue([]); mocks.db.availabilityException.findMany.mockResolvedValue([]); mocks.db.appointment.findMany.mockResolvedValue([]); mocks.db.calendarEvent.findMany.mockResolvedValue([]); mocks.computeSlots.mockReturnValue([]); }); it("loads any number of providers with four bulk queries", async () => { const startAt = new Date("2026-07-20T09:00:00.000Z"); const endAt = new Date("2026-07-20T10:00:00.000Z"); mocks.db.availabilityRule.findMany.mockResolvedValue([ { providerUserId: "provider_2", dayOfWeek: "monday", startTime: "09:00", endTime: "17:00", timezone: "Europe/Berlin" }, ]); mocks.db.appointment.findMany.mockResolvedValue([{ providerUserId: "provider_1", startAt, endAt }]); mocks.db.calendarEvent.findMany.mockResolvedValue([ { userId: "provider_2", startsAt: startAt, endsAt: endAt, isBusyForAvailability: true, archivedAt: null }, ]); await loadSlotsForDate({ tenantId: "tenant_1", providerUserIds: ["provider_1", "provider_2"], date: "2026-07-20", now: new Date("2026-07-10T00:00:00.000Z"), config: { durationMinutes: 30, bufferBeforeMinutes: 0, bufferAfterMinutes: 0, slotIncrementMinutes: 15, minNoticeHours: 4, maxAdvanceDays: 60, }, }); expect(mocks.db.availabilityRule.findMany).toHaveBeenCalledTimes(1); expect(mocks.db.availabilityException.findMany).toHaveBeenCalledTimes(1); expect(mocks.db.appointment.findMany).toHaveBeenCalledTimes(1); expect(mocks.db.calendarEvent.findMany).toHaveBeenCalledTimes(1); expect(mocks.db.availabilityRule.findMany).toHaveBeenCalledWith( expect.objectContaining({ where: { tenantId: "tenant_1", providerUserId: { in: ["provider_1", "provider_2"] } } }), ); expect(mocks.computeSlots).toHaveBeenCalledWith( expect.objectContaining({ providers: [ expect.objectContaining({ providerUserId: "provider_1", busyIntervals: [{ from: startAt, to: endAt }] }), expect.objectContaining({ providerUserId: "provider_2", rules: [expect.objectContaining({ dayOfWeek: "monday" })], busyIntervals: [{ from: startAt, to: endAt }] }), ], }), ); }); it("short-circuits without querying when no provider is configured", async () => { await expect( loadSlotsForDate({ tenantId: "tenant_1", providerUserIds: [], date: "2026-07-20", now: new Date("2026-07-10T00:00:00.000Z"), config: { durationMinutes: 30, bufferBeforeMinutes: 0, bufferAfterMinutes: 0, slotIncrementMinutes: 15, minNoticeHours: 4, maxAdvanceDays: 60, }, }), ).resolves.toEqual([]); expect(mocks.db.availabilityRule.findMany).not.toHaveBeenCalled(); expect(mocks.computeSlots).not.toHaveBeenCalled(); }); });