From abe98be561661ccd2af6f53e2e66784bf762d5e2 Mon Sep 17 00:00:00 2001 From: Anshuman Pandey <54475686+pandeymangg@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:34:25 +0530 Subject: [PATCH] feat: adds e2e test for invite functionality (#1846) --- .../[environmentId]/components/Navigation.tsx | 4 +- .../members/components/AddMemberModal.tsx | 12 +- .../EditMemberships/MemberActions.tsx | 8 +- .../EditMemberships/MembersInfo.tsx | 4 +- .../members/components/ShareInviteModal.tsx | 3 +- apps/web/playwright/team.spec.ts | 112 ++++++++++++++++++ apps/web/playwright/utils/helper.ts | 20 ++++ apps/web/playwright/utils/mock.ts | 19 +++ 8 files changed, 171 insertions(+), 11 deletions(-) create mode 100644 apps/web/playwright/team.spec.ts diff --git a/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx b/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx index 1640d38195..8faf4ad6f1 100644 --- a/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/components/Navigation.tsx @@ -312,7 +312,7 @@ export default function Navigation({ {/* User Dropdown */}
- +
{session.user.imageUrl ? (
- + Signed in as {session?.user?.name && session?.user?.name.length > 30 ? ( diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx index 98f61d30c6..dcf9433c6c 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/AddMemberModal.tsx @@ -79,15 +79,21 @@ export default function AddMemberModal({
- + value.trim() !== "" })} />
- - + +
{canDoRoleManagement && }
diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MemberActions.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MemberActions.tsx index 5a6a090e00..9a48bfcbcb 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MemberActions.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MemberActions.tsx @@ -97,7 +97,7 @@ export default function MemberActions({ team, member, invite, showDeleteButton } return ( <> {showDeleteButton && ( - )} @@ -109,7 +109,8 @@ export default function MemberActions({ team, member, invite, showDeleteButton } @@ -122,7 +123,8 @@ export default function MemberActions({ team, member, invite, showDeleteButton } diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MembersInfo.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MembersInfo.tsx index acd3c23f9f..f13b848e44 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MembersInfo.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/EditMemberships/MembersInfo.tsx @@ -36,10 +36,10 @@ const MembersInfo = async ({ const allMembers = [...members, ...invites]; return ( -
+
{allMembers.map((member) => (
{isInvitee(member) ? ( diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/ShareInviteModal.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/ShareInviteModal.tsx index cc43730680..34f36d4202 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/components/ShareInviteModal.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/components/ShareInviteModal.tsx @@ -43,7 +43,8 @@ export default function ShareInviteModal({ inviteToken, open, setOpen }: ShareIn

handleTextSelection()}> + onClick={() => handleTextSelection()} + id="inviteLinkText"> {`${window.location.protocol}//${window.location.host}/invite?token=${inviteToken}`}

diff --git a/apps/web/playwright/team.spec.ts b/apps/web/playwright/team.spec.ts new file mode 100644 index 0000000000..76342b7caf --- /dev/null +++ b/apps/web/playwright/team.spec.ts @@ -0,0 +1,112 @@ +import { expect, test } from "playwright/test"; + +import { login, signUpAndLogin, signupUsingInviteToken, skipOnboarding } from "./utils/helper"; +import { invites, users } from "./utils/mock"; + +test.describe("Invite, accept and remove team member", async () => { + test.describe.configure({ mode: "serial" }); + const { email, password, name } = users.team[0]; + let inviteLink: string; + + test("Invite team member", async ({ page }) => { + await signUpAndLogin(page, name, email, password); + await skipOnboarding(page); + + const dropdownTrigger = page.locator("#userDropdownTrigger"); + await expect(dropdownTrigger).toBeVisible(); + await dropdownTrigger.click(); + + const dropdownContentWrapper = page.locator("#userDropdownContentWrapper"); + await expect(dropdownContentWrapper).toBeVisible(); + + await page.getByRole("link", { name: "Team" }).click(); + + // Add member button + await expect(page.getByRole("button", { name: "Add Member" })).toBeVisible(); + await page.getByRole("button", { name: "Add Member" }).click(); + + // Fill the member name and email form + await expect(page.getByLabel("Email")).toBeVisible(); + await page.getByLabel("Full Name").fill(invites.addMember.name); + + await expect(page.getByLabel("Email Address")).toBeVisible(); + await page.getByLabel("Email Address").fill(invites.addMember.email); + + await page.getByRole("button", { name: "Send Invitation", exact: true }).click(); + }); + + test("Copy Invite Link", async ({ page }) => { + await login(page, email, password); + + const dropdownTrigger = page.locator("#userDropdownTrigger"); + await expect(dropdownTrigger).toBeVisible(); + await dropdownTrigger.click(); + + const dropdownContentWrapper = page.locator("#userDropdownContentWrapper"); + await expect(dropdownContentWrapper).toBeVisible(); + + await page.getByRole("link", { name: "Team" }).click(); + + await expect(page.locator("#membersInfoWrapper")).toBeVisible(); + + const lastMemberInfo = page.locator("#membersInfoWrapper > .singleMemberInfo:last-child"); + await expect(lastMemberInfo).toBeVisible(); + + const pendingSpan = lastMemberInfo.locator("span").filter({ hasText: "Pending" }); + await expect(pendingSpan).toBeVisible(); + + const shareInviteButton = page.locator("#shareInviteButton"); + await expect(shareInviteButton).toBeVisible(); + + await shareInviteButton.click(); + + const inviteLinkText = page.locator("#inviteLinkText"); + await expect(inviteLinkText).toBeVisible(); + + // invite link text is a paragraph, and we need the text inside it + const inviteLinkTextContent = await inviteLinkText.textContent(); + if (inviteLinkTextContent) { + inviteLink = inviteLinkTextContent; + } + }); + + test("Accept Invite", async ({ page }) => { + const { email, name, password } = users.team[1]; + page.goto(inviteLink); + + await page.waitForURL(/\/invite\?token=[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+/); + + // Create account button + await expect(page.getByRole("link", { name: "Create account" })).toBeVisible(); + await page.getByRole("link", { name: "Create account" }).click(); + + await signupUsingInviteToken(page, name, email, password); + await skipOnboarding(page); + }); + + test("Remove Member", async ({ page }) => { + await login(page, email, password); + + const dropdownTrigger = page.locator("#userDropdownTrigger"); + await expect(dropdownTrigger).toBeVisible(); + await dropdownTrigger.click(); + + const dropdownContentWrapper = page.locator("#userDropdownContentWrapper"); + await expect(dropdownContentWrapper).toBeVisible(); + + await page.getByRole("link", { name: "Team" }).click(); + + await expect(page.locator("#membersInfoWrapper")).toBeVisible(); + + const lastMemberInfo = page.locator("#membersInfoWrapper > .singleMemberInfo:last-child"); + await expect(lastMemberInfo).toBeVisible(); + + const deleteMemberButton = lastMemberInfo.locator("#deleteMemberButton"); + await expect(deleteMemberButton).toBeVisible(); + + await deleteMemberButton.click(); + + await expect(page.getByRole("button", { name: "Delete", exact: true })).toBeVisible(); + await page.getByRole("button", { name: "Delete", exact: true }).click(); + }); +}); diff --git a/apps/web/playwright/utils/helper.ts b/apps/web/playwright/utils/helper.ts index b9f1b19596..20a755e485 100644 --- a/apps/web/playwright/utils/helper.ts +++ b/apps/web/playwright/utils/helper.ts @@ -51,3 +51,23 @@ export const replaceEnvironmentIdInHtml = (filePath: string, environmentId: stri writeFileSync(filePath, htmlContent); return "file:///" + filePath; }; + +export const signupUsingInviteToken = async (page: Page, name: string, email: string, password: string) => { + await page.getByRole("button", { name: "Continue with Email" }).click(); + await page.getByPlaceholder("Full Name").fill(name); + await page.getByPlaceholder("Full Name").press("Tab"); + + // the email is already filled in the input field + const inputValue = await page.getByPlaceholder("work@email.com").inputValue(); + expect(inputValue).toEqual(email); + + await page.getByPlaceholder("work@email.com").press("Tab"); + await page.getByPlaceholder("*******").fill(password); + await page.press('input[name="password"]', "Enter"); + await page.getByRole("link", { name: "Login" }).click(); + await page.getByRole("button", { name: "Login with Email" }).click(); + await page.getByPlaceholder("work@email.com").fill(email); + await page.getByPlaceholder("*******").click(); + await page.getByPlaceholder("*******").fill(password); + await page.getByRole("button", { name: "Login with Email" }).click(); +}; diff --git a/apps/web/playwright/utils/mock.ts b/apps/web/playwright/utils/mock.ts index 58edb39256..b7b93a12e2 100644 --- a/apps/web/playwright/utils/mock.ts +++ b/apps/web/playwright/utils/mock.ts @@ -32,6 +32,18 @@ export const users = { password: "XpP%X9UU3efj8vJa", }, ], + team: [ + { + name: "Team User 1", + email: "team1@formbricks.com", + password: "Test#1234", + }, + { + name: "Team User 2", + email: "team2@formbricks.com", + password: "Test#1234", + }, + ], }; export const teams = { @@ -97,3 +109,10 @@ export const surveys = { }, }, }; + +export const invites = { + addMember: { + name: "Team User 2", + email: "team2@formbricks.com", + }, +};