From 5bc8f87144b7fe273259c3e5031446d7d07e4b35 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 28 Feb 2022 14:03:08 -0500 Subject: [PATCH 1/9] Hide unpinnable pinned messages in more cases Signed-off-by: Robin Townsend --- src/components/views/right_panel/PinnedMessagesCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index 7e4bc3a7ae6..69f27d0546f 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -99,7 +99,7 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => { const promises = pinnedEventIds.map(async eventId => { const timelineSet = room.getUnfilteredTimelineSet(); const localEvent = timelineSet?.getTimelineForEvent(eventId)?.getEvents().find(e => e.getId() === eventId); - if (localEvent) return localEvent; + if (localEvent && PinningUtils.isPinnable(event)) return localEvent; try { const evJson = await cli.fetchRoomEvent(room.roomId, eventId); From f4dad43b27a0d1293958a9a50b574cfd1649700e Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Mon, 28 Feb 2022 14:13:25 -0500 Subject: [PATCH 2/9] Fix typo Signed-off-by: Robin Townsend --- src/components/views/right_panel/PinnedMessagesCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index 69f27d0546f..e221dd0ce65 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -99,7 +99,7 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => { const promises = pinnedEventIds.map(async eventId => { const timelineSet = room.getUnfilteredTimelineSet(); const localEvent = timelineSet?.getTimelineForEvent(eventId)?.getEvents().find(e => e.getId() === eventId); - if (localEvent && PinningUtils.isPinnable(event)) return localEvent; + if (localEvent && PinningUtils.isPinnable(localEvent)) return localEvent; try { const evJson = await cli.fetchRoomEvent(room.roomId, eventId); From 19fdbece1bec4d01cc43c1d429d56247a67e0a62 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 14:43:38 -0500 Subject: [PATCH 3/9] Test that unpinnable pinned messages get hidden Signed-off-by: Robin Townsend --- .../views/right_panel/PinnedMessagesCard.tsx | 2 +- .../right_panel/PinnedMessagesCard-test.tsx | 91 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 test/components/views/right_panel/PinnedMessagesCard-test.tsx diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx index b74090449a0..1b110a76c32 100644 --- a/src/components/views/right_panel/PinnedMessagesCard.tsx +++ b/src/components/views/right_panel/PinnedMessagesCard.tsx @@ -99,7 +99,7 @@ const PinnedMessagesCard = ({ room, onClose }: IProps) => { const promises = pinnedEventIds.map(async eventId => { const timelineSet = room.getUnfilteredTimelineSet(); const localEvent = timelineSet?.getTimelineForEvent(eventId)?.getEvents().find(e => e.getId() === eventId); - if (localEvent && PinningUtils.isPinnable(localEvent)) return localEvent; + if (localEvent) return PinningUtils.isPinnable(localEvent) ? localEvent : null; try { // Fetch the event and latest edit in parallel diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx new file mode 100644 index 00000000000..23051216c4c --- /dev/null +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -0,0 +1,91 @@ +/* +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 React from "react"; +import { mount } from "enzyme"; +import { act } from "react-dom/test-utils"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { EventType } from "matrix-js-sdk/src/@types/event"; + +import "../../../skinned-sdk"; +import { stubClient, wrapInMatrixClientContext, mkStubRoom, mkEvent } from "../../../test-utils"; +import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; +import _PinnedMessagesCard from "../../../../src/components/views/right_panel/PinnedMessagesCard"; + +describe("", () => { + stubClient(); + const cli = MatrixClientPeg.get(); + cli.setRoomAccountData = () => {}; + const PinnedMessagesCard = wrapInMatrixClientContext(_PinnedMessagesCard); + + const mkRoom = (localPins: MatrixEvent[], nonLocalPins: MatrixEvent[]) => { + const pins = [...localPins, ...nonLocalPins]; + const room = mkStubRoom(); + + // Insert pin IDs into room state + const pinState = new MatrixEvent(mkEvent({ + type: EventType.RoomPinnedEvents, + content: { + pinned: pins.map(e => e.getId()), + }, + })); + room.currentState.getStateEvents.mockReturnValue(pinState); + + // Insert local pins into local timeline set + room.getUnfilteredTimelineSet = () => ({ + getTimelineForEvent: () => ({ + getEvents: () => localPins, + }), + }); + + // Return all pins over fetchRoomEvent + cli.fetchRoomEvent = (roomId, eventId) => pins.find(e => e.getId() === eventId); + + return room; + }; + + it("hides unpinnable events found in local timeline", async () => { + const pin = new MatrixEvent(mkEvent({ + type: EventType.RoomMessage, + content: {}, + })); + pin.isRedacted = () => true; // Redacted messages are unpinnable + + let pins; + await act(async () => { + pins = mount( {}} />); + // Wait a tick for state updates + await new Promise(resolve => setImmediate(resolve)); + }); + expect(pins.find("PinnedEventTile").length).toBe(0); + }); + + it("hides unpinnable events not found in local timeline", async () => { + const pin = new MatrixEvent(mkEvent({ + type: EventType.RoomMessage, + content: {}, + })); + pin.isRedacted = () => true; // Redacted messages are unpinnable + + let pins; + await act(async () => { + pins = mount( {}} />); + // Wait a tick for state updates + await new Promise(resolve => setImmediate(resolve)); + }); + expect(pins.find("PinnedEventTile").length).toBe(0); + }); +}); From ecb9c0bd886a21ce5f6e9e41611ab256f0b5998c Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 15:47:29 -0500 Subject: [PATCH 4/9] Fix cli.relations error in test Signed-off-by: Robin Townsend --- test/components/views/right_panel/PinnedMessagesCard-test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index 23051216c4c..d4323e62936 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -29,6 +29,7 @@ describe("", () => { stubClient(); const cli = MatrixClientPeg.get(); cli.setRoomAccountData = () => {}; + cli.relations = jest.fn().mockReturnValue({ events: [] }); const PinnedMessagesCard = wrapInMatrixClientContext(_PinnedMessagesCard); const mkRoom = (localPins: MatrixEvent[], nonLocalPins: MatrixEvent[]) => { From 0527a02235f5a419ba39aef40f2386763f0e9dc5 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 15:47:45 -0500 Subject: [PATCH 5/9] Use event: true shortcut when calling mkEvent Signed-off-by: Robin Townsend --- .../views/right_panel/PinnedMessagesCard-test.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index d4323e62936..564aab1a5a2 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -37,12 +37,13 @@ describe("", () => { const room = mkStubRoom(); // Insert pin IDs into room state - const pinState = new MatrixEvent(mkEvent({ + const pinState = mkEvent({ + event: true, type: EventType.RoomPinnedEvents, content: { pinned: pins.map(e => e.getId()), }, - })); + }); room.currentState.getStateEvents.mockReturnValue(pinState); // Insert local pins into local timeline set @@ -59,10 +60,11 @@ describe("", () => { }; it("hides unpinnable events found in local timeline", async () => { - const pin = new MatrixEvent(mkEvent({ + const pin = mkEvent({ + event: true, type: EventType.RoomMessage, content: {}, - })); + }); pin.isRedacted = () => true; // Redacted messages are unpinnable let pins; @@ -75,10 +77,11 @@ describe("", () => { }); it("hides unpinnable events not found in local timeline", async () => { - const pin = new MatrixEvent(mkEvent({ + const pin = mkEvent({ + event: true, type: EventType.RoomMessage, content: {}, - })); + }); pin.isRedacted = () => true; // Redacted messages are unpinnable let pins; From e8b3d4293fc370db112a76d44a1c2d7d9efe7cbd Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 15:51:52 -0500 Subject: [PATCH 6/9] Use mockResolvedValue instead of mockReturnValue for async mock Signed-off-by: Robin Townsend --- test/components/views/right_panel/PinnedMessagesCard-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index 564aab1a5a2..034644e24ab 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -29,7 +29,7 @@ describe("", () => { stubClient(); const cli = MatrixClientPeg.get(); cli.setRoomAccountData = () => {}; - cli.relations = jest.fn().mockReturnValue({ events: [] }); + cli.relations = jest.fn().mockResolvedValue({ events: [] }); const PinnedMessagesCard = wrapInMatrixClientContext(_PinnedMessagesCard); const mkRoom = (localPins: MatrixEvent[], nonLocalPins: MatrixEvent[]) => { From dc938fe5cd7e2b29bba150f503a661d71e7dc0e4 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 16:33:54 -0500 Subject: [PATCH 7/9] Actually mock redacted messages correctly Signed-off-by: Robin Townsend --- .../views/right_panel/PinnedMessagesCard-test.tsx | 8 +++++--- test/test-utils/test-utils.ts | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index 034644e24ab..01e01da3a61 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -54,18 +54,19 @@ describe("", () => { }); // Return all pins over fetchRoomEvent - cli.fetchRoomEvent = (roomId, eventId) => pins.find(e => e.getId() === eventId); + cli.fetchRoomEvent = (roomId, eventId) => pins.find(e => e.getId() === eventId)?.event; return room; }; it("hides unpinnable events found in local timeline", async () => { + // Redacted messages are unpinnable const pin = mkEvent({ event: true, type: EventType.RoomMessage, content: {}, + unsigned: { redacted_because: {} }, }); - pin.isRedacted = () => true; // Redacted messages are unpinnable let pins; await act(async () => { @@ -77,12 +78,13 @@ describe("", () => { }); it("hides unpinnable events not found in local timeline", async () => { + // Redacted messages are unpinnable const pin = mkEvent({ event: true, type: EventType.RoomMessage, content: {}, + unsigned: { redacted_because: {} }, }); - pin.isRedacted = () => true; // Redacted messages are unpinnable let pins; await act(async () => { diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index a894faf5500..747aa9ab1b9 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -172,6 +172,7 @@ export function mkEvent(opts: MakeEventProps): MatrixEvent { prev_content: opts.prev_content, event_id: "$" + Math.random() + "-" + Math.random(), origin_server_ts: opts.ts, + unsigned: opts.unsigned, }; if (opts.skey) { event.state_key = opts.skey; From 93a8011d7fd8bd68912598752f04e49d0546459a Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 17:51:20 -0500 Subject: [PATCH 8/9] Ensure that panel is updated before assertions are made Signed-off-by: Robin Townsend --- .../views/right_panel/PinnedMessagesCard-test.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index 01e01da3a61..972465e873d 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -24,6 +24,7 @@ import "../../../skinned-sdk"; import { stubClient, wrapInMatrixClientContext, mkStubRoom, mkEvent } from "../../../test-utils"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import _PinnedMessagesCard from "../../../../src/components/views/right_panel/PinnedMessagesCard"; +import PinnedEventTile from "../../../../src/components/views/rooms/PinnedEventTile"; describe("", () => { stubClient(); @@ -73,8 +74,9 @@ describe("", () => { pins = mount( {}} />); // Wait a tick for state updates await new Promise(resolve => setImmediate(resolve)); + pins.update(); }); - expect(pins.find("PinnedEventTile").length).toBe(0); + expect(pins.find(PinnedEventTile).length).toBe(0); }); it("hides unpinnable events not found in local timeline", async () => { @@ -91,7 +93,8 @@ describe("", () => { pins = mount( {}} />); // Wait a tick for state updates await new Promise(resolve => setImmediate(resolve)); + pins.update(); }); - expect(pins.find("PinnedEventTile").length).toBe(0); + expect(pins.find(PinnedEventTile).length).toBe(0); }); }); From 312949dc0cc10229c0f4d3461dbd4ca2012fad55 Mon Sep 17 00:00:00 2001 From: Robin Townsend Date: Wed, 2 Mar 2022 18:24:19 -0500 Subject: [PATCH 9/9] Move calls to update out of act They don't need to be there. Signed-off-by: Robin Townsend --- test/components/views/right_panel/PinnedMessagesCard-test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/components/views/right_panel/PinnedMessagesCard-test.tsx b/test/components/views/right_panel/PinnedMessagesCard-test.tsx index 972465e873d..3c0fb73aa12 100644 --- a/test/components/views/right_panel/PinnedMessagesCard-test.tsx +++ b/test/components/views/right_panel/PinnedMessagesCard-test.tsx @@ -74,8 +74,8 @@ describe("", () => { pins = mount( {}} />); // Wait a tick for state updates await new Promise(resolve => setImmediate(resolve)); - pins.update(); }); + pins.update(); expect(pins.find(PinnedEventTile).length).toBe(0); }); @@ -93,8 +93,8 @@ describe("", () => { pins = mount( {}} />); // Wait a tick for state updates await new Promise(resolve => setImmediate(resolve)); - pins.update(); }); + pins.update(); expect(pins.find(PinnedEventTile).length).toBe(0); }); });