mirror of
https://github.com/Novaloop-AG/healthchat-web.git
synced 2026-11-04 01:19:41 +00:00
Absorb the matrix-react-sdk repository (#28192)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com> Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Florian Duros <florian.duros@ormaz.fr> Co-authored-by: Kim Brose <kim.brose@nordeck.net> Co-authored-by: Florian Duros <florianduros@element.io> Co-authored-by: R Midhun Suresh <hi@midhun.dev> Co-authored-by: dbkr <986903+dbkr@users.noreply.github.com> Co-authored-by: ElementRobot <releases@riot.im> Co-authored-by: dbkr <dbkr@users.noreply.github.com> Co-authored-by: David Baker <dbkr@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Co-authored-by: David Langley <davidl@element.io> Co-authored-by: Michael Weimann <michaelw@matrix.org> Co-authored-by: Timshel <Timshel@users.noreply.github.com> Co-authored-by: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Co-authored-by: Will Hunt <will@half-shot.uk> Co-authored-by: Hubert Chathi <hubert@uhoreg.ca> Co-authored-by: Andrew Ferrazzutti <andrewf@element.io> Co-authored-by: Robin <robin@robin.town> Co-authored-by: Tulir Asokan <tulir@maunium.net>
This commit is contained in:
committed by
GitHub
parent
2b99496025
commit
c05c429803
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { Page } from "@playwright/test";
|
||||
|
||||
import { test as base, expect } from "../../element-web-test";
|
||||
import { Client } from "../../pages/client";
|
||||
import { ElementAppPage } from "../../pages/ElementAppPage";
|
||||
import { Bot } from "../../pages/bot";
|
||||
|
||||
/**
|
||||
* Set up for pinned message tests.
|
||||
*/
|
||||
export const test = base.extend<{
|
||||
room1Name?: string;
|
||||
room1: { name: string; roomId: string };
|
||||
util: Helpers;
|
||||
}>({
|
||||
displayName: "Alice",
|
||||
botCreateOpts: { displayName: "Other User" },
|
||||
|
||||
room1Name: "Room 1",
|
||||
room1: async ({ room1Name: name, app, user, bot }, use) => {
|
||||
const roomId = await app.client.createRoom({ name, invite: [bot.credentials.userId] });
|
||||
await use({ name, roomId });
|
||||
},
|
||||
|
||||
util: async ({ page, app, bot }, use) => {
|
||||
await use(new Helpers(page, app, bot));
|
||||
},
|
||||
});
|
||||
|
||||
export class Helpers {
|
||||
constructor(
|
||||
private page: Page,
|
||||
private app: ElementAppPage,
|
||||
private bot: Bot,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Sends messages into given room as a bot
|
||||
* @param room - the name of the room to send messages into
|
||||
* @param messages - the list of messages to send, these can be strings or implementations of MessageSpec like `editOf`
|
||||
*/
|
||||
async receiveMessages(room: string | { name: string }, messages: string[]) {
|
||||
await this.sendMessageAsClient(this.bot, room, messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the supplied client to send messages or perform actions as specified by
|
||||
* the supplied {@link Message} items.
|
||||
*/
|
||||
private async sendMessageAsClient(cli: Client, roomName: string | { name: string }, messages: string[]) {
|
||||
const room = await this.findRoomByName(typeof roomName === "string" ? roomName : roomName.name);
|
||||
const roomId = await room.evaluate((room) => room.roomId);
|
||||
|
||||
for (const message of messages) {
|
||||
await cli.sendMessage(roomId, { body: message, msgtype: "m.text" });
|
||||
|
||||
// TODO: without this wait, some tests that send lots of messages flake
|
||||
// from time to time. I (andyb) have done some investigation, but it
|
||||
// needs more work to figure out. The messages do arrive over sync, but
|
||||
// they never appear in the timeline, and they never fire a
|
||||
// Room.timeline event. I think this only happens with events that refer
|
||||
// to other events (e.g. replies), so it might be caused by the
|
||||
// referring event arriving before the referred-to event.
|
||||
await this.page.waitForTimeout(100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a room by its name
|
||||
* @param roomName
|
||||
* @private
|
||||
*/
|
||||
private async findRoomByName(roomName: string) {
|
||||
return this.app.client.evaluateHandle((cli, roomName) => {
|
||||
return cli.getRooms().find((r) => r.name === roomName);
|
||||
}, roomName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the room with the supplied name.
|
||||
*/
|
||||
async goTo(room: string | { name: string }) {
|
||||
await this.app.viewRoomByName(typeof room === "string" ? room : room.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeline tile for the given message
|
||||
* @param message
|
||||
*/
|
||||
getEventTile(message: string) {
|
||||
return this.page.locator(".mx_EventTile", { hasText: message });
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin the given message from the quick actions
|
||||
* @param message
|
||||
* @param unpin
|
||||
*/
|
||||
async pinMessageFromQuickActions(message: string, unpin = false) {
|
||||
const timelineMessage = this.page.locator(".mx_MTextBody", { hasText: message });
|
||||
await timelineMessage.hover();
|
||||
await this.page.getByRole("button", { name: unpin ? "Unpin" : "Pin", exact: true }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin the given messages from the quick actions
|
||||
* @param messages
|
||||
* @param unpin
|
||||
*/
|
||||
async pinMessagesFromQuickActions(messages: string[], unpin = false) {
|
||||
for (const message of messages) {
|
||||
await this.pinMessageFromQuickActions(message, unpin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin the given message from the contextual menu
|
||||
* @param message
|
||||
*/
|
||||
async pinMessage(message: string) {
|
||||
const timelineMessage = this.page.locator(".mx_MTextBody", { hasText: message });
|
||||
await timelineMessage.click({ button: "right" });
|
||||
await this.page.getByRole("menuitem", { name: "Pin", exact: true }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin the given messages
|
||||
* @param messages
|
||||
*/
|
||||
async pinMessages(messages: string[]) {
|
||||
for (const message of messages) {
|
||||
await this.pinMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the room info panel
|
||||
*/
|
||||
async openRoomInfo() {
|
||||
await this.page.getByRole("button", { name: "Room info" }).nth(1).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the pinned count in the room info is correct
|
||||
* Open the room info and check the pinned count
|
||||
* @param count
|
||||
*/
|
||||
async assertPinnedCountInRoomInfo(count: number) {
|
||||
await expect(this.page.getByRole("menuitem", { name: "Pinned messages" })).toHaveText(
|
||||
`Pinned messages${count}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the pinned messages list
|
||||
*/
|
||||
async openPinnedMessagesList() {
|
||||
await this.page.getByRole("menuitem", { name: "Pinned messages" }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the right panel
|
||||
*/
|
||||
public getRightPanel() {
|
||||
return this.page.locator("#mx_RightPanel");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the pinned message list contains the given messages
|
||||
* @param messages
|
||||
*/
|
||||
async assertPinnedMessagesList(messages: string[]) {
|
||||
const rightPanel = this.getRightPanel();
|
||||
await expect(rightPanel.getByRole("heading", { name: "Pinned messages" })).toHaveText(
|
||||
`${messages.length} Pinned messages`,
|
||||
);
|
||||
|
||||
const list = rightPanel.getByRole("list");
|
||||
await expect(list.getByRole("listitem")).toHaveCount(messages.length);
|
||||
|
||||
for (const message of messages) {
|
||||
await expect(list.getByText(message)).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the pinned message list is empty
|
||||
*/
|
||||
async assertEmptyPinnedMessagesList() {
|
||||
const rightPanel = this.getRightPanel();
|
||||
await expect(rightPanel).toMatchScreenshot(`pinned-messages-list-empty.png`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the unpin all dialog
|
||||
*/
|
||||
async openUnpinAllDialog() {
|
||||
await this.openRoomInfo();
|
||||
await this.openPinnedMessagesList();
|
||||
await this.page.getByRole("button", { name: "Unpin all" }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unpin all dialog
|
||||
*/
|
||||
getUnpinAllDialog() {
|
||||
return this.page.locator(".mx_Dialog", { hasText: "Unpin all messages?" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the Continue button of the unoin all dialog
|
||||
*/
|
||||
async confirmUnpinAllDialog() {
|
||||
await this.getUnpinAllDialog().getByRole("button", { name: "Continue" }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go back from the pinned messages list
|
||||
*/
|
||||
async backPinnedMessagesList() {
|
||||
await this.page.locator("#mx_RightPanel").getByTestId("base-card-back-button").click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the contextual menu of a message in the pin message list and click on unpin
|
||||
* @param message
|
||||
*/
|
||||
async unpinMessageFromMessageList(message: string) {
|
||||
const item = this.getRightPanel().getByRole("list").getByRole("listitem").filter({
|
||||
hasText: message,
|
||||
});
|
||||
|
||||
await item.getByRole("button").click();
|
||||
await this.page.getByRole("menu", { name: "Open menu" }).getByRole("menuitem", { name: "Unpin" }).click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the banner
|
||||
* @private
|
||||
*/
|
||||
public getBanner() {
|
||||
return this.page.getByTestId("pinned-message-banner");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the banner contains the given message
|
||||
* @param msg
|
||||
*/
|
||||
async assertMessageInBanner(msg: string) {
|
||||
await expect(this.getBanner().getByText(msg)).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the view all button
|
||||
*/
|
||||
public getViewAllButton() {
|
||||
return this.page.getByRole("button", { name: "View all" });
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the close list button
|
||||
*/
|
||||
public getCloseListButton() {
|
||||
return this.page.getByRole("button", { name: "Close list" });
|
||||
}
|
||||
}
|
||||
|
||||
export { expect };
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { test } from "./index";
|
||||
import { expect } from "../../element-web-test";
|
||||
|
||||
test.describe("Pinned messages", () => {
|
||||
test("should show the empty state when there are no pinned messages", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.openRoomInfo();
|
||||
await util.assertPinnedCountInRoomInfo(0);
|
||||
await util.openPinnedMessagesList();
|
||||
await util.assertEmptyPinnedMessagesList();
|
||||
});
|
||||
|
||||
test("should pin one message and to have the pinned message badge in the timeline", async ({
|
||||
page,
|
||||
app,
|
||||
room1,
|
||||
util,
|
||||
}) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1"]);
|
||||
await util.pinMessages(["Msg1"]);
|
||||
|
||||
const tile = util.getEventTile("Msg1");
|
||||
await expect(tile).toMatchScreenshot("pinned-message-Msg1.png", {
|
||||
mask: [tile.locator(".mx_MessageTimestamp")],
|
||||
});
|
||||
});
|
||||
|
||||
test("should pin messages and show them in the room info panel", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
|
||||
await util.pinMessages(["Msg1", "Msg2", "Msg4"]);
|
||||
await util.openRoomInfo();
|
||||
await util.assertPinnedCountInRoomInfo(3);
|
||||
});
|
||||
|
||||
test("should pin messages and show them in the pinned message panel", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
|
||||
// Pin the messages
|
||||
await util.pinMessages(["Msg1", "Msg2", "Msg4"]);
|
||||
await util.openRoomInfo();
|
||||
await util.openPinnedMessagesList();
|
||||
await util.assertPinnedMessagesList(["Msg1", "Msg2", "Msg4"]);
|
||||
});
|
||||
|
||||
test("should unpin one message", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
await util.pinMessages(["Msg1", "Msg2", "Msg4"]);
|
||||
|
||||
await util.openRoomInfo();
|
||||
await util.openPinnedMessagesList();
|
||||
await util.unpinMessageFromMessageList("Msg2");
|
||||
await util.assertPinnedMessagesList(["Msg1", "Msg4"]);
|
||||
await util.backPinnedMessagesList();
|
||||
await util.assertPinnedCountInRoomInfo(2);
|
||||
});
|
||||
|
||||
test("should unpin all messages", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
await util.pinMessages(["Msg1", "Msg2", "Msg4"]);
|
||||
|
||||
await util.openUnpinAllDialog();
|
||||
await expect(util.getUnpinAllDialog()).toMatchScreenshot("unpin-all-dialog.png");
|
||||
await util.confirmUnpinAllDialog();
|
||||
|
||||
await util.assertEmptyPinnedMessagesList();
|
||||
await util.backPinnedMessagesList();
|
||||
await util.assertPinnedCountInRoomInfo(0);
|
||||
});
|
||||
|
||||
test("should be able to pin and unpin from the quick actions", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
await util.pinMessagesFromQuickActions(["Msg1"]);
|
||||
await util.openRoomInfo();
|
||||
await util.assertPinnedCountInRoomInfo(1);
|
||||
|
||||
await util.pinMessagesFromQuickActions(["Msg1"], true);
|
||||
await util.assertPinnedCountInRoomInfo(0);
|
||||
});
|
||||
|
||||
test("should display one message in the banner", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1"]);
|
||||
await util.pinMessages(["Msg1"]);
|
||||
await util.assertMessageInBanner("Msg1");
|
||||
await expect(util.getBanner()).toMatchScreenshot("pinned-message-banner-1-Msg1.png");
|
||||
});
|
||||
|
||||
test("should display 2 messages in the banner", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2"]);
|
||||
await util.pinMessages(["Msg1", "Msg2"]);
|
||||
|
||||
await util.assertMessageInBanner("Msg2");
|
||||
await expect(util.getBanner()).toMatchScreenshot("pinned-message-banner-2-Msg2.png");
|
||||
|
||||
await util.getBanner().click();
|
||||
await util.assertMessageInBanner("Msg1");
|
||||
await expect(util.getBanner()).toMatchScreenshot("pinned-message-banner-2-Msg1.png");
|
||||
|
||||
await util.getBanner().click();
|
||||
await util.assertMessageInBanner("Msg2");
|
||||
await expect(util.getBanner()).toMatchScreenshot("pinned-message-banner-2-Msg2.png");
|
||||
});
|
||||
|
||||
test("should display 4 messages in the banner", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
await util.pinMessages(["Msg1", "Msg2", "Msg3", "Msg4"]);
|
||||
|
||||
for (const msg of ["Msg4", "Msg3", "Msg2", "Msg1"]) {
|
||||
await util.assertMessageInBanner(msg);
|
||||
await expect(util.getBanner()).toMatchScreenshot(`pinned-message-banner-4-${msg}.png`);
|
||||
await util.getBanner().click();
|
||||
}
|
||||
});
|
||||
|
||||
test("should open the pinned messages list from the banner", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2"]);
|
||||
await util.pinMessages(["Msg1", "Msg2"]);
|
||||
|
||||
await util.getViewAllButton().click();
|
||||
await util.assertPinnedMessagesList(["Msg1", "Msg2"]);
|
||||
|
||||
await expect(util.getCloseListButton()).toBeVisible();
|
||||
});
|
||||
|
||||
test("banner should listen to pinned message list", async ({ page, app, room1, util }) => {
|
||||
await util.goTo(room1);
|
||||
await util.receiveMessages(room1, ["Msg1", "Msg2"]);
|
||||
await util.pinMessages(["Msg1", "Msg2"]);
|
||||
|
||||
await expect(util.getViewAllButton()).toBeVisible();
|
||||
|
||||
await util.openRoomInfo();
|
||||
await util.openPinnedMessagesList();
|
||||
await expect(util.getCloseListButton()).toBeVisible();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user