From b5fff42adcea8997c7dca22df4bdc81b15bc3bdf Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 14 Mar 2025 11:00:01 +0100 Subject: [PATCH 1/2] Test: Add more integrations test Testing access, register, login, logout. Create and join as guest --- playwright.config.ts | 7 +- playwright/access.spec.ts | 131 ++++++++++++++++++++++++++++++++++++++ src/Header.tsx | 7 +- 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 playwright/access.spec.ts diff --git a/playwright.config.ts b/playwright.config.ts index 1d3db581..b664ba47 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -37,7 +37,12 @@ export default defineConfig({ name: "chromium", use: { ...devices["Desktop Chrome"], - permissions: ["microphone", "camera"], + permissions: [ + "clipboard-write", + "clipboard-read", + "microphone", + "camera", + ], ignoreHTTPSErrors: true, launchOptions: { args: [ diff --git a/playwright/access.spec.ts b/playwright/access.spec.ts new file mode 100644 index 00000000..52eef171 --- /dev/null +++ b/playwright/access.spec.ts @@ -0,0 +1,131 @@ +/* +Copyright 2025 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { expect, test } from "@playwright/test"; + +test("Sign up a new account, then login, then logout", async ({ browser }) => { + const userId = `test_user-id_${Date.now()}`; + + const newUserContext = await browser.newContext(); + const newUserPage = await newUserContext.newPage(); + await newUserPage.goto("/"); + + await expect(newUserPage.getByTestId("home_register")).toBeVisible(); + await newUserPage.getByTestId("home_register").click(); + + await newUserPage.getByTestId("register_username").click(); + await newUserPage.getByTestId("register_username").fill(userId); + + await newUserPage.getByTestId("register_password").click(); + await newUserPage.getByTestId("register_password").fill("password1!"); + await newUserPage.getByTestId("register_confirm_password").click(); + await newUserPage.getByTestId("register_confirm_password").fill("password1!"); + await newUserPage.getByTestId("register_register").click(); + + await expect( + newUserPage.getByRole("heading", { name: "Start new call" }), + ).toBeVisible(); + + // Now use a new page to login this account + const returningUserContext = await browser.newContext(); + const returningUserPage = await returningUserContext.newPage(); + await returningUserPage.goto("/"); + + await expect(returningUserPage.getByTestId("home_login")).toBeVisible(); + await returningUserPage.getByTestId("home_login").click(); + await returningUserPage.getByTestId("login_username").click(); + await returningUserPage.getByTestId("login_username").fill(userId); + await returningUserPage.getByTestId("login_password").click(); + await returningUserPage.getByTestId("login_password").fill("password1!"); + await returningUserPage.getByTestId("login_login").click(); + + await expect( + returningUserPage.getByRole("heading", { name: "Start new call" }), + ).toBeVisible(); + + // logout + await returningUserPage.getByTestId("usermenu_open").click(); + await returningUserPage.locator('[data-test-id="usermenu_logout"]').click(); + + await expect( + returningUserPage.getByRole("link", { name: "Log In" }), + ).toBeVisible(); + await expect(returningUserPage.getByTestId("home_login")).toBeVisible(); +}); + +test("As a guest, create a call, share link and other join", async ({ + browser, +}) => { + // Use reduce motion to disable animations that are making the tests a bit flaky + const creatorContext = await browser.newContext({ reducedMotion: "reduce" }); + const creatorPage = await creatorContext.newPage(); + + await creatorPage.goto("/"); + + // ======== + // ARRANGE: The first user creates a call as guest, join it, then click the invite button to copy the invite link + // ======== + await creatorPage.getByTestId("home_callName").click(); + await creatorPage.getByTestId("home_callName").fill("Welcome"); + await creatorPage.getByTestId("home_displayName").click(); + await creatorPage.getByTestId("home_displayName").fill("Inviter"); + await creatorPage.getByTestId("home_go").click(); + await expect(creatorPage.locator("video")).toBeVisible(); + + // join + await creatorPage.getByTestId("lobby_joinCall").click(); + // Spotlight mode to make checking the test visually clearer + await creatorPage.getByRole("radio", { name: "Spotlight" }).check(); + + // Get the invite link + await creatorPage.getByRole("button", { name: "Invite" }).click(); + await expect( + creatorPage.getByRole("heading", { name: "Invite to this call" }), + ).toBeVisible(); + await expect(creatorPage.getByRole("img", { name: "QR Code" })).toBeVisible(); + await expect(creatorPage.getByTestId("modal_inviteLink")).toBeVisible(); + await expect(creatorPage.getByTestId("modal_inviteLink")).toBeVisible(); + await creatorPage.getByTestId("modal_inviteLink").click(); + + let inviteLink = (await creatorPage.evaluate( + "navigator.clipboard.readText()", + )) as string; + expect(inviteLink).toContain("room/#/"); + + // ======== + // ACT: The other user use the invite link to join the call as a guest + // ======== + const guestInviteeContext = await browser.newContext({ + reducedMotion: "reduce", + }); + const guestPage = await guestInviteeContext.newPage(); + + await guestPage.goto(inviteLink); + await guestPage.getByTestId("joincall_displayName").fill("Invitee"); + await expect(guestPage.getByTestId("joincall_joincall")).toBeVisible(); + await guestPage.getByTestId("joincall_joincall").click(); + await guestPage.getByTestId("lobby_joinCall").click(); + await guestPage.getByRole("radio", { name: "Spotlight" }).check(); + + // ======== + // ASSERT: check that there are two members in the call + // ======== + + // There should be two participants now + await expect( + guestPage.getByTestId("roomHeader_participants_count"), + ).toContainText("2"); + expect(await guestPage.getByTestId("videoTile").count()).toBe(2); + + // Same in creator page + await expect( + creatorPage.getByTestId("roomHeader_participants_count"), + ).toContainText("2"); + expect(await creatorPage.getByTestId("videoTile").count()).toBe(2); + + // XXX check the display names on the video tiles +}); diff --git a/src/Header.tsx b/src/Header.tsx index 8a312983..89455411 100644 --- a/src/Header.tsx +++ b/src/Header.tsx @@ -161,7 +161,12 @@ export const RoomHeaderInfo: FC = ({ height={20} aria-label={t("header_participants_label")} /> - + {t("participant_count", { count: participantCount ?? 0 })} From 83198c061a53ffc7642e6a012a68df3aa9e44d0f Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 14 Mar 2025 11:00:37 +0100 Subject: [PATCH 2/2] Disable rate limiting on dev homeserver to avoid flaky tests --- backend/dev_homeserver.yaml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/backend/dev_homeserver.yaml b/backend/dev_homeserver.yaml index 5697c32e..d4d0a041 100644 --- a/backend/dev_homeserver.yaml +++ b/backend/dev_homeserver.yaml @@ -41,10 +41,23 @@ max_event_delay_duration: 24h # - burst_count: number of requests a client can send before being throttled. rc_message: - # This needs to match at least the heart-beat frequency plus a bit of headroom - # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s - per_second: 0.5 - burst_count: 30 + per_second: 10000 + burst_count: 10000 + +rc_login: + address: + per_second: 10000 + burst_count: 10000 + account: + per_second: 10000 + burst_count: 10000 + failed_attempts: + per_second: 10000 + burst_count: 10000 + +rc_registration: + per_second: 10000 + burst_count: 10000 # Required for Element Call in Single Page Mode due to on-the-fly user registration enable_registration: true