Files

240 lines
7.1 KiB
TypeScript

import prisma from "@calcom/prisma";
import kysely from "@calcom/kysely";
import type { Booking, EventType, User } from "@calcom/prisma/client";
import { BookingStatus } from "@calcom/prisma/enums";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { getBookings } from "./get.handler";
let user1: User;
let user2: User;
let eventType1: EventType;
let booking1: Booking;
let booking2: Booking;
let booking3: Booking;
const timestamp = Date.now();
describe("getBookings - integration", () => {
beforeAll(async () => {
user1 = await prisma.user.create({
data: {
username: `getbookings-user1-${timestamp}`,
email: `getbookings-user1-${timestamp}@example.com`,
name: "GetBookings User 1",
},
});
user2 = await prisma.user.create({
data: {
username: `getbookings-user2-${timestamp}`,
email: `getbookings-user2-${timestamp}@example.com`,
name: "GetBookings User 2",
},
});
eventType1 = await prisma.eventType.create({
data: {
title: `GetBookings Event ${timestamp}`,
slug: `getbookings-event-${timestamp}`,
length: 30,
userId: user1.id,
},
});
const futureDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
const futureDate2 = new Date(Date.now() + 8 * 24 * 60 * 60 * 1000);
const futureDate3 = new Date(Date.now() + 9 * 24 * 60 * 60 * 1000);
booking1 = await prisma.booking.create({
data: {
uid: `getbookings-booking1-${timestamp}`,
title: "Booking 1",
startTime: futureDate,
endTime: new Date(futureDate.getTime() + 30 * 60 * 1000),
userId: user1.id,
eventTypeId: eventType1.id,
status: BookingStatus.ACCEPTED,
attendees: {
create: {
email: user2.email,
name: user2.name ?? "User 2",
timeZone: "UTC",
},
},
},
});
booking2 = await prisma.booking.create({
data: {
uid: `getbookings-booking2-${timestamp}`,
title: "Booking 2",
startTime: futureDate2,
endTime: new Date(futureDate2.getTime() + 30 * 60 * 1000),
userId: user1.id,
eventTypeId: eventType1.id,
status: BookingStatus.ACCEPTED,
attendees: {
create: {
email: `getbookings-external-${timestamp}@example.com`,
name: "External Attendee",
timeZone: "UTC",
},
},
},
});
booking3 = await prisma.booking.create({
data: {
uid: `getbookings-booking3-${timestamp}`,
title: "Booking 3",
startTime: futureDate3,
endTime: new Date(futureDate3.getTime() + 30 * 60 * 1000),
userId: user2.id,
eventTypeId: eventType1.id,
status: BookingStatus.ACCEPTED,
attendees: {
create: {
email: user1.email,
name: user1.name ?? "User 1",
timeZone: "UTC",
},
},
},
});
});
afterAll(async () => {
try {
const bookingIds = [booking1?.id, booking2?.id, booking3?.id].filter(Boolean);
if (bookingIds.length > 0) {
await prisma.attendee.deleteMany({ where: { bookingId: { in: bookingIds } } });
await prisma.booking.deleteMany({ where: { id: { in: bookingIds } } });
}
const eventTypeIds = [eventType1?.id].filter(Boolean);
if (eventTypeIds.length > 0) {
await prisma.eventType.deleteMany({ where: { id: { in: eventTypeIds } } });
}
const userIds = [user1?.id, user2?.id].filter(Boolean);
if (userIds.length > 0) {
await prisma.user.deleteMany({ where: { id: { in: userIds } } });
}
} catch (error) {
console.warn("Test cleanup failed:", error);
}
});
it("should return bookings created by the user", async () => {
const result = await getBookings({
user: { id: user1.id, email: user1.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 50,
skip: 0,
});
const bookingIds = result.bookings.map((b) => b.id);
expect(bookingIds).toContain(booking1.id);
expect(bookingIds).toContain(booking2.id);
});
it("should return bookings where user is an attendee", async () => {
const result = await getBookings({
user: { id: user1.id, email: user1.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 50,
skip: 0,
});
const bookingIds = result.bookings.map((b) => b.id);
expect(bookingIds).toContain(booking3.id);
});
it("should not return duplicate bookings when user is both creator and attendee matches", async () => {
const result = await getBookings({
user: { id: user1.id, email: user1.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 50,
skip: 0,
});
const testBookingIds = [booking1.id, booking2.id, booking3.id];
const relevantBookingIds = result.bookings.map((b) => b.id).filter((id) => testBookingIds.includes(id));
const uniqueIds = new Set(relevantBookingIds);
expect(relevantBookingIds.length).toBe(uniqueIds.size);
});
it("should return correct totalCount without duplicates", async () => {
const resultUser1 = await getBookings({
user: { id: user1.id, email: user1.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 50,
skip: 0,
});
const expectedBookingIds = [booking1.id, booking2.id, booking3.id];
const returnedIds = resultUser1.bookings.map((b) => b.id);
for (const id of expectedBookingIds) {
expect(returnedIds).toContain(id);
}
expect(resultUser1.totalCount).toBe(resultUser1.bookings.length);
});
it("should respect pagination with correct ordering", async () => {
const page1 = await getBookings({
user: { id: user1.id, email: user1.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 1,
skip: 0,
});
const page2 = await getBookings({
user: { id: user1.id, email: user1.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 1,
skip: 1,
});
expect(page1.bookings.length).toBe(1);
expect(page2.bookings.length).toBe(1);
expect(page1.bookings[0].id).not.toBe(page2.bookings[0].id);
const date1 = new Date(page1.bookings[0].startTime);
const date2 = new Date(page2.bookings[0].startTime);
expect(date1.getTime()).toBeLessThanOrEqual(date2.getTime());
});
it("should return bookings for user2 including those where user2 is an attendee", async () => {
const result = await getBookings({
user: { id: user2.id, email: user2.email, orgId: null },
prisma,
kysely,
bookingListingByStatus: ["upcoming"],
filters: {},
take: 50,
skip: 0,
});
const bookingIds = result.bookings.map((b) => b.id);
expect(bookingIds).toContain(booking3.id);
expect(bookingIds).toContain(booking1.id);
});
});