/* Copyright 2024 New Vector Ltd. Copyright 2023 The Matrix.org Foundation C.I.C. Copyright 2022 Mikhail Aheichyk Copyright 2022 Nordeck IT + Consulting GmbH. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import type { IWidget } from "matrix-widget-api/src/interfaces/IWidget"; import type { MatrixEvent, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { test, expect } from "../../element-web-test"; import { Client } from "../../pages/client"; 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 = ` Demo Widget `; // mostly copied from src/utils/WidgetUtils.waitForRoomWidget with small modifications async function waitForRoomWidget(client: Client, widgetId: string, roomId: string, add: boolean): Promise { await client.evaluate( (matrixClient, { widgetId, roomId, add }) => { return new Promise((resolve, reject) => { function eventsInIntendedState(evList: MatrixEvent[]) { const widgetPresent = evList.some((ev) => { return ev.getContent() && ev.getContent()["id"] === widgetId; }); if (add) { return widgetPresent; } else { return !widgetPresent; } } const room = matrixClient.getRoom(roomId); const startingWidgetEvents = room.currentState.getStateEvents("im.vector.modular.widgets"); if (eventsInIntendedState(startingWidgetEvents)) { resolve(); return; } function onRoomStateEvents(ev: MatrixEvent) { if (ev.getRoomId() !== roomId || ev.getType() !== "im.vector.modular.widgets") return; const currentWidgetEvents = room.currentState.getStateEvents("im.vector.modular.widgets"); if (eventsInIntendedState(currentWidgetEvents)) { matrixClient.removeListener("RoomState.events" as RoomStateEvent.Events, onRoomStateEvents); resolve(); } } matrixClient.on("RoomState.events" as RoomStateEvent.Events, onRoomStateEvents); }); }, { widgetId, roomId, add }, ); } test.describe("Widget PIP", () => { test.use({ displayName: "Mike", botCreateOpts: { displayName: "Bot", autoAcceptInvites: false }, }); let demoWidgetUrl: string; test.beforeEach(async ({ webserver }) => { demoWidgetUrl = webserver.start(DEMO_WIDGET_HTML); }); for (const userRemove of ["leave", "kick", "ban"] as const) { test(`should be closed on ${userRemove}`, async ({ page, app, bot, user }) => { const roomId = await app.client.createRoom({ name: ROOM_NAME, invite: [bot.credentials.userId], }); // sets bot to Admin and user to Moderator await app.client.sendStateEvent(roomId, "m.room.power_levels", { users: { [user.userId]: 50, [bot.credentials.userId]: 100, }, }); // bot joins the room await bot.joinRoom(roomId); // setup widget via state event const content: IWidget = { id: DEMO_WIDGET_ID, creatorUserId: "somebody", type: DEMO_WIDGET_TYPE, name: DEMO_WIDGET_NAME, url: demoWidgetUrl, }; await app.client.sendStateEvent(roomId, "im.vector.modular.widgets", content, DEMO_WIDGET_ID); // open the room await app.viewRoomByName(ROOM_NAME); // wait for widget state event await waitForRoomWidget(app.client, DEMO_WIDGET_ID, roomId, true); // activate widget in pip mode await page.evaluate( ({ widgetId, roomId }) => { window.mxActiveWidgetStore.setWidgetPersistence(widgetId, roomId, true); }, { widgetId: DEMO_WIDGET_ID, roomId, }, ); // checks that pip window is opened await expect(page.locator(".mx_WidgetPip")).toBeVisible(); // checks that widget is opened in pip const iframe = page.frameLocator(`iframe[title="${DEMO_WIDGET_NAME}"]`); await expect(iframe.locator("#demo")).toBeVisible(); const userId = user.userId; if (userRemove == "leave") { await app.client.leave(roomId); } else if (userRemove == "kick") { await bot.kick(roomId, userId); } else if (userRemove == "ban") { await bot.ban(roomId, userId); } // checks that pip window is closed await expect(iframe.locator(".mx_WidgetPip")).not.toBeVisible(); }); } });