Overlay virtual room call events into main timeline (#9626)
* super WIP POC for merging virtual room events into main timeline * remove some debugs * c * add some todos * remove hardcoded fake virtual user * insert overlay events into main timeline without resorting main tl events * remove more debugs * add extra tick to roomview tests * RoomView test case for virtual room * test case for merged timeline * make overlay event filter generic * remove TODOs from LegacyCallEventGrouper * tidy comments * remove some newlines * test timelinepanel room timeline event handling * use newState.roomId * fix strict errors in RoomView * fix strict errors in TimelinePanel * add type * pr tweaks * strict errors * more strict fix * strict error whackamole * update ROomView tests to use rtl
This commit is contained in:
parent
1b6d753cfe
commit
6150b86421
7 changed files with 1171 additions and 85 deletions
|
@ -17,15 +17,21 @@ limitations under the License.
|
|||
import React from "react";
|
||||
// eslint-disable-next-line deprecate/import
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import { act } from "react-dom/test-utils";
|
||||
import { mocked, MockedObject } from "jest-mock";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { ClientEvent, 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 { EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { MEGOLM_ALGORITHM } from "matrix-js-sdk/src/crypto/olmlib";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
|
||||
import { stubClient, mockPlatformPeg, unmockPlatformPeg, wrapInMatrixClientContext } from "../../test-utils";
|
||||
import {
|
||||
stubClient,
|
||||
mockPlatformPeg,
|
||||
unmockPlatformPeg,
|
||||
wrapInMatrixClientContext,
|
||||
flushPromises,
|
||||
} from "../../test-utils";
|
||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||
import { Action } from "../../../src/dispatcher/actions";
|
||||
import { defaultDispatcher } from "../../../src/dispatcher/dispatcher";
|
||||
|
@ -42,6 +48,7 @@ import { DirectoryMember } from "../../../src/utils/direct-messages";
|
|||
import { createDmLocalRoom } from "../../../src/utils/dm/createDmLocalRoom";
|
||||
import { UPDATE_EVENT } from "../../../src/stores/AsyncStore";
|
||||
import { SdkContextClass, SDKContext } from "../../../src/contexts/SDKContext";
|
||||
import VoipUserMapper from "../../../src/VoipUserMapper";
|
||||
|
||||
const RoomView = wrapInMatrixClientContext(_RoomView);
|
||||
|
||||
|
@ -67,6 +74,8 @@ describe("RoomView", () => {
|
|||
stores = new SdkContextClass();
|
||||
stores.client = cli;
|
||||
stores.rightPanelStore.useUnitTestClient(cli);
|
||||
|
||||
jest.spyOn(VoipUserMapper.sharedInstance(), 'getVirtualRoomForRoom').mockResolvedValue(null);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
@ -89,7 +98,7 @@ describe("RoomView", () => {
|
|||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
metricsTrigger: null,
|
||||
metricsTrigger: undefined,
|
||||
});
|
||||
|
||||
await switchedRoom;
|
||||
|
@ -98,16 +107,52 @@ describe("RoomView", () => {
|
|||
const roomView = mount(
|
||||
<SDKContext.Provider value={stores}>
|
||||
<RoomView
|
||||
threepidInvite={null}
|
||||
oobData={null}
|
||||
// threepidInvite should be optional on RoomView props
|
||||
// it is treated as optional in RoomView
|
||||
threepidInvite={undefined as any}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
justCreatedOpts={null}
|
||||
forceTimeline={false}
|
||||
onRegistered={null}
|
||||
/>
|
||||
</SDKContext.Provider>,
|
||||
);
|
||||
await act(() => Promise.resolve()); // Allow state to settle
|
||||
await flushPromises();
|
||||
return roomView;
|
||||
};
|
||||
|
||||
const renderRoomView = async (): Promise<ReturnType<typeof render>> => {
|
||||
if (stores.roomViewStore.getRoomId() !== room.roomId) {
|
||||
const switchedRoom = new Promise<void>(resolve => {
|
||||
const subFn = () => {
|
||||
if (stores.roomViewStore.getRoomId()) {
|
||||
stores.roomViewStore.off(UPDATE_EVENT, subFn);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
stores.roomViewStore.on(UPDATE_EVENT, subFn);
|
||||
});
|
||||
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
metricsTrigger: undefined,
|
||||
});
|
||||
|
||||
await switchedRoom;
|
||||
}
|
||||
|
||||
const roomView = render(
|
||||
<SDKContext.Provider value={stores}>
|
||||
<RoomView
|
||||
// threepidInvite should be optional on RoomView props
|
||||
// it is treated as optional in RoomView
|
||||
threepidInvite={undefined as any}
|
||||
resizeNotifier={new ResizeNotifier()}
|
||||
forceTimeline={false}
|
||||
onRegistered={jest.fn()}
|
||||
/>
|
||||
</SDKContext.Provider>,
|
||||
);
|
||||
await flushPromises();
|
||||
return roomView;
|
||||
};
|
||||
const getRoomViewInstance = async (): Promise<_RoomView> =>
|
||||
|
@ -137,7 +182,7 @@ describe("RoomView", () => {
|
|||
// and fake an encryption event into the room to prompt it to re-check
|
||||
room.addLiveEvents([new MatrixEvent({
|
||||
type: "m.room.encryption",
|
||||
sender: cli.getUserId(),
|
||||
sender: cli.getUserId()!,
|
||||
content: {},
|
||||
event_id: "someid",
|
||||
room_id: room.roomId,
|
||||
|
@ -155,6 +200,26 @@ describe("RoomView", () => {
|
|||
expect(roomViewInstance.state.liveTimeline).not.toEqual(oldTimeline);
|
||||
});
|
||||
|
||||
describe('with virtual rooms', () => {
|
||||
it("checks for a virtual room on initial load", async () => {
|
||||
const { container } = await renderRoomView();
|
||||
expect(VoipUserMapper.sharedInstance().getVirtualRoomForRoom).toHaveBeenCalledWith(room.roomId);
|
||||
|
||||
// quick check that rendered without error
|
||||
expect(container.querySelector('.mx_ErrorBoundary')).toBeFalsy();
|
||||
});
|
||||
|
||||
it("checks for a virtual room on room event", async () => {
|
||||
await renderRoomView();
|
||||
expect(VoipUserMapper.sharedInstance().getVirtualRoomForRoom).toHaveBeenCalledWith(room.roomId);
|
||||
|
||||
cli.emit(ClientEvent.Room, room);
|
||||
|
||||
// called again after room event
|
||||
expect(VoipUserMapper.sharedInstance().getVirtualRoomForRoom).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("video rooms", () => {
|
||||
beforeEach(async () => {
|
||||
// Make it a video room
|
||||
|
@ -178,7 +243,6 @@ describe("RoomView", () => {
|
|||
|
||||
describe("for a local room", () => {
|
||||
let localRoom: LocalRoom;
|
||||
let roomView: ReactWrapper;
|
||||
|
||||
beforeEach(async () => {
|
||||
localRoom = room = await createDmLocalRoom(cli, [new DirectoryMember({ user_id: "@user:example.com" })]);
|
||||
|
@ -186,15 +250,15 @@ describe("RoomView", () => {
|
|||
});
|
||||
|
||||
it("should remove the room from the store on unmount", async () => {
|
||||
roomView = await mountRoomView();
|
||||
roomView.unmount();
|
||||
const { unmount } = await renderRoomView();
|
||||
unmount();
|
||||
expect(cli.store.removeRoom).toHaveBeenCalledWith(room.roomId);
|
||||
});
|
||||
|
||||
describe("in state NEW", () => {
|
||||
it("should match the snapshot", async () => {
|
||||
roomView = await mountRoomView();
|
||||
expect(roomView.html()).toMatchSnapshot();
|
||||
const { container } = await renderRoomView();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("that is encrypted", () => {
|
||||
|
@ -208,8 +272,8 @@ describe("RoomView", () => {
|
|||
content: {
|
||||
algorithm: MEGOLM_ALGORITHM,
|
||||
},
|
||||
user_id: cli.getUserId(),
|
||||
sender: cli.getUserId(),
|
||||
user_id: cli.getUserId()!,
|
||||
sender: cli.getUserId()!,
|
||||
state_key: "",
|
||||
room_id: localRoom.roomId,
|
||||
origin_server_ts: Date.now(),
|
||||
|
@ -218,33 +282,32 @@ describe("RoomView", () => {
|
|||
});
|
||||
|
||||
it("should match the snapshot", async () => {
|
||||
const roomView = await mountRoomView();
|
||||
expect(roomView.html()).toMatchSnapshot();
|
||||
const { container } = await renderRoomView();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("in state CREATING should match the snapshot", async () => {
|
||||
localRoom.state = LocalRoomState.CREATING;
|
||||
roomView = await mountRoomView();
|
||||
expect(roomView.html()).toMatchSnapshot();
|
||||
const { container } = await renderRoomView();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("in state ERROR", () => {
|
||||
beforeEach(async () => {
|
||||
localRoom.state = LocalRoomState.ERROR;
|
||||
roomView = await mountRoomView();
|
||||
});
|
||||
|
||||
it("should match the snapshot", async () => {
|
||||
expect(roomView.html()).toMatchSnapshot();
|
||||
const { container } = await renderRoomView();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("clicking retry should set the room state to new dispatch a local room event", () => {
|
||||
it("clicking retry should set the room state to new dispatch a local room event", async () => {
|
||||
jest.spyOn(defaultDispatcher, "dispatch");
|
||||
roomView.findWhere((w: ReactWrapper) => {
|
||||
return w.hasClass("mx_RoomStatusBar_unsentRetry") && w.text() === "Retry";
|
||||
}).first().simulate("click");
|
||||
const { getByText } = await renderRoomView();
|
||||
fireEvent.click(getByText('Retry'));
|
||||
expect(localRoom.state).toBe(LocalRoomState.NEW);
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: "local_room_event",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue