Files
calendar/packages/features/bookings/lib/handleNewBooking/getBookingData.test.ts
T
Anik Dhabal BabuandGitHub c183223b8d fix: prevent attendee phone number from overriding organizer default app location (#27620)
* se organizer default app

* nit

* Add tests: packages/features/bookings/lib/handleNewBooking/getBookingData.test.ts

Generated by Paragon from proposal for PR #27620
2026-02-04 16:55:17 +00:00

221 lines
6.2 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
import { z } from "zod";
import { OrganizerDefaultConferencingAppType } from "@calcom/app-store/locations";
import { getBookingData } from "./getBookingData";
import type { getEventTypeResponse } from "./getEventTypesFromDB";
// Mock the dependencies
vi.mock("@calcom/features/bookings/lib/getCalEventResponses", () => ({
getCalEventResponses: vi.fn().mockReturnValue({
userFieldsResponses: {},
responses: {},
}),
}));
vi.mock("@calcom/lib/sentryWrapper", () => ({
withReporting: (fn: Function) => fn,
}));
const createMockEventType = (overrides: Partial<getEventTypeResponse> = {}): getEventTypeResponse => {
return {
id: 1,
length: 30,
bookingFields: [
{ name: "name", type: "name", required: true },
{ name: "email", type: "email", required: true },
{ name: "location", type: "radioInput", required: false },
],
customInputs: [],
seatsPerTimeSlot: null,
...overrides,
} as getEventTypeResponse;
};
const createMockSchema = () => {
return z.object({
eventTypeId: z.number(),
start: z.string(),
end: z.string().optional(),
timeZone: z.string(),
language: z.string(),
metadata: z.record(z.string()),
responses: z.object({
name: z.string(),
email: z.string(),
location: z
.object({
value: z.string(),
optionValue: z.string().optional(),
})
.optional(),
attendeePhoneNumber: z.string().optional(),
guests: z.array(z.string()).optional(),
smsReminderNumber: z.string().optional(),
notes: z.string().optional(),
rescheduleReason: z.string().optional(),
}),
});
};
describe("getBookingData", () => {
beforeEach(() => {
vi.clearAllMocks();
});
describe("location extraction", () => {
it("should ignore optionValue when location type is OrganizerDefaultConferencingAppType", async () => {
const mockEventType = createMockEventType();
const schema = createMockSchema();
const reqBody = {
eventTypeId: 1,
start: "2024-01-15T10:00:00.000Z",
end: "2024-01-15T10:30:00.000Z",
timeZone: "America/New_York",
language: "en",
metadata: {},
responses: {
name: "Test User",
email: "test@example.com",
location: {
value: OrganizerDefaultConferencingAppType, // "conferencing"
optionValue: "+15551234567", // Phone number that should be ignored
},
},
};
const result = await getBookingData({
reqBody,
eventType: mockEventType,
schema,
});
// The location should be the conferencing type, NOT the phone number
expect(result.location).toBe(OrganizerDefaultConferencingAppType);
expect(result.location).not.toBe("+15551234567");
});
it("should use optionValue for non-OrganizerDefaultConferencingAppType locations", async () => {
const mockEventType = createMockEventType();
const schema = createMockSchema();
const reqBody = {
eventTypeId: 1,
start: "2024-01-15T10:00:00.000Z",
end: "2024-01-15T10:30:00.000Z",
timeZone: "America/New_York",
language: "en",
metadata: {},
responses: {
name: "Test User",
email: "test@example.com",
location: {
value: "phone",
optionValue: "+15551234567",
},
},
};
const result = await getBookingData({
reqBody,
eventType: mockEventType,
schema,
});
// For phone location type, optionValue should be used
expect(result.location).toBe("+15551234567");
});
it("should fall back to value when optionValue is empty for non-conferencing locations", async () => {
const mockEventType = createMockEventType();
const schema = createMockSchema();
const reqBody = {
eventTypeId: 1,
start: "2024-01-15T10:00:00.000Z",
end: "2024-01-15T10:30:00.000Z",
timeZone: "America/New_York",
language: "en",
metadata: {},
responses: {
name: "Test User",
email: "test@example.com",
location: {
value: "integrations:daily",
optionValue: "",
},
},
};
const result = await getBookingData({
reqBody,
eventType: mockEventType,
schema,
});
// Should fall back to value when optionValue is empty
expect(result.location).toBe("integrations:daily");
});
it("should return empty string when location is not provided", async () => {
const mockEventType = createMockEventType();
const schema = createMockSchema();
const reqBody = {
eventTypeId: 1,
start: "2024-01-15T10:00:00.000Z",
end: "2024-01-15T10:30:00.000Z",
timeZone: "America/New_York",
language: "en",
metadata: {},
responses: {
name: "Test User",
email: "test@example.com",
// No location provided
},
};
const result = await getBookingData({
reqBody,
eventType: mockEventType,
schema,
});
expect(result.location).toBe("");
});
it("should use OrganizerDefaultConferencingAppType value even when optionValue contains meeting URL", async () => {
const mockEventType = createMockEventType();
const schema = createMockSchema();
const reqBody = {
eventTypeId: 1,
start: "2024-01-15T10:00:00.000Z",
end: "2024-01-15T10:30:00.000Z",
timeZone: "America/New_York",
language: "en",
metadata: {},
responses: {
name: "Test User",
email: "test@example.com",
location: {
value: OrganizerDefaultConferencingAppType,
optionValue: "https://meet.google.com/abc-defg-hij", // Should be ignored
},
},
};
const result = await getBookingData({
reqBody,
eventType: mockEventType,
schema,
});
// The location should be the conferencing type, NOT the URL
expect(result.location).toBe(OrganizerDefaultConferencingAppType);
});
});
});