From 364e403b0b8300a0bbe088d1faa62ef843645517 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Wed, 22 Jun 2022 15:07:19 +0300 Subject: [PATCH 01/10] Jitsi call is ended when member is banned --- src/components/views/elements/AppTile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index e9e8c9474a5..d2318e90805 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -210,7 +210,7 @@ export default class AppTile extends React.Component { } private onMyMembership = (room: Room, membership: string): void => { - if (membership === "leave" && room.roomId === this.props.room?.roomId) { + if ((membership === "leave" || membership === "ban") && room.roomId === this.props.room?.roomId) { this.onUserLeftRoom(); } }; From a4f76efa1bda98f6400bcf07c17e6121ba7870e9 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Tue, 2 Aug 2022 11:27:57 +0300 Subject: [PATCH 02/10] cypress tests for widget PIP close on leave/kick/ban --- cypress/e2e/widgets/widget-pip-close.spec.ts | 197 +++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 cypress/e2e/widgets/widget-pip-close.spec.ts diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts new file mode 100644 index 00000000000..0f3c8071214 --- /dev/null +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -0,0 +1,197 @@ +/* +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 { IWidget } from "matrix-widget-api/src/interfaces/IWidget"; +import { MatrixClient, MatrixEvent, RoomStateEvent } from "matrix-js-sdk/src/matrix"; + +import { SynapseInstance } from "../../plugins/synapsedocker"; +import { UserCredentials } from "../../support/login"; + +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 +function waitForRoomWidget(matrixClient: MatrixClient, widgetId: string, roomId: string, add: boolean): Promise { + return new Promise((resolve, reject) => { + function eventsInIntendedState(evList) { + 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(RoomStateEvent.Events, onRoomStateEvents); + resolve(); + } + } + + matrixClient.on(RoomStateEvent.Events, onRoomStateEvents); + }); +} + +describe("Widget PIP", () => { + let synapse: SynapseInstance; + let user: UserCredentials; + let bot: MatrixClient; + let demoWidgetUrl: string; + + function roomCreateAddWidgetPip(userRemove: 'leave' | 'kick' | 'ban') { + cy.createRoom({ + name: ROOM_NAME, + invite: [bot.getUserId()], + }).then(roomId => { + // sets bot to Admin and user to Moderator + cy.getClient().then(matrixClient => { + return matrixClient.sendStateEvent(roomId, 'm.room.power_levels', { + users: { + [user.userId]: 50, + [bot.getUserId()]: 100, + }, + }); + }).as('powerLevelsChanged'); + + // bot joins the room + cy.botJoinRoom(bot, roomId).as('botJoined'); + + // open the room + cy.viewRoomByName(ROOM_NAME); + + // setup widget via state event + cy.getClient().then(matrixClient => { + const content: IWidget = { + id: DEMO_WIDGET_ID, + creatorUserId: 'somebody', + type: DEMO_WIDGET_TYPE, + name: DEMO_WIDGET_NAME, + url: demoWidgetUrl, + }; + matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, DEMO_WIDGET_ID); + }); + + cy.all([ + cy.get("@powerLevelsChanged"), + cy.get("@botJoined"), + ]).then(() => { + cy.window().then(async win => { + // wait for widget state event + await waitForRoomWidget(win.mxMatrixClientPeg.get(), DEMO_WIDGET_ID, roomId, true); + + // activate widget in pip mode + win.mxActiveWidgetStore.setWidgetPersistence(DEMO_WIDGET_ID, roomId, true); + + // checks that pip window is opened + cy.get(".mx_CallView_pip").should("exist"); + + // checks that widget is opened in pip + cy.accessIframe(`iframe[title="${DEMO_WIDGET_NAME}"]`).within({}, () => { + cy.get("#demo").should('exist'); + }); + + const userId = user.userId; + if (userRemove == 'leave') { + cy.getClient().then(async matrixClient => { + await matrixClient.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 + cy.get(".mx_CallView_pip").should("not.exist"); + }); + }); + }); + } + + beforeEach(() => { + cy.startSynapse("default").then(data => { + synapse = data; + + cy.initTestUser(synapse, "Mike").then(_user => { + user = _user; + }); + cy.getBot(synapse, { displayName: "Bot" }).then(_bot => { + bot = _bot; + }); + }); + cy.serveHtmlFile(DEMO_WIDGET_HTML).then(url => { + demoWidgetUrl = url; + }); + }); + + afterEach(() => { + cy.stopSynapse(synapse); + cy.stopWebServers(); + }); + + it('should be closed on leave', () => { + roomCreateAddWidgetPip('leave'); + }); + + it('should be closed on kick', () => { + roomCreateAddWidgetPip('kick'); + }); + + it('should be closed on ban', () => { + roomCreateAddWidgetPip('ban'); + }); +}); From 500bb2a5c8f557c5590cd7dea0ccd21f01a712bf Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Wed, 3 Aug 2022 10:25:04 +0300 Subject: [PATCH 03/10] copyright updated --- cypress/e2e/widgets/widget-pip-close.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index 0f3c8071214..eb215b110d0 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -1,5 +1,6 @@ /* -Copyright 2022 The Matrix.org Foundation C.I.C. +Copyright 2022 Mikhail Aheichyk +Copyright 2022 Nordeck IT + Consulting GmbH. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 95b48b8a020dd57542ebcf20cb0f0938579f37dc Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Thu, 11 Aug 2022 15:24:06 +0300 Subject: [PATCH 04/10] import changes --- cypress/e2e/widgets/widget-pip-close.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index eb215b110d0..67f8c3e03cb 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -18,8 +18,9 @@ limitations under the License. /// import { IWidget } from "matrix-widget-api/src/interfaces/IWidget"; -import { MatrixClient, MatrixEvent, RoomStateEvent } from "matrix-js-sdk/src/matrix"; +import { RoomStateEvent } from "matrix-js-sdk/src/matrix"; +import type { MatrixClient, MatrixEvent} from "matrix-js-sdk/src/matrix"; import { SynapseInstance } from "../../plugins/synapsedocker"; import { UserCredentials } from "../../support/login"; From 4af1c32c945c5791750ef66c5a02f253e16b8910 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Thu, 11 Aug 2022 15:30:46 +0300 Subject: [PATCH 05/10] import changes, lint fixed --- cypress/e2e/widgets/widget-pip-close.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index 67f8c3e03cb..a90a3447ac7 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -20,7 +20,7 @@ limitations under the License. import { IWidget } from "matrix-widget-api/src/interfaces/IWidget"; import { RoomStateEvent } from "matrix-js-sdk/src/matrix"; -import type { MatrixClient, MatrixEvent} from "matrix-js-sdk/src/matrix"; +import type { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { SynapseInstance } from "../../plugins/synapsedocker"; import { UserCredentials } from "../../support/login"; From cab3a68eafa452f4982eda6515e78188ef7273a5 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Fri, 12 Aug 2022 14:38:33 +0300 Subject: [PATCH 06/10] import changes --- cypress/e2e/widgets/widget-pip-close.spec.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index a90a3447ac7..945c51d6e1e 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -18,7 +18,7 @@ limitations under the License. /// import { IWidget } from "matrix-widget-api/src/interfaces/IWidget"; -import { RoomStateEvent } from "matrix-js-sdk/src/matrix"; +// import { RoomStateEvent } from "matrix-js-sdk/src/matrix"; import type { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { SynapseInstance } from "../../plugins/synapsedocker"; @@ -79,12 +79,14 @@ function waitForRoomWidget(matrixClient: MatrixClient, widgetId: string, roomId: const currentWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets'); if (eventsInIntendedState(currentWidgetEvents)) { - matrixClient.removeListener(RoomStateEvent.Events, onRoomStateEvents); + // @ts-ignore + matrixClient.removeListener('RoomState.events', onRoomStateEvents); resolve(); } } - matrixClient.on(RoomStateEvent.Events, onRoomStateEvents); + // @ts-ignore + matrixClient.on('RoomState.events', onRoomStateEvents); }); } From 1007885e730a3f09daf186d0a7aa3621a22785d5 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Mon, 15 Aug 2022 11:54:30 +0300 Subject: [PATCH 07/10] smaller spec changes to fix problems --- cypress/e2e/widgets/widget-pip-close.spec.ts | 62 +++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index 945c51d6e1e..e8debd0f9b4 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -112,26 +112,27 @@ describe("Widget PIP", () => { }).as('powerLevelsChanged'); // bot joins the room - cy.botJoinRoom(bot, roomId).as('botJoined'); + cy.botJoinRoom(bot, roomId).then(async () => { + // wait for bot to join the room, otherwise sometimes widget event is not found + // setup widget via state event + cy.getClient().then(async matrixClient => { + const content: IWidget = { + id: DEMO_WIDGET_ID, + creatorUserId: 'somebody', + type: DEMO_WIDGET_TYPE, + name: DEMO_WIDGET_NAME, + url: demoWidgetUrl, + }; + await matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, DEMO_WIDGET_ID); + }); + }).as('botJoinedWidgetEventSent'); // open the room cy.viewRoomByName(ROOM_NAME); - // setup widget via state event - cy.getClient().then(matrixClient => { - const content: IWidget = { - id: DEMO_WIDGET_ID, - creatorUserId: 'somebody', - type: DEMO_WIDGET_TYPE, - name: DEMO_WIDGET_NAME, - url: demoWidgetUrl, - }; - matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, DEMO_WIDGET_ID); - }); - cy.all([ cy.get("@powerLevelsChanged"), - cy.get("@botJoined"), + cy.get("@botJoinedWidgetEventSent"), ]).then(() => { cy.window().then(async win => { // wait for widget state event @@ -146,21 +147,24 @@ describe("Widget PIP", () => { // checks that widget is opened in pip cy.accessIframe(`iframe[title="${DEMO_WIDGET_NAME}"]`).within({}, () => { cy.get("#demo").should('exist'); + }).then(async () => { + const userId = user.userId; + if (userRemove == 'leave') { + cy.getClient().then(async matrixClient => { + await matrixClient.leave(roomId); + }); + } else if (userRemove == 'kick') { + // wait, otherwise sometimes not work + cy.wait(500).then(async () => { + await bot.kick(roomId, userId); + }); + } else if (userRemove == 'ban') { + await bot.ban(roomId, userId); + } + + // checks that pip window is closed + cy.get(".mx_CallView_pip").should("not.exist"); }); - - const userId = user.userId; - if (userRemove == 'leave') { - cy.getClient().then(async matrixClient => { - await matrixClient.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 - cy.get(".mx_CallView_pip").should("not.exist"); }); }); }); @@ -173,7 +177,7 @@ describe("Widget PIP", () => { cy.initTestUser(synapse, "Mike").then(_user => { user = _user; }); - cy.getBot(synapse, { displayName: "Bot" }).then(_bot => { + cy.getBot(synapse, { displayName: "Bot", autoAcceptInvites: false }).then(_bot => { bot = _bot; }); }); From f897274fe5bbaa5af42dee52b8eea5be0d72ef51 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Tue, 16 Aug 2022 13:41:52 +0300 Subject: [PATCH 08/10] stale import removed, win.matrixcs.RoomStateEvent.Events is used --- cypress/e2e/widgets/widget-pip-close.spec.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index e8debd0f9b4..c89aee4b347 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -18,7 +18,6 @@ limitations under the License. /// import { IWidget } from "matrix-widget-api/src/interfaces/IWidget"; -// import { RoomStateEvent } from "matrix-js-sdk/src/matrix"; import type { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { SynapseInstance } from "../../plugins/synapsedocker"; @@ -52,7 +51,9 @@ const DEMO_WIDGET_HTML = ` `; // mostly copied from src/utils/WidgetUtils.waitForRoomWidget with small modifications -function waitForRoomWidget(matrixClient: MatrixClient, widgetId: string, roomId: string, add: boolean): Promise { +function waitForRoomWidget(win: Cypress.AUTWindow, widgetId: string, roomId: string, add: boolean): Promise { + const matrixClient = win.mxMatrixClientPeg.get(); + return new Promise((resolve, reject) => { function eventsInIntendedState(evList) { const widgetPresent = evList.some((ev) => { @@ -79,14 +80,12 @@ function waitForRoomWidget(matrixClient: MatrixClient, widgetId: string, roomId: const currentWidgetEvents = room.currentState.getStateEvents('im.vector.modular.widgets'); if (eventsInIntendedState(currentWidgetEvents)) { - // @ts-ignore - matrixClient.removeListener('RoomState.events', onRoomStateEvents); + matrixClient.removeListener(win.matrixcs.RoomStateEvent.Events, onRoomStateEvents); resolve(); } } - // @ts-ignore - matrixClient.on('RoomState.events', onRoomStateEvents); + matrixClient.on(win.matrixcs.RoomStateEvent.Events, onRoomStateEvents); }); } @@ -136,7 +135,7 @@ describe("Widget PIP", () => { ]).then(() => { cy.window().then(async win => { // wait for widget state event - await waitForRoomWidget(win.mxMatrixClientPeg.get(), DEMO_WIDGET_ID, roomId, true); + await waitForRoomWidget(win, DEMO_WIDGET_ID, roomId, true); // activate widget in pip mode win.mxActiveWidgetStore.setWidgetPersistence(DEMO_WIDGET_ID, roomId, true); From ba2239d2c1cc21ffcd48057ba8ea16c4e69534fa Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Thu, 18 Aug 2022 10:06:01 +0300 Subject: [PATCH 09/10] fixed problem with kick, smaller test optimisations --- cypress/e2e/widgets/widget-pip-close.spec.ts | 60 ++++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index c89aee4b347..e9f6769550c 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -111,27 +111,27 @@ describe("Widget PIP", () => { }).as('powerLevelsChanged'); // bot joins the room - cy.botJoinRoom(bot, roomId).then(async () => { - // wait for bot to join the room, otherwise sometimes widget event is not found - // setup widget via state event - cy.getClient().then(async matrixClient => { - const content: IWidget = { - id: DEMO_WIDGET_ID, - creatorUserId: 'somebody', - type: DEMO_WIDGET_TYPE, - name: DEMO_WIDGET_NAME, - url: demoWidgetUrl, - }; - await matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, DEMO_WIDGET_ID); - }); - }).as('botJoinedWidgetEventSent'); + cy.botJoinRoom(bot, roomId).as('botJoined'); + + // setup widget via state event + cy.getClient().then(async matrixClient => { + const content: IWidget = { + id: DEMO_WIDGET_ID, + creatorUserId: 'somebody', + type: DEMO_WIDGET_TYPE, + name: DEMO_WIDGET_NAME, + url: demoWidgetUrl, + }; + await matrixClient.sendStateEvent(roomId, 'im.vector.modular.widgets', content, DEMO_WIDGET_ID); + }).as('widgetEventSent'); // open the room cy.viewRoomByName(ROOM_NAME); cy.all([ cy.get("@powerLevelsChanged"), - cy.get("@botJoinedWidgetEventSent"), + cy.get("@botJoined"), + cy.get("@widgetEventSent"), ]).then(() => { cy.window().then(async win => { // wait for widget state event @@ -145,24 +145,22 @@ describe("Widget PIP", () => { // checks that widget is opened in pip cy.accessIframe(`iframe[title="${DEMO_WIDGET_NAME}"]`).within({}, () => { - cy.get("#demo").should('exist'); - }).then(async () => { - const userId = user.userId; - if (userRemove == 'leave') { - cy.getClient().then(async matrixClient => { - await matrixClient.leave(roomId); - }); - } else if (userRemove == 'kick') { - // wait, otherwise sometimes not work - cy.wait(500).then(async () => { + cy.get("#demo").should('exist').then(async () => { + const userId = user.userId; + if (userRemove == 'leave') { + cy.getClient().then(async matrixClient => { + await matrixClient.leave(roomId); + }); + } else if (userRemove == 'kick') { + // wait, otherwise sometimes not work await bot.kick(roomId, userId); - }); - } else if (userRemove == 'ban') { - await bot.ban(roomId, userId); - } + } else if (userRemove == 'ban') { + await bot.ban(roomId, userId); + } - // checks that pip window is closed - cy.get(".mx_CallView_pip").should("not.exist"); + // checks that pip window is closed + cy.get(".mx_CallView_pip").should("not.exist"); + }); }); }); }); From 46c0326515dd1859743437f698263f6f82158b12 Mon Sep 17 00:00:00 2001 From: "mikhail.aheichyk" Date: Thu, 18 Aug 2022 15:33:33 +0300 Subject: [PATCH 10/10] comment removed --- cypress/e2e/widgets/widget-pip-close.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/cypress/e2e/widgets/widget-pip-close.spec.ts b/cypress/e2e/widgets/widget-pip-close.spec.ts index e9f6769550c..7689e38ed00 100644 --- a/cypress/e2e/widgets/widget-pip-close.spec.ts +++ b/cypress/e2e/widgets/widget-pip-close.spec.ts @@ -152,7 +152,6 @@ describe("Widget PIP", () => { await matrixClient.leave(roomId); }); } else if (userRemove == 'kick') { - // wait, otherwise sometimes not work await bot.kick(roomId, userId); } else if (userRemove == 'ban') { await bot.ban(roomId, userId);