From a6967458be11bf956c10342363aa90cc218a18f3 Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Wed, 5 Feb 2025 23:35:39 +0530 Subject: [PATCH] Fix broken tests --- playwright/e2e/crypto/dehydration.spec.ts | 25 ----------------- playwright/e2e/crypto/event-shields.spec.ts | 28 +++---------------- .../e2e/crypto/user-verification.spec.ts | 27 ++++++++---------- playwright/e2e/crypto/utils.ts | 24 ++++++++++++++++ 4 files changed, 39 insertions(+), 65 deletions(-) diff --git a/playwright/e2e/crypto/dehydration.spec.ts b/playwright/e2e/crypto/dehydration.spec.ts index b3ac82a19da..97082ea3d50 100644 --- a/playwright/e2e/crypto/dehydration.spec.ts +++ b/playwright/e2e/crypto/dehydration.spec.ts @@ -6,21 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ -import { Locator, type Page } from "@playwright/test"; - import { test, expect } from "../../element-web-test"; -import { viewRoomSummaryByName } from "../right-panel/utils"; import { isDendrite } from "../../plugins/homeserver/dendrite"; import { completeCreateSecretStorageDialog, createBot, logIntoElement } from "./utils.ts"; import { Client } from "../../pages/client.ts"; -const ROOM_NAME = "Test room"; const NAME = "Alice"; -function getMemberTileByName(page: Page, name: string): Locator { - return page.locator(`.mx_MemberTileView, [title="${name}"]`); -} - test.use({ displayName: NAME, synapseConfig: { @@ -70,23 +62,6 @@ test.describe("Dehydration", () => { // device. const sessionsTab = await app.settings.openUserSettings("Sessions"); await expect(sessionsTab.getByText("Dehydrated device")).not.toBeVisible(); - - await app.settings.closeDialog(); - - // now check that the user info right-panel shows the dehydrated device - // as a feature rather than as a normal device - await app.client.createRoom({ name: ROOM_NAME }); - - await viewRoomSummaryByName(page, app, ROOM_NAME); - - await page.locator(".mx_RightPanel").getByRole("menuitem", { name: "People" }).click(); - await expect(page.locator(".mx_MemberListView")).toBeVisible(); - - await getMemberTileByName(page, NAME).click(); - await page.locator(".mx_UserInfo_devices .mx_UserInfo_expand").click(); - - await expect(page.locator(".mx_UserInfo_devices").getByText("Offline device enabled")).toBeVisible(); - await expect(page.locator(".mx_UserInfo_devices").getByText("Dehydrated device")).not.toBeVisible(); }); test("Reset recovery key during login re-creates dehydrated device", async ({ diff --git a/playwright/e2e/crypto/event-shields.spec.ts b/playwright/e2e/crypto/event-shields.spec.ts index c0f1e280a2f..cd57175cf09 100644 --- a/playwright/e2e/crypto/event-shields.spec.ts +++ b/playwright/e2e/crypto/event-shields.spec.ts @@ -17,6 +17,7 @@ import { logIntoElement, logOutOfElement, verify, + waitForDevices, } from "./utils"; import { bootstrapCrossSigningForClient } from "../../pages/client.ts"; import { ElementAppPage } from "../../pages/ElementAppPage.ts"; @@ -144,25 +145,8 @@ test.describe("Cryptography", function () { // bob deletes his second device await bobSecondDevice.evaluate((cli) => cli.logout(true)); - // wait for the logout to propagate. Workaround for https://github.com/vector-im/element-web/issues/26263 by repeatedly closing and reopening Bob's user info. - async function awaitOneDevice(iterations = 1) { - const rightPanel = page.locator(".mx_RightPanel"); - await rightPanel.getByTestId("base-card-back-button").click(); - await rightPanel.getByText("Bob").click(); - const sessionCountText = await rightPanel - .locator(".mx_UserInfo_devices") - .getByText(" session", { exact: false }) - .textContent(); - // cf https://github.com/vector-im/element-web/issues/26279: Element-R uses the wrong text here - if (sessionCountText != "1 session" && sessionCountText != "1 verified session") { - if (iterations >= 10) { - throw new Error(`Bob still has ${sessionCountText} after 10 iterations`); - } - await awaitOneDevice(iterations + 1); - } - } - - await awaitOneDevice(); + // wait for the logout to propagate. + await waitForDevices(app, bob.credentials.userId, 1); // close and reopen the room, to get the shield to update. await app.viewRoomByName("Bob"); @@ -285,11 +269,7 @@ test.describe("Cryptography", function () { // Workaround for https://github.com/element-hq/element-web/issues/28640: // make sure that Alice has seen Bob's identity before she goes offline. We do this by opening // his user info. - await app.toggleRoomInfoPanel(); - const rightPanel = page.locator(".mx_RightPanel"); - await rightPanel.getByRole("menuitem", { name: "People" }).click(); - await rightPanel.getByRole("button", { name: bob.credentials!.userId }).click(); - await expect(rightPanel.locator(".mx_UserInfo_devices")).toContainText("1 session"); + await waitForDevices(app, bob.credentials.userId, 1); // Our app is blocked from syncing while Bob sends his messages. await app.client.network.goOffline(); diff --git a/playwright/e2e/crypto/user-verification.spec.ts b/playwright/e2e/crypto/user-verification.spec.ts index 175c8d5fdfd..35139fe3e9a 100644 --- a/playwright/e2e/crypto/user-verification.spec.ts +++ b/playwright/e2e/crypto/user-verification.spec.ts @@ -8,9 +8,8 @@ Please see LICENSE files in the repository root for full details. import { type Preset, type Visibility } from "matrix-js-sdk/src/matrix"; -import type { Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; -import { doTwoWaySasVerification, awaitVerifier } from "./utils"; +import { doTwoWaySasVerification, awaitVerifier, waitForDevices } from "./utils"; import { Client } from "../../pages/client"; test.describe("User verification", () => { @@ -33,13 +32,17 @@ test.describe("User verification", () => { }); test("can receive a verification request when there is no existing DM", async ({ + app, page, bot: bob, user: aliceCredentials, toasts, room: { roomId: dmRoomId }, }) => { - await waitForDeviceKeys(page); + await waitForDevices(app, bob.credentials.userId, 1); + await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible(); + const avatar = page.getByRole("button", { name: "Avatar" }); + await avatar.click(); // once Alice has joined, Bob starts the verification const bobVerificationRequest = await bob.evaluateHandle( @@ -84,13 +87,17 @@ test.describe("User verification", () => { }); test("can abort emoji verification when emoji mismatch", async ({ + app, page, bot: bob, user: aliceCredentials, toasts, room: { roomId: dmRoomId }, }) => { - await waitForDeviceKeys(page); + await waitForDevices(app, bob.credentials.userId, 1); + await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible(); + const avatar = page.getByRole("button", { name: "Avatar" }); + await avatar.click(); // once Alice has joined, Bob starts the verification const bobVerificationRequest = await bob.evaluateHandle( @@ -154,15 +161,3 @@ async function createDMRoom(client: Client, userId: string): Promise { ], }); } - -/** - * Wait until we get the other user's device keys. - * In newer rust-crypto versions, the verification request will be ignored if we - * don't have the sender's device keys. - */ -async function waitForDeviceKeys(page: Page): Promise { - await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible(); - const avatar = await page.getByRole("button", { name: "Avatar" }); - await avatar.click(); - await expect(page.getByText("1 session")).toBeVisible(); -} diff --git a/playwright/e2e/crypto/utils.ts b/playwright/e2e/crypto/utils.ts index 6753ae651c3..656c9607ca0 100644 --- a/playwright/e2e/crypto/utils.ts +++ b/playwright/e2e/crypto/utils.ts @@ -494,3 +494,27 @@ export async function deleteCachedSecrets(page: Page) { }); await page.reload(); } + +/** + * Wait until the given user has a given number of devices. + * This function will check the device keys ten times and if + * the expected number of devices were not found by then, an + * error is thrown. + */ +export async function waitForDevices(app: ElementAppPage, userId: string, expectedNumberOfDevices: number): Promise { + const result = await app.client.evaluate( + async (cli, { userId, expectedNumberOfDevices }) => { + for (let i = 0; i < 10; ++i) { + const userDeviceMap = await cli.getCrypto()?.getUserDeviceInfo([userId], true); + const deviceMap = userDeviceMap?.get(userId); + if (deviceMap.size === expectedNumberOfDevices) return true; + await new Promise((r) => setTimeout(r, 500)); + } + return false; + }, + { userId, expectedNumberOfDevices }, + ); + if (!result) { + throw new Error(`User ${userId} did not have ${expectedNumberOfDevices} devices within ten iterations!`); + } +}