Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/modules/booking/services/SlotQueryService.server.test.ts
T

92 lines
3.5 KiB
TypeScript

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();
});
});