diff --git a/cypress/e2e/editing/editing.spec.ts b/cypress/e2e/editing/editing.spec.ts
index 8695531a60..113da3421a 100644
--- a/cypress/e2e/editing/editing.spec.ts
+++ b/cypress/e2e/editing/editing.spec.ts
@@ -16,17 +16,8 @@ limitations under the License.
///
-import type { EventType, MsgType, ISendEventResponse, IContent } from "matrix-js-sdk/src/matrix";
-import { SettingLevel } from "../../../src/settings/SettingLevel";
+import type { MsgType, IContent } from "matrix-js-sdk/src/matrix";
import { HomeserverInstance } from "../../plugins/utils/homeserver";
-import Chainable = Cypress.Chainable;
-
-const sendEvent = (roomId: string): Chainable => {
- return cy.sendEvent(roomId, null, "m.room.message" as EventType, {
- msgtype: "m.text" as MsgType,
- body: "Message",
- });
-};
/** generate a message event which will take up some room on the page. */
function mkPadding(n: number): IContent {
@@ -40,37 +31,13 @@ function mkPadding(n: number): IContent {
describe("Editing", () => {
let homeserver: HomeserverInstance;
- let roomId: string;
-
- // Edit "Message"
- const editLastMessage = (edit: string) => {
- cy.get(".mx_EventTile_last").realHover().findByRole("button", { name: "Edit" }).click();
- cy.findByRole("textbox", { name: "Edit message" }).type(`{selectAll}{del}${edit}{enter}`);
- };
-
- const clickEditedMessage = (edited: string) => {
- // Assert that the message was edited
- cy.contains(".mx_EventTile", edited)
- .should("exist")
- .within(() => {
- // Click to display the message edit history dialog
- cy.contains(".mx_EventTile_edited", "(edited)").click();
- });
- };
-
- const clickButtonViewSource = () => {
- // Assert that "View Source" button is rendered and click it
- cy.get(".mx_EventTile .mx_EventTile_line").realHover().findByRole("button", { name: "View Source" }).click();
- };
beforeEach(() => {
cy.startHomeserver("default").then((data) => {
homeserver = data;
cy.initTestUser(homeserver, "Edith").then(() => {
- cy.createRoom({ name: "Test room" }).then((_room1Id) => {
- roomId = _room1Id;
- }),
- cy.injectAxe();
+ cy.createRoom({ name: "Test room" });
+ cy.injectAxe();
});
});
});
@@ -79,224 +46,6 @@ describe("Editing", () => {
cy.stopHomeserver(homeserver);
});
- it("should render and interact with the message edit history dialog", () => {
- // Click the "Remove" button on the message edit history dialog
- const clickButtonRemove = () => {
- cy.get(".mx_EventTile_line").realHover().findByRole("button", { name: "Remove" }).click();
- };
-
- cy.visit("/#/room/" + roomId);
-
- // Send "Message"
- sendEvent(roomId);
-
- cy.get(".mx_RoomView_MessageList").within(() => {
- // Edit "Message" to "Massage"
- editLastMessage("Massage");
-
- // Assert that the edit label is visible
- cy.get(".mx_EventTile_edited").should("be.visible");
-
- clickEditedMessage("Massage");
- });
-
- cy.get(".mx_Dialog").within(() => {
- // Assert that the message edit history dialog is rendered
- cy.get(".mx_MessageEditHistoryDialog").within(() => {
- // Assert CSS styles which are difficult or cannot be detected with snapshots are applied as expected
- cy.get("li").should("have.css", "clear", "both");
- cy.get(".mx_EventTile .mx_MessageTimestamp")
- .should("have.css", "position", "absolute")
- .should("have.css", "inset-inline-start", "0px")
- .should("have.css", "text-align", "center");
- // Assert that monospace characters can fill the content line as expected
- cy.get(".mx_EventTile .mx_EventTile_content").should("have.css", "margin-inline-end", "0px");
-
- // Assert that zero block start padding is applied to mx_EventTile as expected
- // See: .mx_EventTile on _EventTile.pcss
- cy.get(".mx_EventTile").should("have.css", "padding-block-start", "0px");
-
- // Assert that the date separator is rendered at the top
- cy.get("li:nth-child(1) .mx_TimelineSeparator").within(() => {
- cy.get("h2").within(() => {
- cy.findByText("today").should("have.css", "text-transform", "capitalize");
- });
- });
-
- // Assert that the edited message is rendered under the date separator
- cy.get("li:nth-child(2) .mx_EventTile").within(() => {
- // Assert that the edited message body consists of both deleted character and inserted character
- // Above the first "e" of "Message" was replaced with "a"
- cy.get(".mx_EventTile_content .mx_EventTile_body").should("have.text", "Meassage");
-
- cy.get(".mx_EventTile_content .mx_EventTile_body").within(() => {
- cy.get(".mx_EditHistoryMessage_deletion").within(() => {
- cy.findByText("e");
- });
- cy.get(".mx_EditHistoryMessage_insertion").within(() => {
- cy.findByText("a");
- });
- });
- });
-
- // Assert that the original message is rendered at the bottom
- cy.get("li:nth-child(3) .mx_EventTile").within(() => {
- cy.get(".mx_EventTile_content .mx_EventTile_body").within(() => {
- cy.findByText("Message");
- });
- });
- });
- });
-
- // Exclude timestamps from a snapshot
- const percyCSS = ".mx_MessageTimestamp { visibility: hidden !important; }";
-
- // Take a snapshot of the dialog
- cy.get(".mx_Dialog_wrapper").percySnapshotElement("Message edit history dialog", { percyCSS });
-
- cy.get(".mx_Dialog").within(() => {
- cy.get(".mx_MessageEditHistoryDialog li:nth-child(2) .mx_EventTile").within(() => {
- cy.get(".mx_EventTile_content .mx_EventTile_body").should("have.text", "Meassage");
-
- // Click the "Remove" button again
- clickButtonRemove();
- });
-
- // Do nothing and close the dialog to confirm that the message edit history dialog is rendered
- cy.get(".mx_TextInputDialog").closeDialog();
-
- // Assert that the message edit history dialog is rendered again after it was closed
- cy.get(".mx_MessageEditHistoryDialog li:nth-child(2) .mx_EventTile").within(() => {
- cy.get(".mx_EventTile_content .mx_EventTile_body").should("have.text", "Meassage");
-
- // Click the "Remove" button again
- clickButtonRemove();
- });
-
- // This time remove the message really
- cy.get(".mx_TextInputDialog").within(() => {
- cy.findByRole("textbox", { name: "Reason (optional)" }).type("This is a test."); // Reason
- cy.findByRole("button", { name: "Remove" }).click();
- });
-
- // Assert that the message edit history dialog is rendered again
- cy.get(".mx_MessageEditHistoryDialog").within(() => {
- // Assert that the date is rendered
- cy.get("li:nth-child(1) .mx_TimelineSeparator").within(() => {
- cy.get("h2").within(() => {
- cy.findByText("today").should("have.css", "text-transform", "capitalize");
- });
- });
-
- // Assert that the original message is rendered under the date on the dialog
- cy.get("li:nth-child(2) .mx_EventTile").within(() => {
- cy.get(".mx_EventTile_content .mx_EventTile_body").within(() => {
- cy.findByText("Message");
- });
- });
-
- // Assert that the edited message is gone
- cy.contains(".mx_EventTile_content .mx_EventTile_body", "Meassage").should("not.exist");
-
- cy.closeDialog();
- });
- });
-
- // Assert that the main timeline is rendered
- cy.get(".mx_RoomView_MessageList").within(() => {
- cy.get(".mx_EventTile_last .mx_RedactedBody").within(() => {
- // Assert that the placeholder is rendered
- cy.findByText("Message deleted");
- });
- });
- });
-
- it("should render 'View Source' button in developer mode on the message edit history dialog", () => {
- cy.visit("/#/room/" + roomId);
-
- // Send "Message"
- sendEvent(roomId);
-
- cy.get(".mx_RoomView_MessageList").within(() => {
- // Edit "Message" to "Massage"
- editLastMessage("Massage");
-
- // Assert that the edit label is visible
- cy.get(".mx_EventTile_edited").should("be.visible");
-
- clickEditedMessage("Massage");
- });
-
- cy.get(".mx_Dialog").within(() => {
- // Assert that the original message is rendered
- cy.get(".mx_MessageEditHistoryDialog li:nth-child(3)").within(() => {
- // Assert that "View Source" is not rendered
- cy.get(".mx_EventTile .mx_EventTile_line")
- .realHover()
- .findByRole("button", { name: "View Source" })
- .should("not.exist");
- });
-
- cy.closeDialog();
- });
-
- // Enable developer mode
- cy.setSettingValue("developerMode", null, SettingLevel.ACCOUNT, true);
-
- cy.get(".mx_RoomView_MessageList").within(() => {
- clickEditedMessage("Massage");
- });
-
- cy.get(".mx_Dialog").within(() => {
- // Assert that the edited message is rendered
- cy.get(".mx_MessageEditHistoryDialog li:nth-child(2)").within(() => {
- // Assert that "Remove" button for the original message is rendered
- cy.get(".mx_EventTile .mx_EventTile_line").realHover().findByRole("button", { name: "Remove" });
-
- clickButtonViewSource();
- });
-
- // Assert that view source dialog is rendered and close the dialog
- cy.get(".mx_ViewSource").closeDialog();
-
- // Assert that the original message is rendered
- cy.get(".mx_MessageEditHistoryDialog li:nth-child(3)").within(() => {
- // Assert that "Remove" button for the original message does not exist
- cy.get(".mx_EventTile .mx_EventTile_line")
- .realHover()
- .findByRole("button", { name: "Remove" })
- .should("not.exist");
-
- clickButtonViewSource();
- });
-
- // Assert that view source dialog is rendered and close the dialog
- cy.get(".mx_ViewSource").closeDialog();
- });
- });
-
- it("should close the composer when clicking save after making a change and undoing it", () => {
- cy.visit("/#/room/" + roomId);
-
- sendEvent(roomId);
-
- // Edit message
- cy.get(".mx_RoomView_body .mx_EventTile").within(() => {
- cy.findByText("Message");
- cy.get(".mx_EventTile_line").realHover().findByRole("button", { name: "Edit" }).click().checkA11y();
- cy.get(".mx_EventTile_line")
- .findByRole("textbox", { name: "Edit message" })
- .type("Foo{backspace}{backspace}{backspace}{enter}")
- .checkA11y();
- });
- cy.get(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]").within(() => {
- cy.findByText("Message");
- });
-
- // Assert that the edit composer has gone away
- cy.findByRole("textbox", { name: "Edit message" }).should("not.exist");
- });
-
it("should correctly display events which are edited, where we lack the edit event", () => {
// This tests the behaviour when a message has been edited some time after it has been sent, and we
// jump back in room history to view the event, but do not have the actual edit event.
diff --git a/playwright/e2e/editing/editing.spec.ts b/playwright/e2e/editing/editing.spec.ts
new file mode 100644
index 0000000000..f05f6f3382
--- /dev/null
+++ b/playwright/e2e/editing/editing.spec.ts
@@ -0,0 +1,292 @@
+/*
+Copyright 2022 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { Locator, Page } from "@playwright/test";
+
+import type { EventType, MsgType, ISendEventResponse } from "matrix-js-sdk/src/matrix";
+import { test, expect } from "../../element-web-test";
+import { ElementAppPage } from "../../pages/ElementAppPage";
+import { SettingLevel } from "../../../src/settings/SettingLevel";
+
+const sendEvent = async (app: ElementAppPage, roomId: string): Promise => {
+ return app.sendEvent(roomId, null, "m.room.message" as EventType, {
+ msgtype: "m.text" as MsgType,
+ body: "Message",
+ });
+};
+
+test.describe("Editing", () => {
+ // Edit "Message"
+ const editLastMessage = async (page: Page, edit: string) => {
+ const eventTile = page.locator(".mx_RoomView_MessageList .mx_EventTile_last");
+ await eventTile.hover();
+ await eventTile.getByRole("button", { name: "Edit" }).click();
+
+ const textbox = page.getByRole("textbox", { name: "Edit message" });
+ await textbox.fill(edit);
+ await textbox.press("Enter");
+ };
+
+ const clickEditedMessage = async (page: Page, edited: string) => {
+ // Assert that the message was edited
+ const eventTile = page.locator(".mx_EventTile", { hasText: edited });
+ await expect(eventTile).toBeVisible();
+ // Click to display the message edit history dialog
+ await eventTile.getByText("(edited)").click();
+ };
+
+ const clickButtonViewSource = async (locator: Locator) => {
+ const eventTile = locator.locator(".mx_EventTile_line");
+ await eventTile.hover();
+ // Assert that "View Source" button is rendered and click it
+ await eventTile.getByRole("button", { name: "View Source" }).click();
+ };
+
+ test.use({
+ displayName: "Edith",
+ room: async ({ user, app }, use) => {
+ const roomId = await app.createRoom({ name: "Test room" });
+ await use({ roomId });
+ },
+ });
+
+ test("should render and interact with the message edit history dialog", async ({ page, user, app, room }) => {
+ // Click the "Remove" button on the message edit history dialog
+ const clickButtonRemove = async (locator: Locator) => {
+ const eventTileLine = locator.locator(".mx_EventTile_line");
+ await eventTileLine.hover();
+ await eventTileLine.getByRole("button", { name: "Remove" }).click();
+ };
+
+ await page.goto(`#/room/${room.roomId}`);
+
+ // Send "Message"
+ await sendEvent(app, room.roomId);
+
+ // Edit "Message" to "Massage"
+ await editLastMessage(page, "Massage");
+
+ // Assert that the edit label is visible
+ await expect(page.locator(".mx_EventTile_edited")).toBeVisible();
+
+ await clickEditedMessage(page, "Massage");
+
+ // Assert that the message edit history dialog is rendered
+ const dialog = page.getByRole("dialog");
+ const li = dialog.getByRole("listitem").last();
+ // Assert CSS styles which are difficult or cannot be detected with snapshots are applied as expected
+ await expect(li).toHaveCSS("clear", "both");
+
+ const timestamp = li.locator(".mx_EventTile .mx_MessageTimestamp");
+ await expect(timestamp).toHaveCSS("position", "absolute");
+ await expect(timestamp).toHaveCSS("inset-inline-start", "0px");
+ await expect(timestamp).toHaveCSS("text-align", "center");
+
+ // Assert that monospace characters can fill the content line as expected
+ await expect(li.locator(".mx_EventTile .mx_EventTile_content")).toHaveCSS("margin-inline-end", "0px");
+
+ // Assert that zero block start padding is applied to mx_EventTile as expected
+ // See: .mx_EventTile on _EventTile.pcss
+ await expect(li.locator(".mx_EventTile")).toHaveCSS("padding-block-start", "0px");
+
+ // Assert that the date separator is rendered at the top
+ await expect(dialog.getByRole("listitem").first().locator("h2", { hasText: "today" })).toHaveCSS(
+ "text-transform",
+ "capitalize",
+ );
+
+ {
+ // Assert that the edited message is rendered under the date separator
+ const tile = dialog.locator("li:nth-child(2) .mx_EventTile");
+ // Assert that the edited message body consists of both deleted character and inserted character
+ // Above the first "e" of "Message" was replaced with "a"
+ await expect(tile.locator(".mx_EventTile_body")).toHaveText("Meassage");
+
+ const body = tile.locator(".mx_EventTile_content .mx_EventTile_body");
+ await expect(body.locator(".mx_EditHistoryMessage_deletion").getByText("e")).toBeVisible();
+ await expect(body.locator(".mx_EditHistoryMessage_insertion").getByText("a")).toBeVisible();
+ }
+
+ // Assert that the original message is rendered at the bottom
+ await expect(
+ dialog
+ .locator("li:nth-child(3) .mx_EventTile")
+ .locator(".mx_EventTile_content .mx_EventTile_body", { hasText: "Message" }),
+ ).toBeVisible();
+
+ // Take a snapshot of the dialog
+ await expect(dialog).toHaveScreenshot("message-edit-history-dialog.png", {
+ mask: [page.locator(".mx_MessageTimestamp")],
+ });
+
+ {
+ const tile = dialog.locator("li:nth-child(2) .mx_EventTile");
+ await expect(tile.locator(".mx_EventTile_body")).toHaveText("Meassage");
+ // Click the "Remove" button again
+ await clickButtonRemove(tile);
+ }
+
+ // Do nothing and close the dialog to confirm that the message edit history dialog is rendered
+ await app.closeDialog();
+
+ {
+ // Assert that the message edit history dialog is rendered again after it was closed
+ const tile = dialog.locator("li:nth-child(2) .mx_EventTile");
+ await expect(tile.locator(".mx_EventTile_body")).toHaveText("Meassage");
+ // Click the "Remove" button again
+ await clickButtonRemove(tile);
+ }
+
+ // This time remove the message really
+ const textInputDialog = page.locator(".mx_TextInputDialog");
+ await textInputDialog.getByRole("textbox", { name: "Reason (optional)" }).fill("This is a test."); // Reason
+ await textInputDialog.getByRole("button", { name: "Remove" }).click();
+
+ // Assert that the message edit history dialog is rendered again
+ const messageEditHistoryDialog = page.locator(".mx_MessageEditHistoryDialog");
+ // Assert that the date is rendered
+ await expect(
+ messageEditHistoryDialog.getByRole("listitem").first().locator("h2", { hasText: "today" }),
+ ).toHaveCSS("text-transform", "capitalize");
+
+ // Assert that the original message is rendered under the date on the dialog
+ await expect(
+ messageEditHistoryDialog
+ .locator("li:nth-child(2) .mx_EventTile")
+ .locator(".mx_EventTile_content .mx_EventTile_body", { hasText: "Message" }),
+ ).toBeVisible();
+
+ // Assert that the edited message is gone
+ await expect(
+ messageEditHistoryDialog.locator(".mx_EventTile_content .mx_EventTile_body", { hasText: "Meassage" }),
+ ).not.toBeVisible();
+
+ await app.closeDialog();
+
+ // Assert that the redaction placeholder is rendered
+ await expect(
+ page
+ .locator(".mx_RoomView_MessageList")
+ .locator(".mx_EventTile_last .mx_RedactedBody", { hasText: "Message deleted" }),
+ ).toBeVisible();
+ });
+
+ test("should render 'View Source' button in developer mode on the message edit history dialog", async ({
+ page,
+ user,
+ app,
+ room,
+ }) => {
+ await page.goto(`#/room/${room.roomId}`);
+
+ // Send "Message"
+ await sendEvent(app, room.roomId);
+
+ // Edit "Message" to "Massage"
+ await editLastMessage(page, "Massage");
+
+ // Assert that the edit label is visible
+ await expect(page.locator(".mx_EventTile_edited")).toBeVisible();
+
+ await clickEditedMessage(page, "Massage");
+
+ {
+ const dialog = page.getByRole("dialog");
+ // Assert that the original message is rendered
+ const li = dialog.locator("li:nth-child(3)");
+ // Assert that "View Source" is not rendered
+ const eventLine = li.locator(".mx_EventTile_line");
+ await eventLine.hover();
+ await expect(eventLine.getByRole("button", { name: "View Source" })).not.toBeVisible();
+ }
+
+ await app.closeDialog();
+
+ // Enable developer mode
+ await app.setSettingValue("developerMode", null, SettingLevel.ACCOUNT, true);
+
+ await clickEditedMessage(page, "Massage");
+
+ {
+ const dialog = page.getByRole("dialog");
+ {
+ // Assert that the edited message is rendered
+ const li = dialog.locator("li:nth-child(2)");
+ // Assert that "Remove" button for the original message is rendered
+ const line = li.locator(".mx_EventTile_line");
+ await line.hover();
+ await expect(line.getByRole("button", { name: "Remove" })).toBeVisible();
+ await clickButtonViewSource(li);
+ }
+
+ // Assert that view source dialog is rendered and close the dialog
+ await app.closeDialog();
+
+ {
+ // Assert that the original message is rendered
+ const li = dialog.locator("li:nth-child(3)");
+ // Assert that "Remove" button for the original message does not exist
+ const line = li.locator(".mx_EventTile_line");
+ await line.hover();
+ await expect(line.getByRole("button", { name: "Remove" })).not.toBeVisible();
+
+ await clickButtonViewSource(li);
+ }
+
+ // Assert that view source dialog is rendered and close the dialog
+ await app.closeDialog();
+ }
+ });
+
+ test("should close the composer when clicking save after making a change and undoing it", async ({
+ page,
+ user,
+ app,
+ room,
+ axe,
+ checkA11y,
+ }) => {
+ axe.disableRules("color-contrast"); // XXX: We have some known contrast issues here
+ axe.exclude(".mx_Tooltip_visible"); // XXX: this is fine but would be good to fix
+
+ await page.goto(`#/room/${room.roomId}`);
+
+ await sendEvent(app, room.roomId);
+
+ {
+ // Edit message
+ const tile = page.locator(".mx_RoomView_body .mx_EventTile").last();
+ await expect(tile.getByText("Message", { exact: true })).toBeVisible();
+ const line = tile.locator(".mx_EventTile_line");
+ await line.hover();
+ await line.getByRole("button", { name: "Edit" }).click();
+ await checkA11y();
+ const editComposer = page.getByRole("textbox", { name: "Edit message" });
+ await editComposer.pressSequentially("Foo");
+ await editComposer.press("Backspace");
+ await editComposer.press("Backspace");
+ await editComposer.press("Backspace");
+ await editComposer.press("Enter");
+ await checkA11y();
+ }
+ await expect(
+ page.locator(".mx_RoomView_body .mx_EventTile[data-scroll-tokens]", { hasText: "Message" }),
+ ).toBeVisible();
+
+ // Assert that the edit composer has gone away
+ await expect(page.getByRole("textbox", { name: "Edit message" })).not.toBeVisible();
+ });
+});
diff --git a/playwright/element-web-test.ts b/playwright/element-web-test.ts
index 28956919b0..042af50a56 100644
--- a/playwright/element-web-test.ts
+++ b/playwright/element-web-test.ts
@@ -64,6 +64,7 @@ export const test = base.extend<
app: ElementAppPage;
mailhog?: { api: mailhog.API; instance: Instance };
crypto: Crypto;
+ room?: { roomId: string };
toasts: Toasts;
}
>({
diff --git a/playwright/global.d.ts b/playwright/global.d.ts
index 784c09cee4..8b4a280153 100644
--- a/playwright/global.d.ts
+++ b/playwright/global.d.ts
@@ -16,10 +16,15 @@ limitations under the License.
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
+import { type SettingLevel } from "../src/settings/SettingLevel";
+
declare global {
interface Window {
mxMatrixClientPeg: {
get(): MatrixClient;
};
+ mxSettingsStore: {
+ setValue(settingName: string, roomId: string | null, level: SettingLevel, value: any): Promise;
+ };
}
}
diff --git a/playwright/pages/ElementAppPage.ts b/playwright/pages/ElementAppPage.ts
index a984ba0d00..359c0a54b8 100644
--- a/playwright/pages/ElementAppPage.ts
+++ b/playwright/pages/ElementAppPage.ts
@@ -15,11 +15,42 @@ limitations under the License.
*/
import { type Locator, type Page } from "@playwright/test";
-import { type ICreateRoomOpts } from "matrix-js-sdk/src/matrix";
+
+import type { IContent, ICreateRoomOpts, ISendEventResponse } from "matrix-js-sdk/src/matrix";
+import type { SettingLevel } from "../../src/settings/SettingLevel";
export class ElementAppPage {
public constructor(private readonly page: Page) {}
+ /**
+ * Sets the value for a setting. The room ID is optional if the
+ * setting is not being set for a particular room, otherwise it
+ * should be supplied. The value may be null to indicate that the
+ * level should no longer have an override.
+ * @param {string} settingName The name of the setting to change.
+ * @param {String} roomId The room ID to change the value in, may be
+ * null.
+ * @param {SettingLevel} level The level to change the value at.
+ * @param {*} value The new value of the setting, may be null.
+ * @return {Promise} Resolves when the setting has been changed.
+ */
+ public async setSettingValue(settingName: string, roomId: string, level: SettingLevel, value: any): Promise {
+ return this.page.evaluate<
+ Promise,
+ {
+ settingName: string;
+ roomId: string | null;
+ level: SettingLevel;
+ value: any;
+ }
+ >(
+ ({ settingName, roomId, level, value }) => {
+ return window.mxSettingsStore.setValue(settingName, roomId, level, value);
+ },
+ { settingName, roomId, level, value },
+ );
+ }
+
/**
* Open the top left user menu, returning a Locator to the resulting context menu.
*/
@@ -100,4 +131,32 @@ export class ElementAppPage {
await composer.getByRole("button", { name: "More options", exact: true }).click();
return this.page.getByRole("menu");
}
+
+ /**
+ * @param {string} roomId
+ * @param {string} threadId
+ * @param {string} eventType
+ * @param {Object} content
+ */
+ public async sendEvent(
+ roomId: string,
+ threadId: string | null,
+ eventType: string,
+ content: IContent,
+ ): Promise {
+ return this.page.evaluate<
+ Promise,
+ {
+ roomId: string;
+ threadId: string | null;
+ eventType: string;
+ content: IContent;
+ }
+ >(
+ async ({ roomId, threadId, eventType, content }) => {
+ return window.mxMatrixClientPeg.get().sendEvent(roomId, threadId, eventType, content);
+ },
+ { roomId, threadId, eventType, content },
+ );
+ }
}
diff --git a/playwright/snapshots/editing/editing.spec.ts/message-edit-history-dialog-linux.png b/playwright/snapshots/editing/editing.spec.ts/message-edit-history-dialog-linux.png
new file mode 100644
index 0000000000..0135b0a66e
Binary files /dev/null and b/playwright/snapshots/editing/editing.spec.ts/message-edit-history-dialog-linux.png differ