Files
calendar/packages/lib/server/service/__tests__/BookingWebhookFactory.test.ts
T
Benny JooGitHubbenny@cal.com <sldisek783@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

324 lines
10 KiB
TypeScript

import { describe, it, expect } from "vitest";
import type { Person } from "@calcom/types/Calendar";
import { BookingWebhookFactory } from "../BookingWebhookFactory";
const createTestOrganizer = (overrides?: Partial<Person>): Person => ({
email: "organizer@example.com",
name: "Test Organizer",
timeZone: "UTC",
language: { locale: "en", translate: (() => "") as any },
...overrides,
});
const createTestAttendee = (overrides?: Partial<Person>): Person => ({
email: "attendee@example.com",
name: "Test Attendee",
timeZone: "UTC",
language: { locale: "en", translate: (() => "") as any },
...overrides,
});
const createTestBooking = (overrides?: Record<string, any>) => ({
id: 12345,
uid: "test-uid-123",
title: "Test Event",
description: "Test Description",
startTime: new Date("2025-01-24T10:00:00Z"),
endTime: new Date("2025-01-24T11:00:00Z"),
location: "https://meet.example.com",
customInputs: { field1: "value1" },
responses: { name: { value: "Test User" } },
userFieldsResponses: { company: { value: "Test Corp" } },
smsReminderNumber: "+1234567890",
iCalUID: "ical-uid-123",
...overrides,
});
describe("BookingWebhookFactory", () => {
describe("createCancelledEventPayload", () => {
it("should create a basic cancelled event payload with required fields", () => {
const factory = new BookingWebhookFactory();
const booking = createTestBooking();
const organizer = createTestOrganizer();
const attendees = [createTestAttendee()];
const payload = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: booking.title,
eventSlug: "test-event",
description: booking.description,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: booking.location,
customInputs: booking.customInputs,
responses: booking.responses,
userFieldsResponses: booking.userFieldsResponses,
smsReminderNumber: booking.smsReminderNumber,
iCalUID: booking.iCalUID,
organizer,
attendees,
destinationCalendar: null,
cancelledBy: "test@example.com",
cancellationReason: "User requested",
});
expect(payload.bookingId).toBe(12345);
expect(payload.uid).toBe("test-uid-123");
expect(payload.title).toBe("Test Event");
expect(payload.description).toBe("Test Description");
expect(payload.organizer).toEqual(organizer);
expect(payload.attendees).toEqual(attendees);
expect(payload.type).toBe("test-event");
expect(payload.startTime).toBe(booking.startTime.toISOString());
expect(payload.endTime).toBe(booking.endTime.toISOString());
expect(payload.location).toBe("https://meet.example.com");
expect(payload.customInputs).toEqual({ field1: "value1" });
expect(payload.responses).toEqual({ name: { value: "Test User" } });
expect(payload.userFieldsResponses).toEqual({ company: { value: "Test Corp" } });
expect(payload.smsReminderNumber).toBe("+1234567890");
expect(payload.iCalUID).toBe("ical-uid-123");
expect(payload.destinationCalendar).toEqual([]);
expect(payload.cancellationReason).toBe("User requested");
expect(payload.cancelledBy).toBe("test@example.com");
// Verify no extra properties exist
const expectedKeys = [
"bookingId",
"type",
"title",
"description",
"customInputs",
"responses",
"eventTitle",
"eventTypeId",
"length",
"requestReschedule",
"iCalSequence",
"userFieldsResponses",
"startTime",
"endTime",
"organizer",
"attendees",
"uid",
"location",
"destinationCalendar",
"iCalUID",
"smsReminderNumber",
"cancellationReason",
"cancelledBy",
"status",
];
const actualKeys = Object.keys(payload).sort();
expect(actualKeys).toEqual(expectedKeys.sort());
});
it("should handle responses and userFieldsResponses", () => {
const factory = new BookingWebhookFactory();
const booking = createTestBooking();
const responses = { field1: "response1", field2: "response2" };
const userFieldsResponses = { company: "Test Corp", department: "Engineering" };
const payload = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: booking.title,
eventSlug: null,
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses,
userFieldsResponses,
smsReminderNumber: null,
iCalUID: null,
organizer: createTestOrganizer(),
attendees: [createTestAttendee()],
destinationCalendar: null,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payload.responses).toEqual(responses);
expect(payload.userFieldsResponses).toEqual(userFieldsResponses);
});
it("should handle destination calendar as single object", () => {
const factory = new BookingWebhookFactory();
const booking = createTestBooking();
const destinationCalendar = {
id: 1,
integration: "google",
externalId: "cal123",
primaryEmail: null,
userId: null,
eventTypeId: null,
credentialId: null,
createdAt: null,
updatedAt: null,
delegationCredentialId: null,
};
const payload = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: booking.title,
eventSlug: null,
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses: {},
userFieldsResponses: {},
smsReminderNumber: null,
iCalUID: null,
organizer: createTestOrganizer(),
attendees: [],
destinationCalendar,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payload.destinationCalendar).toEqual([destinationCalendar]);
});
it("should handle null destination calendar", () => {
const factory = new BookingWebhookFactory();
const booking = createTestBooking();
const payload = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: booking.title,
eventSlug: null,
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses: {},
userFieldsResponses: {},
smsReminderNumber: null,
iCalUID: null,
organizer: createTestOrganizer(),
attendees: [],
destinationCalendar: null,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payload.destinationCalendar).toEqual([]);
});
it("should handle sms reminder number and iCal UID", () => {
const factory = new BookingWebhookFactory();
const booking = createTestBooking();
const payload = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: booking.title,
eventSlug: null,
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses: {},
userFieldsResponses: {},
smsReminderNumber: "+1234567890",
iCalUID: "ical-uid-123",
organizer: createTestOrganizer(),
attendees: [],
destinationCalendar: null,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payload.smsReminderNumber).toBe("+1234567890");
expect(payload.iCalUID).toBe("ical-uid-123");
});
it("should derive type from eventSlug when available, otherwise from title", () => {
const factory = new BookingWebhookFactory();
const booking = createTestBooking();
// Test with eventSlug provided
const payloadWithSlug = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: "Meeting Title",
eventSlug: "team-standup",
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses: {},
userFieldsResponses: {},
smsReminderNumber: null,
iCalUID: null,
organizer: createTestOrganizer(),
attendees: [],
destinationCalendar: null,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payloadWithSlug.type).toBe("team-standup");
// Test with eventSlug null, should use title
const payloadWithoutSlug = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: "Meeting Title",
eventSlug: null,
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses: {},
userFieldsResponses: {},
smsReminderNumber: null,
iCalUID: null,
organizer: createTestOrganizer(),
attendees: [],
destinationCalendar: null,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payloadWithoutSlug.type).toBe("Meeting Title");
// Test with both eventSlug and title empty
const payloadEmpty = factory.createCancelledEventPayload({
bookingId: booking.id,
uid: booking.uid,
title: "",
eventSlug: "",
description: null,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
location: null,
customInputs: null,
responses: {},
userFieldsResponses: {},
smsReminderNumber: null,
iCalUID: null,
organizer: createTestOrganizer(),
attendees: [],
destinationCalendar: null,
cancelledBy: "user@example.com",
cancellationReason: "Test",
});
expect(payloadEmpty.type).toBe("");
});
});
});