diff --git a/apps/web/pages/booking/[uid].tsx b/apps/web/pages/booking/[uid].tsx
index fe3ab436a9..dc0d14977b 100644
--- a/apps/web/pages/booking/[uid].tsx
+++ b/apps/web/pages/booking/[uid].tsx
@@ -409,7 +409,9 @@ export default function Success(props: SuccessProps) {
>
)}
{reschedule && !!formerTime && (
diff --git a/apps/web/playwright/fixtures/users.ts b/apps/web/playwright/fixtures/users.ts
index acb364e27a..2af6ac85a1 100644
--- a/apps/web/playwright/fixtures/users.ts
+++ b/apps/web/playwright/fixtures/users.ts
@@ -6,9 +6,10 @@ import { hashSync as hash } from "bcryptjs";
import dayjs from "@calcom/dayjs";
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
import { prisma } from "@calcom/prisma";
+import { SchedulingType } from "@calcom/prisma/enums";
import { MembershipRole } from "@calcom/prisma/enums";
-import { selectFirstAvailableTimeSlotNextMonth } from "../lib/testUtils";
+import { selectFirstAvailableTimeSlotNextMonth, teamEventSlug, teamEventTitle } from "../lib/testUtils";
import type { TimeZoneEnum } from "./types";
// Don't import hashPassword from app as that ends up importing next-auth and initializing it before NEXTAUTH_URL can be updated during tests.
@@ -42,7 +43,7 @@ const createTeamAndAddUser = async (
) => {
const team = await prisma.team.create({
data: {
- name: "",
+ name: `user-id-${user.id}'s Team`,
slug: `team-${workerInfo.workerIndex}-${Date.now()}`,
},
});
@@ -68,6 +69,10 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
scenario: {
seedRoutingForms?: boolean;
hasTeam?: true;
+ teammates?: CustomUserOpts[];
+ schedulingType?: SchedulingType;
+ teamEventTitle?: string;
+ teamEventSlug?: string;
} = {}
) => {
const _user = await prisma.user.create({
@@ -212,7 +217,7 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
});
if (scenario.hasTeam) {
const team = await createTeamAndAddUser({ user: { id: user.id, role: "OWNER" } }, workerInfo);
- await prisma.eventType.create({
+ const teamEvent = await prisma.eventType.create({
data: {
team: {
connect: {
@@ -229,12 +234,48 @@ export const createUsersFixture = (page: Page, workerInfo: WorkerInfo) => {
id: _user.id,
},
},
- schedulingType: "COLLECTIVE",
- title: "Team Event - 30min",
- slug: "team-event-30min",
+ schedulingType: scenario.schedulingType ?? SchedulingType.COLLECTIVE,
+ title: scenario.teamEventTitle ?? teamEventTitle,
+ slug: scenario.teamEventSlug ?? teamEventSlug,
length: 30,
},
});
+ if (scenario.teammates) {
+ // Create Teammate users
+ for (const teammateObj of scenario.teammates) {
+ const teamUser = await prisma.user.create({
+ data: createUser(workerInfo, teammateObj),
+ });
+
+ // Add teammates to the team
+ await prisma.membership.create({
+ data: {
+ teamId: team.id,
+ userId: teamUser.id,
+ role: MembershipRole.MEMBER,
+ accepted: true,
+ },
+ });
+
+ // Add teammate to the host list of team event
+ await prisma.host.create({
+ data: {
+ userId: teamUser.id,
+ eventTypeId: teamEvent.id,
+ isFixed: scenario.schedulingType === SchedulingType.COLLECTIVE ? true : false,
+ },
+ });
+
+ const teammateFixture = createUserFixture(
+ await prisma.user.findUniqueOrThrow({
+ where: { id: teamUser.id },
+ include: userIncludes,
+ }),
+ store.page
+ );
+ store.users.push(teammateFixture);
+ }
+ }
}
const userFixture = createUserFixture(user, store.page);
store.users.push(userFixture);
@@ -271,6 +312,7 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
}))!;
return {
id: user.id,
+ name: user.name,
username: user.username,
eventTypes: user.eventTypes,
routingForms: user.routingForms,
@@ -280,6 +322,12 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
logout: async () => {
await page.goto("/auth/logout");
},
+ getTeam: async () => {
+ return prisma.membership.findFirstOrThrow({
+ where: { userId: user.id },
+ include: { team: true },
+ });
+ },
getPaymentCredential: async () => getPaymentCredential(store.page),
setupEventWithPrice: async (eventType: Pick
) =>
setupEventWithPrice(eventType, store.page),
diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts
index ab0e7d92db..4ef9eaaa43 100644
--- a/apps/web/playwright/lib/testUtils.ts
+++ b/apps/web/playwright/lib/testUtils.ts
@@ -18,6 +18,9 @@ type RequestHandler = (opts: RequestHandlerOptions) => void;
export const testEmail = "test@example.com";
export const testName = "Test Testson";
+export const teamEventTitle = "Team Event - 30min";
+export const teamEventSlug = "team-event-30min";
+
export function createHttpServer(opts: { requestHandler?: RequestHandler } = {}) {
const {
requestHandler = ({ res }) => {
diff --git a/apps/web/playwright/teams.e2e.ts b/apps/web/playwright/teams.e2e.ts
index c25b56d73a..8b6e72e254 100644
--- a/apps/web/playwright/teams.e2e.ts
+++ b/apps/web/playwright/teams.e2e.ts
@@ -1,10 +1,17 @@
import { expect } from "@playwright/test";
import { prisma } from "@calcom/prisma";
-import { MembershipRole } from "@calcom/prisma/enums";
+import { SchedulingType } from "@calcom/prisma/enums";
import { test } from "./lib/fixtures";
-import { bookTimeSlot, selectFirstAvailableTimeSlotNextMonth, testName } from "./lib/testUtils";
+import {
+ bookTimeSlot,
+ selectFirstAvailableTimeSlotNextMonth,
+ teamEventSlug,
+ teamEventTitle,
+ testName,
+ todo,
+} from "./lib/testUtils";
test.describe.configure({ mode: "parallel" });
@@ -66,84 +73,63 @@ test.describe("Teams", () => {
});
test("Can create a booking for Collective EventType", async ({ page, users }) => {
const ownerObj = { username: "pro-user", name: "pro-user" };
- const teamMate1Obj = { username: "teammate-1", name: "teammate-1" };
- const teamMate2Obj = { username: "teammate-2", name: "teammate-2" };
+ const teamMatesObj = [
+ { username: "teammate-1", name: "teammate-1" },
+ { username: "teammate-2", name: "teammate-2" },
+ { username: "teammate-3", name: "teammate-3" },
+ { username: "teammate-4", name: "teammate-4" },
+ ];
- const owner = await users.create(ownerObj, { hasTeam: true });
- const teamMate1 = await users.create(teamMate1Obj);
- const teamMate2 = await users.create(teamMate2Obj);
- teamMate1.username, teamMate2.username;
- // TODO: Create a fixture and follow DRY
- const { team } = await prisma.membership.findFirstOrThrow({
- where: { userId: owner.id },
- include: { team: true },
+ const owner = await users.create(ownerObj, {
+ hasTeam: true,
+ teammates: teamMatesObj,
+ schedulingType: SchedulingType.COLLECTIVE,
});
+ const { team } = await owner.getTeam();
- // Add teamMate1 to the team
- await prisma.membership.create({
- data: {
- teamId: team.id,
- userId: teamMate1.id,
- role: MembershipRole.MEMBER,
- accepted: true,
- },
- });
-
- // Add teamMate2 to the team
- await prisma.membership.create({
- data: {
- teamId: team.id,
- userId: teamMate2.id,
- role: MembershipRole.MEMBER,
- accepted: true,
- },
- });
- // No need to remove membership row manually as it will be deleted with the user, at the end of the test.
-
- const { id: eventTypeId } = await prisma.eventType.findFirstOrThrow({
- where: { userId: owner.id, teamId: team.id },
- select: { id: true },
- });
-
- // Assign owner and teammates to the eventtype host list
- await prisma.host.create({
- data: {
- userId: owner.id,
- eventTypeId,
- isFixed: true,
- },
- });
- await prisma.host.create({
- data: {
- userId: teamMate1.id,
- eventTypeId,
- isFixed: true,
- },
- });
- await prisma.host.create({
- data: {
- userId: teamMate2.id,
- eventTypeId,
- isFixed: true,
- },
- });
-
- await page.goto(`/team/${team.slug}/team-event-30min`);
+ await page.goto(`/team/${team.slug}/${teamEventSlug}`);
await selectFirstAvailableTimeSlotNextMonth(page);
await bookTimeSlot(page);
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
- // The first user added to the host list will be the host name
- await expect(page.locator(`[data-testid="host-name-${ownerObj.name}"]`)).toHaveText(ownerObj.name);
+ for (const teammate of teamMatesObj) {
+ await expect(page.getByText(teammate.name, { exact: true })).toBeVisible();
+ }
- // The remaining hosts will be shown as the attendees
- await expect(page.locator(`[data-testid="attendee-name-${teamMate1Obj.name}"]`)).toHaveText(
- teamMate1Obj.name
- );
- await expect(page.locator(`[data-testid="attendee-name-${teamMate2Obj.name}"]`)).toHaveText(
- teamMate2Obj.name
- );
// TODO: Assert whether the user received an email
});
+ test("Can create a booking for Round Robin EventType", async ({ page, users }) => {
+ const ownerObj = { username: "pro-user", name: "pro-user" };
+ const teamMatesObj = [
+ { username: "teammate-1", name: "teammate-1" },
+ { username: "teammate-2", name: "teammate-2" },
+ { username: "teammate-3", name: "teammate-3" },
+ { username: "teammate-4", name: "teammate-4" },
+ ];
+ const owner = await users.create(ownerObj, {
+ hasTeam: true,
+ teammates: teamMatesObj,
+ schedulingType: SchedulingType.ROUND_ROBIN,
+ });
+
+ const { team } = await owner.getTeam();
+
+ await page.goto(`/team/${team.slug}/${teamEventSlug}`);
+ await selectFirstAvailableTimeSlotNextMonth(page);
+ await bookTimeSlot(page);
+ await expect(page.locator("[data-testid=success-page]")).toBeVisible();
+
+ // The person who booked the meeting should be in the attendee list
+ await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
+
+ // The title of the booking
+ const BookingTitle = `${teamEventTitle} between ${team.name} and ${testName}`;
+ await expect(page.locator("[data-testid=booking-title]")).toHaveText(BookingTitle);
+
+ // TODO: Assert one of the teamates from the list to be the host
+ // TODO: Assert whether the user received an email
+ });
+ todo("Reschedule a Collective EventType booking");
+ todo("Reschedule a Round Robin EventType booking");
});