Files
calendar/packages/lib/server/repository/booking.test.ts
T
devin-ai-integration[bot]GitHubmorgan@cal.com <morgan@cal.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>morgan@cal.com <morgan@cal.com>
c316721051 refactor: convert BookingRepository to use dependency injection pattern (#22389)
* 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>
2025-07-10 18:06:57 +00:00

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