* refactor: convert BookingRepository to use dependency injection pattern - Add constructor injection for PrismaClient to BookingRepository - Convert all static methods to instance methods using this.prismaClient - Update all usage sites to use two-step instantiation pattern: const bookingRepo = new BookingRepository(prisma); bookingRepo.method(...) - Apply same dependency injection pattern as UserRepository, TeamRepository, and SelectedSlotsRepository - Update test files to use correct prismaMock import paths - Maintain all existing functionality and type safety Files updated: - BookingRepository class structure and all 15 static methods - Video meeting pages and booking views - Booking utilities and services (handleNewBooking, originalRescheduledBookingUtils) - Round robin handlers and reassignment logic - Interval limits and booking limits checking - Test files with proper mocking setup Co-Authored-By: morgan@cal.com <morgan@cal.com> * chore: bump platform libs --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: morgan@cal.com <morgan@cal.com>
257 lines
8.2 KiB
TypeScript
257 lines
8.2 KiB
TypeScript
import prismaMock from "../../../../tests/libs/__mocks__/prisma";
|
|
|
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
|
|
import { BookingStatus, RRTimestampBasis } from "@calcom/prisma/enums";
|
|
|
|
import { BookingRepository } from "./booking";
|
|
|
|
const createAttendeeNoShowTestBookings = async () => {
|
|
await Promise.all([
|
|
prismaMock.booking.create({
|
|
data: {
|
|
userId: 1,
|
|
uid: "123",
|
|
eventTypeId: 1,
|
|
status: BookingStatus.ACCEPTED,
|
|
attendees: {
|
|
create: {
|
|
email: "test1@example.com",
|
|
noShow: false,
|
|
name: "Test 1",
|
|
timeZone: "America/Toronto",
|
|
},
|
|
},
|
|
startTime: new Date("2025-05-01T00:00:00.000Z"),
|
|
endTime: new Date("2025-05-01T01:00:00.000Z"),
|
|
title: "Test Event",
|
|
},
|
|
}),
|
|
prismaMock.booking.create({
|
|
data: {
|
|
userId: 1,
|
|
uid: "123",
|
|
eventTypeId: 1,
|
|
status: BookingStatus.ACCEPTED,
|
|
attendees: {
|
|
create: {
|
|
email: "test1@example.com",
|
|
noShow: true,
|
|
name: "Test 1",
|
|
timeZone: "America/Toronto",
|
|
},
|
|
},
|
|
startTime: new Date("2025-05-01T00:00:00.000Z"),
|
|
endTime: new Date("2025-05-01T01:00:00.000Z"),
|
|
title: "Test Event",
|
|
},
|
|
}),
|
|
]);
|
|
};
|
|
|
|
const createHostNoShowTestBookings = async () => {
|
|
await Promise.all([
|
|
prismaMock.booking.create({
|
|
data: {
|
|
userId: 1,
|
|
uid: "123",
|
|
eventTypeId: 1,
|
|
status: BookingStatus.ACCEPTED,
|
|
attendees: {
|
|
create: {
|
|
email: "test1@example.com",
|
|
noShow: false,
|
|
name: "Test 1",
|
|
timeZone: "America/Toronto",
|
|
},
|
|
},
|
|
startTime: new Date("2025-05-01T00:00:00.000Z"),
|
|
endTime: new Date("2025-05-01T01:00:00.000Z"),
|
|
title: "Test Event",
|
|
noShowHost: false,
|
|
},
|
|
}),
|
|
prismaMock.booking.create({
|
|
data: {
|
|
userId: 1,
|
|
uid: "123",
|
|
eventTypeId: 1,
|
|
status: BookingStatus.ACCEPTED,
|
|
attendees: {
|
|
create: {
|
|
email: "test1@example.com",
|
|
noShow: false,
|
|
name: "Test 1",
|
|
timeZone: "America/Toronto",
|
|
},
|
|
},
|
|
startTime: new Date("2025-05-01T00:00:00.000Z"),
|
|
endTime: new Date("2025-05-01T01:00:00.000Z"),
|
|
title: "Test Event",
|
|
noShowHost: true,
|
|
},
|
|
}),
|
|
]);
|
|
};
|
|
|
|
describe("BookingRepository", () => {
|
|
beforeEach(() => {
|
|
vi.setSystemTime(new Date("2025-05-01T00:00:00.000Z"));
|
|
vi.resetAllMocks();
|
|
});
|
|
describe("getAllBookingsForRoundRobin", () => {
|
|
describe("includeNoShowInRRCalculation", () => {
|
|
it("it should not include bookings where the attendee is a no show", async () => {
|
|
await createAttendeeNoShowTestBookings();
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date(),
|
|
endDate: new Date(),
|
|
includeNoShowInRRCalculation: false,
|
|
virtualQueuesData: null,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(1);
|
|
});
|
|
it("it should include bookings where the attendee is a no show", async () => {
|
|
await createAttendeeNoShowTestBookings();
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date(),
|
|
endDate: new Date(),
|
|
includeNoShowInRRCalculation: true,
|
|
virtualQueuesData: null,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(2);
|
|
});
|
|
it("it should not include bookings where the host is a no show", async () => {
|
|
await createHostNoShowTestBookings();
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date(),
|
|
endDate: new Date(),
|
|
includeNoShowInRRCalculation: false,
|
|
virtualQueuesData: null,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(1);
|
|
});
|
|
it("it should include bookings where the host is a no show", async () => {
|
|
await createHostNoShowTestBookings();
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date(),
|
|
endDate: new Date(),
|
|
includeNoShowInRRCalculation: true,
|
|
virtualQueuesData: null,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(2);
|
|
});
|
|
it("it should not include bookings where the host or an attendee is a no show", async () => {
|
|
await createHostNoShowTestBookings();
|
|
await createAttendeeNoShowTestBookings();
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date(),
|
|
endDate: new Date(),
|
|
includeNoShowInRRCalculation: false,
|
|
virtualQueuesData: null,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(2);
|
|
});
|
|
it("it should include bookings where the host or an attendee is a no show", async () => {
|
|
await createHostNoShowTestBookings();
|
|
await createAttendeeNoShowTestBookings();
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date(),
|
|
endDate: new Date(),
|
|
includeNoShowInRRCalculation: true,
|
|
virtualQueuesData: null,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(4);
|
|
});
|
|
});
|
|
it("should use start time as timestamp basis for the booking count", async () => {
|
|
await Promise.all([
|
|
prismaMock.booking.create({
|
|
data: {
|
|
userId: 1,
|
|
uid: "booking_may",
|
|
eventTypeId: 1,
|
|
status: BookingStatus.ACCEPTED,
|
|
attendees: {
|
|
create: {
|
|
email: "test1@example.com",
|
|
noShow: false,
|
|
name: "Test 1",
|
|
timeZone: "America/Toronto",
|
|
},
|
|
},
|
|
startTime: new Date("2025-05-26T00:00:00.000Z"),
|
|
endTime: new Date("2025-05-26T01:00:00.000Z"),
|
|
createdAt: new Date("2025-05-03T00:00:00.000Z"),
|
|
title: "Test Event",
|
|
},
|
|
}),
|
|
prismaMock.booking.create({
|
|
data: {
|
|
userId: 1,
|
|
uid: "booking_june",
|
|
eventTypeId: 1,
|
|
status: BookingStatus.ACCEPTED,
|
|
attendees: {
|
|
create: {
|
|
email: "test1@example.com",
|
|
noShow: true,
|
|
name: "Test 1",
|
|
timeZone: "America/Toronto",
|
|
},
|
|
},
|
|
startTime: new Date("2025-06-26T00:00:00.000Z"),
|
|
endTime: new Date("2025-06-26T01:00:00.000Z"),
|
|
createdAt: new Date("2025-05-03T00:00:00.000Z"),
|
|
title: "Test Event",
|
|
},
|
|
}),
|
|
]);
|
|
|
|
const bookingRepo = new BookingRepository(prismaMock);
|
|
const bookings = await bookingRepo.getAllBookingsForRoundRobin({
|
|
users: [{ id: 1, email: "organizer1@example.com" }],
|
|
eventTypeId: 1,
|
|
startDate: new Date("2025-06-01T00:00:00.000Z"),
|
|
endDate: new Date("2025-06-30T23:59:00.000Z"),
|
|
includeNoShowInRRCalculation: true,
|
|
virtualQueuesData: null,
|
|
rrTimestampBasis: RRTimestampBasis.START_TIME,
|
|
});
|
|
|
|
expect(bookings).toHaveLength(1);
|
|
expect(bookings[0].startTime.toISOString()).toBe(new Date("2025-06-26T00:00:00.000Z").toISOString());
|
|
});
|
|
});
|
|
});
|