feat: mailhog fixture (#10606)
* feat: mailhog fixture * fix: nodemailer to dispatch emails with e2e env * fix: remove space from email subject * feat: fixture getFirstEventAsOwner * feat: assert email subjects
This commit is contained in:
parent
851a388853
commit
afe180a0ec
|
@ -1,4 +1,7 @@
|
|||
import { expect } from "@playwright/test";
|
||||
import type { Messages } from "mailhog";
|
||||
|
||||
import { randomString } from "@calcom/lib/random";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import {
|
||||
|
@ -10,30 +13,47 @@ import {
|
|||
testName,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
const freeUserObj = { name: `Free-user-${randomString(3)}` };
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
test.afterEach(async ({ users }) => users.deleteAll());
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
test.describe("free user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const free = await users.create();
|
||||
const free = await users.create(freeUserObj);
|
||||
await page.goto(`/${free.username}`);
|
||||
});
|
||||
|
||||
test("cannot book same slot multiple times", async ({ page }) => {
|
||||
test("cannot book same slot multiple times", async ({ page, users, emails }) => {
|
||||
const [user] = users.get();
|
||||
const bookerObj = { email: `testEmail-${randomString(4)}@example.com`, name: "testBooker" };
|
||||
// Click first event type
|
||||
await page.click('[data-testid="event-type-link"]');
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await bookTimeSlot(page);
|
||||
await bookTimeSlot(page, bookerObj);
|
||||
|
||||
// save booking url
|
||||
const bookingUrl: string = page.url();
|
||||
|
||||
// Make sure we're navigated to the success page
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
const { title: eventTitle } = await user.getFirstEventAsOwner();
|
||||
// TODO: follow DRY
|
||||
const emailsOrganiserReceived = await emails.search(user.email, "to");
|
||||
const emailsBookerReceived = await emails.search(bookerObj.email, "to");
|
||||
expect(emailsOrganiserReceived?.total).toBe(1);
|
||||
expect(emailsBookerReceived?.total).toBe(1);
|
||||
|
||||
const [organizerFirstEmail] = (emailsOrganiserReceived as Messages).items;
|
||||
const [bookerFirstEmail] = (emailsBookerReceived as Messages).items;
|
||||
const emailSubject = `${eventTitle} between ${user.name} and ${bookerObj.name}`;
|
||||
|
||||
expect(organizerFirstEmail.subject).toBe(emailSubject);
|
||||
expect(bookerFirstEmail.subject).toBe(emailSubject);
|
||||
|
||||
// return to same time spot booking page
|
||||
await page.goto(bookingUrl);
|
||||
|
||||
// book same time spot again
|
||||
|
|
|
@ -2,6 +2,7 @@ import type { Page, WorkerInfo } from "@playwright/test";
|
|||
import type Prisma from "@prisma/client";
|
||||
import { Prisma as PrismaType } from "@prisma/client";
|
||||
import { hashSync as hash } from "bcryptjs";
|
||||
import type { API } from "mailhog";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
|
@ -116,7 +117,7 @@ const createTeamAndAddUser = async (
|
|||
};
|
||||
|
||||
// creates a user fixture instance and stores the collection
|
||||
export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
|
||||
export const createUsersFixture = (page: Page, emails: API, workerInfo: WorkerInfo) => {
|
||||
const store = { users: [], page } as { users: UserFixture[]; page: typeof page };
|
||||
return {
|
||||
create: async (
|
||||
|
@ -330,7 +331,19 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
|
|||
await page.goto("/auth/logout");
|
||||
},
|
||||
deleteAll: async () => {
|
||||
const emailMessageIds: string[] = [];
|
||||
const ids = store.users.map((u) => u.id);
|
||||
for (const user of store.users) {
|
||||
const emailMessages = await emails.search(user.email);
|
||||
if (emailMessages && emailMessages.count > 0) {
|
||||
emailMessages.items.forEach((item) => {
|
||||
emailMessageIds.push(item.ID);
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const id of emailMessageIds) {
|
||||
await emails.deleteMessage(id);
|
||||
}
|
||||
await prisma.user.deleteMany({ where: { id: { in: ids } } });
|
||||
store.users = [];
|
||||
},
|
||||
|
@ -387,6 +400,12 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
|
|||
include: { team: { select: { children: true, metadata: true, name: true } } },
|
||||
});
|
||||
},
|
||||
getFirstEventAsOwner: async () =>
|
||||
prisma.eventType.findFirstOrThrow({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
}),
|
||||
getFirstTeamEvent: async (teamId: number) => {
|
||||
return prisma.eventType.findFirstOrThrow({
|
||||
where: {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import type { Page } from "@playwright/test";
|
||||
import { test as base } from "@playwright/test";
|
||||
import type { API } from "mailhog";
|
||||
import mailhog from "mailhog";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
|
@ -19,6 +21,7 @@ export interface Fixtures {
|
|||
getActionFiredDetails: ReturnType<typeof createGetActionFiredDetails>;
|
||||
servers: ReturnType<typeof createServersFixture>;
|
||||
prisma: typeof prisma;
|
||||
emails: API;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -40,8 +43,8 @@ declare global {
|
|||
* @see https://playwright.dev/docs/test-fixtures
|
||||
*/
|
||||
export const test = base.extend<Fixtures>({
|
||||
users: async ({ page, context }, use, workerInfo) => {
|
||||
const usersFixture = createUsersFixture(page, workerInfo);
|
||||
users: async ({ page, context, emails }, use, workerInfo) => {
|
||||
const usersFixture = createUsersFixture(page, emails, workerInfo);
|
||||
await use(usersFixture);
|
||||
},
|
||||
bookings: async ({ page }, use) => {
|
||||
|
@ -67,4 +70,8 @@ export const test = base.extend<Fixtures>({
|
|||
prisma: async ({}, use) => {
|
||||
await use(prisma);
|
||||
},
|
||||
emails: async ({}, use) => {
|
||||
const mailhogAPI = mailhog();
|
||||
await use(mailhogAPI);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"jest-diff": "^29.5.0",
|
||||
"jsdom": "^22.0.0",
|
||||
"lint-staged": "^12.5.0",
|
||||
"mailhog": "^4.16.0",
|
||||
"prettier": "^2.8.6",
|
||||
"tsc-absolute": "^1.0.0",
|
||||
"typescript": "^4.9.4",
|
||||
|
|
|
@ -8,10 +8,6 @@ import { getErrorFromUnknown } from "@calcom/lib/errors";
|
|||
import { serverConfig } from "@calcom/lib/serverConfig";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
declare let global: {
|
||||
E2E_EMAILS?: Record<string, unknown>[];
|
||||
};
|
||||
|
||||
export default class BaseEmail {
|
||||
name = "";
|
||||
|
||||
|
@ -37,12 +33,6 @@ export default class BaseEmail {
|
|||
console.warn("Skipped Sending Email due to active Kill Switch");
|
||||
return new Promise((r) => r("Skipped Sending Email due to active Kill Switch"));
|
||||
}
|
||||
if (process.env.NEXT_PUBLIC_IS_E2E) {
|
||||
global.E2E_EMAILS = global.E2E_EMAILS || [];
|
||||
global.E2E_EMAILS.push(this.getNodeMailerPayload());
|
||||
console.log("Skipped Sending Email as NEXT_PUBLIC_IS_E2E==1");
|
||||
return new Promise((r) => r("Skipped sendEmail for E2E"));
|
||||
}
|
||||
|
||||
const payload = this.getNodeMailerPayload();
|
||||
const parseSubject = z.string().safeParse(payload?.subject);
|
||||
|
|
|
@ -80,7 +80,7 @@ export default class OrganizerScheduledEmail extends BaseEmail {
|
|||
},
|
||||
from: `${APP_NAME} <${this.getMailerOptions().from}>`,
|
||||
to: toAddresses.join(","),
|
||||
subject: `${this.newSeat ? this.t("new_attendee") + ":" : ""} ${this.calEvent.title}`,
|
||||
subject: `${this.newSeat ? this.t("new_attendee") + ": " : ""}${this.calEvent.title}`,
|
||||
html: renderEmail("OrganizerScheduledEmail", {
|
||||
calEvent: clonedCalEvent,
|
||||
attendee: this.calEvent.organizer,
|
||||
|
|
Loading…
Reference in New Issue
Block a user