Add Playwright tests for settings toggles (#30318)

* Add playwright tests

* import pages/ remove duplicate create-room

* Update screenshots

* Fix accessibility for devtools

* Disable region test

* Fixup headers

* remove extra test

* Fix permissions dialog

* fixup tests

* update snapshot

* Update jest tests

* Clear up playwright tests

* update widget screenshot

* Fix wrong snaps from using wrong compound version

* Revert mistaken s/checkbox/switch/
This commit is contained in:
Will Hunt
2025-09-04 08:12:24 +01:00
committed by GitHub
parent cba341f824
commit 07c253d11f
43 changed files with 546 additions and 81 deletions

View File

@@ -1,34 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../element-web-test";
test.describe("Create Room", () => {
test.use({ displayName: "Jim" });
test("should allow us to create a public room with name, topic & address set", async ({ page, user, app }) => {
const name = "Test room 1";
const topic = "This room is dedicated to this test and this test only!";
const dialog = await app.openCreateRoomDialog();
// Fill name & topic
await dialog.getByRole("textbox", { name: "Name" }).fill(name);
await dialog.getByRole("textbox", { name: "Topic" }).fill(topic);
// Change room to public
await dialog.getByRole("button", { name: "Room visibility" }).click();
await dialog.getByRole("option", { name: "Public room" }).click();
// Fill room address
await dialog.getByRole("textbox", { name: "Room address" }).fill("test-room-1");
// Submit
await dialog.getByRole("button", { name: "Create room" }).click();
await expect(page).toHaveURL(new RegExp(`/#/room/#test-room-1:${user.homeServer}`));
const header = page.locator(".mx_RoomHeader");
await expect(header).toContainText(name);
});
});

View File

@@ -0,0 +1,33 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../element-web-test";
test.describe("Devtools", () => {
test.use({
displayName: "Alice",
});
test("should render the devtools", { tag: "@screenshot" }, async ({ page, homeserver, user, app, axe }) => {
await app.client.createRoom({ name: "Test Room" });
await app.viewRoomByName("Test Room");
const composer = app.getComposer().locator("[contenteditable]");
await composer.fill("/devtools");
await composer.press("Enter");
const dialog = page.locator(".mx_Dialog");
await dialog.getByLabel("Developer mode").check();
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(dialog).toMatchScreenshot("devtools-dialog.png", {
css: `.mx_CopyableText {
display: none;
}`,
});
});
});

View File

@@ -0,0 +1,38 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { SettingLevel } from "../../../src/settings/SettingLevel";
import { test, expect } from "../../element-web-test";
test.describe("Room upgrade dialog", () => {
test.use({
displayName: "Alice",
});
test(
"should render the room upgrade dialog",
{ tag: "@screenshot" },
async ({ page, homeserver, user, app, axe }) => {
// Enable developer mode
await app.settings.setValue("developerMode", null, SettingLevel.ACCOUNT, true);
await app.client.createRoom({ name: "Test Room" });
await app.viewRoomByName("Test Room");
const composer = app.getComposer().locator("[contenteditable]");
// Pick a room version that is likely to be supported by all our target homeservers.
await composer.fill("/upgraderoom 5");
await composer.press("Enter");
const dialog = page.locator(".mx_Dialog");
await dialog.getByLabel("Automatically invite members from this room to the new one").check();
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(dialog).toMatchScreenshot("upgrade-room.png");
},
);
});

View File

@@ -0,0 +1,28 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../element-web-test";
test.describe("Decline and block invite dialog", function () {
test.use({
displayName: "Hanako",
});
test(
"should show decline and block dialog for a room",
{ tag: "@screenshot" },
async ({ page, app, user, bot, axe }) => {
await bot.createRoom({ name: "Test Room", invite: [user.userId] });
await app.viewRoomByName("Test Room");
await page.getByRole("button", { name: "Decline and block" }).click();
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("decline-and-block-invite-empty.png");
},
);
});

View File

@@ -1,5 +1,5 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024, 2025 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
@@ -57,4 +57,26 @@ test.describe("Location sharing", { tag: "@no-firefox" }, () => {
await expect(page.locator(".mx_Marker")).toBeVisible();
});
test(
"is prompted for and can consent to live location sharing",
{ tag: "@screenshot" },
async ({ page, user, app, axe }) => {
await app.viewRoomById(await app.client.createRoom({}));
const composerOptions = await app.openMessageComposerOptions();
await composerOptions.getByRole("menuitem", { name: "Location", exact: true }).click();
const menu = page.locator(".mx_LocationShareMenu");
await menu.getByRole("button", { name: "My live location" }).click();
await menu.getByLabel("Enable live location sharing").check();
axe.disableRules([
"color-contrast", // XXX: Inheriting colour contrast issues from room view.
"region", // XXX: ContextMenu managed=false does not provide a role.
]);
await expect(axe).toHaveNoViolations();
await expect(menu).toMatchScreenshot("location-live-share-dialog.png");
},
);
});

View File

@@ -0,0 +1,68 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2022, 2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { SettingLevel } from "../../../src/settings/SettingLevel";
import { test, expect } from "../../element-web-test";
const name = "Test room";
const topic = "A decently explanatory topic for a test room.";
test.describe("Create Room", () => {
test.use({ displayName: "Jim" });
test(
"should create a public room with name, topic & address set",
{ tag: "@screenshot" },
async ({ page, user, app, axe }) => {
const dialog = await app.openCreateRoomDialog();
// Fill name & topic
await dialog.getByRole("textbox", { name: "Name" }).fill(name);
await dialog.getByRole("textbox", { name: "Topic" }).fill(topic);
// Change room to public
await dialog.getByRole("button", { name: "Room visibility" }).click();
await dialog.getByRole("option", { name: "Public room" }).click();
// Fill room address
await dialog.getByRole("textbox", { name: "Room address" }).fill("test-create-room-standard");
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
// Snapshot it
await expect(dialog).toMatchScreenshot("create-room.png");
// Submit
await dialog.getByRole("button", { name: "Create room" }).click();
await expect(page).toHaveURL(new RegExp(`/#/room/#test-create-room-standard:${user.homeServer}`));
const header = page.locator(".mx_RoomHeader");
await expect(header).toContainText(name);
},
);
test("should create a video room", { tag: "@screenshot" }, async ({ page, user, app }) => {
await app.settings.setValue("feature_video_rooms", null, SettingLevel.DEVICE, true);
const dialog = await app.openCreateRoomDialog("New video room");
// Fill name & topic
await dialog.getByRole("textbox", { name: "Name" }).fill(name);
await dialog.getByRole("textbox", { name: "Topic" }).fill(topic);
// Change room to public
await dialog.getByRole("button", { name: "Room visibility" }).click();
await dialog.getByRole("option", { name: "Public room" }).click();
// Fill room address
await dialog.getByRole("textbox", { name: "Room address" }).fill("test-create-room-video");
// Snapshot it
await expect(dialog).toMatchScreenshot("create-video-room.png");
// Submit
await dialog.getByRole("button", { name: "Create video room" }).click();
await expect(page).toHaveURL(new RegExp(`/#/room/#test-create-room-video:${user.homeServer}`));
const header = page.locator(".mx_RoomHeader");
await expect(header).toContainText(name);
});
});

View File

@@ -0,0 +1,28 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../../element-web-test";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
test.describe("Notifications 2 tab", () => {
test.use({
displayName: "Alice",
});
test("should display notification settings", { tag: "@screenshot" }, async ({ page, app, user, axe }) => {
await app.settings.setValue("feature_notification_settings2", null, SettingLevel.DEVICE, true);
await page.setViewportSize({ width: 1024, height: 2000 });
const settings = await app.settings.openUserSettings("Notifications");
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(settings).toMatchScreenshot("standard-notifications-2-settings.png", {
// Mask the mxid.
mask: [settings.locator("#mx_NotificationSettings2_MentionCheckbox span")],
});
});
});

View File

@@ -0,0 +1,25 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../../element-web-test";
test.describe("Notifications tab", () => {
test.use({
displayName: "Alice",
});
test("should display notification settings", { tag: "@screenshot" }, async ({ page, app, user, axe }) => {
await page.setViewportSize({ width: 1024, height: 1400 });
const settings = await app.settings.openUserSettings("Notifications");
await settings.getByLabel("Enable notifications for this account").check();
await settings.getByLabel("Enable notifications for this device").check();
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(settings).toMatchScreenshot("standard-notification-settings.png");
});
});

View File

@@ -8,7 +8,7 @@
import { type Locator } from "@playwright/test";
import { test, expect } from "../../element-web-test";
import { test, expect } from "../../../element-web-test";
test.describe("Roles & Permissions room settings tab", () => {
const roomName = "Test room";

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { type Locator } from "@playwright/test";
import { test, expect } from "../../../element-web-test";
test.describe("Roles & Permissions room settings tab", () => {
const roomName = "Test room";
test.use({
displayName: "Alice",
});
let settings: Locator;
test.beforeEach(async ({ user, app }) => {
await app.client.createRoom({ name: roomName });
await app.viewRoomByName(roomName);
settings = await app.settings.openRoomSettings("Security & Privacy");
});
test(
"should be able to toggle on encryption in a room",
{ tag: "@screenshot" },
async ({ page, app, user, axe }) => {
await page.setViewportSize({ width: 1024, height: 1400 });
const encryptedToggle = settings.getByLabel("Encrypted");
await encryptedToggle.click();
// Accept the dialog.
await page.getByRole("button", { name: "Ok " }).click();
await expect(encryptedToggle).toBeChecked();
await expect(encryptedToggle).toBeDisabled();
await settings.getByLabel("Only send messages to verified users.").check();
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(settings).toMatchScreenshot("room-security-settings.png");
},
);
});

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
* Please see LICENSE files in the repository root for full details.
*/
import { type Locator } from "@playwright/test";
import { test, expect } from "../../../element-web-test";
import { SettingLevel } from "../../../../src/settings/SettingLevel";
test.describe("Voice & Video room settings tab", () => {
const roomName = "Test room";
test.use({
displayName: "Alice",
});
let settings: Locator;
test.beforeEach(async ({ user, app, page }) => {
// Execute client actions before setting, as the setting will force a reload.
await app.client.createRoom({ name: roomName });
await app.settings.setValue("feature_group_calls", null, SettingLevel.DEVICE, true);
await app.viewRoomByName(roomName);
settings = await app.settings.openRoomSettings("Voice & Video");
});
test(
"should be able to toggle on Element Call in the room",
{ tag: "@screenshot" },
async ({ page, app, user, axe }) => {
await page.setViewportSize({ width: 1024, height: 1400 });
const callToggle = settings.getByLabel("Enable Element Call as an additional calling option in this room");
await callToggle.check();
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(settings).toMatchScreenshot("room-video-settings.png");
},
);
});

View File

@@ -41,6 +41,18 @@ test.describe("Security user settings tab", () => {
});
});
test("should render the security tab", { tag: "@screenshot" }, async ({ app, page, user }) => {
await page.setViewportSize({ width: 1024, height: 1400 });
const tab = await app.settings.openUserSettings("Security");
await expect(tab).toMatchScreenshot("security-settings-tab.png", {
mask: [
// Contains IM name.
tab.locator("#mx_SetIntegrationManager_BodyText"),
tab.locator("#mx_SetIntegrationManager_ManagerName"),
],
});
});
test("should be able to set an ID server", async ({ app, context, user, page }) => {
const tab = await app.settings.openUserSettings("Security");

View File

@@ -376,4 +376,19 @@ test.describe("Spaces", () => {
await app.viewSpaceByName("Root Space");
await expect(page.locator(".mx_SpaceRoomView")).toMatchScreenshot("space-room-view.png");
});
test("should render spaces visibility settings", { tag: "@screenshot" }, async ({ page, app, user, axe }) => {
await app.client.createSpace({
name: "My Space",
});
await app.viewSpaceByName("My space");
await page.getByLabel("Settings", { exact: true }).click();
await app.settings.switchTab("Visibility");
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(page.locator("#mx_tabpanel_SPACE_VISIBILITY_TAB")).toMatchScreenshot(
"space-visibility-settings.png",
);
});
});

View File

@@ -0,0 +1,98 @@
/*
Copyright 2025 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { test, expect } from "../../element-web-test";
const DEMO_WIDGET_ID = "demo-widget-id";
const DEMO_WIDGET_NAME = "Demo Widget";
const DEMO_WIDGET_TYPE = "demo";
const ROOM_NAME = "Demo";
const DEMO_WIDGET_HTML = `
<html lang="en">
<head>
<title>Demo Widget</title>
<script>
let sendEventCount = 0
window.onmessage = ev => {
if (ev.data.action === 'capabilities') {
window.parent.postMessage(Object.assign({
response: {
capabilities: [
"org.matrix.msc2762.timeline:*",
"org.matrix.msc2762.receive.state_event:m.room.topic",
"org.matrix.msc2762.send.event:net.widget_echo"
]
},
}, ev.data), '*');
}
};
</script>
</head>
</html>
`;
test.describe("Widger permissions dialog", () => {
test.use({
displayName: "Mike",
});
let demoWidgetUrl: string;
test.beforeEach(async ({ webserver }) => {
demoWidgetUrl = webserver.start(DEMO_WIDGET_HTML);
});
test(
"should be updated if user is re-invited into the room with updated state event",
{ tag: "@screenshot" },
async ({ page, app, user, axe }) => {
const roomId = await app.client.createRoom({
name: ROOM_NAME,
});
// setup widget via state event
await app.client.sendStateEvent(
roomId,
"im.vector.modular.widgets",
{
id: DEMO_WIDGET_ID,
creatorUserId: "somebody",
type: DEMO_WIDGET_TYPE,
name: DEMO_WIDGET_NAME,
url: demoWidgetUrl,
},
DEMO_WIDGET_ID,
);
// set initial layout
await app.client.sendStateEvent(
roomId,
"io.element.widgets.layout",
{
widgets: {
[DEMO_WIDGET_ID]: {
container: "top",
index: 1,
width: 100,
height: 0,
},
},
},
"",
);
// open the room
await app.viewRoomByName(ROOM_NAME);
axe.disableRules("color-contrast"); // XXX: Inheriting colour contrast issues from room view.
await expect(axe).toHaveNoViolations();
await expect(page.locator(".mx_WidgetCapabilitiesPromptDialog")).toMatchScreenshot(
"widget-capabilites-prompt.png",
);
},
);
});