Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add unit tests for sms sending #14737

Merged
merged 15 commits into from May 2, 2024
11 changes: 11 additions & 0 deletions apps/web/test/fixtures/fixtures.ts
Expand Up @@ -2,19 +2,30 @@
import { test as base } from "vitest";

import { getTestEmails } from "@calcom/lib/testEmails";
import { getTestSMS } from "@calcom/lib/testSMS";

export interface Fixtures {
emails: ReturnType<typeof getEmailsFixture>;
sms: ReturnType<typeof getSMSFixture>;
}

export const test = base.extend<Fixtures>({
emails: async ({}, use) => {
await use(getEmailsFixture());
},
sms: async ({}, use) => {
await use(getSMSFixture());
},
});

function getEmailsFixture() {
return {
get: getTestEmails,
};
}

function getSMSFixture() {
return {
get: getTestSMS,
};
}
5 changes: 4 additions & 1 deletion apps/web/test/utils/bookingScenario/bookingScenario.ts
Expand Up @@ -19,7 +19,7 @@
import { safeStringify } from "@calcom/lib/safeStringify";
import { ProfileRepository } from "@calcom/lib/server/repository/profile";
import type { WorkflowActions, WorkflowTemplates, WorkflowTriggerEvents } from "@calcom/prisma/client";
import type { SchedulingType } from "@calcom/prisma/enums";
import type { SchedulingType, SMSLockState } from "@calcom/prisma/enums";
import type { BookingStatus } from "@calcom/prisma/enums";
import type { teamMetadataSchema } from "@calcom/prisma/zod-utils";
import type { userMetadataType } from "@calcom/prisma/zod-utils";
Expand Down Expand Up @@ -202,10 +202,10 @@
});
const allEventTypes = await prismock.eventType.findMany({
include: {
users: true,

Check warning on line 205 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L205

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
workflows: true,

Check warning on line 206 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L206

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
destinationCalendar: true,

Check warning on line 207 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L207

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
schedule: true,

Check warning on line 208 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L208

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
},
});

Expand Down Expand Up @@ -344,8 +344,8 @@
JSON.stringify({
bookings: await prismock.booking.findMany({
include: {
references: true,

Check warning on line 347 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L347

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
attendees: true,

Check warning on line 348 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L348

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
},
}),
})
Expand Down Expand Up @@ -476,15 +476,15 @@
safeStringify({
allUsers: await prismock.user.findMany({
include: {
credentials: true,

Check warning on line 479 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L479

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
teams: true,

Check warning on line 480 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L480

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
profiles: true,

Check warning on line 481 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L481

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
schedules: {
include: {
availability: true,

Check warning on line 484 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L484

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
},
},
destinationCalendar: true,

Check warning on line 487 in apps/web/test/utils/bookingScenario/bookingScenario.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/bookingScenario.ts#L487

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
},
}),
})
Expand Down Expand Up @@ -952,6 +952,7 @@
teams,
organizationId,
metadata,
smsLockState,
}: {
name: string;
email: string;
Expand All @@ -965,6 +966,7 @@
weekStart?: WeekDays;
teams?: InputUser["teams"];
metadata?: userMetadataType;
smsLockState?: SMSLockState;
}) {
return {
...TestData.users.example,
Expand All @@ -981,6 +983,7 @@
organizationId,
profiles: [],
metadata,
smsLockState,
};
}

Expand Down
68 changes: 51 additions & 17 deletions apps/web/test/utils/bookingScenario/expects.ts
Expand Up @@ -170,7 +170,7 @@
pass: false,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
actual: icsObject[icsKey].uid!,

Check warning on line 173 in apps/web/test/utils/bookingScenario/expects.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/expects.ts#L173

[@typescript-eslint/no-non-null-assertion] Forbidden non-null assertion.
expected: expectedEmail.ics?.iCalUID,
message: () => `Expected ICS UID ${isNot ? "is" : "isn't"} present in actual`,
};
Expand Down Expand Up @@ -307,38 +307,72 @@

export function expectWorkflowToBeTriggered({
emails,
organizer,
destinationEmail,
emailsToReceive,
}: {
emails: Fixtures["emails"];
organizer: { email: string; name: string; timeZone: string };
destinationEmail?: string;
emailsToReceive: string[];
}) {
const subjectPattern = /^Reminder: /i;
expect(emails.get()).toEqual(
expect.arrayContaining([
expect.objectContaining({
subject: expect.stringMatching(subjectPattern),
to: destinationEmail ?? organizer.email,
}),
])
);
emailsToReceive.forEach((email) => {
expect(emails.get()).toEqual(
expect.arrayContaining([
expect.objectContaining({
subject: expect.stringMatching(subjectPattern),
to: email,
}),
])
);
});
}

export function expectWorkflowToBeNotTriggered({
emails,
organizer,
emailsToReceive,
}: {
emails: Fixtures["emails"];
organizer: { email: string; name: string; timeZone: string };
emailsToReceive: string[];
}) {
const subjectPattern = /^Reminder: /i;

expect(emails.get()).not.toEqual(
emailsToReceive.forEach((email) => {
expect(emails.get()).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
subject: expect.stringMatching(subjectPattern),
to: email,
}),
])
);
});
}

export function expectSMSWorkflowToBeTriggered({
sms,
toNumber,
}: {
sms: Fixtures["sms"];
toNumber: string;
}) {
expect(sms.get()).toEqual(
expect.arrayContaining([
expect.objectContaining({
to: toNumber,
}),
])
);
}

export function expectSMSWorkflowToBeNotTriggered({
sms,
toNumber,
}: {
sms: Fixtures["sms"];
toNumber: string;
}) {
expect(sms.get()).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
subject: expect.stringMatching(subjectPattern),
to: organizer.email,
to: toNumber,
}),
])
);
Expand All @@ -352,7 +386,7 @@
uid: booking.uid,
},
include: {
references: true,

Check warning on line 389 in apps/web/test/utils/bookingScenario/expects.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/expects.ts#L389

[@calcom/eslint/no-prisma-include-true] Do not pass argument object with include: { AnyPropertyName: true } to prisma methods
},
});

Expand Down Expand Up @@ -735,7 +769,7 @@
booker,
booking,
bookNewTimePath,
organizer,

Check warning on line 772 in apps/web/test/utils/bookingScenario/expects.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

apps/web/test/utils/bookingScenario/expects.ts#L772

[@typescript-eslint/no-unused-vars] 'organizer' is defined but never used. Allowed unused args must match /^_/u.
}: {
emails: Fixtures["emails"];
organizer: ReturnType<typeof getOrganizer>;
Expand Down
Expand Up @@ -30,6 +30,7 @@ export function getMockRequestDataForBooking({
email: string;
name: string;
location: { optionValue: ""; value: string };
smsReminderNumber?: string;
};
};
}) {
Expand Down
6 changes: 4 additions & 2 deletions apps/web/test/utils/bookingScenario/test.ts
Expand Up @@ -15,7 +15,7 @@ const _testWithAndWithoutOrg = (
const t = mode === "only" ? test.only : mode === "skip" ? test.skip : test;
t(
`${description} - With org`,
async ({ emails, meta, task, onTestFailed, expect, skip }) => {
async ({ emails, sms, meta, task, onTestFailed, expect, skip }) => {
const org = await createOrganization({
name: "Test Org",
slug: "testorg",
Expand All @@ -27,6 +27,7 @@ const _testWithAndWithoutOrg = (
onTestFailed,
expect,
emails,
sms,
skip,
org: {
organization: org,
Expand All @@ -39,9 +40,10 @@ const _testWithAndWithoutOrg = (

t(
`${description}`,
async ({ emails, meta, task, onTestFailed, expect, skip }) => {
async ({ emails, sms, meta, task, onTestFailed, expect, skip }) => {
await fn({
emails,
sms,
meta,
task,
onTestFailed,
Expand Down
Expand Up @@ -42,6 +42,7 @@ import {
import { createMockNextJsRequest } from "@calcom/web/test/utils/bookingScenario/createMockNextJsRequest";
import {
expectWorkflowToBeTriggered,
expectWorkflowToBeNotTriggered,
expectSuccessfulBookingCreationEmails,
expectBookingToBeInDatabase,
expectAwaitingPaymentEmails,
Expand All @@ -51,7 +52,6 @@ import {
expectBookingPaymentIntiatedWebhookToHaveBeenFired,
expectBrokenIntegrationEmails,
expectSuccessfulCalendarEventCreationInCalendar,
expectWorkflowToBeNotTriggered,
expectICalUIDAsString,
} from "@calcom/web/test/utils/bookingScenario/expects";
import { getMockRequestDataForBooking } from "@calcom/web/test/utils/bookingScenario/getMockRequestDataForBooking";
Expand Down Expand Up @@ -215,9 +215,8 @@ describe("handleNewBooking", () => {
});

expectWorkflowToBeTriggered({
organizer,
emailsToReceive: [organizerDestinationCalendarEmailOnEventType],
emails,
destinationEmail: organizerDestinationCalendarEmailOnEventType,
});
expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
calendarId: "event-type-1@google-calendar.com",
Expand Down Expand Up @@ -379,7 +378,7 @@ describe("handleNewBooking", () => {
iCalUID: createdBooking.iCalUID,
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });
expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
videoCallUrl: "http://mock-dailyvideo.example.com/meeting-1",
// We won't be sending evt.destinationCalendar in this case.
Expand Down Expand Up @@ -541,7 +540,7 @@ describe("handleNewBooking", () => {
iCalUID: createdBooking.iCalUID,
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });
expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
calendarId: "organizer@google-calendar.com",
videoCallUrl: "http://mock-dailyvideo.example.com/meeting-1",
Expand Down Expand Up @@ -675,7 +674,7 @@ describe("handleNewBooking", () => {
],
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

// FIXME: We should send Broken Integration emails on calendar event creation failure
// expectCalendarEventCreationFailureEmails({ booker, organizer, emails });
Expand Down Expand Up @@ -825,7 +824,7 @@ describe("handleNewBooking", () => {
iCalUID: createdBooking.iCalUID,
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
calendarId: "organizer@google-calendar.com",
Expand Down Expand Up @@ -982,7 +981,7 @@ describe("handleNewBooking", () => {
],
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });
expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
calendarId: "organizer@google-calendar.com",
videoCallUrl: "http://mock-dailyvideo.example.com/meeting-1",
Expand Down Expand Up @@ -1511,7 +1510,7 @@ describe("handleNewBooking", () => {
status: BookingStatus.PENDING,
});

expectWorkflowToBeNotTriggered({ organizer, emails });
expectWorkflowToBeNotTriggered({ emailsToReceive: [organizer.email], emails });

expectBookingRequestedEmails({
booker,
Expand Down Expand Up @@ -1636,7 +1635,7 @@ describe("handleNewBooking", () => {
}),
});

expectWorkflowToBeNotTriggered({ organizer, emails });
expectWorkflowToBeNotTriggered({ emailsToReceive: [organizer.email], emails });

expectBookingRequestedEmails({
booker,
Expand Down Expand Up @@ -1764,7 +1763,7 @@ describe("handleNewBooking", () => {
iCalUID: createdBooking.iCalUID,
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);

Expand Down Expand Up @@ -1897,7 +1896,7 @@ describe("handleNewBooking", () => {
iCalUID: createdBooking.iCalUID,
});

expectWorkflowToBeNotTriggered({ organizer, emails });
expectWorkflowToBeNotTriggered({ emailsToReceive: [organizer.email], emails });

expectBookingRequestedEmails({ booker, organizer, emails });

Expand Down Expand Up @@ -2076,7 +2075,7 @@ describe("handleNewBooking", () => {
iCalUID: createdBooking.iCalUID,
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);

Expand Down Expand Up @@ -2220,7 +2219,7 @@ describe("handleNewBooking", () => {
}),
});

expectWorkflowToBeNotTriggered({ organizer, emails });
expectWorkflowToBeNotTriggered({ emailsToReceive: [organizer.email], emails });

expectAwaitingPaymentEmails({ organizer, booker, emails });

Expand All @@ -2244,7 +2243,7 @@ describe("handleNewBooking", () => {
status: BookingStatus.ACCEPTED,
});

expectWorkflowToBeTriggered({ organizer, emails });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectBookingCreatedWebhookToHaveBeenFired({
booker,
Expand Down Expand Up @@ -2374,7 +2373,7 @@ describe("handleNewBooking", () => {
status: BookingStatus.PENDING,
});

expectWorkflowToBeNotTriggered({ organizer, emails });
expectWorkflowToBeNotTriggered({ emailsToReceive: [organizer.email], emails });

expectAwaitingPaymentEmails({ organizer, booker, emails });
expectBookingPaymentIntiatedWebhookToHaveBeenFired({
Expand Down
Expand Up @@ -240,7 +240,7 @@ describe("handleNewBooking", () => {
],
},
});
expectWorkflowToBeTriggered({ emails, organizer });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectSuccessfulVideoMeetingUpdationInCalendar(videoMock, {
calEvent: {
Expand Down Expand Up @@ -459,7 +459,7 @@ describe("handleNewBooking", () => {
},
});

expectWorkflowToBeTriggered({ emails, organizer });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectSuccessfulVideoMeetingUpdationInCalendar(videoMock, {
calEvent: {
Expand Down Expand Up @@ -656,7 +656,7 @@ describe("handleNewBooking", () => {
},
});

expectWorkflowToBeTriggered({ emails, organizer });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

// FIXME: We should send Broken Integration emails on calendar event updation failure
// expectBrokenIntegrationEmails({ booker, organizer, emails });
Expand Down Expand Up @@ -850,7 +850,7 @@ describe("handleNewBooking", () => {
},
});

expectWorkflowToBeTriggered({ emails, organizer });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectBookingRequestedEmails({
booker,
Expand Down Expand Up @@ -1085,7 +1085,7 @@ describe("handleNewBooking", () => {
},
});

expectWorkflowToBeTriggered({ emails, organizer });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectSuccessfulVideoMeetingUpdationInCalendar(videoMock, {
calEvent: {
Expand Down Expand Up @@ -1312,7 +1312,7 @@ describe("handleNewBooking", () => {
},
});

//expectWorkflowToBeTriggered({emails, organizer});
//expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectBookingRequestedEmails({
booker,
Expand Down Expand Up @@ -1559,7 +1559,7 @@ describe("handleNewBooking", () => {
},
});

expectWorkflowToBeTriggered({ emails, organizer });
expectWorkflowToBeTriggered({ emailsToReceive: [organizer.email], emails });

expectSuccessfulVideoMeetingUpdationInCalendar(videoMock, {
calEvent: {
Expand Down