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

Commit 9f91145

Browse files
committed
Fix and write tests
1 parent 10a5941 commit 9f91145

File tree

3 files changed

+96
-23
lines changed

3 files changed

+96
-23
lines changed

src/components/structures/TimelinePanel.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -1432,13 +1432,16 @@ class TimelinePanel extends React.Component<IProps, IState> {
14321432
if (mainEvents.length > 0) {
14331433
let paginationRequests: Promise<unknown>[];
14341434

1435+
// Keep paginating until the main window is covered
14351436
do {
14361437
paginationRequests = [];
14371438
const overlayEvents = overlayWindow.getEvents();
14381439

14391440
if (
14401441
overlayWindow.canPaginate(EventTimeline.BACKWARDS) &&
1441-
(overlayEvents.length === 0 || overlaysAfter(overlayEvents[0], mainEvents[0]))
1442+
(overlayEvents.length === 0 ||
1443+
overlaysAfter(overlayEvents[0], mainEvents[0]) ||
1444+
!mainWindow.canPaginate(EventTimeline.BACKWARDS))
14421445
) {
14431446
// Paginating backwards could reveal more events to be overlaid in the main window
14441447
paginationRequests.push(
@@ -1448,7 +1451,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
14481451

14491452
if (
14501453
overlayWindow.canPaginate(EventTimeline.FORWARDS) &&
1451-
(overlayEvents.length === 0 || overlaysBefore(overlayEvents.at(-1), mainEvents.at(-1)))
1454+
(overlayEvents.length === 0 ||
1455+
overlaysBefore(overlayEvents.at(-1), mainEvents.at(-1)) ||
1456+
!mainWindow.canPaginate(EventTimeline.FORWARDS))
14521457
) {
14531458
// Paginating forwards could reveal more events to be overlaid in the main window
14541459
paginationRequests.push(
@@ -1581,19 +1586,18 @@ class TimelinePanel extends React.Component<IProps, IState> {
15811586
// This is a hot-path optimization by skipping a promise tick
15821587
// by repeating a no-op sync branch in
15831588
// TimelineSet.getTimelineForEvent & MatrixClient.getEventTimeline
1584-
if (this.props.timelineSet.getTimelineForEvent(eventId)) {
1589+
if (this.props.timelineSet.getTimelineForEvent(eventId) && !this.overlayTimelineWindow) {
15851590
// if we've got an eventId, and the timeline exists, we can skip
15861591
// the promise tick.
15871592
this.timelineWindow.load(eventId, INITIAL_SIZE);
1588-
this.overlayTimelineWindow?.load(undefined, INITIAL_SIZE);
15891593
// in this branch this method will happen in sync time
15901594
onLoaded();
15911595
return;
15921596
}
15931597

15941598
const prom = this.timelineWindow.load(eventId, INITIAL_SIZE).then(async (): Promise<void> => {
15951599
if (this.overlayTimelineWindow) {
1596-
// @TODO(kerrya) use timestampToEvent to load the overlay timeline
1600+
// TODO: use timestampToEvent to load the overlay timeline
15971601
// with more correct position when main TL eventId is truthy
15981602
await this.overlayTimelineWindow.load(undefined, INITIAL_SIZE);
15991603
await this.extendOverlayWindowToCoverMainWindow();

test/components/structures/TimelinePanel-test.tsx

+86-17
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import {
3737
ThreadFilterType,
3838
} from "matrix-js-sdk/src/models/thread";
3939
import React, { createRef } from "react";
40+
import { mocked } from "jest-mock";
41+
import { forEachRight } from "lodash";
4042

4143
import TimelinePanel from "../../../src/components/structures/TimelinePanel";
4244
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
@@ -60,10 +62,10 @@ const newReceipt = (eventId: string, userId: string, readTs: number, fullyReadTs
6062
const getProps = (room: Room, events: MatrixEvent[]): TimelinePanel["props"] => {
6163
const timelineSet = { room: room as Room } as EventTimelineSet;
6264
const timeline = new EventTimeline(timelineSet);
63-
events.forEach((event) => timeline.addEvent(event, { toStartOfTimeline: true }));
65+
events.forEach((event) => timeline.addEvent(event, { toStartOfTimeline: false }));
6466
timelineSet.getLiveTimeline = () => timeline;
6567
timelineSet.getTimelineForEvent = () => timeline;
66-
timelineSet.getPendingEvents = () => events;
68+
timelineSet.getPendingEvents = () => [];
6769
timelineSet.room!.getEventReadUpTo = () => events[1].getId() ?? null;
6870

6971
return {
@@ -97,6 +99,12 @@ const setupTestData = (): [MatrixClient, Room, MatrixEvent[]] => {
9799
return [client, room, events];
98100
};
99101

102+
const expectEvents = (container: HTMLElement, events: MatrixEvent[]): void => {
103+
const eventTiles = container.querySelectorAll(".mx_EventTile");
104+
const eventTileIds = [...eventTiles].map((tileElement) => tileElement.getAttribute("data-event-id"));
105+
expect(eventTileIds).toEqual(events.map((ev) => ev.getId()));
106+
};
107+
100108
describe("TimelinePanel", () => {
101109
beforeEach(() => {
102110
stubClient();
@@ -279,8 +287,7 @@ describe("TimelinePanel", () => {
279287
});
280288

281289
describe("with overlayTimeline", () => {
282-
// Trying to understand why this is not passing anymore
283-
it.skip("renders merged timeline", () => {
290+
it("renders merged timeline", () => {
284291
const [client, room, events] = setupTestData();
285292
const virtualRoom = mkRoom(client, "virtualRoomId");
286293
const virtualCallInvite = new MatrixEvent({
@@ -296,25 +303,87 @@ describe("TimelinePanel", () => {
296303
const virtualEvents = [virtualCallInvite, ...mockEvents(virtualRoom), virtualCallMetaEvent];
297304
const { timelineSet: overlayTimelineSet } = getProps(virtualRoom, virtualEvents);
298305

299-
const props = {
300-
...getProps(room, events),
301-
overlayTimelineSet,
302-
overlayTimelineSetFilter: isCallEvent,
303-
};
304-
305-
const { container } = render(<TimelinePanel {...props} />);
306+
const { container } = render(
307+
<TimelinePanel
308+
{...getProps(room, events)}
309+
overlayTimelineSet={overlayTimelineSet}
310+
overlayTimelineSetFilter={isCallEvent}
311+
/>,
312+
);
306313

307-
const eventTiles = container.querySelectorAll(".mx_EventTile");
308-
const eventTileIds = [...eventTiles].map((tileElement) => tileElement.getAttribute("data-event-id"));
309-
expect(eventTileIds).toEqual([
314+
expectEvents(container, [
310315
// main timeline events are included
311-
events[1].getId(),
312-
events[0].getId(),
316+
events[0],
317+
events[1],
313318
// virtual timeline call event is included
314-
virtualCallInvite.getId(),
319+
virtualCallInvite,
315320
// virtual call event has no tile renderer => not rendered
316321
]);
317322
});
323+
324+
it("paginates to get enough overlay events", async () => {
325+
const [client, room, events] = setupTestData();
326+
const virtualRoom = mkRoom(client, "virtualRoomId");
327+
const overlayEvents = mockEvents(virtualRoom, 5);
328+
const overlayEventsPage1 = overlayEvents.slice(0, 2);
329+
const overlayEventsPage2 = overlayEvents.slice(2, 3);
330+
const overlayEventsPage3 = overlayEvents.slice(3, 5);
331+
332+
// Set the event order that we'll be looking for in the timeline
333+
overlayEventsPage1[0].localTimestamp = 1000;
334+
events[0].localTimestamp = 2000;
335+
overlayEventsPage1[1].localTimestamp = 3000;
336+
overlayEventsPage2[0].localTimestamp = 4000;
337+
overlayEventsPage3[0].localTimestamp = 5000;
338+
events[1].localTimestamp = 6000;
339+
overlayEventsPage3[1].localTimestamp = 7000;
340+
341+
const overlayTimelineSet = {
342+
room: room as Room,
343+
getLiveTimeline: () => overlayTimeline,
344+
getTimelineForEvent: () => overlayTimeline,
345+
getPendingEvents: () => [],
346+
} as EventTimelineSet;
347+
const overlayTimeline = new EventTimeline(overlayTimelineSet);
348+
// Start with only page 2 of the overlay events in the window
349+
overlayEventsPage2.forEach((event) => overlayTimeline.addEvent(event, { toStartOfTimeline: false }));
350+
// Enable the overlay timeline to be paginated
351+
overlayTimeline.setPaginationToken("page2-start", EventTimeline.BACKWARDS);
352+
overlayTimeline.setPaginationToken("page2-end", EventTimeline.FORWARDS);
353+
354+
mocked(client).paginateEventTimeline.mockImplementation(async (timeline, { backwards }) => {
355+
if (timeline === overlayTimeline) {
356+
if (backwards) {
357+
forEachRight(overlayEventsPage1, (event) =>
358+
timeline.addEvent(event, { toStartOfTimeline: true }),
359+
);
360+
} else {
361+
overlayEventsPage3.forEach((event) => timeline.addEvent(event, { toStartOfTimeline: false }));
362+
}
363+
// Prevent any further pagination attempts in this direction
364+
timeline.setPaginationToken(null, backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS);
365+
return true;
366+
} else {
367+
return false;
368+
}
369+
});
370+
371+
const { container } = render(
372+
<TimelinePanel {...getProps(room, events)} overlayTimelineSet={overlayTimelineSet} />,
373+
);
374+
375+
await waitFor(() =>
376+
expectEvents(container, [
377+
overlayEventsPage1[0],
378+
events[0],
379+
overlayEventsPage1[1],
380+
overlayEventsPage2[0],
381+
overlayEventsPage3[0],
382+
events[1],
383+
overlayEventsPage3[1],
384+
]),
385+
);
386+
});
318387
});
319388

320389
describe("when a thread updates", () => {

test/test-utils/test-utils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ export function mkStubRoom(
537537
on: jest.fn(),
538538
off: jest.fn(),
539539
} as unknown as RoomState,
540-
eventShouldLiveIn: jest.fn().mockReturnValue({}),
540+
eventShouldLiveIn: jest.fn().mockReturnValue({ shouldLiveInRoom: true, shouldLiveInThread: false }),
541541
fetchRoomThreads: jest.fn().mockReturnValue(Promise.resolve()),
542542
findEventById: jest.fn().mockReturnValue(undefined),
543543
findPredecessor: jest.fn().mockReturnValue({ roomId: "", eventId: null }),

0 commit comments

Comments
 (0)