diff --git a/.github/workflows/end-to-end-tests.yaml b/.github/workflows/end-to-end-tests.yaml index 4232993fa0b..bd7872ee120 100644 --- a/.github/workflows/end-to-end-tests.yaml +++ b/.github/workflows/end-to-end-tests.yaml @@ -114,6 +114,8 @@ jobs: - Chrome - Firefox - WebKit + - Dendrite + - Pinecone runAllTests: - ${{ github.event_name == 'schedule' || contains(github.event.pull_request.labels.*.name, 'X-Run-All-Tests') }} # Skip the Firefox & Safari runs unless this was a cron trigger or PR has X-Run-All-Tests label @@ -122,6 +124,10 @@ jobs: project: Firefox - runAllTests: false project: WebKit + - runAllTests: false + project: Dendrite + - runAllTests: false + project: Pinecone steps: - uses: actions/checkout@v4 with: diff --git a/playwright.config.ts b/playwright.config.ts index d317c55a6d6..09bd07bb3b8 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -8,19 +8,25 @@ Please see LICENSE files in the repository root for full details. import { defineConfig, devices } from "@playwright/test"; +import { Options } from "./playwright/services"; + const baseURL = process.env["BASE_URL"] ?? "http://localhost:8080"; -export default defineConfig({ +const chromeProject = { + ...devices["Desktop Chrome"], + channel: "chromium", + permissions: ["clipboard-write", "clipboard-read", "microphone"], + launchOptions: { + args: ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream", "--mute-audio"], + }, +}; + +export default defineConfig({ projects: [ { name: "Chrome", use: { - ...devices["Desktop Chrome"], - channel: "chromium", - permissions: ["clipboard-write", "clipboard-read", "microphone"], - launchOptions: { - args: ["--use-fake-ui-for-media-stream", "--use-fake-device-for-media-stream", "--mute-audio"], - }, + ...chromeProject, }, }, { @@ -48,6 +54,22 @@ export default defineConfig({ }, ignoreSnapshots: true, }, + { + name: "Dendrite", + use: { + ...chromeProject, + homeserverType: "dendrite", + }, + ignoreSnapshots: true, + }, + { + name: "Pinecone", + use: { + ...chromeProject, + homeserverType: "pinecone", + }, + ignoreSnapshots: true, + }, ], use: { viewport: { width: 1280, height: 720 }, diff --git a/playwright/e2e/create-room/create-room.spec.ts b/playwright/e2e/create-room/create-room.spec.ts index 4a4fee16207..087a89e68dc 100644 --- a/playwright/e2e/create-room/create-room.spec.ts +++ b/playwright/e2e/create-room/create-room.spec.ts @@ -27,7 +27,7 @@ test.describe("Create Room", () => { // Submit await dialog.getByRole("button", { name: "Create room" }).click(); - await expect(page).toHaveURL(/\/#\/room\/#test-room-1:localhost/); + await expect(page).toHaveURL(new RegExp(`/#/room/#test-room-1:${user.homeServer}`)); const header = page.locator(".mx_RoomHeader"); await expect(header).toContainText(name); }); diff --git a/playwright/e2e/crypto/backups-mas.spec.ts b/playwright/e2e/crypto/backups-mas.spec.ts index 614bde50646..3d56534728d 100644 --- a/playwright/e2e/crypto/backups-mas.spec.ts +++ b/playwright/e2e/crypto/backups-mas.spec.ts @@ -13,7 +13,7 @@ import { TestClientServerAPI } from "../csAPI"; import { masHomeserver } from "../../plugins/homeserver/synapse/masHomeserver.ts"; // These tests register an account with MAS because then we go through the "normal" registration flow -// and crypto gets set up. Using the 'user' fixture create a a user an synthesizes an existing login, +// and crypto gets set up. Using the 'user' fixture create a user and synthesizes an existing login, // which is faster but leaves us without crypto set up. test.use(masHomeserver); test.describe("Encryption state after registration", () => { diff --git a/playwright/e2e/crypto/backups.spec.ts b/playwright/e2e/crypto/backups.spec.ts index a49495edfab..95bf708122e 100644 --- a/playwright/e2e/crypto/backups.spec.ts +++ b/playwright/e2e/crypto/backups.spec.ts @@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details. import { type Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; async function expectBackupVersionToBe(page: Page, version: string) { await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(5) td")).toHaveText( @@ -19,6 +20,7 @@ async function expectBackupVersionToBe(page: Page, version: string) { } test.describe("Backups", () => { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); test.use({ displayName: "Hanako", }); diff --git a/playwright/e2e/crypto/complete-security.spec.ts b/playwright/e2e/crypto/complete-security.spec.ts index da6974459c9..d4c303fae44 100644 --- a/playwright/e2e/crypto/complete-security.spec.ts +++ b/playwright/e2e/crypto/complete-security.spec.ts @@ -8,8 +8,10 @@ Please see LICENSE files in the repository root for full details. import { test, expect } from "../../element-web-test"; import { logIntoElement } from "./utils"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Complete security", () => { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); test.use({ displayName: "Jeff", }); diff --git a/playwright/e2e/crypto/crypto.spec.ts b/playwright/e2e/crypto/crypto.spec.ts index 2b6844574ec..f99a7a64588 100644 --- a/playwright/e2e/crypto/crypto.spec.ts +++ b/playwright/e2e/crypto/crypto.spec.ts @@ -11,6 +11,7 @@ import { expect, test } from "../../element-web-test"; import { autoJoin, copyAndContinue, createSharedRoomWithUser, enableKeyBackup, verify } from "./utils"; import { Bot } from "../../pages/bot"; import { ElementAppPage } from "../../pages/ElementAppPage"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; const checkDMRoom = async (page: Page) => { const body = page.locator(".mx_RoomView_body"); @@ -67,6 +68,7 @@ const bobJoin = async (page: Page, bob: Bot) => { }; test.describe("Cryptography", function () { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); test.use({ displayName: "Alice", botCreateOpts: { diff --git a/playwright/e2e/crypto/decryption-failure-messages.spec.ts b/playwright/e2e/crypto/decryption-failure-messages.spec.ts index e1952bfec60..529251b223b 100644 --- a/playwright/e2e/crypto/decryption-failure-messages.spec.ts +++ b/playwright/e2e/crypto/decryption-failure-messages.spec.ts @@ -28,6 +28,8 @@ test.describe("Cryptography", function () { }); test.describe("decryption failure messages", () => { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); + test("should handle device-relative historical messages", async ({ homeserver, page, diff --git a/playwright/e2e/crypto/device-verification.spec.ts b/playwright/e2e/crypto/device-verification.spec.ts index a028bfb70c2..d3fa2f33c99 100644 --- a/playwright/e2e/crypto/device-verification.spec.ts +++ b/playwright/e2e/crypto/device-verification.spec.ts @@ -219,9 +219,10 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => { /* And we're all done! */ const infoDialog = page.locator(".mx_InfoDialog"); await infoDialog.getByRole("button", { name: "They match" }).click(); - await expect( - infoDialog.getByText(`You've successfully verified (${aliceBotClient.credentials.deviceId})!`), - ).toBeVisible(); + // We don't assert the full string as the device name is unset on Synapse but set to the user ID on Dendrite + await expect(infoDialog.getByText(`You've successfully verified`)).toContainText( + `(${aliceBotClient.credentials.deviceId})`, + ); await infoDialog.getByRole("button", { name: "Got it" }).click(); }); }); diff --git a/playwright/e2e/crypto/logout.spec.ts b/playwright/e2e/crypto/logout.spec.ts index 2bafe0ece88..faaf1e6a1e3 100644 --- a/playwright/e2e/crypto/logout.spec.ts +++ b/playwright/e2e/crypto/logout.spec.ts @@ -8,8 +8,10 @@ Please see LICENSE files in the repository root for full details. import { test, expect } from "../../element-web-test"; import { createRoom, enableKeyBackup, logIntoElement, sendMessageInCurrentRoom } from "./utils"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Logout tests", () => { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); test.beforeEach(async ({ page, homeserver, credentials }) => { await logIntoElement(page, credentials); }); diff --git a/playwright/e2e/editing/editing.spec.ts b/playwright/e2e/editing/editing.spec.ts index 83ae6ba2d9c..934c4aa42ec 100644 --- a/playwright/e2e/editing/editing.spec.ts +++ b/playwright/e2e/editing/editing.spec.ts @@ -12,6 +12,7 @@ import type { EventType, IContent, ISendEventResponse, MsgType, Visibility } fro import { expect, test } from "../../element-web-test"; import { ElementAppPage } from "../../pages/ElementAppPage"; import { SettingLevel } from "../../../src/settings/SettingLevel"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; async function sendEvent(app: ElementAppPage, roomId: string): Promise { return app.client.sendEvent(roomId, null, "m.room.message" as EventType, { @@ -31,6 +32,8 @@ function mkPadding(n: number): IContent { } test.describe("Editing", () => { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488"); + // Edit "Message" const editLastMessage = async (page: Page, edit: string) => { const eventTile = page.locator(".mx_RoomView_MessageList .mx_EventTile_last"); diff --git a/playwright/e2e/integration-manager/kick.spec.ts b/playwright/e2e/integration-manager/kick.spec.ts index b12215fe332..acd50bfbd4a 100644 --- a/playwright/e2e/integration-manager/kick.spec.ts +++ b/playwright/e2e/integration-manager/kick.spec.ts @@ -69,29 +69,15 @@ async function sendActionFromIntegrationManager( await iframe.getByRole("button", { name: "Press to send action" }).click(); } -async function clickUntilGone(page: Page, selector: string, attempt = 0) { - if (attempt === 11) { - throw new Error("clickUntilGone attempt count exceeded"); - } - - await page.locator(selector).last().click(); - - const count = await page.locator(selector).count(); - if (count > 0) { - return clickUntilGone(page, selector, ++attempt); - } -} - async function expectKickedMessage(page: Page, shouldExist: boolean) { - // Expand any event summaries, we can't use a click multiple here because clicking one might de-render others - // This is quite horrible but seems the most stable way of clicking 0-N buttons, - // one at a time with a full re-evaluation after each click - await clickUntilGone(page, ".mx_GenericEventListSummary_toggle[aria-expanded=false]"); + await expect(async () => { + await page.locator(".mx_GenericEventListSummary_toggle[aria-expanded=false]").last().click(); + await expect(page.getByText(`${USER_DISPLAY_NAME} removed ${BOT_DISPLAY_NAME}: ${KICK_REASON}`)).toBeVisible({ + visible: shouldExist, + }); + }).toPass(); // Check for the event message (or lack thereof) - await expect(page.getByText(`${USER_DISPLAY_NAME} removed ${BOT_DISPLAY_NAME}: ${KICK_REASON}`)).toBeVisible({ - visible: shouldExist, - }); } test.describe("Integration Manager: Kick", () => { diff --git a/playwright/e2e/knock/create-knock-room.spec.ts b/playwright/e2e/knock/create-knock-room.spec.ts index 1c729ff610e..29733481ddc 100644 --- a/playwright/e2e/knock/create-knock-room.spec.ts +++ b/playwright/e2e/knock/create-knock-room.spec.ts @@ -9,8 +9,10 @@ Please see LICENSE files in the repository root for full details. import { test, expect } from "../../element-web-test"; import { waitForRoom } from "../utils"; import { Filter } from "../../pages/Spotlight"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Create Knock Room", () => { + test.skip(isDendrite, "Dendrite does not have support for knocking"); test.use({ displayName: "Alice", labsFlags: ["feature_ask_to_join"], diff --git a/playwright/e2e/knock/knock-into-room.spec.ts b/playwright/e2e/knock/knock-into-room.spec.ts index a87c33415b3..9c2f1ee76be 100644 --- a/playwright/e2e/knock/knock-into-room.spec.ts +++ b/playwright/e2e/knock/knock-into-room.spec.ts @@ -13,8 +13,10 @@ import { type Visibility } from "matrix-js-sdk/src/matrix"; import { test, expect } from "../../element-web-test"; import { waitForRoom } from "../utils"; import { Filter } from "../../pages/Spotlight"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Knock Into Room", () => { + test.skip(isDendrite, "Dendrite does not have support for knocking"); test.use({ displayName: "Alice", labsFlags: ["feature_ask_to_join"], diff --git a/playwright/e2e/knock/manage-knocks.spec.ts b/playwright/e2e/knock/manage-knocks.spec.ts index fb7e2751945..870656398e6 100644 --- a/playwright/e2e/knock/manage-knocks.spec.ts +++ b/playwright/e2e/knock/manage-knocks.spec.ts @@ -10,8 +10,10 @@ Please see LICENSE files in the repository root for full details. import { test, expect } from "../../element-web-test"; import { waitForRoom } from "../utils"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Manage Knocks", () => { + test.skip(isDendrite, "Dendrite does not have support for knocking"); test.use({ displayName: "Alice", labsFlags: ["feature_ask_to_join"], diff --git a/playwright/e2e/lazy-loading/lazy-loading.spec.ts b/playwright/e2e/lazy-loading/lazy-loading.spec.ts index ace6fdb7380..06fb0b3a71e 100644 --- a/playwright/e2e/lazy-loading/lazy-loading.spec.ts +++ b/playwright/e2e/lazy-loading/lazy-loading.spec.ts @@ -10,8 +10,12 @@ import { Bot } from "../../pages/bot"; import type { Locator, Page } from "@playwright/test"; import type { ElementAppPage } from "../../pages/ElementAppPage"; import { test, expect } from "../../element-web-test"; +import { Credentials } from "../../plugins/homeserver"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Lazy Loading", () => { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488"); + const charlies: Bot[] = []; test.use({ @@ -35,12 +39,18 @@ test.describe("Lazy Loading", () => { }); const name = "Lazy Loading Test"; - const alias = "#lltest:localhost"; const charlyMsg1 = "hi bob!"; const charlyMsg2 = "how's it going??"; let roomId: string; - async function setupRoomWithBobAliceAndCharlies(page: Page, app: ElementAppPage, bob: Bot, charlies: Bot[]) { + async function setupRoomWithBobAliceAndCharlies( + page: Page, + app: ElementAppPage, + user: Credentials, + bob: Bot, + charlies: Bot[], + ) { + const alias = `#lltest:${user.homeServer}`; const visibility = await page.evaluate(() => (window as any).matrixcs.Visibility.Public); roomId = await bob.createRoom({ name, @@ -95,7 +105,13 @@ test.describe("Lazy Loading", () => { } } - async function joinCharliesWhileAliceIsOffline(page: Page, app: ElementAppPage, charlies: Bot[]) { + async function joinCharliesWhileAliceIsOffline( + page: Page, + app: ElementAppPage, + user: Credentials, + charlies: Bot[], + ) { + const alias = `#lltest:${user.homeServer}`; await app.client.network.goOffline(); for (const charly of charlies) { await charly.joinRoom(alias); @@ -107,19 +123,19 @@ test.describe("Lazy Loading", () => { await app.client.waitForNextSync(); } - test("should handle lazy loading properly even when offline", async ({ page, app, bot }) => { + test("should handle lazy loading properly even when offline", async ({ page, app, bot, user }) => { test.slow(); const charly1to5 = charlies.slice(0, 5); const charly6to10 = charlies.slice(5); // Set up room with alice, bob & charlies 1-5 - await setupRoomWithBobAliceAndCharlies(page, app, bot, charly1to5); + await setupRoomWithBobAliceAndCharlies(page, app, user, bot, charly1to5); // Alice should see 2 messages from every charly with the correct display name await checkPaginatedDisplayNames(app, charly1to5); await openMemberlist(app); await checkMemberList(page, charly1to5); - await joinCharliesWhileAliceIsOffline(page, app, charly6to10); + await joinCharliesWhileAliceIsOffline(page, app, user, charly6to10); await checkMemberList(page, charly6to10); for (const charly of charlies) { diff --git a/playwright/e2e/login/login-consent.spec.ts b/playwright/e2e/login/login-consent.spec.ts index ab70e1d1869..32f08463511 100644 --- a/playwright/e2e/login/login-consent.spec.ts +++ b/playwright/e2e/login/login-consent.spec.ts @@ -12,6 +12,7 @@ import { expect, test } from "../../element-web-test"; import { selectHomeserver } from "../utils"; import { Credentials, HomeserverInstance } from "../../plugins/homeserver"; import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; // This test requires fixed credentials for the device signing keys below to work const username = "user1234"; @@ -102,6 +103,8 @@ test.use({ test.describe("Login", () => { test.describe("Password login", () => { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); + test("Loads the welcome page by default; then logs in with an existing account and lands on the home screen", async ({ credentials, page, diff --git a/playwright/e2e/oidc/oidc-native.spec.ts b/playwright/e2e/oidc/oidc-native.spec.ts index 63cf0a5b59f..3c7ffef4ac1 100644 --- a/playwright/e2e/oidc/oidc-native.spec.ts +++ b/playwright/e2e/oidc/oidc-native.spec.ts @@ -9,12 +9,10 @@ Please see LICENSE files in the repository root for full details. import { test, expect } from "../../element-web-test.ts"; import { registerAccountMas } from "."; import { ElementAppPage } from "../../pages/ElementAppPage.ts"; -import { isDendrite } from "../../plugins/homeserver/dendrite"; import { masHomeserver } from "../../plugins/homeserver/synapse/masHomeserver.ts"; test.use(masHomeserver); test.describe("OIDC Native", { tag: ["@no-firefox", "@no-webkit"] }, () => { - test.skip(isDendrite, "does not yet support MAS"); test.slow(); // trace recording takes a while here test("can register the oauth2 client and an account", async ({ context, page, homeserver, mailhogClient, mas }) => { diff --git a/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts b/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts index deefb305dbc..37b510faa5d 100644 --- a/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts +++ b/playwright/e2e/one-to-one-chat/one-to-one-chat.spec.ts @@ -9,12 +9,15 @@ Please see LICENSE files in the repository root for full details. import { test as base, expect } from "../../element-web-test"; import { Credentials } from "../../plugins/homeserver"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; const test = base.extend<{ user2?: Credentials; }>({}); test.describe("1:1 chat room", () => { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3492"); + test.use({ displayName: "Jeff", user2: async ({ homeserver }, use) => { diff --git a/playwright/e2e/permalinks/permalinks.spec.ts b/playwright/e2e/permalinks/permalinks.spec.ts index 9b448455ecf..e7657b13946 100644 --- a/playwright/e2e/permalinks/permalinks.spec.ts +++ b/playwright/e2e/permalinks/permalinks.spec.ts @@ -31,7 +31,7 @@ test.describe("permalinks", () => { await charlotte.prepareClient(); // We don't use a bot for danielle as we want a stable MXID. - const danielleId = "@danielle:localhost"; + const danielleId = `@danielle:${user.homeServer}`; const room1Id = await app.client.createRoom({ name: room1Name }); const room2Id = await app.client.createRoom({ name: room2Name }); diff --git a/playwright/e2e/polls/polls.spec.ts b/playwright/e2e/polls/polls.spec.ts index 727c453a31c..fc49906b47c 100644 --- a/playwright/e2e/polls/polls.spec.ts +++ b/playwright/e2e/polls/polls.spec.ts @@ -11,8 +11,11 @@ import { Bot } from "../../pages/bot"; import { SettingLevel } from "../../../src/settings/SettingLevel"; import { Layout } from "../../../src/settings/enums/Layout"; import type { Locator, Page } from "@playwright/test"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Polls", () => { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3492"); + type CreatePollOptions = { title: string; options: string[]; diff --git a/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts b/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts index da27d39a2ca..4fa204bacea 100644 --- a/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts +++ b/playwright/e2e/read-receipts/editing-messages-in-threads.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("editing messages", () => { test.describe("in threads", () => { test("An edit of a threaded message makes the room unread", async ({ diff --git a/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts b/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts index bc4eff711b0..6c9596a5b2b 100644 --- a/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts +++ b/playwright/e2e/read-receipts/editing-messages-main-timeline.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("editing messages", () => { test.describe("in the main timeline", () => { test("Editing a message leaves a room read", async ({ roomAlpha: room1, roomBeta: room2, util, msg }) => { diff --git a/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts b/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts index a750fd9ba76..9cd158430a8 100644 --- a/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts +++ b/playwright/e2e/read-receipts/editing-messages-thread-roots.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("editing messages", () => { test.describe("thread roots", () => { test("An edit of a thread root leaves the room read", async ({ diff --git a/playwright/e2e/read-receipts/high-level.spec.ts b/playwright/e2e/read-receipts/high-level.spec.ts index 627b2d348d3..a723928c57a 100644 --- a/playwright/e2e/read-receipts/high-level.spec.ts +++ b/playwright/e2e/read-receipts/high-level.spec.ts @@ -9,8 +9,10 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { customEvent, many, test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); test.slow(); test.describe("Ignored events", () => { diff --git a/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts b/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts index 8deef2d2f52..2f3c153f201 100644 --- a/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts +++ b/playwright/e2e/read-receipts/new-messages-in-threads.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { many, test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("new messages", () => { test.describe("in threads", () => { test("Receiving a message makes a room unread", async ({ diff --git a/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts b/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts index 4f94e7b09fb..16c8132378a 100644 --- a/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts +++ b/playwright/e2e/read-receipts/new-messages-main-timeline.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { many, test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("new messages", () => { test.describe("in the main timeline", () => { test("Receiving a message makes a room unread", async ({ diff --git a/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts b/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts index 0e101d311a4..a711d889a16 100644 --- a/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts +++ b/playwright/e2e/read-receipts/new-messages-thread-roots.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { many, test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("new messages", () => { test.describe("thread roots", () => { test("Reading a thread root does not mark the thread as read", async ({ diff --git a/playwright/e2e/read-receipts/reactions-in-threads.spec.ts b/playwright/e2e/read-receipts/reactions-in-threads.spec.ts index eb733d3a12d..b88e18afd8b 100644 --- a/playwright/e2e/read-receipts/reactions-in-threads.spec.ts +++ b/playwright/e2e/read-receipts/reactions-in-threads.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test, expect } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("reactions", () => { test.describe("in threads", () => { test("A reaction to a threaded message does not make the room unread", async ({ diff --git a/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts b/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts index d8c16473836..77ed8cd5823 100644 --- a/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts +++ b/playwright/e2e/read-receipts/reactions-main-timeline.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("reactions", () => { test.describe("in the main timeline", () => { test("Receiving a reaction to a message does not make a room unread", async ({ diff --git a/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts b/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts index d83d55e5dca..a6d21cb34ed 100644 --- a/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts +++ b/playwright/e2e/read-receipts/reactions-thread-roots.spec.ts @@ -9,8 +9,10 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); test.describe("reactions", () => { test.describe("thread roots", () => { test("A reaction to a thread root does not make the room unread", async ({ diff --git a/playwright/e2e/read-receipts/read-receipts.spec.ts b/playwright/e2e/read-receipts/read-receipts.spec.ts index 5d42513b560..8e079e14fdd 100644 --- a/playwright/e2e/read-receipts/read-receipts.spec.ts +++ b/playwright/e2e/read-receipts/read-receipts.spec.ts @@ -12,8 +12,10 @@ import { expect } from "../../element-web-test"; import { ElementAppPage } from "../../pages/ElementAppPage"; import { Bot } from "../../pages/bot"; import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); test.use({ displayName: "Mae", botCreateOpts: { displayName: "Other User" }, diff --git a/playwright/e2e/read-receipts/redactions-in-threads.spec.ts b/playwright/e2e/read-receipts/redactions-in-threads.spec.ts index dc229d0b1b7..4e8b6bef5a3 100644 --- a/playwright/e2e/read-receipts/redactions-in-threads.spec.ts +++ b/playwright/e2e/read-receipts/redactions-in-threads.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("redactions", () => { test.describe("in threads", () => { test("Redacting the threaded message pointed to by my receipt leaves the room read", async ({ diff --git a/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts b/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts index 356d03938f1..203cbb997f8 100644 --- a/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts +++ b/playwright/e2e/read-receipts/redactions-main-timeline.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("redactions", () => { test.describe("in the main timeline", () => { test("Redacting the message pointed to by my receipt leaves the room read", async ({ diff --git a/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts b/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts index d875b0cecb3..108e61df34e 100644 --- a/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts +++ b/playwright/e2e/read-receipts/redactions-thread-roots.spec.ts @@ -9,8 +9,11 @@ Please see LICENSE files in the repository root for full details. /* See readme.md for tips on writing these tests. */ import { test } from "."; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Read receipts", { tag: "@mergequeue" }, () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.describe("redactions", () => { test.describe("thread roots", () => { test("Redacting a thread root after it was read leaves the room read", async ({ diff --git a/playwright/e2e/register/register.spec.ts b/playwright/e2e/register/register.spec.ts index 90854de33a6..a76900d8aa8 100644 --- a/playwright/e2e/register/register.spec.ts +++ b/playwright/e2e/register/register.spec.ts @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. import { test, expect } from "../../element-web-test"; import { consentHomeserver } from "../../plugins/homeserver/synapse/consentHomeserver.ts"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.use(consentHomeserver); test.use({ @@ -23,6 +24,8 @@ test.use({ }); test.describe("Registration", () => { + test.skip(isDendrite, "Dendrite lacks support for MSC3967 so requires additional auth here"); + test.beforeEach(async ({ page }) => { await page.goto("/#/register"); }); diff --git a/playwright/e2e/right-panel/file-panel.spec.ts b/playwright/e2e/right-panel/file-panel.spec.ts index 579ba05bb7f..1c936f43b89 100644 --- a/playwright/e2e/right-panel/file-panel.spec.ts +++ b/playwright/e2e/right-panel/file-panel.spec.ts @@ -10,6 +10,7 @@ import { Download, type Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; import { viewRoomSummaryByName } from "./utils"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; const ROOM_NAME = "Test room"; const NAME = "Alice"; @@ -181,6 +182,8 @@ test.describe("FilePanel", () => { }); test.describe("download", () => { + test.skip(isDendrite, "due to a Dendrite sending Content-Disposition inline"); + test("should download an image via the link on the panel", async ({ page, context }) => { // Upload an image file await uploadFile(page, "playwright/sample-files/riot.png"); diff --git a/playwright/e2e/right-panel/right-panel.spec.ts b/playwright/e2e/right-panel/right-panel.spec.ts index cb2a11ac002..a41b63f93c6 100644 --- a/playwright/e2e/right-panel/right-panel.spec.ts +++ b/playwright/e2e/right-panel/right-panel.spec.ts @@ -38,29 +38,33 @@ test.describe("RightPanel", () => { }); test.describe("in rooms", () => { - test("should handle long room address and long room name", { tag: "@screenshot" }, async ({ page, app }) => { - await app.client.createRoom({ name: ROOM_NAME_LONG }); - await viewRoomSummaryByName(page, app, ROOM_NAME_LONG); - - await app.settings.openRoomSettings(); - - // Set a local room address - const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" }); - await localAddresses.getByRole("textbox").fill(ROOM_ADDRESS_LONG); - await localAddresses.getByRole("button", { name: "Add" }).click(); - await expect(localAddresses.getByText(`#${ROOM_ADDRESS_LONG}:localhost`)).toHaveClass( - "mx_EditableItem_item", - ); - - await app.closeDialog(); - - // Close and reopen the right panel to render the room address - await app.toggleRoomInfoPanel(); - await expect(page.locator(".mx_RightPanel")).not.toBeVisible(); - await app.toggleRoomInfoPanel(); - - await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-name-and-address.png"); - }); + test( + "should handle long room address and long room name", + { tag: "@screenshot" }, + async ({ page, app, user }) => { + await app.client.createRoom({ name: ROOM_NAME_LONG }); + await viewRoomSummaryByName(page, app, ROOM_NAME_LONG); + + await app.settings.openRoomSettings(); + + // Set a local room address + const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" }); + await localAddresses.getByRole("textbox").fill(ROOM_ADDRESS_LONG); + await localAddresses.getByRole("button", { name: "Add" }).click(); + await expect(localAddresses.getByText(`#${ROOM_ADDRESS_LONG}:${user.homeServer}`)).toHaveClass( + "mx_EditableItem_item", + ); + + await app.closeDialog(); + + // Close and reopen the right panel to render the room address + await app.toggleRoomInfoPanel(); + await expect(page.locator(".mx_RightPanel")).not.toBeVisible(); + await app.toggleRoomInfoPanel(); + + await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-name-and-address.png"); + }, + ); test("should handle clicking add widgets", async ({ page, app }) => { await viewRoomSummaryByName(page, app, ROOM_NAME); diff --git a/playwright/e2e/room-directory/room-directory.spec.ts b/playwright/e2e/room-directory/room-directory.spec.ts index 34004c90d27..b48a90b2b7d 100644 --- a/playwright/e2e/room-directory/room-directory.spec.ts +++ b/playwright/e2e/room-directory/room-directory.spec.ts @@ -10,6 +10,7 @@ import type { Preset, Visibility } from "matrix-js-sdk/src/matrix"; import { test, expect } from "../../element-web-test"; test.describe("Room Directory", () => { + test.skip(({ homeserverType }) => homeserverType === "pinecone", "Pinecone's /publicRooms API takes forever"); test.use({ displayName: "Ray", botCreateOpts: { displayName: "Paul" }, @@ -31,14 +32,14 @@ test.describe("Room Directory", () => { const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" }); await localAddresses.getByRole("textbox").fill("gaming"); await localAddresses.getByRole("button", { name: "Add" }).click(); - await expect(localAddresses.getByText("#gaming:localhost")).toHaveClass("mx_EditableItem_item"); + await expect(localAddresses.getByText(`#gaming:${user.homeServer}`)).toHaveClass("mx_EditableItem_item"); // Publish into the public rooms directory const publishedAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Published Addresses" }); - await expect(publishedAddresses.locator("#canonicalAlias")).toHaveValue("#gaming:localhost"); + await expect(publishedAddresses.locator("#canonicalAlias")).toHaveValue(`#gaming:${user.homeServer}`); const checkbox = publishedAddresses .locator(".mx_SettingsFlag", { - hasText: "Publish this room to the public in localhost's room directory?", + hasText: `Publish this room to the public in ${user.homeServer}'s room directory?`, }) .getByRole("switch"); await checkbox.check(); @@ -86,7 +87,7 @@ test.describe("Room Directory", () => { .getByRole("button", { name: "Join" }) .click(); - await expect(page).toHaveURL("/#/room/#test1234:localhost"); + await expect(page).toHaveURL(`/#/room/#test1234:${user.homeServer}`); }, ); }); diff --git a/playwright/e2e/room_options/marked_unread.spec.ts b/playwright/e2e/room_options/marked_unread.spec.ts index b314152e684..2817bbc921a 100644 --- a/playwright/e2e/room_options/marked_unread.spec.ts +++ b/playwright/e2e/room_options/marked_unread.spec.ts @@ -7,10 +7,13 @@ Please see LICENSE files in the repository root for full details. */ import { test, expect } from "../../element-web-test"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; const TEST_ROOM_NAME = "The mark unread test room"; test.describe("Mark as Unread", () => { + test.skip(isDendrite, "due to Dendrite bug https://github.com/element-hq/dendrite/issues/2970"); + test.use({ displayName: "Tom", botCreateOpts: { @@ -48,6 +51,6 @@ test.describe("Mark as Unread", () => { await roomTile.getByRole("button", { name: "Room options" }).click(); await page.getByRole("menuitem", { name: "Mark as unread" }).click(); - expect(page.getByLabel(TEST_ROOM_NAME + " Unread messages.")).toBeVisible(); + await expect(page.getByLabel(TEST_ROOM_NAME + " Unread messages.")).toBeVisible(); }); }); diff --git a/playwright/e2e/settings/general-room-settings-tab.spec.ts b/playwright/e2e/settings/general-room-settings-tab.spec.ts index eec32f7af5e..4216deca220 100644 --- a/playwright/e2e/settings/general-room-settings-tab.spec.ts +++ b/playwright/e2e/settings/general-room-settings-tab.spec.ts @@ -36,7 +36,7 @@ test.describe("General room settings tab", () => { await expect(settings.getByText("Show more")).toBeVisible(); }); - test("long address should not cause dialog to overflow", { tag: "@no-webkit" }, async ({ page, app }) => { + test("long address should not cause dialog to overflow", { tag: "@no-webkit" }, async ({ page, app, user }) => { const settings = await app.settings.openRoomSettings("General"); // 1. Set the room-address to be a really long string const longString = "abcasdhjasjhdaj1jh1asdhasjdhajsdhjavhjksd".repeat(4); @@ -44,7 +44,7 @@ test.describe("General room settings tab", () => { await settings.locator("#roomAliases").getByText("Add", { exact: true }).click(); // 2. wait for the new setting to apply ... - await expect(settings.locator("#canonicalAlias")).toHaveValue(`#${longString}:localhost`); + await expect(settings.locator("#canonicalAlias")).toHaveValue(`#${longString}:${user.homeServer}`); // 3. Check if the dialog overflows const dialogBoundingBox = await page.locator(".mx_Dialog").boundingBox(); diff --git a/playwright/e2e/sliding-sync/sliding-sync.spec.ts b/playwright/e2e/sliding-sync/sliding-sync.spec.ts index 29a612ccd32..2f32c821054 100644 --- a/playwright/e2e/sliding-sync/sliding-sync.spec.ts +++ b/playwright/e2e/sliding-sync/sliding-sync.spec.ts @@ -69,6 +69,11 @@ const test = base.extend<{ }); test.describe("Sliding Sync", () => { + test.skip( + ({ homeserverType }) => homeserverType === "pinecone", + "due to a bug in Pinecone https://github.com/element-hq/dendrite/issues/3490", + ); + const checkOrder = async (wantOrder: string[], page: Page) => { await expect(page.getByRole("group", { name: "Rooms" }).locator(".mx_RoomTile_title")).toHaveText(wantOrder); }; diff --git a/playwright/e2e/spaces/spaces.spec.ts b/playwright/e2e/spaces/spaces.spec.ts index 48bcc13c53a..5acb3a672fe 100644 --- a/playwright/e2e/spaces/spaces.spec.ts +++ b/playwright/e2e/spaces/spaces.spec.ts @@ -10,6 +10,7 @@ import type { Locator, Page } from "@playwright/test"; import { test, expect } from "../../element-web-test"; import type { Preset, ICreateRoomOpts } from "matrix-js-sdk/src/matrix"; import { ElementAppPage } from "../../pages/ElementAppPage"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; async function openSpaceCreateMenu(page: Page): Promise { await page.getByRole("button", { name: "Create a space" }).click(); @@ -50,6 +51,7 @@ function spaceChildInitialState(roomId: string): ICreateRoomOpts["initial_state" } test.describe("Spaces", () => { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488"); test.use({ displayName: "Sue", botCreateOpts: { displayName: "BotBob" }, @@ -82,7 +84,7 @@ test.describe("Spaces", () => { // Copy matrix.to link await page.getByRole("button", { name: "Share invite link" }).click(); - expect(await app.getClipboardText()).toEqual("https://matrix.to/#/#lets-have-a-riot:localhost"); + expect(await app.getClipboardText()).toEqual(`https://matrix.to/#/#lets-have-a-riot:${user.homeServer}`); // Go to space home await page.getByRole("button", { name: "Go to my first room" }).click(); @@ -169,13 +171,13 @@ test.describe("Spaces", () => { room_alias_name: "space", }); - const menu = await openSpaceContextMenu(page, app, "#space:localhost"); + const menu = await openSpaceContextMenu(page, app, `#space:${user.homeServer}`); await menu.getByRole("menuitem", { name: "Invite" }).click(); const shareDialog = page.locator(".mx_SpacePublicShare"); // Copy link first await shareDialog.getByRole("button", { name: "Share invite link" }).click(); - expect(await app.getClipboardText()).toEqual("https://matrix.to/#/#space:localhost"); + expect(await app.getClipboardText()).toEqual(`https://matrix.to/#/#space:${user.homeServer}`); // Start Matrix invite flow await shareDialog.getByRole("button", { name: "Invite people" }).click(); diff --git a/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts b/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts index c45222d035f..683577dce41 100644 --- a/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts +++ b/playwright/e2e/spaces/threads-activity-centre/threadsActivityCentre.spec.ts @@ -8,8 +8,14 @@ import { expect, test } from "."; import { CommandOrControl } from "../../utils"; +import { isDendrite } from "../../../plugins/homeserver/dendrite"; test.describe("Threads Activity Centre", { tag: "@no-firefox" }, () => { + test.skip( + isDendrite, + "due to Dendrite lacking full threads support https://github.com/element-hq/dendrite/issues/3283", + ); + test.use({ displayName: "Alice", botCreateOpts: { displayName: "Other User" }, diff --git a/playwright/e2e/spotlight/spotlight.spec.ts b/playwright/e2e/spotlight/spotlight.spec.ts index d1bb3dec258..444c88d0884 100644 --- a/playwright/e2e/spotlight/spotlight.spec.ts +++ b/playwright/e2e/spotlight/spotlight.spec.ts @@ -12,6 +12,7 @@ import { Filter } from "../../pages/Spotlight"; import { Bot } from "../../pages/bot"; import type { Locator, Page } from "@playwright/test"; import type { ElementAppPage } from "../../pages/ElementAppPage"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; function roomHeaderName(page: Page): Locator { return page.locator(".mx_RoomHeader_heading"); @@ -39,6 +40,8 @@ async function startDM(app: ElementAppPage, page: Page, name: string): Promise { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488"); + const bot1Name = "BotBob"; let bot1: Bot; diff --git a/playwright/e2e/threads/threads.spec.ts b/playwright/e2e/threads/threads.spec.ts index edcc0578d8a..6b8279e344b 100644 --- a/playwright/e2e/threads/threads.spec.ts +++ b/playwright/e2e/threads/threads.spec.ts @@ -8,8 +8,10 @@ Please see LICENSE files in the repository root for full details. import { SettingLevel } from "../../../src/settings/SettingLevel"; import { Layout } from "../../../src/settings/enums/Layout"; import { test, expect } from "../../element-web-test"; +import { isDendrite } from "../../plugins/homeserver/dendrite"; test.describe("Threads", () => { + test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3489"); test.use({ displayName: "Tom", botCreateOpts: { diff --git a/playwright/e2e/widgets/stickers.spec.ts b/playwright/e2e/widgets/stickers.spec.ts index 54de1b69e28..2b7b2709f7c 100644 --- a/playwright/e2e/widgets/stickers.spec.ts +++ b/playwright/e2e/widgets/stickers.spec.ts @@ -88,7 +88,7 @@ async function sendStickerFromPicker(page: Page) { await expect(page.locator(".mx_AppTileFullWidth#stickers")).not.toBeVisible(); } -async function expectTimelineSticker(page: Page, roomId: string, contentUri: string) { +async function expectTimelineSticker(page: Page, serverName: string, roomId: string, contentUri: string) { const contentId = contentUri.split("/").slice(-1)[0]; // Make sure it's in the right room await expect(page.locator(".mx_EventTile_sticker > a")).toHaveAttribute("href", new RegExp(`/${roomId}/`)); @@ -98,7 +98,7 @@ async function expectTimelineSticker(page: Page, roomId: string, contentUri: str // download URL. await expect(page.locator(`img[alt="${STICKER_NAME}"]`)).toHaveAttribute( "src", - new RegExp(`/localhost/${contentId}`), + new RegExp(`/${serverName}/${contentId}`), ); } @@ -156,7 +156,7 @@ test.describe("Stickers", { tag: ["@no-firefox", "@no-webkit"] }, () => { await expect(page).toHaveURL(`/#/room/${room.roomId}`); await openStickerPicker(app); await sendStickerFromPicker(page); - await expectTimelineSticker(page, room.roomId, contentUri); + await expectTimelineSticker(page, user.homeServer, room.roomId, contentUri); // Ensure that when we switch to a different room that the sticker // goes to the right place @@ -164,7 +164,7 @@ test.describe("Stickers", { tag: ["@no-firefox", "@no-webkit"] }, () => { await expect(page).toHaveURL(`/#/room/${roomId2}`); await openStickerPicker(app); await sendStickerFromPicker(page); - await expectTimelineSticker(page, roomId2, contentUri); + await expectTimelineSticker(page, user.homeServer, roomId2, contentUri); }); test("should handle a sticker picker widget missing creatorUserId", async ({ @@ -183,7 +183,7 @@ test.describe("Stickers", { tag: ["@no-firefox", "@no-webkit"] }, () => { await expect(page).toHaveURL(`/#/room/${room.roomId}`); await openStickerPicker(app); await sendStickerFromPicker(page); - await expectTimelineSticker(page, room.roomId, contentUri); + await expectTimelineSticker(page, user.homeServer, room.roomId, contentUri); }); test("should render invalid mimetype as a file", async ({ webserver, page, app, user, room }) => { diff --git a/playwright/element-web-test.ts b/playwright/element-web-test.ts index 0c6392fdc21..2aa87bda95e 100644 --- a/playwright/element-web-test.ts +++ b/playwright/element-web-test.ts @@ -6,7 +6,15 @@ 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 { expect as baseExpect, Locator, Page, ExpectMatcherState, ElementHandle } from "@playwright/test"; +import { + expect as baseExpect, + Locator, + Page, + ExpectMatcherState, + ElementHandle, + PlaywrightTestArgs, + Fixtures as _Fixtures, +} from "@playwright/test"; import { sanitizeForFilePath } from "playwright-core/lib/utils"; import AxeBuilder from "@axe-core/playwright"; import _ from "lodash"; @@ -19,7 +27,7 @@ import { Crypto } from "./pages/crypto"; import { Toasts } from "./pages/toasts"; import { Bot, CreateBotOpts } from "./pages/bot"; import { Webserver } from "./plugins/webserver"; -import { test as base } from "./services.ts"; +import { Options, Services, test as base } from "./services.ts"; // Enable experimental service worker support // See https://playwright.dev/docs/service-workers-experimental#how-to-enable @@ -45,7 +53,7 @@ interface CredentialsWithDisplayName extends Credentials { displayName: string; } -export interface Fixtures { +export interface TestFixtures { axe: AxeBuilder; checkA11y: () => Promise; @@ -102,7 +110,10 @@ export interface Fixtures { disablePresence: boolean; } -export const test = base.extend({ +type CombinedTestFixtures = PlaywrightTestArgs & TestFixtures; +export type Fixtures = _Fixtures; + +export const test = base.extend({ context: async ({ context }, use, testInfo) => { // We skip tests instead of using grep-invert to still surface the counts in the html report test.skip( @@ -150,7 +161,7 @@ export const test = base.extend({ const displayName = testDisplayName ?? _.sample(names)!; const credentials = await homeserver.registerUser(`user_${testInfo.testId}`, password, displayName); - console.log(`Registered test user @user:localhost with displayname ${displayName}`); + console.log(`Registered test user ${credentials.userId} with displayname ${displayName}`); await use({ ...credentials, diff --git a/playwright/flaky-reporter.ts b/playwright/flaky-reporter.ts index ad92aca12e5..2a47f40a013 100644 --- a/playwright/flaky-reporter.ts +++ b/playwright/flaky-reporter.ts @@ -11,7 +11,7 @@ Please see LICENSE files in the repository root for full details. * Only intended to run from within GitHub Actions */ -import type { Reporter, TestCase } from "@playwright/test/reporter"; +import type { Reporter, Suite, TestCase, FullConfig } from "@playwright/test/reporter"; const REPO = "element-hq/element-web"; const LABEL = "Z-Flaky-Test"; @@ -26,8 +26,16 @@ type PaginationLinks = { class FlakyReporter implements Reporter { private flakes = new Set(); + private ignoreSuite = false; + + public onBegin(config: FullConfig, suite: Suite) { + const projectName = suite.project().name; + // Ignores flakes on Dendrite and Pinecone as they have their own flakes we do not track + this.ignoreSuite = ["Dendrite", "Pinecone"].includes(projectName); + } public onTestEnd(test: TestCase): void { + if (this.ignoreSuite) return; const title = `${test.location.file.split("playwright/e2e/")[1]}: ${test.title}`; if (test.outcome() === "flaky") { this.flakes.add(title); diff --git a/playwright/pages/bot.ts b/playwright/pages/bot.ts index 1d414c7bf6a..159d7fcbc2e 100644 --- a/playwright/pages/bot.ts +++ b/playwright/pages/bot.ts @@ -121,7 +121,7 @@ export class Bot extends Client { return logger as unknown as Logger; } - const logger = getLogger(`cypress bot ${credentials.userId}`); + const logger = getLogger(`playwright bot ${credentials.userId}`); const keys = {}; diff --git a/playwright/plugins/homeserver/dendrite/index.ts b/playwright/plugins/homeserver/dendrite/index.ts index 897cafc5a3d..fb3537f4170 100644 --- a/playwright/plugins/homeserver/dendrite/index.ts +++ b/playwright/plugins/homeserver/dendrite/index.ts @@ -6,36 +6,8 @@ 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 { Fixtures } from "@playwright/test"; +import { Options } from "../../../services.ts"; -import { DendriteContainer, PineconeContainer } from "../../../testcontainers/dendrite.ts"; -import { Services } from "../../../services.ts"; - -export const dendriteHomeserver: Fixtures<{}, Services> = { - _homeserver: [ - // eslint-disable-next-line no-empty-pattern - async ({}, use) => { - const container = - process.env["PLAYWRIGHT_HOMESERVER"] === "dendrite" ? new DendriteContainer() : new PineconeContainer(); - await use(container); - }, - { scope: "worker" }, - ], - homeserver: [ - async ({ logger, network, _homeserver: homeserver }, use) => { - const container = await homeserver - .withNetwork(network) - .withNetworkAliases("homeserver") - .withLogConsumer(logger.getConsumer("dendrite")) - .start(); - - await use(container); - await container.stop(); - }, - { scope: "worker" }, - ], +export const isDendrite = ({ homeserverType }: Options): boolean => { + return homeserverType === "dendrite" || homeserverType === "pinecone"; }; - -export function isDendrite(): boolean { - return process.env["PLAYWRIGHT_HOMESERVER"] === "dendrite" || process.env["PLAYWRIGHT_HOMESERVER"] === "pinecone"; -} diff --git a/playwright/plugins/homeserver/index.ts b/playwright/plugins/homeserver/index.ts index 50dea472f78..63847ecbfa9 100644 --- a/playwright/plugins/homeserver/index.ts +++ b/playwright/plugins/homeserver/index.ts @@ -43,3 +43,5 @@ export interface Credentials { displayName?: string; username: string; // the localpart of the userId } + +export type HomeserverType = "synapse" | "dendrite" | "pinecone"; diff --git a/playwright/plugins/homeserver/synapse/consentHomeserver.ts b/playwright/plugins/homeserver/synapse/consentHomeserver.ts index 4abf22b16e4..e714e8a9c11 100644 --- a/playwright/plugins/homeserver/synapse/consentHomeserver.ts +++ b/playwright/plugins/homeserver/synapse/consentHomeserver.ts @@ -6,11 +6,9 @@ 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 { Fixtures } from "@playwright/test"; +import { Fixtures } from "../../../element-web-test.ts"; -import { Services } from "../../../services.ts"; - -export const consentHomeserver: Fixtures<{}, Services> = { +export const consentHomeserver: Fixtures = { _homeserver: [ async ({ _homeserver: container, mailhog }, use) => { container @@ -56,4 +54,9 @@ export const consentHomeserver: Fixtures<{}, Services> = { }, { scope: "worker" }, ], + + context: async ({ homeserverType, context }, use, testInfo) => { + testInfo.skip(homeserverType !== "synapse", "does not yet support MAS"); + await use(context); + }, }; diff --git a/playwright/plugins/homeserver/synapse/emailHomeserver.ts b/playwright/plugins/homeserver/synapse/emailHomeserver.ts index 0df3a670484..f7dee7b01a9 100644 --- a/playwright/plugins/homeserver/synapse/emailHomeserver.ts +++ b/playwright/plugins/homeserver/synapse/emailHomeserver.ts @@ -6,11 +6,9 @@ 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 { Fixtures } from "@playwright/test"; +import { Fixtures } from "../../../element-web-test.ts"; -import { Services } from "../../../services.ts"; - -export const emailHomeserver: Fixtures<{}, Services> = { +export const emailHomeserver: Fixtures = { _homeserver: [ async ({ _homeserver: container, mailhog }, use) => { container.withConfig({ @@ -28,4 +26,9 @@ export const emailHomeserver: Fixtures<{}, Services> = { }, { scope: "worker" }, ], + + context: async ({ homeserverType, context }, use, testInfo) => { + testInfo.skip(homeserverType !== "synapse", "does not yet support MAS"); + await use(context); + }, }; diff --git a/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts b/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts index 246829e422d..239cd00eeb1 100644 --- a/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts +++ b/playwright/plugins/homeserver/synapse/legacyOAuthHomeserver.ts @@ -6,13 +6,12 @@ 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 { Fixtures } from "@playwright/test"; import { TestContainers } from "testcontainers"; -import { Services } from "../../../services.ts"; import { OAuthServer } from "../../oauth_server"; +import { Fixtures } from "../../../element-web-test.ts"; -export const legacyOAuthHomeserver: Fixtures<{}, Services> = { +export const legacyOAuthHomeserver: Fixtures = { _homeserver: [ async ({ _homeserver: container }, use) => { const server = new OAuthServer(); @@ -48,4 +47,9 @@ export const legacyOAuthHomeserver: Fixtures<{}, Services> = { }, { scope: "worker" }, ], + + context: async ({ homeserverType, context }, use, testInfo) => { + testInfo.skip(homeserverType !== "synapse", "does not yet support MAS"); + await use(context); + }, }; diff --git a/playwright/plugins/homeserver/synapse/masHomeserver.ts b/playwright/plugins/homeserver/synapse/masHomeserver.ts index bf2dd13a1c4..63260c4b89f 100644 --- a/playwright/plugins/homeserver/synapse/masHomeserver.ts +++ b/playwright/plugins/homeserver/synapse/masHomeserver.ts @@ -6,14 +6,10 @@ 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 { Fixtures, PlaywrightTestArgs } from "@playwright/test"; - -import { Services } from "../../../services.ts"; -import { Fixtures as BaseFixtures } from "../../../element-web-test.ts"; +import { Fixtures } from "../../../element-web-test.ts"; import { MatrixAuthenticationServiceContainer } from "../../../testcontainers/mas.ts"; -type Fixture = PlaywrightTestArgs & BaseFixtures; -export const masHomeserver: Fixtures = { +export const masHomeserver: Fixtures = { mas: [ async ({ _homeserver: homeserver, logger, network, postgres, mailhog }, use) => { const config = { @@ -83,4 +79,9 @@ export const masHomeserver: Fixtures = { default_server_config: wellKnown, }); }, + + context: async ({ homeserverType, context }, use, testInfo) => { + testInfo.skip(homeserverType !== "synapse", "does not yet support MAS"); + await use(context); + }, }; diff --git a/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts b/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts index 1a0e41a71f7..1e389e2eac2 100644 --- a/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts +++ b/playwright/plugins/homeserver/synapse/uiaLongSessionTimeoutHomeserver.ts @@ -5,11 +5,9 @@ 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 { Fixtures } from "@playwright/test"; +import { Fixtures } from "../../../element-web-test.ts"; -import { Services } from "../../../services.ts"; - -export const uiaLongSessionTimeoutHomeserver: Fixtures<{}, Services> = { +export const uiaLongSessionTimeoutHomeserver: Fixtures = { synapseConfigOptions: [ async ({ synapseConfigOptions }, use) => { await use({ diff --git a/playwright/services.ts b/playwright/services.ts index b480cbc4054..508671c4fa6 100644 --- a/playwright/services.ts +++ b/playwright/services.ts @@ -14,6 +14,8 @@ import { SynapseConfigOptions, SynapseContainer } from "./testcontainers/synapse import { ContainerLogger } from "./testcontainers/utils.ts"; import { StartedMatrixAuthenticationServiceContainer } from "./testcontainers/mas.ts"; import { HomeserverContainer, StartedHomeserverContainer } from "./testcontainers/HomeserverContainer.ts"; +import { DendriteContainer, PineconeContainer } from "./testcontainers/dendrite.ts"; +import { HomeserverType } from "./plugins/homeserver"; export interface Services { logger: ContainerLogger; @@ -24,16 +26,20 @@ export interface Services { mailhog: StartedTestContainer; mailhogClient: mailhog.API; - synapseConfigOptions: SynapseConfigOptions; _homeserver: HomeserverContainer; homeserver: StartedHomeserverContainer; mas?: StartedMatrixAuthenticationServiceContainer; } -export const test = base.extend<{}, Services>({ +export interface Options { + synapseConfigOptions: SynapseConfigOptions; + homeserverType: HomeserverType; +} + +export const test = base.extend<{}, Services & Options>({ logger: [ // eslint-disable-next-line no-empty-pattern - async ({}, use) => { + async ({}, use, testInfo) => { const logger = new ContainerLogger(); await use(logger); }, @@ -93,27 +99,43 @@ export const test = base.extend<{}, Services>({ ], mailhogClient: [ async ({ mailhog: container }, use) => { - await use(mailhog({ host: container.getHost(), port: container.getMappedPort(8025) })); + const client = mailhog({ host: container.getHost(), port: container.getMappedPort(8025) }); + await use(client); }, { scope: "worker" }, ], synapseConfigOptions: [{}, { option: true, scope: "worker" }], + homeserverType: ["synapse", { option: true, scope: "worker" }], _homeserver: [ - // eslint-disable-next-line no-empty-pattern - async ({}, use) => { - const container = new SynapseContainer(); + async ({ homeserverType }, use) => { + let container: HomeserverContainer; + switch (homeserverType) { + case "synapse": + container = new SynapseContainer(); + break; + case "dendrite": + container = new DendriteContainer(); + break; + case "pinecone": + container = new PineconeContainer(); + break; + } + await use(container); }, { scope: "worker" }, ], homeserver: [ - async ({ logger, network, _homeserver: homeserver, synapseConfigOptions, mas }, use) => { + async ({ homeserverType, logger, network, _homeserver: homeserver, synapseConfigOptions, mas }, use) => { + if (homeserver instanceof SynapseContainer) { + homeserver.withConfig(synapseConfigOptions); + } + const container = await homeserver .withNetwork(network) .withNetworkAliases("homeserver") - .withLogConsumer(logger.getConsumer("synapse")) - .withConfig(synapseConfigOptions) + .withLogConsumer(logger.getConsumer(homeserverType)) .start(); await use(container); @@ -131,7 +153,12 @@ export const test = base.extend<{}, Services>({ { scope: "worker" }, ], - context: async ({ logger, context, request, homeserver }, use, testInfo) => { + context: async ({ homeserverType, synapseConfigOptions, logger, context, request, homeserver }, use, testInfo) => { + testInfo.skip( + !(homeserver instanceof SynapseContainer) && Object.keys(synapseConfigOptions).length > 0, + `Test specifies Synapse config options so is unsupported with ${homeserverType}`, + ); + homeserver.setRequest(request); await logger.testStarted(testInfo); await use(context); diff --git a/playwright/testcontainers/synapse.ts b/playwright/testcontainers/synapse.ts index 5111a6f0a66..9b592a2e405 100644 --- a/playwright/testcontainers/synapse.ts +++ b/playwright/testcontainers/synapse.ts @@ -272,7 +272,7 @@ export class StartedSynapseContainer extends AbstractStartedContainer implements const data = await res.json(); return { - homeServer: data.home_server, + homeServer: data.home_server || data.user_id.split(":").slice(1).join(":"), accessToken: data.access_token, userId: data.user_id, deviceId: data.device_id, @@ -305,7 +305,7 @@ export class StartedSynapseContainer extends AbstractStartedContainer implements accessToken: json.access_token, userId: json.user_id, deviceId: json.device_id, - homeServer: json.home_server, + homeServer: json.home_server || json.user_id.split(":").slice(1).join(":"), username: userId.slice(1).split(":")[0], }; }