Merge 4b79bb6b18
into ebef0d353e
commit
f697a5c161
|
@ -111,17 +111,23 @@ jobs:
|
|||
# Run multiple instances in parallel to speed up the tests
|
||||
runner: ${{ fromJSON(needs.build.outputs.runners-matrix) }}
|
||||
project:
|
||||
- Chrome
|
||||
- Firefox
|
||||
- WebKit
|
||||
# - Chrome
|
||||
# - Firefox
|
||||
# - WebKit
|
||||
- Dendrite
|
||||
- Pinecone
|
||||
runAllTests:
|
||||
- ${{ github.event_name == 'schedule' || contains(github.event.pull_request.labels.*.name, 'X-Run-All-Tests') }}
|
||||
- true
|
||||
# Skip the Firefox & Safari runs unless this was a cron trigger or PR has X-Run-All-Tests label
|
||||
exclude:
|
||||
- runAllTests: false
|
||||
project: Firefox
|
||||
- runAllTests: false
|
||||
project: WebKit
|
||||
- runAllTests: false
|
||||
project: Dendrite
|
||||
- runAllTests: false
|
||||
project: Pinecone
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
|
|
@ -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<Options>({
|
||||
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 },
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
|
@ -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",
|
||||
});
|
||||
|
|
|
@ -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",
|
||||
});
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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<ISendEventResponse> {
|
||||
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");
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 }) => {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 }) => {
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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", () => {
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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 ({
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
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();
|
||||
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",
|
||||
);
|
||||
// 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();
|
||||
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();
|
||||
// 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");
|
||||
});
|
||||
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);
|
||||
|
|
|
@ -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}`);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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<Locator> {
|
||||
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();
|
||||
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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<v
|
|||
}
|
||||
|
||||
test.describe("Spotlight", () => {
|
||||
test.skip(isDendrite, "due to a Dendrite bug https://github.com/element-hq/dendrite/issues/3488");
|
||||
|
||||
const bot1Name = "BotBob";
|
||||
let bot1: Bot;
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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 }) => {
|
||||
|
|
|
@ -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<void>;
|
||||
|
||||
|
@ -102,7 +110,10 @@ export interface Fixtures {
|
|||
disablePresence: boolean;
|
||||
}
|
||||
|
||||
export const test = base.extend<Fixtures>({
|
||||
type CombinedTestFixtures = PlaywrightTestArgs & TestFixtures;
|
||||
export type Fixtures = _Fixtures<CombinedTestFixtures, Services & Options, CombinedTestFixtures>;
|
||||
|
||||
export const test = base.extend<TestFixtures>({
|
||||
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<Fixtures>({
|
|||
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,
|
||||
|
|
|
@ -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<string>();
|
||||
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);
|
||||
|
|
|
@ -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 = {};
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -43,3 +43,5 @@ export interface Credentials {
|
|||
displayName?: string;
|
||||
username: string; // the localpart of the userId
|
||||
}
|
||||
|
||||
export type HomeserverType = "synapse" | "dendrite" | "pinecone";
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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<Fixture, Services, Fixture> = {
|
||||
export const masHomeserver: Fixtures = {
|
||||
mas: [
|
||||
async ({ _homeserver: homeserver, logger, network, postgres, mailhog }, use) => {
|
||||
const config = {
|
||||
|
@ -83,4 +79,9 @@ export const masHomeserver: Fixtures<Fixture, Services, Fixture> = {
|
|||
default_server_config: wellKnown,
|
||||
});
|
||||
},
|
||||
|
||||
context: async ({ homeserverType, context }, use, testInfo) => {
|
||||
testInfo.skip(homeserverType !== "synapse", "does not yet support MAS");
|
||||
await use(context);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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<any>;
|
||||
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<any>;
|
||||
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);
|
||||
|
|
|
@ -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],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -237,7 +237,8 @@ const ForwardDialog: React.FC<IProps> = ({ matrixClient: cli, event, permalinkCr
|
|||
room_id: event.getRoomId(),
|
||||
origin_server_ts: event.getTs(),
|
||||
});
|
||||
mockEvent.sender = {
|
||||
// @ts-ignore - private field access
|
||||
mockEvent._sender = {
|
||||
name: profileInfo.displayname || userId,
|
||||
rawDisplayName: profileInfo.displayname,
|
||||
userId,
|
||||
|
|
|
@ -89,7 +89,8 @@ export default class EventTilePreview extends React.Component<IProps, IState> {
|
|||
/* eslint-enable quote-props */
|
||||
|
||||
// Fake it more
|
||||
event.sender = {
|
||||
// @ts-ignore - private field access
|
||||
event._sender = {
|
||||
name: this.props.displayName || this.props.userId,
|
||||
rawDisplayName: this.props.displayName,
|
||||
userId: this.props.userId,
|
||||
|
|
|
@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixEvent, MatrixEventEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import * as TextForEvent from "../../../TextForEvent";
|
||||
|
@ -21,6 +21,19 @@ export default class TextualEvent extends React.Component<IProps> {
|
|||
public static contextType = RoomContext;
|
||||
declare public context: React.ContextType<typeof RoomContext>;
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.props.mxEvent.on(MatrixEventEvent.SentinelUpdated, this.onEventSentinelUpdated);
|
||||
}
|
||||
public componentWillUnmount(): void {
|
||||
this.props.mxEvent.off(MatrixEventEvent.SentinelUpdated, this.onEventSentinelUpdated);
|
||||
}
|
||||
|
||||
private onEventSentinelUpdated = (): void => {
|
||||
// XXX: this is crap, but we don't have a better way to force a re-render
|
||||
// Many TextForEvent handlers render parts of `event.sender` and `event.target` so ensure they are updated
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const text = TextForEvent.textForEvent(
|
||||
this.props.mxEvent,
|
||||
|
|
|
@ -154,7 +154,7 @@ async function fetchPinnedEvent(room: Room, pinnedEventId: string, cli: MatrixCl
|
|||
const senderUserId = event.getSender();
|
||||
if (senderUserId && PinningUtils.isUnpinnable(event)) {
|
||||
// Inject sender information
|
||||
event.sender = room.getMember(senderUserId);
|
||||
event.setMetadata(room.currentState, false);
|
||||
// Also inject any edits we've found
|
||||
if (edit) event.makeReplaced(edit);
|
||||
|
||||
|
|
|
@ -761,7 +761,8 @@ export default class EventIndex extends EventEmitter {
|
|||
// We set this manually to avoid emitting RoomMember.membership and
|
||||
// RoomMember.name events.
|
||||
member.events.member = memberEvent;
|
||||
matrixEvent.sender = member;
|
||||
// @ts-ignore - private field access
|
||||
matrixEvent._sender = member;
|
||||
|
||||
return matrixEvent;
|
||||
});
|
||||
|
|
|
@ -110,12 +110,7 @@ export default abstract class Exporter {
|
|||
}
|
||||
|
||||
protected setEventMetadata(event: MatrixEvent): MatrixEvent {
|
||||
const roomState = this.room.currentState;
|
||||
const sender = event.getSender();
|
||||
event.sender = (!!sender && roomState?.getSentinelMember(sender)) || null;
|
||||
if (event.getType() === "m.room.member") {
|
||||
event.target = roomState?.getSentinelMember(event.getStateKey()!) ?? null;
|
||||
}
|
||||
event.setMetadata(this.room.currentState, false);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
|
|
@ -350,7 +350,8 @@ export default class HTMLExporter extends Exporter {
|
|||
}
|
||||
const modifiedEvent = new MatrixEvent();
|
||||
modifiedEvent.event = mxEv.event;
|
||||
modifiedEvent.sender = mxEv.sender;
|
||||
// @ts-ignore - private field access
|
||||
modifiedEvent._sender = mxEv.sender;
|
||||
modifiedEvent.event.type = "m.room.message";
|
||||
modifiedEvent.event.content = modifiedContent;
|
||||
return modifiedEvent;
|
||||
|
|
|
@ -405,7 +405,8 @@ export function mkEvent(opts: MakeEventProps): MatrixEvent {
|
|||
|
||||
const mxEvent = opts.event ? new MatrixEvent(event) : (event as unknown as MatrixEvent);
|
||||
if (!mxEvent.sender && opts.user && opts.room) {
|
||||
mxEvent.sender = {
|
||||
// @ts-ignore - private field access
|
||||
mxEvent._sender = {
|
||||
userId: opts.user,
|
||||
membership: KnownMembership.Join,
|
||||
name: opts.user,
|
||||
|
@ -470,7 +471,8 @@ export function mkMembership(
|
|||
}
|
||||
const e = mkEvent(event);
|
||||
if (opts.target) {
|
||||
e.target = opts.target;
|
||||
// @ts-ignore - private field access
|
||||
e._target = opts.target;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -179,7 +179,8 @@ describe("TextForEvent", () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
mxEvent.sender = { name: userA.name } as RoomMember;
|
||||
// @ts-ignore - private field access
|
||||
mxEvent._sender = { name: userA.name } as RoomMember;
|
||||
return mxEvent;
|
||||
};
|
||||
|
||||
|
|
|
@ -122,8 +122,9 @@ describe("ReactionEventPreview", () => {
|
|||
type: "m.reaction",
|
||||
room: roomId,
|
||||
});
|
||||
event.sender = new RoomMember(roomId, userId);
|
||||
event.sender.name = "Bob";
|
||||
// @ts-ignore - private field access
|
||||
event._sender = new RoomMember(roomId, userId);
|
||||
event.sender!.name = "Bob";
|
||||
|
||||
expect(preview.getTextFor(event)).toMatchInlineSnapshot(`"Bob reacted 🪿 to duck duck goose"`);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue