mv element.io @types __mocks__/ debian docker module_system/ playwright res src test webapp Dockerfile .dockerignore .eslintignore .stylelintrc.cjs babel.config.cjs recorder-worklet-loader.cjs .modernizr.json components.json config.json config.sample.json package.json project.json tsconfig.json tsconfig.module_system.json jest.config.ts playwright.config.ts webpack.config.ts build_config.sample.yaml apps/web/
mkdir apps/web/scripts
mv scripts/{cleanup.sh,ci_package.sh,copy-res.ts,deploy.py,package.sh} apps/web/scripts
And a couple of gitignore tweaks
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 Suguru Hirahara
|
||||
|
||||
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 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";
|
||||
|
||||
async function uploadFile(page: Page, file: string) {
|
||||
// Upload a file from the message composer
|
||||
await page.locator(".mx_MessageComposer_actions input[type='file']").setInputFiles(file);
|
||||
|
||||
await page.locator(".mx_Dialog").getByRole("button", { name: "Upload" }).click();
|
||||
|
||||
// Wait until the file is sent
|
||||
await expect(page.locator(".mx_RoomView_statusArea_expanded")).not.toBeVisible();
|
||||
await expect(page.locator(".mx_EventTile.mx_EventTile_last").getByRole("status")).toHaveAccessibleName(
|
||||
"Your message was sent",
|
||||
);
|
||||
}
|
||||
|
||||
test.describe("FilePanel", () => {
|
||||
test.use({
|
||||
displayName: NAME,
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ page, user, app }) => {
|
||||
await app.client.createRoom({ name: ROOM_NAME });
|
||||
|
||||
// Open the file panel
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
await page.getByRole("menuitem", { name: "Files" }).click();
|
||||
await expect(page.locator(".mx_FilePanel")).toBeVisible();
|
||||
});
|
||||
|
||||
test.describe("render", { tag: ["@no-firefox", "@no-webkit"] }, () => {
|
||||
test("should render empty state", { tag: "@screenshot" }, async ({ page }) => {
|
||||
// Wait until the information about the empty state is rendered
|
||||
await expect(page.locator(".mx_EmptyState")).toBeVisible();
|
||||
|
||||
// Take a snapshot of RightPanel - fix https://github.com/vector-im/element-web/issues/25332
|
||||
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("empty.png");
|
||||
});
|
||||
|
||||
test("should list tiles on the panel", { tag: "@screenshot" }, async ({ page }) => {
|
||||
// Upload multiple files
|
||||
await uploadFile(page, "playwright/sample-files/riot.png"); // Image
|
||||
await uploadFile(page, "playwright/sample-files/1sec.ogg"); // Audio
|
||||
await uploadFile(page, "playwright/sample-files/matrix-org-client-versions.json"); // JSON
|
||||
|
||||
const roomViewBody = page.locator(".mx_RoomView_body");
|
||||
// Assert that all of the file were uploaded and rendered
|
||||
await expect(roomViewBody.locator(".mx_EventTile[data-layout='group']")).toHaveCount(3);
|
||||
|
||||
// Assert that the image exists and has the alt string
|
||||
await expect(roomViewBody.locator(".mx_EventTile[data-layout='group'] img[alt='riot.png']")).toBeVisible();
|
||||
|
||||
// Assert that the audio player is rendered
|
||||
await expect(roomViewBody.getByRole("region", { name: "Audio player" })).toBeVisible();
|
||||
|
||||
// Assert that the file button exists
|
||||
await expect(
|
||||
roomViewBody.locator(".mx_EventTile_last[data-layout='group'] .mx_MFileBody", { hasText: ".json" }),
|
||||
).toBeVisible();
|
||||
|
||||
const filePanel = page.locator(".mx_FilePanel");
|
||||
// Assert that the file panel is opened inside mx_RightPanel and visible
|
||||
await expect(filePanel).toBeVisible();
|
||||
|
||||
const filePanelMessageList = filePanel.locator(".mx_RoomView_MessageList");
|
||||
|
||||
// Assert that data-layout attribute is not applied to file tiles on the panel
|
||||
await expect(filePanelMessageList.locator(".mx_EventTile[data-layout]")).not.toBeVisible();
|
||||
|
||||
// Assert that all of the file tiles are rendered
|
||||
await expect(filePanelMessageList.locator(".mx_EventTile")).toHaveCount(3);
|
||||
|
||||
// Assert that the download links are rendered
|
||||
await expect(filePanelMessageList.locator(".mx_MFileBody_download,.mx_MFileBody_info")).toHaveCount(3);
|
||||
|
||||
// Assert that the sender of the files is rendered on all of the tiles
|
||||
await expect(filePanelMessageList.getByText(NAME)).toHaveCount(3);
|
||||
|
||||
// Detect the image file
|
||||
const image = filePanelMessageList.locator(".mx_EventTile_mediaLine.mx_EventTile_image .mx_MImageBody");
|
||||
// Assert that the image is specified as thumbnail and has the alt string
|
||||
await expect(image.locator("img[class='mx_MImageBody_thumbnail']")).toBeVisible();
|
||||
await expect(image.locator("img[alt='riot.png']")).toBeVisible();
|
||||
|
||||
// Detect the audio file
|
||||
const audio = filePanelMessageList.getByRole("region", { name: "Audio player" });
|
||||
// Assert that the play button is rendered
|
||||
await expect(audio.getByRole("button", { name: "Play" })).toBeVisible();
|
||||
|
||||
// Detect the JSON file
|
||||
// Assert that the tile is rendered as a button
|
||||
const file = filePanelMessageList.locator(
|
||||
".mx_EventTile_mediaLine .mx_MFileBody .mx_MFileBody_info[role='button'] .mx_MFileBody_info_filename",
|
||||
);
|
||||
// Assert that the file name is rendered inside the button with ellipsis
|
||||
await expect(file.getByText(/matrix.*?\.json/)).toBeVisible();
|
||||
|
||||
// Make the viewport tall enough to display all of the file tiles on FilePanel
|
||||
await page.setViewportSize({ width: 800, height: 1000 });
|
||||
|
||||
// In case the panel is scrollable on the resized viewport
|
||||
// Assert that the value for flexbox is applied
|
||||
await expect(filePanel.locator(".mx_ScrollPanel .mx_RoomView_MessageList")).toHaveCSS(
|
||||
"justify-content",
|
||||
"flex-end",
|
||||
);
|
||||
// Assert that all of the file tiles are visible before taking a snapshot
|
||||
await expect(filePanelMessageList.locator(".mx_MImageBody")).toBeVisible(); // top
|
||||
await expect(filePanelMessageList.locator(".mx_MAudioBody")).toBeVisible(); // middle
|
||||
const senderDetails = filePanelMessageList.locator(".mx_EventTile_last .mx_EventTile_senderDetails");
|
||||
await expect(senderDetails.locator(".mx_DisambiguatedProfile")).toBeVisible();
|
||||
await expect(senderDetails.locator(".mx_MessageTimestamp")).toBeVisible();
|
||||
|
||||
// Take a snapshot of file tiles list on FilePanel
|
||||
await expect(filePanelMessageList).toMatchScreenshot("file-tiles-list.png", {
|
||||
// Exclude timestamps & flaky seek bar from snapshot
|
||||
mask: [page.getByTestId("audio-player-seek")],
|
||||
css: `
|
||||
.mx_MessageTimestamp {
|
||||
visibility: hidden;
|
||||
}
|
||||
`,
|
||||
});
|
||||
});
|
||||
|
||||
test("should render the audio player and play the audio file on the panel", async ({ page }) => {
|
||||
// Upload an image file
|
||||
await uploadFile(page, "playwright/sample-files/1sec.ogg");
|
||||
|
||||
const audioBody = page.getByTestId("right-panel").getByRole("region", { name: "Audio player" });
|
||||
|
||||
// Assert that the audio player is rendered
|
||||
// Assert that the audio file information is rendered;
|
||||
await expect(audioBody.getByText("1sec.ogg")).toBeVisible(); // extension
|
||||
await expect(audioBody.getByRole("time")).toHaveText("00:01"); // duration
|
||||
await expect(audioBody.getByText("(3.56 KB)")).toBeVisible(); // actual size;
|
||||
|
||||
// Assert that the duration counter is 00:01 before clicking the play button
|
||||
await expect(audioBody.getByRole("time")).toHaveText("00:01");
|
||||
|
||||
// Assert that the counter is zero before clicking the play button
|
||||
await expect(audioBody.getByRole("timer")).toHaveText("00:00");
|
||||
|
||||
// Click the play button
|
||||
await audioBody.getByRole("button", { name: "Play" }).click();
|
||||
|
||||
// Assert that the pause button is rendered
|
||||
await expect(audioBody.getByRole("button", { name: "Pause" })).toBeVisible();
|
||||
|
||||
// Assert that the timer is reset when the audio file finished playing
|
||||
await expect(audioBody.getByRole("timer")).toHaveText("00:00");
|
||||
|
||||
// Assert that the play button is rendered
|
||||
await expect(audioBody.getByRole("button", { name: "Play" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("should render file size in kibibytes on a file tile", async ({ page }) => {
|
||||
const size = "1.12 KB"; // actual file size in kibibytes (1024 bytes)
|
||||
|
||||
// Upload a file
|
||||
await uploadFile(page, "playwright/sample-files/matrix-org-client-versions.json");
|
||||
|
||||
const tile = page.locator(".mx_FilePanel .mx_EventTile");
|
||||
// Assert that the file size is displayed in kibibytes, not kilobytes (1000 bytes)
|
||||
// See: https://github.com/vector-im/element-web/issues/24866
|
||||
await expect(tile.locator(".mx_MFileBody_info_filename", { hasText: size })).toBeVisible();
|
||||
await expect(tile.locator(".mx_MFileBody_info", { hasText: size })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
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");
|
||||
|
||||
// Detect the image file on the panel
|
||||
const imageBody = page.locator(
|
||||
".mx_FilePanel .mx_RoomView_MessageList .mx_EventTile_mediaLine.mx_EventTile_image .mx_MImageBody",
|
||||
);
|
||||
|
||||
const link = imageBody.locator(".mx_MFileBody_download a");
|
||||
|
||||
const downloadPromise = page.waitForEvent("download");
|
||||
|
||||
// Click the anchor link (not the image itself)
|
||||
await link.click();
|
||||
|
||||
const download = await downloadPromise;
|
||||
expect(download.suggestedFilename()).toBe("riot.png");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright 2024 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 { Bot } from "../../pages/bot";
|
||||
|
||||
const ROOM_NAME = "Test room";
|
||||
const NAME = "Alice";
|
||||
|
||||
async function setupRoomWithMembers(
|
||||
app: any,
|
||||
page: any,
|
||||
homeserver: any,
|
||||
roomName: string,
|
||||
memberNames: string[],
|
||||
): Promise<string> {
|
||||
const visibility = await page.evaluate(() => (window as any).matrixcs.Visibility.Public);
|
||||
const id = await app.client.createRoom({ name: roomName, visibility });
|
||||
const bots: Bot[] = [];
|
||||
|
||||
for (let i = 0; i < memberNames.length; i++) {
|
||||
const displayName = memberNames[i];
|
||||
const bot = new Bot(page, homeserver, { displayName, startClient: false, autoAcceptInvites: false });
|
||||
if (displayName === "Susan") {
|
||||
await bot.prepareClient();
|
||||
await app.client.inviteUser(id, bot.credentials?.userId);
|
||||
} else {
|
||||
await bot.joinRoom(id);
|
||||
}
|
||||
bots.push(bot);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
test.use({
|
||||
synapseConfig: {
|
||||
presence: {
|
||||
enabled: false,
|
||||
include_offline_users_on_sync: false,
|
||||
},
|
||||
},
|
||||
displayName: NAME,
|
||||
disablePresence: true,
|
||||
});
|
||||
|
||||
test.describe("Memberlist", () => {
|
||||
test.beforeEach(async ({ app, user, page, homeserver }, testInfo) => {
|
||||
testInfo.setTimeout(testInfo.timeout + 30_000);
|
||||
const names = ["Bob", "Bob", "Susan"];
|
||||
await setupRoomWithMembers(app, page, homeserver, ROOM_NAME, names);
|
||||
});
|
||||
|
||||
test("Renders correctly", { tag: "@screenshot" }, async ({ page, app }) => {
|
||||
await app.viewRoomByName(ROOM_NAME);
|
||||
const memberlist = await app.toggleMemberlistPanel();
|
||||
await expect(memberlist.locator(".mx_MemberTileView")).toHaveCount(4);
|
||||
await expect(memberlist.getByText("Invited")).toHaveCount(1);
|
||||
await expect(page.locator(".mx_MemberListView")).toMatchScreenshot("with-four-members.png");
|
||||
});
|
||||
|
||||
test("should handle scroll and click to view member profile", async ({ page, app, homeserver }) => {
|
||||
// Create a room with many members to enable scrolling
|
||||
const memberNames = Array.from({ length: 15 }, (_, i) => `Member${i.toString()}`);
|
||||
await setupRoomWithMembers(app, page, homeserver, "Large Room", memberNames);
|
||||
|
||||
// Navigate to the room and open member list
|
||||
await app.viewRoomByName("Large Room");
|
||||
|
||||
const memberlist = await app.toggleMemberlistPanel();
|
||||
|
||||
// Get the scrollable container
|
||||
const memberListContainer = memberlist.locator(".mx_AutoHideScrollbar");
|
||||
|
||||
// Scroll down to the bottom of the member list
|
||||
await app.scrollListToBottom(memberListContainer);
|
||||
|
||||
// Wait for the target member to be visible after scrolling
|
||||
// Member9 is the last in the list as they are lexicographically sorted
|
||||
const targetName = "Member9";
|
||||
const targetMember = memberlist.locator(".mx_MemberTileView_name").filter({ hasText: targetName });
|
||||
await targetMember.waitFor({ state: "visible" });
|
||||
// Alice is not visible and will require scrolling to,
|
||||
// but is likely in the dom as we have an overscan on the top and bottom of the list.
|
||||
// Click on a member near the bottom of the list
|
||||
await expect(targetMember).toBeVisible();
|
||||
await targetMember.click();
|
||||
|
||||
// Verify that the user info screen is shown and hasn't scrolled back to top
|
||||
await expect(page.locator(".mx_UserInfo")).toBeVisible();
|
||||
await expect(page.locator(".mx_UserInfo_profile").getByText(targetName)).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2023 Suguru Hirahara
|
||||
|
||||
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 ROOM_NAME = "Test room";
|
||||
const NAME = "Alice";
|
||||
|
||||
test.describe("NotificationPanel", () => {
|
||||
test.use({
|
||||
displayName: NAME,
|
||||
labsFlags: ["feature_notifications"],
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ app, user }) => {
|
||||
await app.client.createRoom({ name: ROOM_NAME });
|
||||
});
|
||||
|
||||
test("should render empty state", { tag: "@screenshot" }, async ({ page, app }) => {
|
||||
await app.viewRoomByName(ROOM_NAME);
|
||||
|
||||
await page.getByRole("button", { name: "Notifications" }).click();
|
||||
|
||||
// Wait until the information about the empty state is rendered
|
||||
await expect(page.locator(".mx_EmptyState")).toBeVisible();
|
||||
|
||||
// Take a snapshot of RightPanel
|
||||
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("empty.png");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
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
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type Locator, type Page } from "@playwright/test";
|
||||
|
||||
import { test, expect } from "../../element-web-test";
|
||||
import { checkRoomSummaryCard, viewRoomSummaryByName } from "./utils";
|
||||
import { isDendrite } from "../../plugins/homeserver/dendrite";
|
||||
import { Bot } from "../../pages/bot";
|
||||
|
||||
const ROOM_NAME = "Test room";
|
||||
const ROOM_NAME_LONG =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore " +
|
||||
"et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " +
|
||||
"aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum " +
|
||||
"dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui " +
|
||||
"officia deserunt mollit anim id est laborum.";
|
||||
const SPACE_NAME = "Test space";
|
||||
const NAME = "Alice";
|
||||
const LONG_NAME = "Bob long long long long long long long long long long long long long long long name";
|
||||
|
||||
const ROOM_ADDRESS_LONG =
|
||||
"loremIpsumDolorSitAmetConsecteturAdipisicingElitSedDoEiusmodTemporIncididuntUtLaboreEtDoloreMagnaAliqua";
|
||||
|
||||
function getMemberTileByName(page: Page, name: string): Locator {
|
||||
return page.locator(".mx_MemberListView .mx_MemberTileView_name").filter({ hasText: name });
|
||||
}
|
||||
|
||||
test.describe("RightPanel", () => {
|
||||
let testRoomId: string;
|
||||
test.use({
|
||||
displayName: NAME,
|
||||
});
|
||||
|
||||
test.beforeEach(async ({ app, user }) => {
|
||||
testRoomId = await app.client.createRoom({ name: ROOM_NAME });
|
||||
await app.client.createSpace({ name: SPACE_NAME });
|
||||
});
|
||||
|
||||
test.describe("in rooms", () => {
|
||||
test(
|
||||
"should handle long room address and long room name",
|
||||
{ tag: "@screenshot" },
|
||||
async ({ page, app, user }) => {
|
||||
await app.client.createRoom({ name: ROOM_NAME_LONG });
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME_LONG);
|
||||
|
||||
await app.settings.openRoomSettings();
|
||||
|
||||
// Set a local room address
|
||||
const localAddresses = page.locator(".mx_SettingsFieldset", { hasText: "Local Addresses" });
|
||||
await localAddresses.getByRole("textbox").fill(ROOM_ADDRESS_LONG);
|
||||
await expect(page.getByText("This address is available to use")).toBeVisible();
|
||||
await localAddresses.getByRole("button", { name: "Add" }).click();
|
||||
await expect(localAddresses.getByText(`#${ROOM_ADDRESS_LONG}:${user.homeServer}`)).toHaveClass(
|
||||
"mx_EditableItem_item",
|
||||
);
|
||||
|
||||
await app.closeDialog();
|
||||
|
||||
// Close and reopen the right panel to render the room address
|
||||
await app.toggleRoomInfoPanel();
|
||||
await expect(page.locator(".mx_RightPanel")).not.toBeVisible();
|
||||
await app.toggleRoomInfoPanel();
|
||||
|
||||
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-name-and-address.png");
|
||||
},
|
||||
);
|
||||
|
||||
test("should have padding under leave room", { tag: "@screenshot" }, async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
const leaveButton = await page.getByRole("menuitem", { name: "Leave Room" });
|
||||
await leaveButton.scrollIntoViewIfNeeded();
|
||||
|
||||
await expect(page.locator(".mx_RightPanel")).toMatchScreenshot("with-leave-room.png");
|
||||
});
|
||||
|
||||
test("should handle clicking add widgets", { tag: "@screenshot" }, async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Extensions" }).click();
|
||||
await expect(page.getByTestId("right-panel")).toMatchScreenshot("with-extensions.png");
|
||||
|
||||
await page.getByRole("button", { name: "Add extensions" }).click();
|
||||
await expect(page.locator(".mx_IntegrationManager")).toBeVisible();
|
||||
});
|
||||
|
||||
test("should handle viewing export chat", async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Export Chat" }).click();
|
||||
await expect(page.locator(".mx_ExportDialog")).toBeVisible();
|
||||
});
|
||||
|
||||
test("should handle viewing share room", async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Copy link" }).click();
|
||||
await expect(page.locator(".mx_ShareDialog")).toBeVisible();
|
||||
});
|
||||
|
||||
test("should handle viewing room settings", async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Settings" }).click();
|
||||
await expect(page.locator(".mx_RoomSettingsDialog")).toBeVisible();
|
||||
await expect(page.locator(".mx_Dialog_title").getByText("Room Settings - " + ROOM_NAME)).toBeVisible();
|
||||
});
|
||||
|
||||
test("should handle viewing files", async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Files" }).click();
|
||||
await expect(page.locator(".mx_FilePanel")).toBeVisible();
|
||||
await expect(page.locator(".mx_EmptyState")).toBeVisible();
|
||||
|
||||
await page.getByTestId("base-card-back-button").click();
|
||||
await checkRoomSummaryCard(page, ROOM_NAME);
|
||||
});
|
||||
|
||||
test("should handle viewing room member", async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.locator(".mx_RightPanel").getByRole("menuitem", { name: "People" }).click();
|
||||
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
||||
|
||||
await getMemberTileByName(page, NAME).click();
|
||||
await expect(page.locator(".mx_UserInfo")).toBeVisible();
|
||||
await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();
|
||||
|
||||
await page.getByTestId("base-card-back-button").click();
|
||||
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
||||
|
||||
await page.getByLabel("Room info").nth(1).click();
|
||||
await checkRoomSummaryCard(page, ROOM_NAME);
|
||||
});
|
||||
|
||||
test(
|
||||
"should handle viewing long room member name",
|
||||
{ tag: "@screenshot" },
|
||||
async ({ page, homeserver, app }) => {
|
||||
const bobLongName = new Bot(page, homeserver, { displayName: LONG_NAME });
|
||||
await bobLongName.prepareClient();
|
||||
await app.client.inviteUser(testRoomId, bobLongName.credentials.userId);
|
||||
await bobLongName.joinRoom(testRoomId);
|
||||
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.locator(".mx_RightPanel").getByRole("menuitem", { name: "People" }).click();
|
||||
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
||||
|
||||
await getMemberTileByName(page, LONG_NAME).click();
|
||||
await expect(page.locator(".mx_UserInfo")).toBeVisible();
|
||||
await expect(page.locator(".mx_UserInfo_profile").getByText(LONG_NAME)).toBeVisible();
|
||||
|
||||
await expect(page.locator(".mx_UserInfo")).toMatchScreenshot("with-long-name.png", {
|
||||
mask: [page.locator(".mx_UserInfo_profile_mxid")],
|
||||
css: `
|
||||
/* Use monospace font for consistent mask width */
|
||||
.mx_UserInfo_profile_mxid {
|
||||
font-family: "Fira Code" !important;
|
||||
}
|
||||
`,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.describe("room reporting", () => {
|
||||
test.skip(isDendrite, "Dendrite does not implement room reporting");
|
||||
test("should handle reporting a room", { tag: "@screenshot" }, async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Report room" }).click();
|
||||
const dialog = await page.getByRole("dialog", { name: "Report Room" });
|
||||
await dialog.getByLabel("reason").fill("This room should be reported");
|
||||
await expect(dialog).toMatchScreenshot("room-report-dialog.png");
|
||||
await dialog.getByRole("button", { name: "Send report" }).click();
|
||||
|
||||
// Dialog should have gone
|
||||
await expect(page.locator(".mx_Dialog")).toHaveCount(0);
|
||||
});
|
||||
test("should handle reporting a room and leaving the room", async ({ page, app }) => {
|
||||
await viewRoomSummaryByName(page, app, ROOM_NAME);
|
||||
|
||||
await page.getByRole("menuitem", { name: "Report room" }).click();
|
||||
const dialog = await page.getByRole("dialog", { name: "Report room" });
|
||||
await dialog.getByRole("switch", { name: "Leave room" }).click();
|
||||
await dialog.getByLabel("reason").fill("This room should be reported");
|
||||
await dialog.getByRole("button", { name: "Send report" }).click();
|
||||
await page.getByRole("dialog", { name: "Leave room" }).getByRole("button", { name: "Leave" }).click();
|
||||
|
||||
// Dialog should have gone
|
||||
await expect(page.locator(".mx_Dialog")).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("in spaces", () => {
|
||||
test("should handle viewing space member", async ({ page, app }) => {
|
||||
await app.viewSpaceHomeByName(SPACE_NAME);
|
||||
|
||||
// \d represents the number of the space members
|
||||
await page
|
||||
.locator(".mx_RoomInfoLine")
|
||||
.getByRole("button", { name: /\d member/ })
|
||||
.click();
|
||||
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
||||
|
||||
await getMemberTileByName(page, NAME).click();
|
||||
await expect(page.locator(".mx_UserInfo")).toBeVisible();
|
||||
await expect(page.locator(".mx_UserInfo_profile").getByText(NAME)).toBeVisible();
|
||||
|
||||
await page.getByTestId("base-card-back-button").click();
|
||||
await expect(page.locator(".mx_MemberListView")).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 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 { type Page, expect } from "@playwright/test";
|
||||
|
||||
import { type ElementAppPage } from "../../pages/ElementAppPage";
|
||||
|
||||
export async function viewRoomSummaryByName(page: Page, app: ElementAppPage, name: string): Promise<void> {
|
||||
await app.viewRoomByName(name);
|
||||
await app.toggleRoomInfoPanel();
|
||||
return checkRoomSummaryCard(page, name);
|
||||
}
|
||||
|
||||
export async function checkRoomSummaryCard(page: Page, name: string): Promise<void> {
|
||||
await expect(page.locator(".mx_RoomSummaryCard")).toBeVisible();
|
||||
await expect(page.locator(".mx_RoomSummaryCard")).toContainText(name);
|
||||
}
|
||||
Reference in New Issue
Block a user