Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Update the live timeline when the JS SDK resets it #8806

Merged
merged 1 commit into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { logger } from "matrix-js-sdk/src/logger";
import { EventTimeline } from 'matrix-js-sdk/src/models/event-timeline';
import { EventType } from 'matrix-js-sdk/src/@types/event';
import { RoomState, RoomStateEvent } from 'matrix-js-sdk/src/models/room-state';
import { EventTimelineSet } from "matrix-js-sdk/src/models/event-timeline-set";
import { CallState, CallType, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import { throttle } from "lodash";
import { MatrixError } from 'matrix-js-sdk/src/http-api';
Expand Down Expand Up @@ -282,6 +283,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.dispatcherRef = dis.register(this.onAction);
context.on(ClientEvent.Room, this.onRoom);
context.on(RoomEvent.Timeline, this.onRoomTimeline);
context.on(RoomEvent.TimelineReset, this.onRoomTimelineReset);
context.on(RoomEvent.Name, this.onRoomName);
context.on(RoomStateEvent.Events, this.onRoomStateEvents);
context.on(RoomStateEvent.Update, this.onRoomStateUpdate);
Expand Down Expand Up @@ -1022,6 +1024,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
});
};

private onRoomTimelineReset = (room: Room, timelineSet: EventTimelineSet) => {
if (!room || room.roomId !== this.state.room?.roomId) return;
logger.log(`Live timeline of ${room.roomId} was reset`);
this.setState({ liveTimeline: timelineSet.getLiveTimeline() });
};

private getRoomTombstone(room = this.state.room) {
return room?.currentState.getStateEvents(EventType.RoomTombstone, "");
}
Expand Down
108 changes: 61 additions & 47 deletions test/components/structures/RoomView-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,82 @@ limitations under the License.
*/

import React from "react";
import TestRenderer from "react-test-renderer";
import { mount, ReactWrapper } from "enzyme";
import { mocked, MockedObject } from "jest-mock";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";

import { stubClient, wrapInMatrixClientContext } from "../../test-utils";
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 { RoomView as _RoomView } from "../../../src/components/structures/RoomView";
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
import { RoomViewStore } from "../../../src/stores/RoomViewStore";
import DMRoomMap from "../../../src/utils/DMRoomMap";

const RoomView = wrapInMatrixClientContext(_RoomView);

describe("RoomView", () => {
it("updates url preview visibility on encryption state change", async () => {
let cli: MockedObject<MatrixClient>;
let room: Room;
beforeEach(() => {
stubClient();
const cli = MatrixClientPeg.get();
cli.hasLazyLoadMembersEnabled = () => false;
cli.isInitialSyncComplete = () => true;
cli.stopPeeking = () => undefined;
cli = mocked(MatrixClientPeg.get());

const r1 = new Room("r1", cli, "@name:example.com");
cli.getRoom = () => r1;
r1.getPendingEvents = () => [];
room = new Room("r1", cli, "@alice:example.com");
room.getPendingEvents = () => [];
cli.getRoom.mockReturnValue(room);
// Re-emit certain events on the mocked client
room.on(RoomEvent.Timeline, (...args) => cli.emit(RoomEvent.Timeline, ...args));
room.on(RoomEvent.TimelineReset, (...args) => cli.emit(RoomEvent.TimelineReset, ...args));

DMRoomMap.makeShared();
});

const switchRoomPromise = new Promise<void>(resolve => {
const subscription = RoomViewStore.instance.addListener(() => {
if (RoomViewStore.instance.getRoomId()) {
subscription.remove();
resolve();
}
const mountRoomView = async (): Promise<ReactWrapper> => {
if (RoomViewStore.instance.getRoomId() !== room.roomId) {
const switchRoomPromise = new Promise<void>(resolve => {
const subscription = RoomViewStore.instance.addListener(() => {
if (RoomViewStore.instance.getRoomId()) {
subscription.remove();
resolve();
}
});
});
});

dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: r1.roomId,
metricsTrigger: null,
});
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: room.roomId,
metricsTrigger: null,
});

await switchRoomPromise;
await switchRoomPromise;
}

const renderer = TestRenderer.create(<MatrixClientContext.Provider value={cli}>
<RoomView mxClient={cli}
return mount(
<RoomView
mxClient={cli}
threepidInvite={null}
oobData={null}
resizeNotifier={new ResizeNotifier()}
justCreatedOpts={null}
forceTimeline={false}
onRegistered={null}
/>
</MatrixClientContext.Provider>);
/>,
);
};
const getRoomViewInstance = async (): Promise<_RoomView> =>
(await mountRoomView()).find(_RoomView).instance() as _RoomView;

it("updates url preview visibility on encryption state change", async () => {
// we should be starting unencrypted
expect(cli.isCryptoEnabled()).toEqual(false);
expect(cli.isRoomEncrypted(room.roomId)).toEqual(false);

const roomViewInstance = renderer.root.findByType(RoomView).instance;
const roomViewInstance = await getRoomViewInstance();

// 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
Expand All @@ -84,32 +102,28 @@ describe("RoomView", () => {
// 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;
// now enable encryption
cli.isCryptoEnabled.mockReturnValue(true);
cli.isRoomEncrypted.mockReturnValue(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<void>(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({
room.addLiveEvents([new MatrixEvent({
type: "m.room.encryption",
sender: cli.getUserId(),
content: {},
event_id: "someid",
room_id: r1.roomId,
room_id: room.roomId,
})]);

await eventAddedPromise;

// URL previews should now be disabled
expect(roomViewInstance.state.showUrlPreview).toBe(false);
});

it("updates live timeline when a timeline reset happens", async () => {
const roomViewInstance = await getRoomViewInstance();
const oldTimeline = roomViewInstance.state.liveTimeline;

room.getUnfilteredTimelineSet().resetLiveTimeline();
expect(roomViewInstance.state.liveTimeline).not.toEqual(oldTimeline);
});
});
5 changes: 4 additions & 1 deletion test/test-utils/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function createTestClient(): MatrixClient {
emit: eventEmitter.emit.bind(eventEmitter),
isRoomEncrypted: jest.fn().mockReturnValue(false),
peekInRoom: jest.fn().mockResolvedValue(mkStubRoom(undefined, undefined, undefined)),
stopPeeking: jest.fn(),

paginateEventTimeline: jest.fn().mockResolvedValue(undefined),
sendReadReceipt: jest.fn().mockResolvedValue(undefined),
Expand Down Expand Up @@ -155,6 +156,8 @@ export function createTestClient(): MatrixClient {
setPushRuleActions: jest.fn().mockResolvedValue(undefined),
relations: jest.fn().mockRejectedValue(undefined),
isCryptoEnabled: jest.fn().mockReturnValue(false),
hasLazyLoadMembersEnabled: jest.fn().mockReturnValue(false),
isInitialSyncComplete: jest.fn().mockReturnValue(true),
downloadKeys: jest.fn(),
fetchRoomEvent: jest.fn(),
} as unknown as MatrixClient;
Expand Down Expand Up @@ -358,7 +361,7 @@ export function mkStubRoom(roomId: string = null, name: string, client: MatrixCl
getJoinedMemberCount: jest.fn().mockReturnValue(1),
getMembers: jest.fn().mockReturnValue([]),
getPendingEvents: () => [],
getLiveTimeline: () => stubTimeline,
getLiveTimeline: jest.fn().mockReturnValue(stubTimeline),
getUnfilteredTimelineSet: () => null,
findEventById: () => null,
getAccountData: () => null,
Expand Down