You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-07-30 02:21:17 +03:00
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:
@ -26,6 +26,8 @@ import {
|
||||
MatrixEvent,
|
||||
PendingEventOrdering,
|
||||
Room,
|
||||
RoomEvent,
|
||||
TimelineWindow,
|
||||
} from 'matrix-js-sdk/src/matrix';
|
||||
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
||||
import {
|
||||
@ -41,7 +43,8 @@ import TimelinePanel from '../../../src/components/structures/TimelinePanel';
|
||||
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
||||
import { MatrixClientPeg } from '../../../src/MatrixClientPeg';
|
||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||
import { mkRoom, stubClient } from "../../test-utils";
|
||||
import { isCallEvent } from '../../../src/components/structures/LegacyCallEventGrouper';
|
||||
import { flushPromises, mkRoom, stubClient } from "../../test-utils";
|
||||
|
||||
const newReceipt = (eventId: string, userId: string, readTs: number, fullyReadTs: number): MatrixEvent => {
|
||||
const receiptContent = {
|
||||
@ -80,7 +83,7 @@ const mockEvents = (room: Room, count = 2): MatrixEvent[] => {
|
||||
for (let index = 0; index < count; index++) {
|
||||
events.push(new MatrixEvent({
|
||||
room_id: room.roomId,
|
||||
event_id: `event_${index}`,
|
||||
event_id: `${room.roomId}_event_${index}`,
|
||||
type: EventType.RoomMessage,
|
||||
user_id: "userId",
|
||||
content: MessageEvent.from(`Event${index}`).serialize().content,
|
||||
@ -90,6 +93,13 @@ const mockEvents = (room: Room, count = 2): MatrixEvent[] => {
|
||||
return events;
|
||||
};
|
||||
|
||||
const setupTestData = (): [MatrixClient, Room, MatrixEvent[]] => {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = mkRoom(client, "roomId");
|
||||
const events = mockEvents(room);
|
||||
return [client, room, events];
|
||||
};
|
||||
|
||||
describe('TimelinePanel', () => {
|
||||
beforeEach(() => {
|
||||
stubClient();
|
||||
@ -155,9 +165,7 @@ describe('TimelinePanel', () => {
|
||||
});
|
||||
|
||||
it("sends public read receipt when enabled", () => {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = mkRoom(client, "roomId");
|
||||
const events = mockEvents(room);
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const getValueCopy = SettingsStore.getValue;
|
||||
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
||||
@ -170,9 +178,7 @@ describe('TimelinePanel', () => {
|
||||
});
|
||||
|
||||
it("does not send public read receipt when enabled", () => {
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = mkRoom(client, "roomId");
|
||||
const events = mockEvents(room);
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const getValueCopy = SettingsStore.getValue;
|
||||
SettingsStore.getValue = jest.fn().mockImplementation((name: string) => {
|
||||
@ -202,6 +208,146 @@ describe('TimelinePanel', () => {
|
||||
expect(props.onEventScrolledIntoView).toHaveBeenCalledWith(events[1].getId());
|
||||
});
|
||||
|
||||
describe('onRoomTimeline', () => {
|
||||
it('ignores events for other timelines', () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const otherTimelineSet = { room: room as Room } as EventTimelineSet;
|
||||
const otherTimeline = new EventTimeline(otherTimelineSet);
|
||||
|
||||
const props = {
|
||||
...getProps(room, events),
|
||||
onEventScrolledIntoView: jest.fn(),
|
||||
};
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
const event = new MatrixEvent({ type: RoomEvent.Timeline });
|
||||
const data = { timeline: otherTimeline, liveEvent: true };
|
||||
client.emit(RoomEvent.Timeline, event, room, false, false, data);
|
||||
|
||||
expect(paginateSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ignores timeline updates without a live event', () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const props = getProps(room, events);
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
const event = new MatrixEvent({ type: RoomEvent.Timeline });
|
||||
const data = { timeline: props.timelineSet.getLiveTimeline(), liveEvent: false };
|
||||
client.emit(RoomEvent.Timeline, event, room, false, false, data);
|
||||
|
||||
expect(paginateSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ignores timeline where toStartOfTimeline is true', () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const props = getProps(room, events);
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
const event = new MatrixEvent({ type: RoomEvent.Timeline });
|
||||
const data = { timeline: props.timelineSet.getLiveTimeline(), liveEvent: false };
|
||||
const toStartOfTimeline = true;
|
||||
client.emit(RoomEvent.Timeline, event, room, toStartOfTimeline, false, data);
|
||||
|
||||
expect(paginateSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('advances the timeline window', () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const props = getProps(room, events);
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
const event = new MatrixEvent({ type: RoomEvent.Timeline });
|
||||
const data = { timeline: props.timelineSet.getLiveTimeline(), liveEvent: true };
|
||||
client.emit(RoomEvent.Timeline, event, room, false, false, data);
|
||||
|
||||
expect(paginateSpy).toHaveBeenCalledWith(EventTimeline.FORWARDS, 1, false);
|
||||
});
|
||||
|
||||
it('advances the overlay timeline window', async () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
|
||||
const virtualRoom = mkRoom(client, "virtualRoomId");
|
||||
const virtualEvents = mockEvents(virtualRoom);
|
||||
const { timelineSet: overlayTimelineSet } = getProps(virtualRoom, virtualEvents);
|
||||
|
||||
const props = {
|
||||
...getProps(room, events),
|
||||
overlayTimelineSet,
|
||||
};
|
||||
|
||||
const paginateSpy = jest.spyOn(TimelineWindow.prototype, 'paginate').mockClear();
|
||||
|
||||
render(<TimelinePanel {...props} />);
|
||||
|
||||
const event = new MatrixEvent({ type: RoomEvent.Timeline });
|
||||
const data = { timeline: props.timelineSet.getLiveTimeline(), liveEvent: true };
|
||||
client.emit(RoomEvent.Timeline, event, room, false, false, data);
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(paginateSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with overlayTimeline', () => {
|
||||
it('renders merged timeline', () => {
|
||||
const [client, room, events] = setupTestData();
|
||||
const virtualRoom = mkRoom(client, "virtualRoomId");
|
||||
const virtualCallInvite = new MatrixEvent({
|
||||
type: 'm.call.invite',
|
||||
room_id: virtualRoom.roomId,
|
||||
event_id: `virtualCallEvent1`,
|
||||
});
|
||||
const virtualCallMetaEvent = new MatrixEvent({
|
||||
type: 'org.matrix.call.sdp_stream_metadata_changed',
|
||||
room_id: virtualRoom.roomId,
|
||||
event_id: `virtualCallEvent2`,
|
||||
});
|
||||
const virtualEvents = [
|
||||
virtualCallInvite,
|
||||
...mockEvents(virtualRoom),
|
||||
virtualCallMetaEvent,
|
||||
];
|
||||
const { timelineSet: overlayTimelineSet } = getProps(virtualRoom, virtualEvents);
|
||||
|
||||
const props = {
|
||||
...getProps(room, events),
|
||||
overlayTimelineSet,
|
||||
overlayTimelineSetFilter: isCallEvent,
|
||||
};
|
||||
|
||||
const { container } = render(<TimelinePanel {...props} />);
|
||||
|
||||
const eventTiles = container.querySelectorAll('.mx_EventTile');
|
||||
const eventTileIds = [...eventTiles].map(tileElement => tileElement.getAttribute('data-event-id'));
|
||||
expect(eventTileIds).toEqual([
|
||||
// main timeline events are included
|
||||
events[1].getId(),
|
||||
events[0].getId(),
|
||||
// virtual timeline call event is included
|
||||
virtualCallInvite.getId(),
|
||||
// virtual call event has no tile renderer => not rendered
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when a thread updates", () => {
|
||||
let client: MatrixClient;
|
||||
let room: Room;
|
||||
|
Reference in New Issue
Block a user