2016-03-31 07:48:46 +08:00
|
|
|
/*
|
2024-09-09 21:57:16 +08:00
|
|
|
Copyright 2024 New Vector Ltd.
|
|
|
|
Copyright 2019-2021 , 2022 The Matrix.org Foundation C.I.C.
|
2016-03-31 07:48:46 +08:00
|
|
|
Copyright 2016 OpenMarket Ltd
|
|
|
|
|
2024-09-09 21:57:16 +08:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|
|
|
Please see LICENSE files in the repository root for full details.
|
2016-03-31 07:48:46 +08:00
|
|
|
*/
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
import React from "react";
|
2019-03-15 16:57:26 +08:00
|
|
|
import { EventEmitter } from "events";
|
2024-03-18 22:40:52 +08:00
|
|
|
import { MatrixEvent, Room, RoomMember, Thread, ReceiptType } from "matrix-js-sdk/src/matrix";
|
|
|
|
import { KnownMembership } from "matrix-js-sdk/src/types";
|
2022-12-12 19:24:14 +08:00
|
|
|
import { render } from "@testing-library/react";
|
2020-02-14 06:25:54 +08:00
|
|
|
|
2022-03-27 06:06:25 +08:00
|
|
|
import MessagePanel, { shouldFormContinuation } from "../../../src/components/structures/MessagePanel";
|
2021-10-23 06:23:32 +08:00
|
|
|
import SettingsStore from "../../../src/settings/SettingsStore";
|
2019-12-18 01:26:12 +08:00
|
|
|
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
|
2022-06-30 20:41:53 +08:00
|
|
|
import RoomContext, { TimelineRenderingType } from "../../../src/contexts/RoomContext";
|
2020-11-06 00:27:41 +08:00
|
|
|
import DMRoomMap from "../../../src/utils/DMRoomMap";
|
2022-03-09 19:22:36 +08:00
|
|
|
import * as TestUtilsMatrix from "../../test-utils";
|
2022-06-30 20:41:53 +08:00
|
|
|
import {
|
2023-06-22 00:29:44 +08:00
|
|
|
createTestClient,
|
2022-06-30 20:41:53 +08:00
|
|
|
getMockClientWithEventEmitter,
|
|
|
|
makeBeaconInfoEvent,
|
|
|
|
mockClientMethodsEvents,
|
|
|
|
mockClientMethodsUser,
|
2022-12-12 19:24:14 +08:00
|
|
|
} from "../../test-utils";
|
|
|
|
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
|
|
|
|
import { IRoomState } from "../../../src/components/structures/RoomView";
|
2023-02-03 23:36:37 +08:00
|
|
|
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
2022-05-03 17:04:47 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
jest.mock("../../../src/utils/beacon", () => ({
|
2022-05-03 17:04:47 +08:00
|
|
|
useBeacon: jest.fn(),
|
|
|
|
}));
|
2021-10-23 06:23:32 +08:00
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const roomId = "!roomId:server_name";
|
2016-11-15 02:20:15 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
describe("MessagePanel", function () {
|
2017-10-12 00:56:17 +08:00
|
|
|
const events = mkEvents();
|
2022-12-12 19:24:14 +08:00
|
|
|
const userId = "@me:here";
|
2022-06-30 20:41:53 +08:00
|
|
|
const client = getMockClientWithEventEmitter({
|
|
|
|
...mockClientMethodsUser(userId),
|
|
|
|
...mockClientMethodsEvents(),
|
|
|
|
getAccountData: jest.fn(),
|
|
|
|
isUserIgnored: jest.fn().mockReturnValue(false),
|
|
|
|
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
|
|
|
getRoom: jest.fn(),
|
|
|
|
getClientWellKnown: jest.fn().mockReturnValue({}),
|
2023-02-20 22:46:07 +08:00
|
|
|
supportsThreads: jest.fn().mockReturnValue(true),
|
2022-06-30 20:41:53 +08:00
|
|
|
});
|
2023-02-03 23:36:37 +08:00
|
|
|
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(client);
|
2016-03-31 07:48:46 +08:00
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const room = new Room(roomId, client, userId);
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const bobMember = new RoomMember(roomId, "@bob:id");
|
|
|
|
bobMember.name = "Bob";
|
|
|
|
jest.spyOn(bobMember, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
|
|
|
jest.spyOn(bobMember, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
2022-06-30 20:41:53 +08:00
|
|
|
|
|
|
|
const alice = "@alice:example.org";
|
|
|
|
const aliceMember = new RoomMember(roomId, alice);
|
2022-12-12 19:24:14 +08:00
|
|
|
aliceMember.name = "Alice";
|
|
|
|
jest.spyOn(aliceMember, "getAvatarUrl").mockReturnValue("avatar.jpeg");
|
|
|
|
jest.spyOn(aliceMember, "getMxcAvatarUrl").mockReturnValue("mxc://avatar.url/image.png");
|
2022-06-30 20:41:53 +08:00
|
|
|
|
|
|
|
const defaultProps = {
|
2022-12-12 19:24:14 +08:00
|
|
|
resizeNotifier: new EventEmitter() as unknown as ResizeNotifier,
|
2022-06-30 20:41:53 +08:00
|
|
|
callEventGroupers: new Map(),
|
|
|
|
room,
|
2022-12-12 19:24:14 +08:00
|
|
|
className: "cls",
|
2023-02-13 19:39:16 +08:00
|
|
|
events: [] as MatrixEvent[],
|
2022-06-30 20:41:53 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const defaultRoomContext = {
|
|
|
|
...RoomContext,
|
|
|
|
timelineRenderingType: TimelineRenderingType.Room,
|
|
|
|
room,
|
|
|
|
roomId: room.roomId,
|
|
|
|
canReact: true,
|
|
|
|
canSendMessages: true,
|
|
|
|
showReadReceipts: true,
|
|
|
|
showRedactions: false,
|
|
|
|
showJoinLeaves: false,
|
|
|
|
showAvatarChanges: false,
|
|
|
|
showDisplaynameChanges: true,
|
|
|
|
showHiddenEvents: false,
|
|
|
|
} as unknown as IRoomState;
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) => (
|
2022-06-30 20:41:53 +08:00
|
|
|
<MatrixClientContext.Provider value={client}>
|
|
|
|
<RoomContext.Provider value={{ ...defaultRoomContext, ...roomContext }}>
|
2024-04-12 20:56:23 +08:00
|
|
|
<MessagePanel {...defaultProps} {...props} />
|
2022-12-12 19:24:14 +08:00
|
|
|
</RoomContext.Provider>
|
|
|
|
</MatrixClientContext.Provider>
|
|
|
|
);
|
2017-10-29 15:43:52 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
beforeEach(function () {
|
2022-06-30 20:41:53 +08:00
|
|
|
jest.clearAllMocks();
|
2017-10-29 15:43:52 +08:00
|
|
|
// HACK: We assume all settings want to be disabled
|
2022-12-12 19:24:14 +08:00
|
|
|
jest.spyOn(SettingsStore, "getValue").mockImplementation((arg) => {
|
2019-12-16 19:55:01 +08:00
|
|
|
return arg === "showDisplaynameChanges";
|
|
|
|
});
|
2019-03-21 01:43:19 +08:00
|
|
|
|
2023-05-23 23:24:12 +08:00
|
|
|
DMRoomMap.makeShared(client);
|
2016-04-07 23:47:17 +08:00
|
|
|
});
|
|
|
|
|
2016-03-31 07:48:46 +08:00
|
|
|
function mkEvents() {
|
2023-02-15 21:36:22 +08:00
|
|
|
const events: MatrixEvent[] = [];
|
2017-10-12 00:56:17 +08:00
|
|
|
const ts0 = Date.now();
|
|
|
|
for (let i = 0; i < 10; i++) {
|
2022-12-12 19:24:14 +08:00
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
2021-05-07 14:15:52 +08:00
|
|
|
ts: ts0 + i * 1000,
|
2022-12-12 19:24:14 +08:00
|
|
|
}),
|
|
|
|
);
|
2021-05-07 14:15:52 +08:00
|
|
|
}
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
2021-05-11 09:56:30 +08:00
|
|
|
// Just to avoid breaking Dateseparator tests that might run at 00hrs
|
2021-05-07 14:15:52 +08:00
|
|
|
function mkOneDayEvents() {
|
2023-02-15 21:36:22 +08:00
|
|
|
const events: MatrixEvent[] = [];
|
2022-12-12 19:24:14 +08:00
|
|
|
const ts0 = Date.parse("09 May 2004 00:12:00 GMT");
|
2021-05-07 14:15:52 +08:00
|
|
|
for (let i = 0; i < 10; i++) {
|
2022-12-12 19:24:14 +08:00
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
2021-05-07 14:15:52 +08:00
|
|
|
ts: ts0 + i * 1000,
|
2022-12-12 19:24:14 +08:00
|
|
|
}),
|
|
|
|
);
|
2016-03-31 07:48:46 +08:00
|
|
|
}
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
2022-02-09 18:51:12 +08:00
|
|
|
// make a collection of events with some member events that should be collapsed with an EventListSummary
|
2019-11-27 03:06:02 +08:00
|
|
|
function mkMelsEvents() {
|
2023-02-15 21:36:22 +08:00
|
|
|
const events: MatrixEvent[] = [];
|
2019-11-27 03:06:02 +08:00
|
|
|
const ts0 = Date.now();
|
|
|
|
|
|
|
|
let i = 0;
|
2022-12-12 19:24:14 +08:00
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
ts: ts0 + ++i * 1000,
|
|
|
|
}),
|
|
|
|
);
|
2019-11-27 03:06:02 +08:00
|
|
|
|
|
|
|
for (i = 0; i < 10; i++) {
|
2022-12-12 19:24:14 +08:00
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMembership({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
target: bobMember,
|
|
|
|
ts: ts0 + i * 1000,
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
|
|
|
prevMship: KnownMembership.Join,
|
2022-12-12 19:24:14 +08:00
|
|
|
name: "A user",
|
|
|
|
}),
|
|
|
|
);
|
2019-11-27 03:06:02 +08:00
|
|
|
}
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
ts: ts0 + ++i * 1000,
|
|
|
|
}),
|
|
|
|
);
|
2019-11-27 03:06:02 +08:00
|
|
|
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
2020-04-02 22:07:50 +08:00
|
|
|
// A list of membership events only with nothing else
|
|
|
|
function mkMelsEventsOnly() {
|
2023-02-15 21:36:22 +08:00
|
|
|
const events: MatrixEvent[] = [];
|
2020-04-02 22:07:50 +08:00
|
|
|
const ts0 = Date.now();
|
|
|
|
|
|
|
|
let i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < 10; i++) {
|
2022-12-12 19:24:14 +08:00
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMembership({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
target: bobMember,
|
|
|
|
ts: ts0 + i * 1000,
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
|
|
|
prevMship: KnownMembership.Join,
|
2022-12-12 19:24:14 +08:00
|
|
|
name: "A user",
|
|
|
|
}),
|
|
|
|
);
|
2020-04-02 22:07:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return events;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A list of room creation, encryption, and invite events.
|
|
|
|
function mkCreationEvents() {
|
2021-07-02 03:54:04 +08:00
|
|
|
const mkEvent = TestUtilsMatrix.mkEvent;
|
|
|
|
const mkMembership = TestUtilsMatrix.mkMembership;
|
2020-04-02 22:07:50 +08:00
|
|
|
const roomId = "!someroom";
|
2022-06-30 20:41:53 +08:00
|
|
|
|
2020-04-02 22:07:50 +08:00
|
|
|
const ts0 = Date.now();
|
|
|
|
|
|
|
|
return [
|
|
|
|
mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.room.create",
|
|
|
|
room: roomId,
|
|
|
|
user: alice,
|
|
|
|
content: {
|
|
|
|
creator: alice,
|
|
|
|
room_version: "5",
|
|
|
|
predecessor: {
|
|
|
|
room_id: "!prevroom",
|
|
|
|
event_id: "$someevent",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ts: ts0,
|
|
|
|
}),
|
|
|
|
mkMembership({
|
|
|
|
event: true,
|
|
|
|
room: roomId,
|
|
|
|
user: alice,
|
2022-06-30 20:41:53 +08:00
|
|
|
target: aliceMember,
|
2020-04-02 22:07:50 +08:00
|
|
|
ts: ts0 + 1,
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
2022-12-12 19:24:14 +08:00
|
|
|
name: "Alice",
|
2020-04-02 22:07:50 +08:00
|
|
|
}),
|
|
|
|
mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.room.join_rules",
|
|
|
|
room: roomId,
|
|
|
|
user: alice,
|
|
|
|
content: {
|
2022-12-12 19:24:14 +08:00
|
|
|
join_rule: "invite",
|
2020-04-02 22:07:50 +08:00
|
|
|
},
|
|
|
|
ts: ts0 + 2,
|
|
|
|
}),
|
|
|
|
mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.room.history_visibility",
|
|
|
|
room: roomId,
|
|
|
|
user: alice,
|
|
|
|
content: {
|
2022-12-12 19:24:14 +08:00
|
|
|
history_visibility: "invited",
|
2020-04-02 22:07:50 +08:00
|
|
|
},
|
|
|
|
ts: ts0 + 3,
|
|
|
|
}),
|
|
|
|
mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.room.encryption",
|
|
|
|
room: roomId,
|
|
|
|
user: alice,
|
|
|
|
content: {
|
2022-12-12 19:24:14 +08:00
|
|
|
algorithm: "m.megolm.v1.aes-sha2",
|
2020-04-02 22:07:50 +08:00
|
|
|
},
|
|
|
|
ts: ts0 + 4,
|
|
|
|
}),
|
|
|
|
mkMembership({
|
|
|
|
event: true,
|
|
|
|
room: roomId,
|
|
|
|
user: alice,
|
|
|
|
skey: "@bob:example.org",
|
2022-06-30 20:41:53 +08:00
|
|
|
target: bobMember,
|
2020-04-02 22:07:50 +08:00
|
|
|
ts: ts0 + 5,
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Invite,
|
2022-12-12 19:24:14 +08:00
|
|
|
name: "Bob",
|
2020-04-02 22:07:50 +08:00
|
|
|
}),
|
|
|
|
];
|
|
|
|
}
|
2022-04-15 07:23:22 +08:00
|
|
|
|
|
|
|
function mkMixedHiddenAndShownEvents() {
|
|
|
|
const roomId = "!room:id";
|
|
|
|
const userId = "@alice:example.org";
|
|
|
|
const ts0 = Date.now();
|
|
|
|
|
|
|
|
return [
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: roomId,
|
|
|
|
user: userId,
|
|
|
|
ts: ts0,
|
|
|
|
}),
|
|
|
|
TestUtilsMatrix.mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "org.example.a_hidden_event",
|
|
|
|
room: roomId,
|
|
|
|
user: userId,
|
|
|
|
content: {},
|
|
|
|
ts: ts0 + 1,
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-02-13 19:39:16 +08:00
|
|
|
function isReadMarkerVisible(rmContainer?: Element) {
|
2023-02-15 21:36:22 +08:00
|
|
|
return !!rmContainer?.children.length;
|
2020-04-02 22:07:50 +08:00
|
|
|
}
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should show the events", function () {
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container } = render(getComponent({ events }));
|
2016-03-31 07:48:46 +08:00
|
|
|
|
|
|
|
// just check we have the right number of tiles for now
|
2022-12-12 19:24:14 +08:00
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
2016-03-31 07:48:46 +08:00
|
|
|
expect(tiles.length).toEqual(10);
|
|
|
|
});
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should collapse adjacent member events", function () {
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container } = render(getComponent({ events: mkMelsEvents() }));
|
2019-11-27 03:06:02 +08:00
|
|
|
|
|
|
|
// just check we have the right number of tiles for now
|
2022-12-12 19:24:14 +08:00
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
2019-11-27 03:06:02 +08:00
|
|
|
expect(tiles.length).toEqual(2);
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const summaryTiles = container.getElementsByClassName("mx_GenericEventListSummary");
|
2019-11-27 03:06:02 +08:00
|
|
|
expect(summaryTiles.length).toEqual(1);
|
|
|
|
});
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should insert the read-marker in the right place", function () {
|
|
|
|
const { container } = render(
|
|
|
|
getComponent({
|
|
|
|
events,
|
|
|
|
readMarkerEventId: events[4].getId(),
|
|
|
|
readMarkerVisible: true,
|
|
|
|
}),
|
|
|
|
);
|
2016-03-31 07:48:46 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
2016-03-31 07:48:46 +08:00
|
|
|
|
|
|
|
// find the <li> which wraps the read marker
|
2023-05-15 19:02:04 +08:00
|
|
|
const [rm] = container.getElementsByClassName("mx_MessagePanel_myReadMarker");
|
2016-03-31 07:48:46 +08:00
|
|
|
|
|
|
|
// it should follow the <li> which wraps the event tile for event 4
|
2023-02-22 18:52:55 +08:00
|
|
|
const eventContainer = tiles[4];
|
2016-03-31 07:48:46 +08:00
|
|
|
expect(rm.previousSibling).toEqual(eventContainer);
|
|
|
|
});
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should show the read-marker that fall in summarised events after the summary", function () {
|
2019-11-27 03:06:02 +08:00
|
|
|
const melsEvents = mkMelsEvents();
|
2022-12-12 19:24:14 +08:00
|
|
|
const { container } = render(
|
|
|
|
getComponent({
|
|
|
|
events: melsEvents,
|
|
|
|
readMarkerEventId: melsEvents[4].getId(),
|
|
|
|
readMarkerVisible: true,
|
|
|
|
}),
|
|
|
|
);
|
2019-11-27 03:06:02 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const [summary] = container.getElementsByClassName("mx_GenericEventListSummary");
|
2019-11-27 03:06:02 +08:00
|
|
|
|
|
|
|
// find the <li> which wraps the read marker
|
2023-05-15 19:02:04 +08:00
|
|
|
const [rm] = container.getElementsByClassName("mx_MessagePanel_myReadMarker");
|
2019-11-27 03:06:02 +08:00
|
|
|
|
|
|
|
expect(rm.previousSibling).toEqual(summary);
|
2020-04-02 22:07:50 +08:00
|
|
|
|
|
|
|
// read marker should be visible given props and not at the last event
|
|
|
|
expect(isReadMarkerVisible(rm)).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should hide the read-marker at the end of summarised events", function () {
|
2020-04-02 22:07:50 +08:00
|
|
|
const melsEvents = mkMelsEventsOnly();
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const { container } = render(
|
|
|
|
getComponent({
|
|
|
|
events: melsEvents,
|
|
|
|
readMarkerEventId: melsEvents[9].getId(),
|
|
|
|
readMarkerVisible: true,
|
|
|
|
}),
|
|
|
|
);
|
2022-06-30 20:41:53 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const [summary] = container.getElementsByClassName("mx_GenericEventListSummary");
|
2020-04-02 22:07:50 +08:00
|
|
|
|
|
|
|
// find the <li> which wraps the read marker
|
2023-05-15 19:02:04 +08:00
|
|
|
const [rm] = container.getElementsByClassName("mx_MessagePanel_myReadMarker");
|
2020-04-02 22:07:50 +08:00
|
|
|
|
|
|
|
expect(rm.previousSibling).toEqual(summary);
|
|
|
|
|
|
|
|
// read marker should be hidden given props and at the last event
|
|
|
|
expect(isReadMarkerVisible(rm)).toBeFalsy();
|
2019-11-27 03:06:02 +08:00
|
|
|
});
|
|
|
|
|
2023-03-01 23:23:35 +08:00
|
|
|
it("shows a ghost read-marker when the read-marker moves", function () {
|
2016-03-31 07:48:46 +08:00
|
|
|
// fake the clock so that we can test the velocity animation.
|
2023-07-17 20:29:51 +08:00
|
|
|
jest.useFakeTimers();
|
2016-03-31 07:48:46 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const { container, rerender } = render(
|
|
|
|
<div>
|
|
|
|
{getComponent({
|
|
|
|
events,
|
|
|
|
readMarkerEventId: events[4].getId(),
|
|
|
|
readMarkerVisible: true,
|
|
|
|
})}
|
|
|
|
</div>,
|
|
|
|
);
|
2016-03-31 07:48:46 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
2016-03-31 07:48:46 +08:00
|
|
|
|
|
|
|
// find the <li> which wraps the read marker
|
2023-05-15 19:02:04 +08:00
|
|
|
const [rm] = container.getElementsByClassName("mx_MessagePanel_myReadMarker");
|
2022-06-30 20:41:53 +08:00
|
|
|
expect(rm.previousSibling).toEqual(tiles[4]);
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
rerender(
|
|
|
|
<div>
|
|
|
|
{getComponent({
|
|
|
|
events,
|
|
|
|
readMarkerEventId: events[6].getId(),
|
|
|
|
readMarkerVisible: true,
|
|
|
|
})}
|
|
|
|
</div>,
|
|
|
|
);
|
2016-03-31 07:48:46 +08:00
|
|
|
|
|
|
|
// now there should be two RM containers
|
2023-05-15 19:02:04 +08:00
|
|
|
const readMarkers = container.getElementsByClassName("mx_MessagePanel_myReadMarker");
|
2022-06-30 20:41:53 +08:00
|
|
|
|
|
|
|
expect(readMarkers.length).toEqual(2);
|
2016-04-20 04:10:23 +08:00
|
|
|
|
2016-03-31 07:48:46 +08:00
|
|
|
// the first should be the ghost
|
2022-06-30 20:41:53 +08:00
|
|
|
expect(readMarkers[0].previousSibling).toEqual(tiles[4]);
|
|
|
|
const hr: HTMLElement = readMarkers[0].children[0] as HTMLElement;
|
2016-03-31 07:48:46 +08:00
|
|
|
|
|
|
|
// the second should be the real thing
|
2022-06-30 20:41:53 +08:00
|
|
|
expect(readMarkers[1].previousSibling).toEqual(tiles[6]);
|
2016-03-31 07:48:46 +08:00
|
|
|
|
2023-03-01 23:23:35 +08:00
|
|
|
// advance the clock, and then let the browser run an animation frame to let the animation start
|
2023-07-17 20:29:51 +08:00
|
|
|
jest.advanceTimersByTime(1500);
|
2023-03-01 23:23:35 +08:00
|
|
|
expect(hr.style.opacity).toEqual("0");
|
2016-03-31 07:48:46 +08:00
|
|
|
});
|
2020-02-14 06:25:54 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should collapse creation events", function () {
|
2020-04-02 22:07:50 +08:00
|
|
|
const events = mkCreationEvents();
|
2023-02-15 21:36:22 +08:00
|
|
|
const createEvent = events.find((event) => event.getType() === "m.room.create")!;
|
|
|
|
const encryptionEvent = events.find((event) => event.getType() === "m.room.encryption")!;
|
2023-02-03 23:36:37 +08:00
|
|
|
client.getRoom.mockImplementation((id) => (id === createEvent!.getRoomId() ? room : null));
|
|
|
|
TestUtilsMatrix.upsertRoomStateEvents(room, events);
|
|
|
|
|
|
|
|
const { container } = render(getComponent({ events }));
|
2020-02-14 06:25:54 +08:00
|
|
|
|
|
|
|
// we expect that
|
|
|
|
// - the room creation event, the room encryption event, and Alice inviting Bob,
|
|
|
|
// should be outside of the room creation summary
|
|
|
|
// - all other events should be inside the room creation summary
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
2020-02-14 06:25:54 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(tiles[0].getAttribute("data-event-id")).toEqual(createEvent.getId());
|
|
|
|
expect(tiles[1].getAttribute("data-event-id")).toEqual(encryptionEvent.getId());
|
2020-02-14 06:25:54 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const [summaryTile] = container.getElementsByClassName("mx_GenericEventListSummary");
|
2020-02-14 06:25:54 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const summaryEventTiles = summaryTile.getElementsByClassName("mx_EventTile");
|
2020-02-14 06:25:54 +08:00
|
|
|
// every event except for the room creation, room encryption, and Bob's
|
|
|
|
// invite event should be in the event summary
|
|
|
|
expect(summaryEventTiles.length).toEqual(tiles.length - 3);
|
|
|
|
});
|
2020-04-02 22:07:50 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should not collapse beacons as part of creation events", function () {
|
2022-06-30 20:41:53 +08:00
|
|
|
const events = mkCreationEvents();
|
2023-02-15 21:36:22 +08:00
|
|
|
const creationEvent = events.find((event) => event.getType() === "m.room.create")!;
|
|
|
|
const beaconInfoEvent = makeBeaconInfoEvent(creationEvent.getSender()!, creationEvent.getRoomId()!, {
|
2022-12-12 19:24:14 +08:00
|
|
|
isLive: true,
|
|
|
|
});
|
2022-06-30 20:41:53 +08:00
|
|
|
const combinedEvents = [...events, beaconInfoEvent];
|
2022-05-03 17:04:47 +08:00
|
|
|
TestUtilsMatrix.upsertRoomStateEvents(room, combinedEvents);
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container } = render(getComponent({ events: combinedEvents }));
|
2022-05-03 17:04:47 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const [summaryTile] = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-05-03 17:04:47 +08:00
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
// beacon body is not in the summary
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(summaryTile.getElementsByClassName("mx_MBeaconBody").length).toBe(0);
|
2022-06-30 20:41:53 +08:00
|
|
|
// beacon tile is rendered
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(container.getElementsByClassName("mx_MBeaconBody").length).toBe(1);
|
2022-05-03 17:04:47 +08:00
|
|
|
});
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should hide read-marker at the end of creation event summary", function () {
|
2020-04-02 22:07:50 +08:00
|
|
|
const events = mkCreationEvents();
|
2023-02-03 23:36:37 +08:00
|
|
|
const createEvent = events.find((event) => event.getType() === "m.room.create");
|
|
|
|
client.getRoom.mockImplementation((id) => (id === createEvent!.getRoomId() ? room : null));
|
2022-03-09 19:22:36 +08:00
|
|
|
TestUtilsMatrix.upsertRoomStateEvents(room, events);
|
2022-06-30 20:41:53 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const { container } = render(
|
|
|
|
getComponent({
|
|
|
|
events,
|
|
|
|
readMarkerEventId: events[5].getId(),
|
|
|
|
readMarkerVisible: true,
|
|
|
|
}),
|
|
|
|
);
|
2020-04-02 22:07:50 +08:00
|
|
|
|
|
|
|
// find the <li> which wraps the read marker
|
2023-05-15 19:02:04 +08:00
|
|
|
const [rm] = container.getElementsByClassName("mx_MessagePanel_myReadMarker");
|
2020-04-02 22:07:50 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const [messageList] = container.getElementsByClassName("mx_RoomView_MessageList");
|
2022-06-30 20:41:53 +08:00
|
|
|
const rows = messageList.children;
|
2020-11-06 00:57:51 +08:00
|
|
|
expect(rows.length).toEqual(7); // 6 events + the NewRoomIntro
|
2022-06-30 20:41:53 +08:00
|
|
|
expect(rm.previousSibling).toEqual(rows[5]);
|
2020-04-02 22:07:50 +08:00
|
|
|
|
|
|
|
// read marker should be hidden given props and at the last event
|
|
|
|
expect(isReadMarkerVisible(rm)).toBeFalsy();
|
|
|
|
});
|
2021-05-07 14:15:52 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("should render Date separators for the events", function () {
|
2021-05-11 09:56:30 +08:00
|
|
|
const events = mkOneDayEvents();
|
2022-06-30 20:41:53 +08:00
|
|
|
const { queryAllByRole } = render(getComponent({ events }));
|
2022-12-12 19:24:14 +08:00
|
|
|
const dates = queryAllByRole("separator");
|
2021-05-21 21:59:26 +08:00
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
expect(dates.length).toEqual(1);
|
2021-05-11 09:56:30 +08:00
|
|
|
});
|
2022-03-01 16:33:07 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("appends events into summaries during forward pagination without changing key", () => {
|
2022-03-01 16:33:07 +08:00
|
|
|
const events = mkMelsEvents().slice(1, 11);
|
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container, rerender } = render(getComponent({ events }));
|
2022-12-12 19:24:14 +08:00
|
|
|
let els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-03-01 16:33:07 +08:00
|
|
|
expect(els.length).toEqual(1);
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(10);
|
2022-03-01 16:33:07 +08:00
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const updatedEvents = [
|
|
|
|
...events,
|
|
|
|
TestUtilsMatrix.mkMembership({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
target: bobMember,
|
|
|
|
ts: Date.now(),
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
|
|
|
prevMship: KnownMembership.Join,
|
2022-12-12 19:24:14 +08:00
|
|
|
name: "A user",
|
2022-06-30 20:41:53 +08:00
|
|
|
}),
|
|
|
|
];
|
|
|
|
rerender(getComponent({ events: updatedEvents }));
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-03-01 16:33:07 +08:00
|
|
|
expect(els.length).toEqual(1);
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(11);
|
2022-03-01 16:33:07 +08:00
|
|
|
});
|
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("prepends events into summaries during backward pagination without changing key", () => {
|
2022-03-01 16:33:07 +08:00
|
|
|
const events = mkMelsEvents().slice(1, 11);
|
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container, rerender } = render(getComponent({ events }));
|
2022-12-12 19:24:14 +08:00
|
|
|
let els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-03-01 16:33:07 +08:00
|
|
|
expect(els.length).toEqual(1);
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(10);
|
2022-06-30 20:41:53 +08:00
|
|
|
|
|
|
|
const updatedEvents = [
|
|
|
|
TestUtilsMatrix.mkMembership({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
target: bobMember,
|
|
|
|
ts: Date.now(),
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
|
|
|
prevMship: KnownMembership.Join,
|
2022-12-12 19:24:14 +08:00
|
|
|
name: "A user",
|
2022-06-30 20:41:53 +08:00
|
|
|
}),
|
|
|
|
...events,
|
|
|
|
];
|
|
|
|
rerender(getComponent({ events: updatedEvents }));
|
2022-03-01 16:33:07 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-03-01 16:33:07 +08:00
|
|
|
expect(els.length).toEqual(1);
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[0].getAttribute("data-testid")).toEqual("eventlistsummary-" + events[0].getId());
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(11);
|
2022-03-01 16:33:07 +08:00
|
|
|
});
|
2022-03-03 00:46:51 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
it("assigns different keys to summaries that get split up", () => {
|
2022-03-03 00:46:51 +08:00
|
|
|
const events = mkMelsEvents().slice(1, 11);
|
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container, rerender } = render(getComponent({ events }));
|
2022-12-12 19:24:14 +08:00
|
|
|
let els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-03-03 00:46:51 +08:00
|
|
|
expect(els.length).toEqual(1);
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[0].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[0].getId()}`);
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(10);
|
2022-03-03 00:46:51 +08:00
|
|
|
|
2022-06-30 20:41:53 +08:00
|
|
|
const updatedEvents = [
|
|
|
|
...events.slice(0, 5),
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
msg: "Hello!",
|
|
|
|
}),
|
|
|
|
...events.slice(5, 10),
|
|
|
|
];
|
|
|
|
rerender(getComponent({ events: updatedEvents }));
|
|
|
|
|
|
|
|
// summaries split becuase room messages are not summarised
|
2022-12-12 19:24:14 +08:00
|
|
|
els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-03-03 00:46:51 +08:00
|
|
|
expect(els.length).toEqual(2);
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[0].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[0].getId()}`);
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(5);
|
2022-06-30 20:41:53 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
expect(els[1].getAttribute("data-testid")).toEqual(`eventlistsummary-${events[5].getId()}`);
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[1].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(5);
|
2022-03-03 00:46:51 +08:00
|
|
|
});
|
2022-04-15 07:23:22 +08:00
|
|
|
|
|
|
|
// We test this because setting lookups can be *slow*, and we don't want
|
|
|
|
// them to happen in this code path
|
|
|
|
it("doesn't lookup showHiddenEventsInTimeline while rendering", () => {
|
|
|
|
// We're only interested in the setting lookups that happen on every render,
|
|
|
|
// rather than those happening on first mount, so let's get those out of the way
|
2022-06-30 20:41:53 +08:00
|
|
|
const { rerender } = render(getComponent({ events: [] }));
|
2022-04-15 07:23:22 +08:00
|
|
|
|
|
|
|
// Set up our spy and re-render with new events
|
|
|
|
const settingsSpy = jest.spyOn(SettingsStore, "getValue").mockClear();
|
2022-06-30 20:41:53 +08:00
|
|
|
|
|
|
|
rerender(getComponent({ events: mkMixedHiddenAndShownEvents() }));
|
2022-04-15 07:23:22 +08:00
|
|
|
|
|
|
|
expect(settingsSpy).not.toHaveBeenCalledWith("showHiddenEventsInTimeline");
|
|
|
|
settingsSpy.mockRestore();
|
|
|
|
});
|
2022-04-22 00:57:08 +08:00
|
|
|
|
|
|
|
it("should group hidden event reactions into an event list summary", () => {
|
|
|
|
const events = [
|
|
|
|
TestUtilsMatrix.mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.reaction",
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
content: {},
|
|
|
|
ts: 1,
|
|
|
|
}),
|
|
|
|
TestUtilsMatrix.mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.reaction",
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
content: {},
|
|
|
|
ts: 2,
|
|
|
|
}),
|
|
|
|
TestUtilsMatrix.mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "m.reaction",
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
content: {},
|
|
|
|
ts: 3,
|
|
|
|
}),
|
|
|
|
];
|
2022-06-30 20:41:53 +08:00
|
|
|
const { container } = render(getComponent({ events }, { showHiddenEvents: true }));
|
2022-04-22 00:57:08 +08:00
|
|
|
|
2022-12-12 19:24:14 +08:00
|
|
|
const els = container.getElementsByClassName("mx_GenericEventListSummary");
|
2022-04-22 00:57:08 +08:00
|
|
|
expect(els.length).toEqual(1);
|
2023-02-15 21:36:22 +08:00
|
|
|
expect(els[0].getAttribute("data-scroll-tokens")?.split(",")).toHaveLength(3);
|
2022-04-22 00:57:08 +08:00
|
|
|
});
|
2023-03-10 22:35:40 +08:00
|
|
|
|
|
|
|
it("should handle large numbers of hidden events quickly", () => {
|
|
|
|
// Increase the length of the loop here to test performance issues with
|
|
|
|
// rendering
|
|
|
|
|
2023-03-16 19:07:29 +08:00
|
|
|
const events: MatrixEvent[] = [];
|
2023-03-10 22:35:40 +08:00
|
|
|
for (let i = 0; i < 100; i++) {
|
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkEvent({
|
|
|
|
event: true,
|
|
|
|
type: "unknown.event.type",
|
|
|
|
content: { key: "value" },
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
ts: 1000000 + i,
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
const { asFragment } = render(getComponent({ events }, { showHiddenEvents: false }));
|
|
|
|
expect(asFragment()).toMatchSnapshot();
|
|
|
|
});
|
2023-03-20 17:50:07 +08:00
|
|
|
|
|
|
|
it("should handle lots of room creation events quickly", () => {
|
|
|
|
// Increase the length of the loop here to test performance issues with
|
|
|
|
// rendering
|
|
|
|
|
|
|
|
const events = [TestUtilsMatrix.mkRoomCreateEvent("@user:id", "!room:id")];
|
|
|
|
for (let i = 0; i < 100; i++) {
|
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMembership({
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
|
|
|
prevMship: KnownMembership.Join,
|
2023-03-20 17:50:07 +08:00
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
event: true,
|
|
|
|
skey: "123",
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
const { asFragment } = render(getComponent({ events }, { showHiddenEvents: false }));
|
|
|
|
expect(asFragment()).toMatchSnapshot();
|
|
|
|
});
|
|
|
|
|
|
|
|
it("should handle lots of membership events quickly", () => {
|
|
|
|
// Increase the length of the loop here to test performance issues with
|
|
|
|
// rendering
|
|
|
|
|
2023-03-27 15:01:09 +08:00
|
|
|
const events: MatrixEvent[] = [];
|
2023-03-20 17:50:07 +08:00
|
|
|
for (let i = 0; i < 100; i++) {
|
|
|
|
events.push(
|
|
|
|
TestUtilsMatrix.mkMembership({
|
2024-03-12 22:52:54 +08:00
|
|
|
mship: KnownMembership.Join,
|
|
|
|
prevMship: KnownMembership.Join,
|
2023-03-20 17:50:07 +08:00
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
event: true,
|
|
|
|
skey: "123",
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
const { asFragment } = render(getComponent({ events }, { showHiddenEvents: true }));
|
|
|
|
const cpt = asFragment();
|
|
|
|
|
|
|
|
// Ignore properties that change every time
|
|
|
|
cpt.querySelectorAll("li").forEach((li) => {
|
|
|
|
li.setAttribute("data-scroll-tokens", "__scroll_tokens__");
|
|
|
|
li.setAttribute("data-testid", "__testid__");
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(cpt).toMatchSnapshot();
|
|
|
|
});
|
2023-07-25 19:50:20 +08:00
|
|
|
|
|
|
|
it("should set lastSuccessful=true on non-last event if last event is not eligible for special receipt", () => {
|
|
|
|
client.getRoom.mockImplementation((id) => (id === room.roomId ? room : null));
|
|
|
|
const events = [
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: room.roomId,
|
|
|
|
user: client.getSafeUserId(),
|
|
|
|
ts: 1000,
|
|
|
|
}),
|
|
|
|
TestUtilsMatrix.mkEvent({
|
|
|
|
event: true,
|
|
|
|
room: room.roomId,
|
|
|
|
user: client.getSafeUserId(),
|
|
|
|
ts: 1000,
|
|
|
|
type: "m.room.topic",
|
|
|
|
skey: "",
|
|
|
|
content: { topic: "TOPIC" },
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
const { container } = render(getComponent({ events, showReadReceipts: true }));
|
|
|
|
|
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
|
|
|
expect(tiles.length).toEqual(2);
|
|
|
|
expect(tiles[0].querySelector(".mx_EventTile_receiptSent")).toBeTruthy();
|
|
|
|
expect(tiles[1].querySelector(".mx_EventTile_receiptSent")).toBeFalsy();
|
|
|
|
});
|
2023-07-27 15:41:36 +08:00
|
|
|
|
|
|
|
it("should set lastSuccessful=false on non-last event if last event has a receipt from someone else", () => {
|
|
|
|
client.getRoom.mockImplementation((id) => (id === room.roomId ? room : null));
|
|
|
|
const events = [
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: room.roomId,
|
|
|
|
user: client.getSafeUserId(),
|
|
|
|
ts: 1000,
|
|
|
|
}),
|
|
|
|
TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: room.roomId,
|
|
|
|
user: "@other:user",
|
|
|
|
ts: 1001,
|
|
|
|
}),
|
|
|
|
];
|
|
|
|
room.addReceiptToStructure(
|
|
|
|
events[1].getId()!,
|
|
|
|
ReceiptType.Read,
|
|
|
|
"@other:user",
|
|
|
|
{
|
|
|
|
ts: 1001,
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
);
|
|
|
|
const { container } = render(getComponent({ events, showReadReceipts: true }));
|
|
|
|
|
|
|
|
const tiles = container.getElementsByClassName("mx_EventTile");
|
|
|
|
expect(tiles.length).toEqual(2);
|
|
|
|
expect(tiles[0].querySelector(".mx_EventTile_receiptSent")).toBeFalsy();
|
|
|
|
expect(tiles[1].querySelector(".mx_EventTile_receiptSent")).toBeFalsy();
|
|
|
|
});
|
2016-03-31 07:48:46 +08:00
|
|
|
});
|
2022-03-27 06:06:25 +08:00
|
|
|
|
|
|
|
describe("shouldFormContinuation", () => {
|
2022-05-13 19:59:50 +08:00
|
|
|
it("does not form continuations from thread roots which have summaries", () => {
|
2022-04-26 16:30:36 +08:00
|
|
|
const message1 = TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
msg: "Here is a message in the main timeline",
|
|
|
|
});
|
|
|
|
|
|
|
|
const message2 = TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
msg: "And here's another message in the main timeline",
|
|
|
|
});
|
|
|
|
|
2022-03-27 06:06:25 +08:00
|
|
|
const threadRoot = TestUtilsMatrix.mkMessage({
|
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
|
|
|
msg: "Here is a thread",
|
|
|
|
});
|
|
|
|
jest.spyOn(threadRoot, "isThreadRoot", "get").mockReturnValue(true);
|
|
|
|
|
2022-04-26 16:30:36 +08:00
|
|
|
const message3 = TestUtilsMatrix.mkMessage({
|
2022-03-27 06:06:25 +08:00
|
|
|
event: true,
|
|
|
|
room: "!room:id",
|
|
|
|
user: "@user:id",
|
2022-04-26 16:30:36 +08:00
|
|
|
msg: "And here's another message in the main timeline after the thread root",
|
2022-03-27 06:06:25 +08:00
|
|
|
});
|
|
|
|
|
2023-06-22 00:29:44 +08:00
|
|
|
const client = createTestClient();
|
|
|
|
expect(shouldFormContinuation(message1, message2, client, false)).toEqual(true);
|
|
|
|
expect(shouldFormContinuation(message2, threadRoot, client, false)).toEqual(true);
|
|
|
|
expect(shouldFormContinuation(threadRoot, message3, client, false)).toEqual(true);
|
2022-05-13 19:59:50 +08:00
|
|
|
|
|
|
|
const thread = {
|
|
|
|
length: 1,
|
|
|
|
replyToEvent: {},
|
2022-06-30 20:41:53 +08:00
|
|
|
} as unknown as Thread;
|
2022-05-13 19:59:50 +08:00
|
|
|
jest.spyOn(threadRoot, "getThread").mockReturnValue(thread);
|
2023-06-22 00:29:44 +08:00
|
|
|
expect(shouldFormContinuation(message2, threadRoot, client, false)).toEqual(false);
|
|
|
|
expect(shouldFormContinuation(threadRoot, message3, client, false)).toEqual(false);
|
2022-03-27 06:06:25 +08:00
|
|
|
});
|
|
|
|
});
|