diff --git a/playwright/e2e/audio-player/audio-player.spec.ts b/playwright/e2e/audio-player/audio-player.spec.ts index 282440f74e..01b0f23bb4 100644 --- a/playwright/e2e/audio-player/audio-player.spec.ts +++ b/playwright/e2e/audio-player/audio-player.spec.ts @@ -351,7 +351,7 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { const composer = thread.locator(".mx_MessageComposer--compact"); // Assert that the reply preview contains audio ReplyTile the file info button await expect( - composer.locator(".mx_ReplyPreview .mx_ReplyTile_audio .mx_MFileBody_info[role='button']"), + composer.locator(".mx_ReplyPreview .mx_ReplyTile .mx_MFileBody_info[role='button']"), ).toBeVisible(); // Select :smile: emoji and send it @@ -360,6 +360,6 @@ test.describe("Audio player", { tag: ["@no-firefox", "@no-webkit"] }, () => { await composer.getByTestId("basicmessagecomposer").press("Enter"); // Assert that the file name is rendered on the file button - await expect(threadTile.locator(".mx_ReplyTile_audio .mx_MFileBody_info[role='button']")).toBeVisible(); + await expect(threadTile.locator(".mx_ReplyTile .mx_MFileBody_info[role='button']")).toBeVisible(); }); }); diff --git a/playwright/e2e/crypto/crypto.spec.ts b/playwright/e2e/crypto/crypto.spec.ts index ae4db1b0c3..d03fa1454e 100644 --- a/playwright/e2e/crypto/crypto.spec.ts +++ b/playwright/e2e/crypto/crypto.spec.ts @@ -31,15 +31,11 @@ const startDMWithBob = async (page: Page, bob: Bot) => { const testMessages = async (page: Page, bob: Bot, bobRoomId: string) => { // check the invite message - await expect( - page.locator(".mx_EventTile", { hasText: "Hey!" }).locator(".mx_EventTile_e2eIcon_warning"), - ).not.toBeVisible(); + await expect(page.locator(".mx_EventTile", { hasText: "Hey!" }).locator(".mx_EventTile_e2eIcon")).not.toBeVisible(); // Bob sends a response await bob.sendMessage(bobRoomId, "Hoo!"); - await expect( - page.locator(".mx_EventTile", { hasText: "Hoo!" }).locator(".mx_EventTile_e2eIcon_warning"), - ).not.toBeVisible(); + await expect(page.locator(".mx_EventTile", { hasText: "Hoo!" }).locator(".mx_EventTile_e2eIcon")).not.toBeVisible(); }; const bobJoin = async (page: Page, bob: Bot) => { diff --git a/playwright/e2e/crypto/decryption-failure-messages.spec.ts b/playwright/e2e/crypto/decryption-failure-messages.spec.ts index 306e073c00..f36b445660 100644 --- a/playwright/e2e/crypto/decryption-failure-messages.spec.ts +++ b/playwright/e2e/crypto/decryption-failure-messages.spec.ts @@ -51,7 +51,10 @@ test.describe("Cryptography", function () { await app.viewRoomByName("Test room"); const lastTile = page.locator(".mx_EventTile").last(); await expect(lastTile).toContainText("Historical messages are not available on this device"); - await expect(lastTile.locator(".mx_EventTile_e2eIcon_decryption_failure")).toBeVisible(); + await expect(lastTile.locator(".mx_EventTile_e2eIcon")).toHaveAccessibleName( + "This message could not be decrypted", + ); + await expect(lastTile).toMatchScreenshot("history-not-available.png"); // Now, we set up key backup, and then send another message. const secretStorageKey = await enableKeyBackup(app); @@ -78,7 +81,9 @@ test.describe("Cryptography", function () { // look at the last two tiles only for (const tile of tiles.slice(-2)) { await expect(tile).toContainText("You need to verify this device for access to historical messages"); - await expect(tile.locator(".mx_EventTile_e2eIcon_decryption_failure")).toBeVisible(); + await expect(tile.locator(".mx_EventTile_e2eIcon")).toHaveAccessibleName( + "This message could not be decrypted", + ); } // Now verify our device (setting up key backup), and check what happens @@ -87,11 +92,13 @@ test.describe("Cryptography", function () { // The first message still cannot be decrypted, because it was never backed up. It's now a regular UTD though. await expect(tilesAfterVerify[0]).toContainText("Unable to decrypt message"); - await expect(tilesAfterVerify[0].locator(".mx_EventTile_e2eIcon_decryption_failure")).toBeVisible(); + await expect(tilesAfterVerify[0].locator(".mx_EventTile_e2eIcon")).toHaveAccessibleName( + "This message could not be decrypted", + ); // The second message should now be decrypted, with a grey shield await expect(tilesAfterVerify[1]).toContainText("test2 test2"); - await expect(tilesAfterVerify[1].locator(".mx_EventTile_e2eIcon_normal")).toBeVisible(); + await expect(tilesAfterVerify[1].locator(".mx_EventTile_e2eIcon")).toHaveAccessibleName("TODO"); }); test.describe("non-joined historical messages", () => { @@ -186,7 +193,9 @@ test.describe("Cryptography", function () { // The first message from Bob was sent before Alice was in the room, so should // be different from the standard UTD message await expect(tiles[tiles.length - 5]).toContainText("You don't have access to this message"); - await expect(tiles[tiles.length - 5].locator(".mx_EventTile_e2eIcon_decryption_failure")).toBeVisible(); + await expect(tiles[tiles.length - 5].locator(".mx_EventTile_e2eIcon")).toHaveAccessibleName( + "This message could not be decrypted", + ); // The second message from Bob should be decryptable await expect(tiles[tiles.length - 2]).toContainText("This should be decryptable"); @@ -196,7 +205,9 @@ test.describe("Cryptography", function () { // in the room and is expected to be decryptable, so this should have the // standard UTD message await expect(tiles[tiles.length - 1]).toContainText("Unable to decrypt message"); - await expect(tiles[tiles.length - 1].locator(".mx_EventTile_e2eIcon_decryption_failure")).toBeVisible(); + await expect(tiles[tiles.length - 1].locator(".mx_EventTile_e2eIcon")).toHaveAccessibleName( + "This message could not be decrypted", + ); }); test("should be able to jump to a message sent before our last join event", async ({ diff --git a/playwright/e2e/crypto/device-verification.spec.ts b/playwright/e2e/crypto/device-verification.spec.ts index eb43d4dc78..6beda36a98 100644 --- a/playwright/e2e/crypto/device-verification.spec.ts +++ b/playwright/e2e/crypto/device-verification.spec.ts @@ -68,7 +68,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { await doTwoWaySasVerification(page, verifier); await infoDialog.getByRole("button", { name: "They match" }).click(); - await expect(page.locator(".mx_E2EIcon_verified")).toMatchScreenshot("device-verified-e2eIcon.png"); + await expect(page.locator(".mx_E2EIcon")).toMatchScreenshot("device-verified-e2eIcon.png"); await infoDialog.getByRole("button", { name: "Got it" }).click(); // Check that our device is now cross-signed diff --git a/playwright/e2e/crypto/event-shields.spec.ts b/playwright/e2e/crypto/event-shields.spec.ts index 722a30a0d2..eb77bb3a0c 100644 --- a/playwright/e2e/crypto/event-shields.spec.ts +++ b/playwright/e2e/crypto/event-shields.spec.ts @@ -77,11 +77,8 @@ test.describe("Cryptography", function () { const last = page.locator(".mx_EventTile_last"); await expect(last).toContainText("Unable to decrypt message"); const lastE2eIcon = last.locator(".mx_EventTile_e2eIcon"); - await expect(lastE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_decryption_failure/); - await lastE2eIcon.focus(); - await expect(await app.getTooltipForElement(lastE2eIcon)).toContainText( - "This message could not be decrypted", - ); + await expect(lastE2eIcon).toHaveAccessibleName("This message could not be decrypted"); + await expect(lastE2eIcon).toMatchScreenshot("event-shield-utd.png"); /* Should show a red padlock for an unencrypted message in an e2e room */ await bob.evaluate( @@ -99,10 +96,8 @@ test.describe("Cryptography", function () { ); await expect(last).toContainText("test unencrypted"); - await expect(lastE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_warning/); + await expect(lastE2eIcon).toHaveAccessibleName("Not encrypted"); await expect(lastE2eIcon).toMatchScreenshot("event-shield-warning.png"); - await lastE2eIcon.focus(); - await expect(await app.getTooltipForElement(lastE2eIcon)).toContainText("Not encrypted"); /* Should show no padlock for an unverified user */ // bob sends a valid event @@ -133,11 +128,8 @@ test.describe("Cryptography", function () { /* should show red padlock for a message from an unverified device */ await bobSecondDevice.sendMessage(testRoomId, "test encrypted from unverified"); await expect(lastTile).toContainText("test encrypted from unverified"); - await expect(lastTileE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_warning/); - await lastTileE2eIcon.focus(); - await expect(await app.getTooltipForElement(lastTileE2eIcon)).toContainText( - "Encrypted by a device not verified by its owner.", - ); + await expect(lastTileE2eIcon).toHaveAccessibleName("Encrypted by a device not verified by its owner."); + await expect(lastE2eIcon).toMatchScreenshot("event-shield-not-verified.png"); /* Should show a red padlock for a message from an unverified device. * Rust crypto remembers the verification state of the sending device, so it will know that the device was @@ -153,11 +145,8 @@ test.describe("Cryptography", function () { await app.viewRoomByName("TestRoom"); await expect(last).toContainText("test encrypted from unverified"); - await expect(lastE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_warning/); - await lastE2eIcon.focus(); - await expect(await app.getTooltipForElement(lastE2eIcon)).toContainText( - "Encrypted by a device not verified by its owner.", - ); + await expect(lastE2eIcon).toHaveAccessibleName("Encrypted by a device not verified by its owner."); + await expect(lastE2eIcon).toMatchScreenshot("event-shield-not-verified.png"); }, ); @@ -200,16 +189,15 @@ test.describe("Cryptography", function () { /* go back to the test room and find Bob's message again */ await app.viewRoomById(testRoomId); await expect(lastTile).toContainText("test encrypted 1"); - // The gray shield would be a mx_EventTile_e2eIcon_normal. The red shield would be a mx_EventTile_e2eIcon_warning. + // The gray shield would be a Compound info icon. The red shield would be a Compound error solid icon. // No shield would have no div mx_EventTile_e2eIcon at all. - await expect(lastTileE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_normal/); - await lastTileE2eIcon.hover(); // The key is coming from backup, so it is not anymore possible to establish if the claimed device // creator of this key is authentic. The tooltip should be "The authenticity of this encrypted message can't be guaranteed on this device." // It is not "Encrypted by an unknown or deleted device." even if the claimed device is actually deleted. - await expect(await app.getTooltipForElement(lastTileE2eIcon)).toContainText( + await expect(lastTileE2eIcon).toHaveAccessibleName( "The authenticity of this encrypted message can't be guaranteed on this device.", ); + await expect(lastTileE2eIcon).toMatchScreenshot("event-shield-authenticity.png"); }); test("should show the correct shield on edited e2e events", async ({ page, app, bot: bob, homeserver }) => { @@ -224,7 +212,7 @@ test.describe("Cryptography", function () { // the message should appear, decrypted, with no warning await expect( - page.locator(".mx_EventTile", { hasText: "Hoo!" }).locator(".mx_EventTile_e2eIcon_warning"), + page.locator(".mx_EventTile", { hasText: "Hoo!" }).locator(".mx_EventTile_e2eIcon"), ).not.toBeVisible(); // bob sends an edit to the first message with his unverified device @@ -241,7 +229,7 @@ test.describe("Cryptography", function () { // the edit should have a warning await expect( - page.locator(".mx_EventTile", { hasText: "Haa!" }).locator(".mx_EventTile_e2eIcon_warning"), + page.locator(".mx_EventTile", { hasText: "Haa!" }).locator(".mx_EventTile_e2eIcon"), ).toBeVisible(); // a second edit from the verified device should be ok @@ -257,7 +245,7 @@ test.describe("Cryptography", function () { }); await expect( - page.locator(".mx_EventTile", { hasText: "Hee!" }).locator(".mx_EventTile_e2eIcon_warning"), + page.locator(".mx_EventTile", { hasText: "Hee!" }).locator(".mx_EventTile_e2eIcon"), ).not.toBeVisible(); }); @@ -294,11 +282,8 @@ test.describe("Cryptography", function () { const last = page.locator(".mx_EventTile_last"); await expect(last).toContainText("test encrypted from unverified", { timeout: 20000 }); const lastE2eIcon = last.locator(".mx_EventTile_e2eIcon"); - await expect(lastE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_warning/); - await lastE2eIcon.focus(); - await expect(await app.getTooltipForElement(lastE2eIcon)).toContainText( - "Encrypted by a device not verified by its owner.", - ); + await expect(lastE2eIcon).toHaveAccessibleName("Encrypted by a device not verified by its owner."); + await expect(lastE2eIcon).toMatchScreenshot("event-shield-not-verified.png"); const penultimate = page.locator(".mx_EventTile").filter({ hasText: "test encrypted from verified" }); await assertNoE2EIcon(penultimate, app); @@ -322,11 +307,8 @@ test.describe("Cryptography", function () { const last = page.locator(".mx_EventTile_last"); await expect(last).toContainText("test encrypted from user that was previously verified"); const lastE2eIcon = last.locator(".mx_EventTile_e2eIcon"); - await expect(lastE2eIcon).toHaveClass(/mx_EventTile_e2eIcon_warning/); - await lastE2eIcon.focus(); - await expect(await app.getTooltipForElement(lastE2eIcon)).toContainText( - "Sender's verified identity was reset", - ); + await expect(lastE2eIcon).toHaveAccessibleName("Sender's verified identity was reset"); + await expect(lastE2eIcon).toMatchScreenshot("event-shield-identity-reset.png"); }); }); }); @@ -343,8 +325,6 @@ async function assertNoE2EIcon(messageLocator: Locator, app: ElementAppPage) { const e2eIcon = messageLocator.locator(".mx_EventTile_e2eIcon"); if ((await e2eIcon.count()) > 0) { // uh-oh, there is an e2e icon. Let's find out what it's about so that we can throw a helpful error. - await e2eIcon.focus(); - const tooltip = await app.getTooltipForElement(e2eIcon); - throw new Error(`Found an unexpected e2eIcon with tooltip '${await tooltip.textContent()}'`); + await expect(e2eIcon).toHaveAccessibleName("None"); } } diff --git a/playwright/pages/ElementAppPage.ts b/playwright/pages/ElementAppPage.ts index e51ed7b5d4..e5a1aab31c 100644 --- a/playwright/pages/ElementAppPage.ts +++ b/playwright/pages/ElementAppPage.ts @@ -244,24 +244,6 @@ export class ElementAppPage { await this.page.getByRole("dialog").getByRole("button", { name: "Invite" }).click(); } - /** - * Get a locator for the tooltip associated with an element - * @param e The element with the tooltip - * @returns Locator to the tooltip - */ - public async getTooltipForElement(e: Locator): Promise { - const [labelledById, describedById] = await Promise.all([ - e.getAttribute("aria-labelledby"), - e.getAttribute("aria-describedby"), - ]); - if (!labelledById && !describedById) { - throw new Error( - "Element has no aria-labelledby or aria-describedy attributes! The tooltip should have added either one of these.", - ); - } - return this.page.locator(`id=${labelledById ?? describedById}`); - } - /** * Close the notification toast */ diff --git a/playwright/snapshots/crypto/event-shields.spec.ts/event-shield-not-verified-linux.png b/playwright/snapshots/crypto/event-shields.spec.ts/event-shield-not-verified-linux.png new file mode 100644 index 0000000000..3499e8f704 Binary files /dev/null and b/playwright/snapshots/crypto/event-shields.spec.ts/event-shield-not-verified-linux.png differ diff --git a/playwright/snapshots/crypto/event-shields.spec.ts/event-shield-utd-linux.png b/playwright/snapshots/crypto/event-shields.spec.ts/event-shield-utd-linux.png new file mode 100644 index 0000000000..3d80c319c8 Binary files /dev/null and b/playwright/snapshots/crypto/event-shields.spec.ts/event-shield-utd-linux.png differ diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png index 5788816cbc..3a444f92b9 100644 Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-emote-irc-layout-linux.png differ diff --git a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png index ade0bfdc06..0e2f7780b6 100644 Binary files a/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png and b/playwright/snapshots/timeline/timeline.spec.ts/expanded-gels-redaction-placeholder-linux.png differ