fix: return 400 instead of 500 for invalid email in iCal generation (#27217)
* fix: return 400 instead of 500 for invalid email in iCal generation Co-Authored-By: benny@cal.com <sldisek783@gmail.com> * test: add unit tests for error handling in generateIcsString Co-Authored-By: benny@cal.com <sldisek783@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
6e1070be31
commit
6a532c2271
2 files changed
+97
-2
No files matched your search
@@ -1,6 +1,8 @@
|
||||
import { describe, expect } from "vitest";
|
||||
import { describe, expect, vi } from "vitest";
|
||||
|
||||
import { ORGANIZER_EMAIL_EXEMPT_DOMAINS } from "@calcom/lib/constants";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { ErrorWithCode } from "@calcom/lib/errors";
|
||||
import { buildCalendarEvent, buildPerson } from "@calcom/lib/test/builder";
|
||||
import { buildVideoCallData } from "@calcom/lib/test/builder";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
@@ -166,4 +168,90 @@ describe("generateIcsString", () => {
|
||||
expect(icsString).toEqual(expect.stringContaining(`LOCATION:${event.location}`));
|
||||
});
|
||||
});
|
||||
describe("error handling", () => {
|
||||
test("throws ErrorWithCode.BadRequest when ics library returns ValidationError", async () => {
|
||||
// Mock the ics library to return a ValidationError
|
||||
const ics = await import("ics");
|
||||
const createEventSpy = vi.spyOn(ics, "createEvent");
|
||||
|
||||
// Simulate a Yup ValidationError (which has name: "ValidationError")
|
||||
const validationError = {
|
||||
name: "ValidationError",
|
||||
message: "attendees[0].email must be a valid email",
|
||||
errors: ["attendees[0].email must be a valid email"],
|
||||
};
|
||||
|
||||
createEventSpy.mockReturnValueOnce({
|
||||
error: validationError as unknown as Error,
|
||||
value: undefined,
|
||||
});
|
||||
|
||||
const event = buildCalendarEvent({
|
||||
iCalSequence: 0,
|
||||
attendees: [buildPerson()],
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
generateIcsString({
|
||||
event,
|
||||
status: "CONFIRMED",
|
||||
})
|
||||
).toThrow(ErrorWithCode);
|
||||
|
||||
try {
|
||||
generateIcsString({
|
||||
event,
|
||||
status: "CONFIRMED",
|
||||
});
|
||||
} catch (error) {
|
||||
expect(error).toBeInstanceOf(ErrorWithCode);
|
||||
expect((error as ErrorWithCode).code).toBe(ErrorCode.BadRequest);
|
||||
expect((error as ErrorWithCode).message).toBe("attendees[0].email must be a valid email");
|
||||
}
|
||||
|
||||
createEventSpy.mockRestore();
|
||||
});
|
||||
|
||||
test("re-throws non-ValidationError errors as-is", async () => {
|
||||
const ics = await import("ics");
|
||||
const createEventSpy = vi.spyOn(ics, "createEvent");
|
||||
|
||||
// Simulate a different type of error
|
||||
const genericError = new Error("Some other error");
|
||||
|
||||
createEventSpy.mockReturnValueOnce({
|
||||
error: genericError,
|
||||
value: undefined,
|
||||
});
|
||||
|
||||
const event = buildCalendarEvent({
|
||||
iCalSequence: 0,
|
||||
attendees: [buildPerson()],
|
||||
});
|
||||
|
||||
expect(() =>
|
||||
generateIcsString({
|
||||
event,
|
||||
status: "CONFIRMED",
|
||||
})
|
||||
).toThrow(genericError);
|
||||
|
||||
createEventSpy.mockRestore();
|
||||
});
|
||||
|
||||
test("returns ics string when there is no error", () => {
|
||||
const event = buildCalendarEvent({
|
||||
iCalSequence: 0,
|
||||
attendees: [buildPerson()],
|
||||
});
|
||||
|
||||
const icsString = generateIcsString({
|
||||
event,
|
||||
status: "CONFIRMED",
|
||||
});
|
||||
|
||||
expect(icsString).toBeDefined();
|
||||
expect(typeof icsString).toBe("string");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,8 @@ import { RRule } from "rrule";
|
||||
import { getRichDescription } from "@calcom/lib/CalEventParser";
|
||||
import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser";
|
||||
import { ORGANIZER_EMAIL_EXEMPT_DOMAINS } from "@calcom/lib/constants";
|
||||
import { ErrorCode } from "@calcom/lib/errorCodes";
|
||||
import { ErrorWithCode } from "@calcom/lib/errors";
|
||||
import type { CalendarEvent, Person } from "@calcom/types/Calendar";
|
||||
|
||||
export enum BookingAction {
|
||||
@@ -55,7 +57,7 @@ const generateIcsString = ({
|
||||
status: EventStatus;
|
||||
partstat?: ParticipationStatus;
|
||||
t?: TFunction;
|
||||
}) => {
|
||||
}): string | undefined => {
|
||||
const location = getVideoCallUrlFromCalEvent(event) || event.location;
|
||||
|
||||
// Taking care of recurrence rule
|
||||
@@ -111,6 +113,11 @@ const generateIcsString = ({
|
||||
busyStatus: "BUSY",
|
||||
});
|
||||
if (icsEvent.error) {
|
||||
// The ics library throws Yup ValidationError objects (not Error instances) for invalid data like invalid email formats.
|
||||
// Convert these to ErrorWithCode.BadRequest so they return 400 instead of falling through to a generic 500.
|
||||
if (icsEvent.error.name === "ValidationError") {
|
||||
throw new ErrorWithCode(ErrorCode.BadRequest, icsEvent.error.message);
|
||||
}
|
||||
throw icsEvent.error;
|
||||
}
|
||||
return icsEvent.value;
|
||||
|
||||
Reference in new issue
Block a user