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

Commit dd88fbb

Browse files
Germainrichvdh
andauthored
Fix checkForPreJoinUISI for thread roots (#9803)
* Fix blank timeline when thread root is UTD * add test for pre join uisi checks and thread roots * ts strict fix * Update to timeline panel test Co-authored-by: Richard van der Hoff <[email protected]> * Fixes to TimelinePanel-test Co-authored-by: Richard van der Hoff <[email protected]>
1 parent 134e3d7 commit dd88fbb

File tree

2 files changed

+71
-6
lines changed

2 files changed

+71
-6
lines changed

src/components/structures/TimelinePanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
16371637
let i = events.length - 1;
16381638
let userMembership = "leave";
16391639
for (; i >= 0; i--) {
1640-
const timeline = room.getTimelineForEvent(events[i].getId());
1640+
const timeline = this.props.timelineSet.getTimelineForEvent(events[i].getId()!);
16411641
if (!timeline) {
16421642
// Somehow, it seems to be possible for live events to not have
16431643
// a timeline, even though that should not happen. :(

test/components/structures/TimelinePanel-test.tsx

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import { render, RenderResult } from "@testing-library/react";
17+
import { render, RenderResult, waitFor, screen } from "@testing-library/react";
1818
// eslint-disable-next-line deprecate/import
1919
import { mount, ReactWrapper } from "enzyme";
2020
import { MessageEvent } from "matrix-events-sdk";
@@ -27,6 +27,8 @@ import {
2727
PendingEventOrdering,
2828
Room,
2929
RoomEvent,
30+
RoomMember,
31+
RoomState,
3032
TimelineWindow,
3133
} from "matrix-js-sdk/src/matrix";
3234
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
@@ -44,7 +46,8 @@ import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
4446
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
4547
import SettingsStore from "../../../src/settings/SettingsStore";
4648
import { isCallEvent } from "../../../src/components/structures/LegacyCallEventGrouper";
47-
import { flushPromises, mkRoom, stubClient } from "../../test-utils";
49+
import { flushPromises, mkMembership, mkRoom, stubClient } from "../../test-utils";
50+
import { mkThread } from "../../test-utils/threads";
4851

4952
const newReceipt = (eventId: string, userId: string, readTs: number, fullyReadTs: number): MatrixEvent => {
5053
const receiptContent = {
@@ -60,7 +63,7 @@ const newReceipt = (eventId: string, userId: string, readTs: number, fullyReadTs
6063
const getProps = (room: Room, events: MatrixEvent[]): TimelinePanel["props"] => {
6164
const timelineSet = { room: room as Room } as EventTimelineSet;
6265
const timeline = new EventTimeline(timelineSet);
63-
events.forEach((event) => timeline.addEvent(event, true));
66+
events.forEach((event) => timeline.addEvent(event, { toStartOfTimeline: true }));
6467
timelineSet.getLiveTimeline = () => timeline;
6568
timelineSet.getTimelineForEvent = () => timeline;
6669
timelineSet.getPendingEvents = () => events;
@@ -430,7 +433,7 @@ describe("TimelinePanel", () => {
430433
// @ts-ignore
431434
thread.fetchEditsWhereNeeded = () => Promise.resolve();
432435
await thread.addEvent(reply1, true);
433-
await allThreads.getLiveTimeline().addEvent(thread.rootEvent!, true);
436+
await allThreads.getLiveTimeline().addEvent(thread.rootEvent!, { toStartOfTimeline: true });
434437
const replyToEvent = jest.spyOn(thread, "replyToEvent", "get");
435438

436439
const dom = render(
@@ -476,7 +479,7 @@ describe("TimelinePanel", () => {
476479
// @ts-ignore
477480
realThread.fetchEditsWhereNeeded = () => Promise.resolve();
478481
await realThread.addEvent(reply1, true);
479-
await allThreads.getLiveTimeline().addEvent(realThread.rootEvent!, true);
482+
await allThreads.getLiveTimeline().addEvent(realThread.rootEvent!, { toStartOfTimeline: true });
480483
const replyToEvent = jest.spyOn(realThread, "replyToEvent", "get");
481484

482485
// @ts-ignore
@@ -513,4 +516,66 @@ describe("TimelinePanel", () => {
513516
replyToEvent.mockClear();
514517
});
515518
});
519+
520+
it("renders when the last message is an undecryptable thread root", async () => {
521+
jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => name === "feature_threadstable");
522+
523+
const client = MatrixClientPeg.get();
524+
client.isRoomEncrypted = () => true;
525+
client.supportsExperimentalThreads = () => true;
526+
client.decryptEventIfNeeded = () => Promise.resolve();
527+
const authorId = client.getUserId()!;
528+
const room = new Room("roomId", client, authorId, {
529+
lazyLoadMembers: false,
530+
pendingEventOrdering: PendingEventOrdering.Detached,
531+
});
532+
533+
const events = mockEvents(room);
534+
const timelineSet = room.getUnfilteredTimelineSet();
535+
536+
const { rootEvent } = mkThread({
537+
room,
538+
client,
539+
authorId,
540+
participantUserIds: [authorId],
541+
});
542+
543+
events.push(rootEvent);
544+
545+
events.forEach((event) => timelineSet.getLiveTimeline().addEvent(event, { toStartOfTimeline: true }));
546+
547+
const roomMembership = mkMembership({
548+
mship: "join",
549+
prevMship: "join",
550+
user: authorId,
551+
room: room.roomId,
552+
event: true,
553+
skey: "123",
554+
});
555+
556+
events.push(roomMembership);
557+
558+
const member = new RoomMember(room.roomId, authorId);
559+
member.membership = "join";
560+
561+
const roomState = new RoomState(room.roomId);
562+
jest.spyOn(roomState, "getMember").mockReturnValue(member);
563+
564+
jest.spyOn(timelineSet.getLiveTimeline(), "getState").mockReturnValue(roomState);
565+
timelineSet.addEventToTimeline(roomMembership, timelineSet.getLiveTimeline(), { toStartOfTimeline: false });
566+
567+
for (const event of events) {
568+
jest.spyOn(event, "isDecryptionFailure").mockReturnValue(true);
569+
jest.spyOn(event, "shouldAttemptDecryption").mockReturnValue(false);
570+
}
571+
572+
const { container } = render(
573+
<MatrixClientContext.Provider value={client}>
574+
<TimelinePanel timelineSet={timelineSet} manageReadReceipts={true} sendReadReceiptOnLoad={true} />
575+
</MatrixClientContext.Provider>,
576+
);
577+
578+
await waitFor(() => expect(screen.queryByRole("progressbar")).toBeNull());
579+
await waitFor(() => expect(container.querySelector(".mx_RoomView_MessageList")).not.toBeEmptyDOMElement());
580+
});
516581
});

0 commit comments

Comments
 (0)