Test typescriptification - MessagePanel (#8943)

* mv test/components/structures/MessagePanel-test.js test/components/structures/MessagePanel-test.tsx

* convert simpler messagepanel tests to rtl

* add data-testid to eventlistsummary

* convert read marker tests to rtl

* formatting

* remove commented
This commit is contained in:
Kerry 2022-06-30 14:41:53 +02:00 committed by GitHub
parent 78a98415eb
commit 7a80ea4bbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 236 additions and 279 deletions

View file

@ -1313,6 +1313,7 @@ class MainGrouper extends BaseGrouper {
ret.push( ret.push(
<EventListSummary <EventListSummary
key={key} key={key}
data-testid={key}
events={this.events} events={this.events}
onToggle={panel.onHeightChanged} // Update scroll state onToggle={panel.onHeightChanged} // Update scroll state
startExpanded={highlightInSummary} startExpanded={highlightInSummary}

View file

@ -527,6 +527,7 @@ export default class EventListSummary extends React.Component<IProps> {
); );
return <GenericEventListSummary return <GenericEventListSummary
data-testid={this.props['data-testid']}
events={this.props.events} events={this.props.events}
threshold={this.props.threshold} threshold={this.props.threshold}
onToggle={this.props.onToggle} onToggle={this.props.onToggle}

View file

@ -43,6 +43,7 @@ interface IProps {
onToggle?(): void; onToggle?(): void;
// The layout currently used // The layout currently used
layout?: Layout; layout?: Layout;
'data-testid'?: string;
} }
const GenericEventListSummary: React.FC<IProps> = ({ const GenericEventListSummary: React.FC<IProps> = ({
@ -54,6 +55,7 @@ const GenericEventListSummary: React.FC<IProps> = ({
summaryMembers = [], summaryMembers = [],
summaryText, summaryText,
layout = Layout.Group, layout = Layout.Group,
'data-testid': testId,
}) => { }) => {
const [expanded, toggleExpanded] = useStateToggle(startExpanded); const [expanded, toggleExpanded] = useStateToggle(startExpanded);
@ -110,7 +112,13 @@ const GenericEventListSummary: React.FC<IProps> = ({
} }
return ( return (
<li className="mx_GenericEventListSummary" data-scroll-tokens={eventIds} data-expanded={expanded + ""} data-layout={layout}> <li
className="mx_GenericEventListSummary"
data-scroll-tokens={eventIds}
data-expanded={expanded + ""}
data-layout={layout}
data-testid={testId}
>
<AccessibleButton className="mx_GenericEventListSummary_toggle" onClick={toggleExpanded} aria-expanded={expanded}> <AccessibleButton className="mx_GenericEventListSummary_toggle" onClick={toggleExpanded} aria-expanded={expanded}>
{ expanded ? _t('collapse') : _t('expand') } { expanded ? _t('collapse') : _t('expand') }
</AccessibleButton> </AccessibleButton>

View file

@ -1,6 +1,6 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2019, 2021 The Matrix.org Foundation C.I.C. Copyright 2019, 2021, 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -18,40 +18,71 @@ limitations under the License.
import React from 'react'; import React from 'react';
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import * as Matrix from 'matrix-js-sdk/src/matrix'; import { Room, RoomMember } from 'matrix-js-sdk/src/matrix';
import FakeTimers from '@sinonjs/fake-timers'; import FakeTimers from '@sinonjs/fake-timers';
import { mount } from "enzyme"; import { render } from '@testing-library/react';
import * as TestUtils from "react-dom/test-utils"; import { Thread } from 'matrix-js-sdk/src/models/thread';
import { MatrixClientPeg } from '../../../src/MatrixClientPeg';
import MessagePanel, { shouldFormContinuation } from "../../../src/components/structures/MessagePanel"; import MessagePanel, { shouldFormContinuation } from "../../../src/components/structures/MessagePanel";
import SettingsStore from "../../../src/settings/SettingsStore"; import SettingsStore from "../../../src/settings/SettingsStore";
import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../src/contexts/RoomContext"; import RoomContext, { TimelineRenderingType } from "../../../src/contexts/RoomContext";
import DMRoomMap from "../../../src/utils/DMRoomMap"; import DMRoomMap from "../../../src/utils/DMRoomMap";
import { UnwrappedEventTile } from "../../../src/components/views/rooms/EventTile";
import * as TestUtilsMatrix from "../../test-utils"; import * as TestUtilsMatrix from "../../test-utils";
import EventListSummary from "../../../src/components/views/elements/EventListSummary"; import {
import GenericEventListSummary from "../../../src/components/views/elements/GenericEventListSummary"; getMockClientWithEventEmitter,
import DateSeparator from "../../../src/components/views/messages/DateSeparator"; makeBeaconInfoEvent,
import { makeBeaconInfoEvent } from '../../test-utils'; mockClientMethodsEvents,
mockClientMethodsUser,
} from '../../test-utils';
import ResizeNotifier from '../../../src/utils/ResizeNotifier';
import { IRoomState } from '../../../src/components/structures/RoomView';
jest.mock('../../../src/utils/beacon', () => ({ jest.mock('../../../src/utils/beacon', () => ({
useBeacon: jest.fn(), useBeacon: jest.fn(),
})); }));
let client; const roomId = "!roomId:server_name";
const room = new Matrix.Room("!roomId:server_name");
// wrap MessagePanel with a component which provides the MatrixClient in the context. describe('MessagePanel', function() {
class WrappedMessagePanel extends React.Component { let clock = null;
resizeNotifier = new EventEmitter(); const realSetTimeout = window.setTimeout;
callEventGroupers = new Map(); const events = mkEvents();
const userId = '@me:here';
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({}),
});
render() { const room = new Room(roomId, client, userId);
const { showHiddenEvents, ...props } = this.props;
const roomContext = { 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');
const alice = "@alice:example.org";
const aliceMember = new RoomMember(roomId, alice);
aliceMember.name = 'Alice';
jest.spyOn(aliceMember, 'getAvatarUrl').mockReturnValue('avatar.jpeg');
jest.spyOn(aliceMember, 'getMxcAvatarUrl').mockReturnValue('mxc://avatar.url/image.png');
const defaultProps = {
resizeNotifier: new EventEmitter as unknown as ResizeNotifier,
callEventGroupers: new Map(),
room,
className: 'cls',
events: [],
};
const defaultRoomContext = {
...RoomContext,
timelineRenderingType: TimelineRenderingType.Room,
room, room,
roomId: room.roomId, roomId: room.roomId,
canReact: true, canReact: true,
@ -61,34 +92,20 @@ class WrappedMessagePanel extends React.Component {
showJoinLeaves: false, showJoinLeaves: false,
showAvatarChanges: false, showAvatarChanges: false,
showDisplaynameChanges: true, showDisplaynameChanges: true,
showHiddenEvents, showHiddenEvents: false,
}; } as unknown as IRoomState;
return <MatrixClientContext.Provider value={client}> const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) =>
<RoomContext.Provider value={roomContext}> <MatrixClientContext.Provider value={client}>
<MessagePanel <RoomContext.Provider value={{ ...defaultRoomContext, ...roomContext }}>
room={room} <MessagePanel {...defaultProps} {...props} />
{...props} </RoomContext.Provider>);
resizeNotifier={this.resizeNotifier}
callEventGroupers={this.callEventGroupers}
/>
</RoomContext.Provider>
</MatrixClientContext.Provider>; </MatrixClientContext.Provider>;
}
}
describe('MessagePanel', function() {
let clock = null;
const realSetTimeout = window.setTimeout;
const events = mkEvents();
beforeEach(function() { beforeEach(function() {
TestUtilsMatrix.stubClient(); jest.clearAllMocks();
client = MatrixClientPeg.get();
client.credentials = { userId: '@me:here' };
// HACK: We assume all settings want to be disabled // HACK: We assume all settings want to be disabled
SettingsStore.getValue = jest.fn((arg) => { jest.spyOn(SettingsStore, 'getValue').mockImplementation((arg) => {
return arg === "showDisplaynameChanges"; return arg === "showDisplaynameChanges";
}); });
@ -143,14 +160,7 @@ describe('MessagePanel', function() {
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
events.push(TestUtilsMatrix.mkMembership({ events.push(TestUtilsMatrix.mkMembership({
event: true, room: "!room:id", user: "@user:id", event: true, room: "!room:id", user: "@user:id",
target: { target: bobMember,
userId: "@user:id",
name: "Bob",
getAvatarUrl: () => {
return "avatar.jpeg";
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
ts: ts0 + i*1000, ts: ts0 + i*1000,
mship: 'join', mship: 'join',
prevMship: 'join', prevMship: 'join',
@ -176,14 +186,7 @@ describe('MessagePanel', function() {
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
events.push(TestUtilsMatrix.mkMembership({ events.push(TestUtilsMatrix.mkMembership({
event: true, room: "!room:id", user: "@user:id", event: true, room: "!room:id", user: "@user:id",
target: { target: bobMember,
userId: "@user:id",
name: "Bob",
getAvatarUrl: () => {
return "avatar.jpeg";
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
ts: ts0 + i * 1000, ts: ts0 + i * 1000,
mship: 'join', mship: 'join',
prevMship: 'join', prevMship: 'join',
@ -199,14 +202,13 @@ describe('MessagePanel', function() {
const mkEvent = TestUtilsMatrix.mkEvent; const mkEvent = TestUtilsMatrix.mkEvent;
const mkMembership = TestUtilsMatrix.mkMembership; const mkMembership = TestUtilsMatrix.mkMembership;
const roomId = "!someroom"; const roomId = "!someroom";
const alice = "@alice:example.org";
const ts0 = Date.now(); const ts0 = Date.now();
return [ return [
mkEvent({ mkEvent({
event: true, event: true,
type: "m.room.create", type: "m.room.create",
sender: '@test:example.org',
room: roomId, room: roomId,
user: alice, user: alice,
content: { content: {
@ -223,14 +225,7 @@ describe('MessagePanel', function() {
event: true, event: true,
room: roomId, room: roomId,
user: alice, user: alice,
target: { target: aliceMember,
userId: alice,
name: "Alice",
getAvatarUrl: () => {
return "avatar.jpeg";
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
ts: ts0 + 1, ts: ts0 + 1,
mship: 'join', mship: 'join',
name: 'Alice', name: 'Alice',
@ -270,14 +265,7 @@ describe('MessagePanel', function() {
room: roomId, room: roomId,
user: alice, user: alice,
skey: "@bob:example.org", skey: "@bob:example.org",
target: { target: bobMember,
userId: "@bob:example.org",
name: "Bob",
getAvatarUrl: () => {
return "avatar.jpeg";
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
ts: ts0 + 5, ts: ts0 + 5,
mship: 'invite', mship: 'invite',
name: 'Bob', name: 'Bob',
@ -313,44 +301,33 @@ describe('MessagePanel', function() {
} }
it('should show the events', function() { it('should show the events', function() {
const res = TestUtils.renderIntoDocument( const { container } = render(getComponent({ events }));
<WrappedMessagePanel className="cls" events={events} />,
);
// just check we have the right number of tiles for now // just check we have the right number of tiles for now
const tiles = TestUtils.scryRenderedComponentsWithType(res, UnwrappedEventTile); const tiles = container.getElementsByClassName('mx_EventTile');
expect(tiles.length).toEqual(10); expect(tiles.length).toEqual(10);
}); });
it('should collapse adjacent member events', function() { it('should collapse adjacent member events', function() {
const res = TestUtils.renderIntoDocument( const { container } = render(getComponent({ events: mkMelsEvents() }));
<WrappedMessagePanel className="cls" events={mkMelsEvents()} />,
);
// just check we have the right number of tiles for now // just check we have the right number of tiles for now
const tiles = TestUtils.scryRenderedComponentsWithType(res, UnwrappedEventTile); const tiles = container.getElementsByClassName('mx_EventTile');
expect(tiles.length).toEqual(2); expect(tiles.length).toEqual(2);
const summaryTiles = TestUtils.scryRenderedComponentsWithType( const summaryTiles = container.getElementsByClassName('mx_GenericEventListSummary');
res, EventListSummary,
);
expect(summaryTiles.length).toEqual(1); expect(summaryTiles.length).toEqual(1);
}); });
it('should insert the read-marker in the right place', function() { it('should insert the read-marker in the right place', function() {
const res = TestUtils.renderIntoDocument( const { container } = render(getComponent({
<WrappedMessagePanel events, readMarkerEventId: events[4].getId(), readMarkerVisible: true,
className="cls" }));
events={events}
readMarkerEventId={events[4].getId()}
readMarkerVisible={true}
/>,
);
const tiles = TestUtils.scryRenderedComponentsWithType(res, UnwrappedEventTile); const tiles = container.getElementsByClassName('mx_EventTile');
// find the <li> which wraps the read marker // find the <li> which wraps the read marker
const rm = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_RoomView_myReadMarker_container'); const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
// it should follow the <li> which wraps the event tile for event 4 // it should follow the <li> which wraps the event tile for event 4
const eventContainer = ReactDOM.findDOMNode(tiles[4]); const eventContainer = ReactDOM.findDOMNode(tiles[4]);
@ -359,19 +336,16 @@ describe('MessagePanel', function() {
it('should show the read-marker that fall in summarised events after the summary', function() { it('should show the read-marker that fall in summarised events after the summary', function() {
const melsEvents = mkMelsEvents(); const melsEvents = mkMelsEvents();
const res = TestUtils.renderIntoDocument( const { container } = render(getComponent({
<WrappedMessagePanel events: melsEvents,
className="cls" readMarkerEventId: melsEvents[4].getId(),
events={melsEvents} readMarkerVisible: true,
readMarkerEventId={melsEvents[4].getId()} }));
readMarkerVisible={true}
/>,
);
const summary = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_GenericEventListSummary'); const [summary] = container.getElementsByClassName('mx_GenericEventListSummary');
// find the <li> which wraps the read marker // find the <li> which wraps the read marker
const rm = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_RoomView_myReadMarker_container'); const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
expect(rm.previousSibling).toEqual(summary); expect(rm.previousSibling).toEqual(summary);
@ -381,19 +355,17 @@ describe('MessagePanel', function() {
it('should hide the read-marker at the end of summarised events', function() { it('should hide the read-marker at the end of summarised events', function() {
const melsEvents = mkMelsEventsOnly(); const melsEvents = mkMelsEventsOnly();
const res = TestUtils.renderIntoDocument(
<WrappedMessagePanel
className="cls"
events={melsEvents}
readMarkerEventId={melsEvents[9].getId()}
readMarkerVisible={true}
/>,
);
const summary = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_GenericEventListSummary'); const { container } = render(getComponent({
events: melsEvents,
readMarkerEventId: melsEvents[9].getId(),
readMarkerVisible: true,
}));
const [summary] = container.getElementsByClassName('mx_GenericEventListSummary');
// find the <li> which wraps the read marker // find the <li> which wraps the read marker
const rm = TestUtils.findRenderedDOMComponentWithClass(res, 'mx_RoomView_myReadMarker_container'); const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
expect(rm.previousSibling).toEqual(summary); expect(rm.previousSibling).toEqual(summary);
@ -405,45 +377,39 @@ describe('MessagePanel', function() {
// fake the clock so that we can test the velocity animation. // fake the clock so that we can test the velocity animation.
clock = FakeTimers.install(); clock = FakeTimers.install();
const parentDiv = document.createElement('div'); const { container, rerender } = render(<div>
{ getComponent({
events,
readMarkerEventId: events[4].getId(),
readMarkerVisible: true,
}) }
</div>);
// first render with the RM in one place const tiles = container.getElementsByClassName('mx_EventTile');
let mp = ReactDOM.render(
<WrappedMessagePanel
className="cls"
events={events}
readMarkerEventId={events[4].getId()}
readMarkerVisible={true}
/>, parentDiv);
const tiles = TestUtils.scryRenderedComponentsWithType(mp, UnwrappedEventTile);
const tileContainers = tiles.map(function(t) {
return ReactDOM.findDOMNode(t);
});
// find the <li> which wraps the read marker // find the <li> which wraps the read marker
const rm = TestUtils.findRenderedDOMComponentWithClass(mp, 'mx_RoomView_myReadMarker_container'); const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
expect(rm.previousSibling).toEqual(tileContainers[4]); expect(rm.previousSibling).toEqual(tiles[4]);
// now move the RM rerender(<div>
mp = ReactDOM.render( { getComponent({
<WrappedMessagePanel events,
className="cls" readMarkerEventId: events[6].getId(),
events={events} readMarkerVisible: true,
readMarkerEventId={events[6].getId()} }) }
readMarkerVisible={true} </div>);
/>, parentDiv);
// now there should be two RM containers // now there should be two RM containers
const found = TestUtils.scryRenderedDOMComponentsWithClass(mp, 'mx_RoomView_myReadMarker_container'); const readMarkers = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
expect(found.length).toEqual(2);
expect(readMarkers.length).toEqual(2);
// the first should be the ghost // the first should be the ghost
expect(found[0].previousSibling).toEqual(tileContainers[4]); expect(readMarkers[0].previousSibling).toEqual(tiles[4]);
const hr = found[0].children[0]; const hr: HTMLElement = readMarkers[0].children[0] as HTMLElement;
// the second should be the real thing // the second should be the real thing
expect(found[1].previousSibling).toEqual(tileContainers[6]); expect(readMarkers[1].previousSibling).toEqual(tiles[6]);
// advance the clock, and then let the browser run an animation frame, // advance the clock, and then let the browser run an animation frame,
// to let the animation start // to let the animation start
@ -463,68 +429,66 @@ describe('MessagePanel', function() {
it('should collapse creation events', function() { it('should collapse creation events', function() {
const events = mkCreationEvents(); const events = mkCreationEvents();
TestUtilsMatrix.upsertRoomStateEvents(room, events); TestUtilsMatrix.upsertRoomStateEvents(room, events);
const res = mount( const { container } = render(getComponent({ events }));
<WrappedMessagePanel className="cls" events={events} />,
); const createEvent = events.find(event => event.getType() === 'm.room.create');
const encryptionEvent = events.find(event => event.getType() === 'm.room.encryption');
// we expect that // we expect that
// - the room creation event, the room encryption event, and Alice inviting Bob, // - the room creation event, the room encryption event, and Alice inviting Bob,
// should be outside of the room creation summary // should be outside of the room creation summary
// - all other events should be inside the room creation summary // - all other events should be inside the room creation summary
const tiles = res.find(UnwrappedEventTile); const tiles = container.getElementsByClassName('mx_EventTile');
expect(tiles.at(0).props().mxEvent.getType()).toEqual("m.room.create"); expect(tiles[0].getAttribute('data-event-id')).toEqual(createEvent.getId());
expect(tiles.at(1).props().mxEvent.getType()).toEqual("m.room.encryption"); expect(tiles[1].getAttribute('data-event-id')).toEqual(encryptionEvent.getId());
const summaryTiles = res.find(GenericEventListSummary); const [summaryTile] = container.getElementsByClassName('mx_GenericEventListSummary');
const summaryTile = summaryTiles.at(0);
const summaryEventTiles = summaryTile.find(UnwrappedEventTile); const summaryEventTiles = summaryTile.getElementsByClassName('mx_EventTile');
// every event except for the room creation, room encryption, and Bob's // every event except for the room creation, room encryption, and Bob's
// invite event should be in the event summary // invite event should be in the event summary
expect(summaryEventTiles.length).toEqual(tiles.length - 3); expect(summaryEventTiles.length).toEqual(tiles.length - 3);
}); });
it('should not collapse beacons as part of creation events', function() { it('should not collapse beacons as part of creation events', function() {
const [creationEvent] = mkCreationEvents(); const events = mkCreationEvents();
const creationEvent = events.find(event => event.getType() === 'm.room.create');
const beaconInfoEvent = makeBeaconInfoEvent( const beaconInfoEvent = makeBeaconInfoEvent(
creationEvent.getSender(), creationEvent.getSender(),
creationEvent.getRoomId(), creationEvent.getRoomId(),
{ isLive: true }, { isLive: true },
); );
const combinedEvents = [creationEvent, beaconInfoEvent]; const combinedEvents = [...events, beaconInfoEvent];
TestUtilsMatrix.upsertRoomStateEvents(room, combinedEvents); TestUtilsMatrix.upsertRoomStateEvents(room, combinedEvents);
const res = mount( const { container } = render(getComponent({ events: combinedEvents }));
<WrappedMessagePanel className="cls" events={combinedEvents} />,
);
const summaryTiles = res.find(GenericEventListSummary); const [summaryTile] = container.getElementsByClassName('mx_GenericEventListSummary');
const summaryTile = summaryTiles.at(0);
const summaryEventTiles = summaryTile.find(UnwrappedEventTile); // beacon body is not in the summary
// nothing in the summary expect(summaryTile.getElementsByClassName('mx_MBeaconBody').length).toBe(0);
expect(summaryEventTiles.length).toEqual(0); // beacon tile is rendered
expect(container.getElementsByClassName('mx_MBeaconBody').length).toBe(1);
}); });
it('should hide read-marker at the end of creation event summary', function() { it('should hide read-marker at the end of creation event summary', function() {
const events = mkCreationEvents(); const events = mkCreationEvents();
TestUtilsMatrix.upsertRoomStateEvents(room, events); TestUtilsMatrix.upsertRoomStateEvents(room, events);
const res = mount(
<WrappedMessagePanel const { container } = render(getComponent({
className="cls" events,
events={events} readMarkerEventId: events[5].getId(),
readMarkerEventId={events[5].getId()} readMarkerVisible: true,
readMarkerVisible={true} }));
/>,
);
// find the <li> which wraps the read marker // find the <li> which wraps the read marker
const rm = res.find('.mx_RoomView_myReadMarker_container').getDOMNode(); const [rm] = container.getElementsByClassName('mx_RoomView_myReadMarker_container');
const rows = res.find('.mx_RoomView_MessageList').children(); const [messageList] = container.getElementsByClassName('mx_RoomView_MessageList');
const rows = messageList.children;
expect(rows.length).toEqual(7); // 6 events + the NewRoomIntro expect(rows.length).toEqual(7); // 6 events + the NewRoomIntro
expect(rm.previousSibling).toEqual(rows.at(5).getDOMNode()); expect(rm.previousSibling).toEqual(rows[5]);
// read marker should be hidden given props and at the last event // read marker should be hidden given props and at the last event
expect(isReadMarkerVisible(rm)).toBeFalsy(); expect(isReadMarkerVisible(rm)).toBeFalsy();
@ -532,104 +496,82 @@ describe('MessagePanel', function() {
it('should render Date separators for the events', function() { it('should render Date separators for the events', function() {
const events = mkOneDayEvents(); const events = mkOneDayEvents();
const res = mount( const { queryAllByRole } = render(getComponent({ events }));
<WrappedMessagePanel const dates = queryAllByRole('separator');
className="cls"
events={events}
/>,
);
const Dates = res.find(DateSeparator);
expect(Dates.length).toEqual(1); expect(dates.length).toEqual(1);
}); });
it('appends events into summaries during forward pagination without changing key', () => { it('appends events into summaries during forward pagination without changing key', () => {
const events = mkMelsEvents().slice(1, 11); const events = mkMelsEvents().slice(1, 11);
const res = mount(<WrappedMessagePanel events={events} />); const { container, rerender } = render(getComponent({ events }));
let els = res.find("EventListSummary"); let els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(1); expect(els.length).toEqual(1);
expect(els.key()).toEqual("eventlistsummary-" + events[0].getId()); expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
expect(els.prop("events").length).toEqual(10); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(10);
res.setProps({ const updatedEvents = [
events: [
...events, ...events,
TestUtilsMatrix.mkMembership({ TestUtilsMatrix.mkMembership({
event: true, event: true,
room: "!room:id", room: "!room:id",
user: "@user:id", user: "@user:id",
target: { target: bobMember,
userId: "@user:id",
name: "Bob",
getAvatarUrl: () => {
return "avatar.jpeg";
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
ts: Date.now(), ts: Date.now(),
mship: 'join', mship: 'join',
prevMship: 'join', prevMship: 'join',
name: 'A user', name: 'A user',
}), }),
], ];
}); rerender(getComponent({ events: updatedEvents }));
els = res.find("EventListSummary"); els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(1); expect(els.length).toEqual(1);
expect(els.key()).toEqual("eventlistsummary-" + events[0].getId()); expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
expect(els.prop("events").length).toEqual(11); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(11);
}); });
it('prepends events into summaries during backward pagination without changing key', () => { it('prepends events into summaries during backward pagination without changing key', () => {
const events = mkMelsEvents().slice(1, 11); const events = mkMelsEvents().slice(1, 11);
const res = mount(<WrappedMessagePanel events={events} />); const { container, rerender } = render(getComponent({ events }));
let els = res.find("EventListSummary"); let els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(1); expect(els.length).toEqual(1);
expect(els.key()).toEqual("eventlistsummary-" + events[0].getId()); expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
expect(els.prop("events").length).toEqual(10); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(10);
res.setProps({ const updatedEvents = [
events: [
TestUtilsMatrix.mkMembership({ TestUtilsMatrix.mkMembership({
event: true, event: true,
room: "!room:id", room: "!room:id",
user: "@user:id", user: "@user:id",
target: { target: bobMember,
userId: "@user:id",
name: "Bob",
getAvatarUrl: () => {
return "avatar.jpeg";
},
getMxcAvatarUrl: () => 'mxc://avatar.url/image.png',
},
ts: Date.now(), ts: Date.now(),
mship: 'join', mship: 'join',
prevMship: 'join', prevMship: 'join',
name: 'A user', name: 'A user',
}), }),
...events, ...events,
], ];
}); rerender(getComponent({ events: updatedEvents }));
els = res.find("EventListSummary"); els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(1); expect(els.length).toEqual(1);
expect(els.key()).toEqual("eventlistsummary-" + events[0].getId()); expect(els[0].getAttribute('data-testid')).toEqual("eventlistsummary-" + events[0].getId());
expect(els.prop("events").length).toEqual(11); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(11);
}); });
it('assigns different keys to summaries that get split up', () => { it('assigns different keys to summaries that get split up', () => {
const events = mkMelsEvents().slice(1, 11); const events = mkMelsEvents().slice(1, 11);
const res = mount(<WrappedMessagePanel events={events} />); const { container, rerender } = render(getComponent({ events }));
let els = res.find("EventListSummary"); let els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(1); expect(els.length).toEqual(1);
expect(els.key()).toEqual("eventlistsummary-" + events[0].getId()); expect(els[0].getAttribute('data-testid')).toEqual(`eventlistsummary-${events[0].getId()}`);
expect(els.prop("events").length).toEqual(10); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(10);
res.setProps({ const updatedEvents = [
events: [
...events.slice(0, 5), ...events.slice(0, 5),
TestUtilsMatrix.mkMessage({ TestUtilsMatrix.mkMessage({
event: true, event: true,
@ -638,14 +580,17 @@ describe('MessagePanel', function() {
msg: "Hello!", msg: "Hello!",
}), }),
...events.slice(5, 10), ...events.slice(5, 10),
], ];
}); rerender(getComponent({ events: updatedEvents }));
els = res.find("EventListSummary"); // summaries split becuase room messages are not summarised
els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(2); expect(els.length).toEqual(2);
expect(els.first().key()).not.toEqual(els.last().key()); expect(els[0].getAttribute('data-testid')).toEqual(`eventlistsummary-${events[0].getId()}`);
expect(els.first().prop("events").length).toEqual(5); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(5);
expect(els.last().prop("events").length).toEqual(5);
expect(els[1].getAttribute('data-testid')).toEqual(`eventlistsummary-${events[5].getId()}`);
expect(els[1].getAttribute("data-scroll-tokens").split(',').length).toEqual(5);
}); });
// We test this because setting lookups can be *slow*, and we don't want // We test this because setting lookups can be *slow*, and we don't want
@ -653,11 +598,12 @@ describe('MessagePanel', function() {
it("doesn't lookup showHiddenEventsInTimeline while rendering", () => { it("doesn't lookup showHiddenEventsInTimeline while rendering", () => {
// We're only interested in the setting lookups that happen on every render, // 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 // rather than those happening on first mount, so let's get those out of the way
const res = mount(<WrappedMessagePanel events={[]} />); const { rerender } = render(getComponent({ events: [] }));
// Set up our spy and re-render with new events // Set up our spy and re-render with new events
const settingsSpy = jest.spyOn(SettingsStore, "getValue").mockClear(); const settingsSpy = jest.spyOn(SettingsStore, "getValue").mockClear();
res.setProps({ events: mkMixedHiddenAndShownEvents() });
rerender(getComponent({ events: mkMixedHiddenAndShownEvents() }));
expect(settingsSpy).not.toHaveBeenCalledWith("showHiddenEventsInTimeline"); expect(settingsSpy).not.toHaveBeenCalledWith("showHiddenEventsInTimeline");
settingsSpy.mockRestore(); settingsSpy.mockRestore();
@ -690,11 +636,11 @@ describe('MessagePanel', function() {
ts: 3, ts: 3,
}), }),
]; ];
const res = mount(<WrappedMessagePanel showHiddenEvents={true} events={events} />); const { container } = render(getComponent({ events }, { showHiddenEvents: true }));
const els = res.find("EventListSummary"); const els = container.getElementsByClassName('mx_GenericEventListSummary');
expect(els.length).toEqual(1); expect(els.length).toEqual(1);
expect(els.prop("events").length).toEqual(3); expect(els[0].getAttribute("data-scroll-tokens").split(',').length).toEqual(3);
}); });
}); });
@ -736,7 +682,7 @@ describe("shouldFormContinuation", () => {
const thread = { const thread = {
length: 1, length: 1,
replyToEvent: {}, replyToEvent: {},
}; } as unknown as Thread;
jest.spyOn(threadRoot, "getThread").mockReturnValue(thread); jest.spyOn(threadRoot, "getThread").mockReturnValue(thread);
expect(shouldFormContinuation(message2, threadRoot, false, true)).toEqual(false); expect(shouldFormContinuation(message2, threadRoot, false, true)).toEqual(false);
expect(shouldFormContinuation(threadRoot, message3, false, true)).toEqual(false); expect(shouldFormContinuation(threadRoot, message3, false, true)).toEqual(false);

View file

@ -80,4 +80,5 @@ export const mockClientMethodsUser = (userId = '@alice:domain') => ({
*/ */
export const mockClientMethodsEvents = () => ({ export const mockClientMethodsEvents = () => ({
decryptEventIfNeeded: jest.fn(), decryptEventIfNeeded: jest.fn(),
getPushActionsForEvent: jest.fn(),
}); });