From 0ecb4d18a89e1c1331ebf6e665e16853cd634d14 Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Wed, 25 Mar 2026 15:36:12 +0000 Subject: [PATCH] Show 'Verify this device' toast even if there are no encrypted rooms yet --- .../accessibility/keyboard-navigation.spec.ts | 3 ++ .../e2e/audio-player/audio-player.spec.ts | 1 + apps/web/playwright/e2e/crypto/crypto.spec.ts | 1 + .../e2e/crypto/device-verification.spec.ts | 1 + .../e2e/crypto/history-sharing.spec.ts | 7 +++++ apps/web/playwright/e2e/crypto/toasts.spec.ts | 9 ------ .../e2e/devtools/lowbandwidth.spec.ts | 1 + .../e2e/invite/invite-dialog.spec.ts | 1 + .../room-list-collapse.spec.ts | 1 + .../room-list-filter-sort.spec.ts | 3 +- .../room-list-panel/room-list-header.spec.ts | 3 +- .../room-list-panel/room-list-panel.spec.ts | 3 +- .../room-list-panel/room-list-search.spec.ts | 3 +- .../room-list-sections.spec.ts | 3 +- .../room-list-panel/room-list.spec.ts | 3 +- .../playwright/e2e/messages/messages.spec.ts | 2 ++ .../e2e/room-directory/room-directory.spec.ts | 1 + .../playwright/e2e/room/create-room.spec.ts | 17 +++++++++-- .../e2e/room/room-status-bar.spec.ts | 2 ++ .../appearance-user-settings-tab.spec.ts | 6 ++++ .../theme-choice-panel.spec.ts | 3 ++ .../encryption-tab.spec.ts | 1 + .../encryption-user-tab/other-devices.spec.ts | 22 +++++++------- .../security-user-settings-tab.spec.ts | 3 +- .../e2e/sliding-sync/sliding-sync.spec.ts | 1 + apps/web/playwright/e2e/spaces/spaces.spec.ts | 7 +++++ .../threadsActivityCentre.spec.ts | 8 +++-- .../timeline/media-preview-settings.spec.ts | 2 ++ .../playwright/e2e/timeline/timeline.spec.ts | 2 ++ .../e2e/toasts/analytics-toast.spec.ts | 2 ++ apps/web/playwright/e2e/voip/pstn.spec.ts | 1 + apps/web/playwright/pages/ElementAppPage.ts | 29 ++++++++++++++----- .../DeviceListenerCurrentDevice.ts | 24 +++------------ .../test/unit-tests/DeviceListener-test.ts | 4 +-- 34 files changed, 119 insertions(+), 61 deletions(-) diff --git a/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts b/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts index 8ba6cc3a92..a43a4e07b4 100644 --- a/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts +++ b/apps/web/playwright/e2e/accessibility/keyboard-navigation.spec.ts @@ -15,6 +15,8 @@ test.describe("Landmark navigation tests", () => { }); test("without any rooms", async ({ page, homeserver, app, user }) => { + await app.closeVerifyToast(); + // sometimes the space button doesn't appear right away await expect(page.locator(".mx_SpaceButton_active")).toBeVisible(); @@ -118,6 +120,7 @@ test.describe("Landmark navigation tests", () => { }, ); + await app.closeVerifyToast(); await app.viewRoomByName("Bob"); // confirm the room was loaded await expect(page.getByText("Bob joined the room")).toBeVisible(); diff --git a/apps/web/playwright/e2e/audio-player/audio-player.spec.ts b/apps/web/playwright/e2e/audio-player/audio-player.spec.ts index f042b07993..a87e7c0a88 100644 --- a/apps/web/playwright/e2e/audio-player/audio-player.spec.ts +++ b/apps/web/playwright/e2e/audio-player/audio-player.spec.ts @@ -144,6 +144,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { }; test.beforeEach(async ({ page, app, user }) => { + await app.closeVerifyToast(); await app.client.createRoom({ name: "Test Room" }); await app.viewRoomByName("Test Room"); diff --git a/apps/web/playwright/e2e/crypto/crypto.spec.ts b/apps/web/playwright/e2e/crypto/crypto.spec.ts index d03fa1454e..05f400cfd9 100644 --- a/apps/web/playwright/e2e/crypto/crypto.spec.ts +++ b/apps/web/playwright/e2e/crypto/crypto.spec.ts @@ -169,6 +169,7 @@ test.describe("Cryptography", function () { "creating a DM should work, being e2e-encrypted / user verification", { tag: "@screenshot" }, async ({ page, app, bot: bob, user: aliceCredentials }) => { + await app.closeVerifyToast(); await app.client.bootstrapCrossSigning(aliceCredentials); await startDMWithBob(page, bob); // send first message diff --git a/apps/web/playwright/e2e/crypto/device-verification.spec.ts b/apps/web/playwright/e2e/crypto/device-verification.spec.ts index 07fa4ed9d8..7fd17177d3 100644 --- a/apps/web/playwright/e2e/crypto/device-verification.spec.ts +++ b/apps/web/playwright/e2e/crypto/device-verification.spec.ts @@ -124,6 +124,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { await infoDialog.getByRole("button", { name: "Got it" }).click(); // There should be no toast (other than the notifications one) + await toasts.rejectToast("Verify this device"); await toasts.rejectToast("Notifications"); await toasts.assertNoToasts(); diff --git a/apps/web/playwright/e2e/crypto/history-sharing.spec.ts b/apps/web/playwright/e2e/crypto/history-sharing.spec.ts index 3974ba79c5..336b4df567 100644 --- a/apps/web/playwright/e2e/crypto/history-sharing.spec.ts +++ b/apps/web/playwright/e2e/crypto/history-sharing.spec.ts @@ -29,12 +29,16 @@ test.describe("History sharing", function () { // we then invite Bob, and ensure Bob can see the content. await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); // Register a second user, and open it in a second instance of the app const bobCredentials = await homeserver.registerUser(`user_${testInfo.testId}_bob`, "password", "Bob"); const bobPage = await createNewInstance(browser, bobCredentials, {}, labsFlags); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); + + await aliceElementApp.closeNotificationToast(); // Create the room and send a message await createRoom(alicePage, "TestRoom", true); @@ -85,6 +89,7 @@ test.describe("History sharing", function () { // 5. Charlie can't see the message. await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); await createRoom(alicePage, "TestRoom", true); // Register a second user, and open it in a second instance of the app @@ -92,6 +97,7 @@ test.describe("History sharing", function () { const bobPage = await createNewInstance(browser, bobCredentials, {}, labsFlags); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); // ... and a third const charlieCredentials = await homeserver.registerUser( @@ -102,6 +108,7 @@ test.describe("History sharing", function () { const charliePage = await createNewInstance(browser, charlieCredentials, {}, labsFlags); const charlieElementApp = new ElementAppPage(charliePage); await charlieElementApp.client.bootstrapCrossSigning(charlieCredentials); + await charlieElementApp.closeKeyStorageToast(); // Alice invites Bob, and Bob accepts const roomId = await aliceElementApp.getCurrentRoomIdFromUrl(); diff --git a/apps/web/playwright/e2e/crypto/toasts.spec.ts b/apps/web/playwright/e2e/crypto/toasts.spec.ts index 9ce1b8a5ae..72451a03da 100644 --- a/apps/web/playwright/e2e/crypto/toasts.spec.ts +++ b/apps/web/playwright/e2e/crypto/toasts.spec.ts @@ -31,15 +31,6 @@ test.describe("Key storage out of sync toast", () => { await logIntoElementAndVerify(page, credentials, recoveryKey.encodedPrivateKey); await deleteCachedSecrets(page); - - // We won't be prompted for crypto setup unless we have an e2e room, so make one - await page - .getByRole("navigation", { name: "Room list" }) - .getByRole("button", { name: "New conversation" }) - .click(); - await page.getByRole("menuitem", { name: "New room" }).click(); - await page.getByRole("textbox", { name: "Name" }).fill("Test room"); - await page.getByRole("button", { name: "Create room" }).click(); }); test("should prompt for recovery key if 'enter recovery key' pressed", { tag: "@screenshot" }, async ({ page }) => { diff --git a/apps/web/playwright/e2e/devtools/lowbandwidth.spec.ts b/apps/web/playwright/e2e/devtools/lowbandwidth.spec.ts index d24ac69b94..8d5022623d 100644 --- a/apps/web/playwright/e2e/devtools/lowbandwidth.spec.ts +++ b/apps/web/playwright/e2e/devtools/lowbandwidth.spec.ts @@ -19,6 +19,7 @@ test.describe("Devtools", () => { const profileSettings = userSettings.locator(".mx_UserProfileSettings"); await profileSettings.getByAltText("Upload").setInputFiles(getSampleFilePath("riot.png")); await app.closeDialog(); + await app.closeVerifyToast(); // Create an initial room. const createRoomDialog = await app.openCreateRoomDialog(); diff --git a/apps/web/playwright/e2e/invite/invite-dialog.spec.ts b/apps/web/playwright/e2e/invite/invite-dialog.spec.ts index 42588f37c7..93873587f5 100644 --- a/apps/web/playwright/e2e/invite/invite-dialog.spec.ts +++ b/apps/web/playwright/e2e/invite/invite-dialog.spec.ts @@ -73,6 +73,7 @@ test.describe("Invite dialog", function () { "should support inviting a user to Direct Messages", { tag: "@screenshot" }, async ({ page, app, user, bot }) => { + await app.closeVerifyToast(); await page .getByRole("navigation", { name: "Room list" }) .getByRole("button", { name: "New conversation" }) diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts index 2bf8b558dd..73a670ee9f 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-collapse.spec.ts @@ -14,6 +14,7 @@ test.describe("Collapsible Room list", () => { }); test.beforeEach(async ({ page, app, user }) => { + await app.closeVerifyToast(); await app.closeNotificationToast(); for (let i = 0; i < 10; i++) { await app.client.createRoom({ name: `room${i}` }); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts index 99ffed3ff8..94a41baa03 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-filter-sort.spec.ts @@ -46,7 +46,8 @@ test.describe("Room list filters and sort", () => { } test.beforeEach(async ({ page, app, bot, user }) => { - // The notification toast is displayed above the search section + // The toasts are displayed above the search section + await app.closeVerifyToast(); await app.closeNotificationToast(); }); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-header.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-header.spec.ts index 96e0ca8597..8a29839ad2 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-header.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-header.spec.ts @@ -22,7 +22,8 @@ test.describe("Header section of the room list", () => { } test.beforeEach(async ({ page, app, user }) => { - // The notification toast is displayed above the search section + // The toasts are displayed above the search section + await app.closeVerifyToast(); await app.closeNotificationToast(); }); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-panel.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-panel.spec.ts index bc1387cbce..5da11b7167 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-panel.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-panel.spec.ts @@ -23,7 +23,8 @@ test.describe("Room list panel", () => { } test.beforeEach(async ({ page, app, user }) => { - // The notification toast is displayed above the search section + // The toasts are displayed above the search section + await app.closeVerifyToast(); await app.closeNotificationToast(); // Populate the room list diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-search.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-search.spec.ts index 028503f622..c6a5824924 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-search.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-search.spec.ts @@ -23,7 +23,8 @@ test.describe("Search section of the room list", () => { } test.beforeEach(async ({ page, app, user }) => { - // The notification toast is displayed above the search section + // The toasts are displayed above the search section + await app.closeVerifyToast(); await app.closeNotificationToast(); }); diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts index 9bc9bbe2b0..39befd6fef 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list-sections.spec.ts @@ -48,7 +48,8 @@ test.describe("Room list sections", () => { } test.beforeEach(async ({ page, app, user }) => { - // The notification toast is displayed above the search section + // The toasts are displayed above the search section + await app.closeVerifyToast(); await app.closeNotificationToast(); // focus the user menu to avoid to have hover decoration diff --git a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts index 79cc0b4cf3..edf70e974b 100644 --- a/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts +++ b/apps/web/playwright/e2e/left-panel/room-list-panel/room-list.spec.ts @@ -29,7 +29,8 @@ test.describe("Room list", () => { } test.beforeEach(async ({ page, app, user }) => { - // The notification toast is displayed above the search section + // The toasts are displayed above the search section + await app.closeVerifyToast(); await app.closeNotificationToast(); // focus the user menu to avoid to have hover decoration diff --git a/apps/web/playwright/e2e/messages/messages.spec.ts b/apps/web/playwright/e2e/messages/messages.spec.ts index 67af9edb42..6dc45b8e65 100644 --- a/apps/web/playwright/e2e/messages/messages.spec.ts +++ b/apps/web/playwright/e2e/messages/messages.spec.ts @@ -88,6 +88,7 @@ test.describe("Message rendering", () => { room: async ({ user, app }, use) => { const roomId = await app.client.createRoom({ name: "Test room" }); await use({ roomId }); + await app.closeVerifyToast(); }, }); @@ -218,6 +219,7 @@ test.describe("Message url previews", () => { room: async ({ user, app }, use) => { const roomId = await app.client.createRoom({ name: "Test room" }); await use({ roomId }); + await app.closeVerifyToast(); }, }); test("should render a basic preview", { tag: "@screenshot" }, async ({ page, user, app, room, axe }) => { diff --git a/apps/web/playwright/e2e/room-directory/room-directory.spec.ts b/apps/web/playwright/e2e/room-directory/room-directory.spec.ts index 6eea5abce7..e0cb32c7fb 100644 --- a/apps/web/playwright/e2e/room-directory/room-directory.spec.ts +++ b/apps/web/playwright/e2e/room-directory/room-directory.spec.ts @@ -65,6 +65,7 @@ test.describe("Room Directory", () => { room_alias_name: "test1234", }); + await app.closeVerifyToast(); await page.getByRole("button", { name: "Explore rooms" }).click(); const dialog = page.locator(".mx_SpotlightDialog"); diff --git a/apps/web/playwright/e2e/room/create-room.spec.ts b/apps/web/playwright/e2e/room/create-room.spec.ts index 554f972c7d..f3d7f9425d 100644 --- a/apps/web/playwright/e2e/room/create-room.spec.ts +++ b/apps/web/playwright/e2e/room/create-room.spec.ts @@ -22,6 +22,7 @@ test.describe("Create Room", () => { "should create a public room with name, topic & address set", { tag: "@screenshot" }, async ({ page, user, app, axe }) => { + await app.closeVerifyToast(); const dialog = await app.openCreateRoomDialog(); // Fill name & topic await dialog.getByRole("textbox", { name: "Name" }).fill(name); @@ -50,6 +51,8 @@ test.describe("Create Room", () => { ); test("should allow us to start a chat and show encryption state", async ({ page, user, app }) => { + await app.closeVerifyToast(); + await page.getByRole("button", { name: "New conversation", exact: true }).click(); await page.getByRole("menuitem", { name: "Start chat" }).click(); @@ -66,6 +69,7 @@ test.describe("Create Room", () => { test("should create a video room", { tag: "@screenshot" }, async ({ page, user, app }) => { await app.settings.setValue("feature_video_rooms", null, SettingLevel.DEVICE, true); + await app.closeVerifyToast(); const dialog = await app.openCreateRoomDialog("New video room"); // Fill name & topic @@ -100,6 +104,7 @@ test.describe("Create Room", () => { }); test("should disallow creating public rooms", { tag: "@screenshot" }, async ({ page, user, app, axe }) => { + await app.closeVerifyToast(); const dialog = await app.openCreateRoomDialog(); // Fill name & topic await dialog.getByRole("textbox", { name: "Name" }).fill(name); @@ -125,7 +130,9 @@ test.describe("Create Room", () => { test.describe("when the encrypted state labs flag is turned off", () => { test.use({ labsFlags: [] }); - test("creates a room without encrypted state", { tag: "@screenshot" }, async ({ page, user: _user }) => { + test("creates a room without encrypted state", { tag: "@screenshot" }, async ({ page, user: _user, app }) => { + await app.closeVerifyToast(); + // When we start to create a room await page.getByRole("button", { name: "New conversation", exact: true }).click(); await page.getByRole("menuitem", { name: "New room" }).click(); @@ -154,7 +161,9 @@ test.describe("Create Room", () => { test( "creates a room with encrypted state if we check the box", { tag: "@screenshot" }, - async ({ page, user: _user }) => { + async ({ page, user: _user, app }) => { + await app.closeVerifyToast(); + // Given we check the Encrypted State checkbox await page.getByRole("button", { name: "New conversation", exact: true }).click(); await page.getByRole("menuitem", { name: "New room" }).click(); @@ -181,7 +190,9 @@ test.describe("Create Room", () => { test( "creates a room without encrypted state if we don't check the box", { tag: "@screenshot" }, - async ({ page, user: _user }) => { + async ({ page, user: _user, app }) => { + await app.closeVerifyToast(); + // Given we did not check the Encrypted State checkbox await page.getByRole("button", { name: "New conversation", exact: true }).click(); await page.getByRole("menuitem", { name: "New room" }).click(); diff --git a/apps/web/playwright/e2e/room/room-status-bar.spec.ts b/apps/web/playwright/e2e/room/room-status-bar.spec.ts index 78d5c49a30..070feeffe2 100644 --- a/apps/web/playwright/e2e/room/room-status-bar.spec.ts +++ b/apps/web/playwright/e2e/room/room-status-bar.spec.ts @@ -19,6 +19,7 @@ test.describe("Room Status Bar", () => { const roomId = await app.client.createRoom({ name: "A room", }); + await app.closeVerifyToast(); await app.closeNotificationToast(); await app.viewRoomById(roomId); await use({ roomId }); @@ -139,6 +140,7 @@ test.describe("Room Status Bar", () => { "should show an error when creating a local room fails", { tag: "@screenshot" }, async ({ page, app, user, bot }) => { + await app.closeVerifyToast(); await page .getByRole("navigation", { name: "Room list" }) .getByRole("button", { name: "New conversation" }) diff --git a/apps/web/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts b/apps/web/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts index 457c5c17cf..8bb89c9c9c 100644 --- a/apps/web/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/appearance-user-settings-tab/appearance-user-settings-tab.spec.ts @@ -14,6 +14,7 @@ test.describe("Appearance user settings tab", () => { }); test("should be rendered properly", { tag: "@screenshot" }, async ({ page, user, app, axe }) => { + await app.closeVerifyToast(); const tab = await app.settings.openUserSettings("Appearance"); // Click "Show advanced" link button @@ -31,6 +32,7 @@ test.describe("Appearance user settings tab", () => { "should support changing font size by using the font size dropdown", { tag: "@screenshot" }, async ({ page, app, user }) => { + await app.closeVerifyToast(); await app.settings.openUserSettings("Appearance"); const tab = page.getByTestId("mx_AppearanceUserSettingsTab"); @@ -46,6 +48,7 @@ test.describe("Appearance user settings tab", () => { ); test("should support enabling system font", async ({ page, app, user }) => { + await app.closeVerifyToast(); await app.settings.openUserSettings("Appearance"); const tab = page.getByTestId("mx_AppearanceUserSettingsTab"); @@ -63,7 +66,10 @@ test.describe("Appearance user settings tab", () => { "should keep same font and emoji when switching theme", { tag: "@screenshot" }, async ({ page, app, user, util }) => { + await app.closeVerifyToast(); + const roomId = await util.createAndDisplayRoom(); + await app.client.sendMessage(roomId, { body: "Message with 🦡", msgtype: "m.text" }); await app.settings.openUserSettings("Appearance"); diff --git a/apps/web/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts b/apps/web/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts index cb38f923e9..f24fb084af 100644 --- a/apps/web/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts +++ b/apps/web/playwright/e2e/settings/appearance-user-settings-tab/theme-choice-panel.spec.ts @@ -17,6 +17,8 @@ test.describe("Appearance user settings tab", () => { test.beforeEach(async ({ app, user, util }) => { // Disable the default theme for consistency in case ThemeWatcher automatically chooses it await util.disableSystemTheme(); + await app.closeVerifyToast(); + await util.openAppearanceTab(); }); @@ -102,6 +104,7 @@ test.describe("Appearance user settings tab", () => { await expect(page).toMatchScreenshot("window-custom-theme.png"); await page.reload(); + await app.closeVerifyToast(); await util.openAppearanceTab(); // Assert that the custom theme is still selected after reloading the page diff --git a/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts b/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts index a53a188d6b..3f5383ae30 100644 --- a/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/encryption-user-tab/encryption-tab.spec.ts @@ -85,6 +85,7 @@ test.describe("Encryption tab", () => { // Fill the recovery key await util.enterRecoveryKey(recoveryKey); + await dialog.getByRole("heading", { name: "Key storage" }).scrollIntoViewIfNeeded(); await expect(dialog).toMatchScreenshot("default-tab.png", { mask: [dialog.getByTestId("deviceId"), dialog.getByTestId("sessionKey")], }); diff --git a/apps/web/playwright/e2e/settings/encryption-user-tab/other-devices.spec.ts b/apps/web/playwright/e2e/settings/encryption-user-tab/other-devices.spec.ts index 6c20af2d9a..ea921f2225 100644 --- a/apps/web/playwright/e2e/settings/encryption-user-tab/other-devices.spec.ts +++ b/apps/web/playwright/e2e/settings/encryption-user-tab/other-devices.spec.ts @@ -24,12 +24,14 @@ test.describe("Other people's devices section in Encryption tab", () => { user: aliceCredentials, }, testInfo) => { await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); // Create a second browser instance. const bobCredentials = await homeserver.registerUser(`user_${testInfo.testId}_bob`, "password", "bob"); const bobPage = await createNewInstance(browser, bobCredentials, {}); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); // Create the room and invite bob await createRoom(alicePage, "TestRoom", true); @@ -53,6 +55,7 @@ test.describe("Other people's devices section in Encryption tab", () => { util, }, testInfo) => { await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); // Enable blacklist toggle. const dialog = await util.openEncryptionTab(); @@ -69,6 +72,7 @@ test.describe("Other people's devices section in Encryption tab", () => { const bobPage = await createNewInstance(browser, bobCredentials, {}); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); // Create the room and invite bob await createRoom(alicePage, "TestRoom", true); @@ -96,6 +100,7 @@ test.describe("Other people's devices section in Encryption tab", () => { util, }, testInfo) => { await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); // Enable blacklist toggle. const dialog = await util.openEncryptionTab(); @@ -112,6 +117,7 @@ test.describe("Other people's devices section in Encryption tab", () => { const bobPage = await createNewInstance(browser, bobCredentials, {}); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); // Create the room and invite bob await createRoom(alicePage, "TestRoom", true); @@ -120,9 +126,7 @@ test.describe("Other people's devices section in Encryption tab", () => { // Bob accepts the invite and dismisses the warnings. await bobPage.getByRole("option", { name: "TestRoom" }).click(); await bobPage.getByRole("button", { name: "Accept" }).click(); - await bobPage.getByRole("button", { name: "Dismiss" }).click(); // enable notifications - await bobPage.getByRole("button", { name: "Dismiss" }).click(); // enable key storage - await bobPage.getByRole("button", { name: "Yes, dismiss" }).click(); // enable key storage x2 + await bobElementApp.closeNotificationToast(); // Perform verification. await verifyApp("alice", aliceElementApp, "bob", bobElementApp); @@ -140,12 +144,14 @@ test.describe("Other people's devices section in Encryption tab", () => { user: aliceCredentials, }, testInfo) => { await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); // Create a second browser instance. const bobCredentials = await homeserver.registerUser(`user_${testInfo.testId}_bob`, "password", "bob"); const bobPage = await createNewInstance(browser, bobCredentials, {}); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); // Alice creates the room and invite Bob. await createRoom(alicePage, "TestRoom", true); @@ -168,10 +174,6 @@ test.describe("Other people's devices section in Encryption tab", () => { ), ).toBeVisible(); - // Alice dismisses key storage warnings, as they now hide the "New conversation" button. - await alicePage.getByRole("button", { name: "Dismiss" }).click(); // enable key storage - await alicePage.getByRole("button", { name: "Yes, dismiss" }).click(); // enable key storage x2 - // Alice creates a second room and invites Bob. await createRoom(alicePage, "TestRoom2", true); await aliceElementApp.toggleRoomInfoPanel(); // should not be necessary, called in body of below @@ -195,6 +197,7 @@ test.describe("Other people's devices section in Encryption tab", () => { util, }, testInfo) => { await aliceElementApp.client.bootstrapCrossSigning(aliceCredentials); + await aliceElementApp.closeKeyStorageToast(); // Enable blacklist toggle. let dialog = await util.openEncryptionTab(); @@ -211,6 +214,7 @@ test.describe("Other people's devices section in Encryption tab", () => { const bobPage = await createNewInstance(browser, bobCredentials, {}); const bobElementApp = new ElementAppPage(bobPage); await bobElementApp.client.bootstrapCrossSigning(bobCredentials); + await bobElementApp.closeKeyStorageToast(); // Alice creates the room and invite Bob. await createRoom(alicePage, "TestRoom", true); @@ -229,10 +233,6 @@ test.describe("Other people's devices section in Encryption tab", () => { await sendMessageInCurrentRoom(alicePage, "Decryptable"); await expect(bobPage.getByText("Decryptable")).toBeVisible(); - // Alice dismisses key storage warnings, as they now hide the "New conversation" button. - await alicePage.getByRole("button", { name: "Dismiss" }).click(); // enable key storage - await alicePage.getByRole("button", { name: "Yes, dismiss" }).click(); // enable key storage x2 - // Alice creates a second room and invites Bob. await createRoom(alicePage, "TestRoom2", true); await aliceElementApp.toggleRoomInfoPanel(); // should not be necessary, called in body of below diff --git a/apps/web/playwright/e2e/settings/security-user-settings-tab.spec.ts b/apps/web/playwright/e2e/settings/security-user-settings-tab.spec.ts index 25f430c68d..6abc7d3491 100644 --- a/apps/web/playwright/e2e/settings/security-user-settings-tab.spec.ts +++ b/apps/web/playwright/e2e/settings/security-user-settings-tab.spec.ts @@ -26,7 +26,8 @@ test.describe("Security user settings tab", () => { }); test.beforeEach(async ({ page, app, user }) => { - // Dismiss "Notification" toast + // Dismiss toasts + await app.closeVerifyToast(); await app.closeNotificationToast(); await page.locator(".mx_Toast_buttons").getByRole("button", { name: "Yes" }).click(); // Allow analytics }); diff --git a/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts b/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts index cde2d57c14..108f0520b3 100644 --- a/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts +++ b/apps/web/playwright/e2e/sliding-sync/sliding-sync.spec.ts @@ -72,6 +72,7 @@ test.describe("Sliding Sync", () => { // Load the user fixture for all tests test.beforeEach(async ({ app, user }) => { + await app.closeVerifyToast(); await app.closeNotificationToast(); }); diff --git a/apps/web/playwright/e2e/spaces/spaces.spec.ts b/apps/web/playwright/e2e/spaces/spaces.spec.ts index 72b7873920..173130fd29 100644 --- a/apps/web/playwright/e2e/spaces/spaces.spec.ts +++ b/apps/web/playwright/e2e/spaces/spaces.spec.ts @@ -68,6 +68,7 @@ test.describe("Spaces", () => { "should allow user to create public space", { tag: ["@screenshot", "@no-webkit"] }, async ({ page, app, user }) => { + await app.closeVerifyToast(); const contextMenu = await openSpaceCreateMenu(page); await expect(contextMenu).toMatchScreenshot("space-create-menu.png"); @@ -104,6 +105,7 @@ test.describe("Spaces", () => { ); test("should allow user to create private space", { tag: "@screenshot" }, async ({ page, app, user }) => { + await app.closeVerifyToast(); const menu = await openSpaceCreateMenu(page); await menu.getByRole("button", { name: "Private" }).click(); @@ -150,6 +152,7 @@ test.describe("Spaces", () => { name: "Sample Room", }); + await app.closeVerifyToast(); const menu = await openSpaceCreateMenu(page); await menu.getByRole("button", { name: "Private" }).click(); @@ -184,6 +187,7 @@ test.describe("Spaces", () => { name: "A Room that will not be selected", }); + await app.closeVerifyToast(); const menu = await openSpaceCreateMenu(page); await menu.getByRole("button", { name: "Private" }).click(); @@ -283,6 +287,8 @@ test.describe("Spaces", () => { "should render subspaces in the space panel only when expanded", { tag: "@screenshot" }, async ({ page, app, user, axe }) => { + await app.closeVerifyToast(); + axe.disableRules([ // Disable this check as it triggers on nested roving tab index elements which are in practice fine "nested-interactive", @@ -404,6 +410,7 @@ test.describe("Spaces", () => { }); test("should disallow creating public rooms", { tag: "@screenshot" }, async ({ page, user, app }) => { + await app.closeVerifyToast(); const menu = await openSpaceCreateMenu(page); await menu .locator('.mx_SpaceBasicSettings_avatarContainer input[type="file"]') diff --git a/apps/web/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts b/apps/web/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts index eec28099a5..00ed8a8df1 100644 --- a/apps/web/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts +++ b/apps/web/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts @@ -24,7 +24,9 @@ test.describe("Threads Activity Centre", { tag: "@no-firefox" }, () => { test( "should have the button correctly aligned and displayed in the space panel when expanded", { tag: "@screenshot" }, - async ({ util }) => { + async ({ util, app }) => { + await app.closeVerifyToast(); + // Open the space panel await util.expandSpacePanel(); // The buttons in the space panel should be aligned when expanded @@ -144,7 +146,9 @@ test.describe("Threads Activity Centre", { tag: "@no-firefox" }, () => { await expect(page.locator(".mx_SpotlightDialog")).not.toBeVisible(); }); - test("should have the correct hover state", { tag: "@screenshot" }, async ({ util, page }) => { + test("should have the correct hover state", { tag: "@screenshot" }, async ({ util, page, app }) => { + await app.closeVerifyToast(); + await util.hoverTacButton(); await expect(util.getSpacePanel()).toMatchScreenshot("tac-hovered.png"); diff --git a/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts b/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts index f88312f682..026c74d926 100644 --- a/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts +++ b/apps/web/playwright/e2e/timeline/media-preview-settings.spec.ts @@ -36,6 +36,8 @@ test.describe("Media preview settings", () => { }); test("should be able to hide avatars of inviters", { tag: "@screenshot" }, async ({ page, app, room, user }) => { + await app.closeVerifyToast(); + let settings = await app.settings.openUserSettings("Preferences"); await settings.getByLabel("Hide avatars of room and inviter").click(); await app.closeDialog(); diff --git a/apps/web/playwright/e2e/timeline/timeline.spec.ts b/apps/web/playwright/e2e/timeline/timeline.spec.ts index 8a1c51b45f..81fa8da9c3 100644 --- a/apps/web/playwright/e2e/timeline/timeline.spec.ts +++ b/apps/web/playwright/e2e/timeline/timeline.spec.ts @@ -790,6 +790,7 @@ test.describe("Timeline", () => { await sendEvent(app.client, room.roomId); await sendEvent(app.client, room.roomId, true); await page.goto(`/#/room/${room.roomId}`); + await app.closeVerifyToast(); await app.toggleRoomInfoPanel(); @@ -815,6 +816,7 @@ test.describe("Timeline", () => { await sendEvent(app.client, room.roomId); await page.goto(`/#/room/${room.roomId}`); + await app.closeVerifyToast(); // Open a room setting dialog await app.toggleRoomInfoPanel(); diff --git a/apps/web/playwright/e2e/toasts/analytics-toast.spec.ts b/apps/web/playwright/e2e/toasts/analytics-toast.spec.ts index ff10629872..d70f2a7575 100644 --- a/apps/web/playwright/e2e/toasts/analytics-toast.spec.ts +++ b/apps/web/playwright/e2e/toasts/analytics-toast.spec.ts @@ -14,6 +14,7 @@ test.describe("Analytics Toast", () => { }); test("should not show an analytics toast if config has nothing about posthog", async ({ user, toasts }) => { + await toasts.rejectToast("Verify this device"); await toasts.rejectToast("Notifications"); await toasts.assertNoToasts(); }); @@ -29,6 +30,7 @@ test.describe("Analytics Toast", () => { }); test.beforeEach(async ({ user, toasts }) => { + await toasts.rejectToast("Verify this device"); await toasts.rejectToast("Notifications"); }); diff --git a/apps/web/playwright/e2e/voip/pstn.spec.ts b/apps/web/playwright/e2e/voip/pstn.spec.ts index 4241db6522..e4c08b1f42 100644 --- a/apps/web/playwright/e2e/voip/pstn.spec.ts +++ b/apps/web/playwright/e2e/voip/pstn.spec.ts @@ -21,6 +21,7 @@ test.describe("PSTN", () => { }); test("should render dialpad as expected", { tag: "@screenshot" }, async ({ page, user, toasts }) => { + await toasts.rejectToast("Verify this device"); await toasts.rejectToast("Notifications"); await toasts.assertNoToasts(); diff --git a/apps/web/playwright/pages/ElementAppPage.ts b/apps/web/playwright/pages/ElementAppPage.ts index e5a1aab31c..8c059524b6 100644 --- a/apps/web/playwright/pages/ElementAppPage.ts +++ b/apps/web/playwright/pages/ElementAppPage.ts @@ -244,15 +244,30 @@ export class ElementAppPage { await this.page.getByRole("dialog").getByRole("button", { name: "Invite" }).click(); } + async closeToast(title: string, button: string): Promise { + await this.page.locator(".mx_Toast_toast", { hasText: title }).getByRole("button", { name: button }).click(); + } + /** - * Close the notification toast + * Dismiss the "Notifications" toast. */ - public closeNotificationToast(): Promise { - // Dismiss "Notification" toast - return this.page - .locator(".mx_Toast_toast", { hasText: "Notifications" }) - .getByRole("button", { name: "Dismiss" }) - .click(); + public async closeNotificationToast(): Promise { + await this.closeToast("Notifications", "Dismiss"); + } + + /** + * Dismiss the "Turn on key storage" toast. + */ + public async closeKeyStorageToast() { + await this.closeToast("Turn on key storage", "Dismiss"); + await this.page.getByRole("button", { name: "Yes, dismiss" }).click(); + } + + /** + * Dismiss the "Verify this device" toast by clicking "Later". + */ + public async closeVerifyToast() { + await this.closeToast("Verify this device", "Later"); } /** diff --git a/apps/web/src/device-listener/DeviceListenerCurrentDevice.ts b/apps/web/src/device-listener/DeviceListenerCurrentDevice.ts index 0460d82366..cc9bef3d32 100644 --- a/apps/web/src/device-listener/DeviceListenerCurrentDevice.ts +++ b/apps/web/src/device-listener/DeviceListenerCurrentDevice.ts @@ -24,7 +24,6 @@ import { showToast as showSetupEncryptionToast, } from "../toasts/SetupEncryptionToast"; import { isSecretStorageBeingAccessed } from "../SecurityManager"; -import { asyncSomeParallel } from "../utils/arrays"; const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000; @@ -271,10 +270,12 @@ export class DeviceListenerCurrentDevice { if (newState === "ok" || this.dismissedThisDeviceToast) { hideSetupEncryptionToast(); - } else if (await this.shouldShowSetupEncryptionToast()) { + } else if (!isSecretStorageBeingAccessed()) { showSetupEncryptionToast(newState); } else { - logSpan.info("Not yet ready, but shouldShowSetupEncryptionToast==false"); + // If we're in the middle of a secret storage operation, we're likely + // modifying the state involved here, so don't add new toasts to setup. + logSpan.info("Device is not yet ready, but secret storage is being accessed, so not showing toast."); } } @@ -386,23 +387,6 @@ export class DeviceListenerCurrentDevice { return this.keyBackupInfo; } - /** - * Is the user in at least one encrypted room? - */ - private async shouldShowSetupEncryptionToast(): Promise { - // If we're in the middle of a secret storage operation, we're likely - // modifying the state involved here, so don't add new toasts to setup. - if (isSecretStorageBeingAccessed()) return false; - - // Show setup toasts once the user is in at least one encrypted room. - const cryptoApi = this.client.getCrypto(); - if (!cryptoApi) return false; - - return await asyncSomeParallel(this.client.getRooms(), ({ roomId }) => - cryptoApi.isEncryptionEnabledInRoom(roomId), - ); - } - /** * Is key backup enabled? Use a cached answer if we have one. */ diff --git a/apps/web/test/unit-tests/DeviceListener-test.ts b/apps/web/test/unit-tests/DeviceListener-test.ts index 5b1e5dd166..f8777182cf 100644 --- a/apps/web/test/unit-tests/DeviceListener-test.ts +++ b/apps/web/test/unit-tests/DeviceListener-test.ts @@ -348,11 +348,11 @@ describe("DeviceListener", () => { expect(SetupEncryptionToast.showToast).not.toHaveBeenCalled(); }); - it("does not show any toasts when no rooms are encrypted", async () => { + it("shows toasts even when no rooms are encrypted", async () => { jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false); await createAndStart(); - expect(SetupEncryptionToast.showToast).not.toHaveBeenCalled(); + expect(SetupEncryptionToast.showToast).toHaveBeenCalled(); }); it("shows verify session toast when account has cross signing", async () => {