diff --git a/package.json b/package.json index 79bab28a1dd..a8c54d1d741 100644 --- a/package.json +++ b/package.json @@ -152,6 +152,7 @@ "@types/react": "17.0.14", "@types/react-beautiful-dnd": "^13.0.0", "@types/react-dom": "17.0.9", + "@types/react-test-renderer": "^17.0.1", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "^2.3.1", "@types/zxcvbn": "^4.4.0", diff --git a/test/TextForEvent-test.ts b/test/TextForEvent-test.ts index 75b54aeb66c..11cb74928d5 100644 --- a/test/TextForEvent-test.ts +++ b/test/TextForEvent-test.ts @@ -1,5 +1,6 @@ import { EventType, MatrixEvent } from "matrix-js-sdk/src/matrix"; import TestRenderer from 'react-test-renderer'; +import { ReactElement } from "react"; import { getSenderName, textForEvent } from "../src/TextForEvent"; import SettingsStore from "../src/settings/SettingsStore"; @@ -80,7 +81,7 @@ describe('TextForEvent', () => { it("mentions message when a single message was pinned, with no previously pinned messages", () => { const event = mockPinnedEvent(['message-1']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com pinned a message to this room. See all pinned messages."; expect(plainText).toBe(expectedText); @@ -90,7 +91,7 @@ describe('TextForEvent', () => { it("mentions message when a single message was pinned, with multiple previously pinned messages", () => { const event = mockPinnedEvent(['message-1', 'message-2', 'message-3'], ['message-1', 'message-2']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com pinned a message to this room. See all pinned messages."; expect(plainText).toBe(expectedText); @@ -100,7 +101,7 @@ describe('TextForEvent', () => { it("mentions message when a single message was unpinned, with a single message previously pinned", () => { const event = mockPinnedEvent([], ['message-1']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com unpinned a message from this room. See all pinned messages."; expect(plainText).toBe(expectedText); @@ -110,7 +111,7 @@ describe('TextForEvent', () => { it("mentions message when a single message was unpinned, with multiple previously pinned messages", () => { const event = mockPinnedEvent(['message-2'], ['message-1', 'message-2']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com unpinned a message from this room. See all pinned messages."; expect(plainText).toBe(expectedText); @@ -120,7 +121,7 @@ describe('TextForEvent', () => { it("shows generic text when multiple messages were pinned", () => { const event = mockPinnedEvent(['message-1', 'message-2', 'message-3'], ['message-1']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com changed the pinned messages for the room."; expect(plainText).toBe(expectedText); @@ -130,7 +131,7 @@ describe('TextForEvent', () => { it("shows generic text when multiple messages were unpinned", () => { const event = mockPinnedEvent(['message-3'], ['message-1', 'message-2', 'message-3']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com changed the pinned messages for the room."; expect(plainText).toBe(expectedText); @@ -140,7 +141,7 @@ describe('TextForEvent', () => { it("shows generic text when one message was pinned, and another unpinned", () => { const event = mockPinnedEvent(['message-2'], ['message-1']); const plainText = textForEvent(event); - const component = TestRenderer.create(textForEvent(event, true)); + const component = TestRenderer.create(textForEvent(event, true) as ReactElement); const expectedText = "@foo:example.com changed the pinned messages for the room."; expect(plainText).toBe(expectedText); diff --git a/test/components/structures/RoomView-test.tsx b/test/components/structures/RoomView-test.tsx new file mode 100644 index 00000000000..98677891b9f --- /dev/null +++ b/test/components/structures/RoomView-test.tsx @@ -0,0 +1,115 @@ +/* +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 TestRenderer from "react-test-renderer"; +import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; + +import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; +import { stubClient } from "../../test-utils"; +import { Action } from "../../../src/dispatcher/actions"; +import dis from "../../../src/dispatcher/dispatcher"; +import { ViewRoomPayload } from "../../../src/dispatcher/payloads/ViewRoomPayload"; +import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; +import { RoomView } from "../../../src/components/structures/RoomView"; +import ResizeNotifier from "../../../src/utils/ResizeNotifier"; +import { RoomViewStore } from "../../../src/stores/RoomViewStore"; +import DMRoomMap from "../../../src/utils/DMRoomMap"; + +describe("RoomView", () => { + it("updates url preview visibility on encryption state change", async () => { + stubClient(); + const cli = MatrixClientPeg.get(); + cli.hasLazyLoadMembersEnabled = () => false; + cli.isInitialSyncComplete = () => true; + cli.stopPeeking = () => undefined; + + const r1 = new Room("r1", cli, "@name:example.com"); + cli.getRoom = () => r1; + r1.getPendingEvents = () => []; + + DMRoomMap.makeShared(); + + const switchRoomPromise = new Promise(resolve => { + const subscription = RoomViewStore.instance.addListener(() => { + if (RoomViewStore.instance.getRoomId()) { + subscription.remove(); + resolve(); + } + }); + }); + + dis.dispatch({ + action: Action.ViewRoom, + room_id: r1.roomId, + metricsTrigger: null, + }); + + await switchRoomPromise; + + const renderer = TestRenderer.create( + + ); + + const roomViewInstance = renderer.root.findByType(RoomView).instance; + + // in a default (non-encrypted room, it should start out with url previews enabled) + // This is a white-box test in that we're asserting things about the state, which + // is not ideal, but asserting that a URL preview just isn't there could risk the + // test being invalid because the previews just hasn't rendered yet. This feels + // like the safest way I think? + // This also relies on the default settings being URL previews on normally and + // off for e2e rooms because 1) it's probably useful to assert this and + // 2) SettingsStore is a static class and so very hard to mock out. + expect(roomViewInstance.state.showUrlPreview).toBe(true); + + // now enable encryption (by mocking out the tests for whether a room is encrypted) + cli.isCryptoEnabled = () => true; + cli.isRoomEncrypted = () => true; + + // and fake an encryption event into the room to prompt it to re-check + // wait until the event has been added + const eventAddedPromise = new Promise(resolve => { + r1.once(RoomEvent.Timeline, (...args) => { + // we're also using mock client that doesn't re-emit, so + // we emit the event to client manually + cli.emit(RoomEvent.Timeline, ...args); + resolve(); + }); + }); + + r1.addLiveEvents([new MatrixEvent({ + type: "m.room.encryption", + sender: cli.getUserId(), + content: {}, + event_id: "someid", + room_id: r1.roomId, + })]); + + await eventAddedPromise; + + // URL previews should now be disabled + expect(roomViewInstance.state.showUrlPreview).toBe(false); + }); +}); diff --git a/yarn.lock b/yarn.lock index 2ec1137f7e2..6a1ae457680 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1936,6 +1936,13 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" +"@types/react-test-renderer@^17.0.1": + version "17.0.1" + resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b" + integrity sha512-3Fi2O6Zzq/f3QR9dRnlnHso9bMl7weKCviFmfF6B4LS1Uat6Hkm15k0ZAQuDz+UBq6B3+g+NM6IT2nr5QgPzCw== + dependencies: + "@types/react" "*" + "@types/react-transition-group@^4.4.0": version "4.4.4" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"