From 66ea75709986774f7dba9cb189ee1b1207ba88d8 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 12 Apr 2022 20:06:32 -0500 Subject: [PATCH 01/76] Ask to refresh timeline when historical messages are imported (MSC2716) Associated matrix-js-sdk PR: https://github.com/matrix-org/matrix-js-sdk/pull/2282 --- res/css/structures/_RoomStatusBar.scss | 6 ++ src/components/structures/RoomStatusBar.tsx | 64 ++++++++++++++++++++- src/i18n/strings/en_EN.json | 3 + 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index a54ceae49e9..8397353eb73 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -145,6 +145,12 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/retry.svg'); } } + + &.mx_RoomStatusBar_refreshTimelineBtn { + &::before { + mask-image: url('$(res)/img/element-icons/retry.svg'); + } + } } .mx_InlineSpinner { diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 94b9905becc..86fce440f7c 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -79,6 +79,7 @@ interface IState { syncStateData: ISyncStateData; unsentMessages: MatrixEvent[]; isResending: boolean; + timelineNeedsRefresh: boolean; } export default class RoomStatusBar extends React.PureComponent { @@ -93,6 +94,8 @@ export default class RoomStatusBar extends React.PureComponent { syncStateData: this.context.getSyncStateData(), unsentMessages: getUnsentMessages(this.props.room), isResending: false, + // TODO: This should be `false` + timelineNeedsRefresh: true, }; } @@ -100,6 +103,7 @@ export default class RoomStatusBar extends React.PureComponent { const client = this.context; client.on("sync", this.onSyncStateChange); client.on("Room.localEchoUpdated", this.onRoomLocalEchoUpdated); + client.on("Room.historyImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline); this.checkSize(); } @@ -115,6 +119,7 @@ export default class RoomStatusBar extends React.PureComponent { if (client) { client.removeListener("sync", this.onSyncStateChange); client.removeListener("Room.localEchoUpdated", this.onRoomLocalEchoUpdated); + client.removeListener("Room.historyImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline); } } @@ -142,6 +147,19 @@ export default class RoomStatusBar extends React.PureComponent { dis.fire(Action.FocusSendMessageComposer); }; + private onRefreshTimelineClick = (): void => { + console.log('TODO: Refresh timeline'); + // TODO: What's the best way to refresh the timeline? Something like + // `room.resetLiveTimeline(null, null);` although this just seems to + // clear the timeline. I also tried to split out + // `scrollbackFromPaginationToken` from the `scrollback` method in to + // paginate from the beginning of the room but it's just not right. + + this.setState({ + timelineNeedsRefresh: false + }); + } + private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { if (room.roomId !== this.props.room.roomId) return; const messages = getUnsentMessages(this.props.room); @@ -151,6 +169,14 @@ export default class RoomStatusBar extends React.PureComponent { }); }; + private onRoomHistoryImportedWithinTimeline = (markerEv: MatrixEvent, room: Room) => { + if (room.roomId !== this.props.room.roomId) return; + + this.setState({ + timelineNeedsRefresh: true, + }); + }; + // Check whether current size is greater than 0, if yes call props.onVisible private checkSize(): void { if (this.getSize()) { @@ -166,7 +192,11 @@ export default class RoomStatusBar extends React.PureComponent { private getSize(): number { if (this.shouldShowConnectionError()) { return STATUS_BAR_EXPANDED; - } else if (this.state.unsentMessages.length > 0 || this.state.isResending) { + } else if ( + this.state.unsentMessages.length > 0 || + this.state.isResending || + this.state.timelineNeedsRefresh + ) { return STATUS_BAR_EXPANDED_LARGE; } return STATUS_BAR_HIDDEN; @@ -182,7 +212,7 @@ export default class RoomStatusBar extends React.PureComponent { this.state.syncStateData.error && this.state.syncStateData.error.name === 'M_RESOURCE_LIMIT_EXCEEDED', ); - return this.state.syncState === "ERROR" && !errorIsMauError; + return (this.state.syncState === "ERROR" && !errorIsMauError); } private getUnsentMessageContent(): JSX.Element { @@ -306,6 +336,36 @@ export default class RoomStatusBar extends React.PureComponent { return this.getUnsentMessageContent(); } + if(this.state.timelineNeedsRefresh) { + return ( +
+
+
+ /!\ +
+
+
+ { _t("History import detected.") } +
+
+ { _t("History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.") } +
+
+
+ + { _t("Refresh timeline") } + +
+
+
+ ) + } + return null; } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c5769f9902a..f533922de1c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -3042,6 +3042,9 @@ "You can select all or individual messages to retry or delete": "You can select all or individual messages to retry or delete", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", + "History import detected.": "History import detected.", + "History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.": "History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.", + "Refresh timeline": "Refresh timeline", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", "You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?", "Search failed": "Search failed", From 6dba3dfbb6368c4b1d5aad8fbf9538c3fb64e301 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 12 Apr 2022 21:06:07 -0500 Subject: [PATCH 02/76] Back to false after getting screenshot --- src/components/structures/RoomStatusBar.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 86fce440f7c..9cfb682b844 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -94,8 +94,7 @@ export default class RoomStatusBar extends React.PureComponent { syncStateData: this.context.getSyncStateData(), unsentMessages: getUnsentMessages(this.props.room), isResending: false, - // TODO: This should be `false` - timelineNeedsRefresh: true, + timelineNeedsRefresh: false, }; } From 12b011545e9b830934ba27f10703022b0e90ca1b Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 13 Apr 2022 01:18:28 -0500 Subject: [PATCH 03/76] Fix lints --- src/components/structures/RoomStatusBar.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 9cfb682b844..08507402d07 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -155,9 +155,9 @@ export default class RoomStatusBar extends React.PureComponent { // paginate from the beginning of the room but it's just not right. this.setState({ - timelineNeedsRefresh: false + timelineNeedsRefresh: false, }); - } + }; private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { if (room.roomId !== this.props.room.roomId) return; @@ -335,7 +335,7 @@ export default class RoomStatusBar extends React.PureComponent { return this.getUnsentMessageContent(); } - if(this.state.timelineNeedsRefresh) { + if (this.state.timelineNeedsRefresh) { return (
@@ -352,17 +352,18 @@ export default class RoomStatusBar extends React.PureComponent { { _t("History import detected.") }
- { _t("History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.") } + { _t("History was just imported somewhere in the room. " + + "In order to see the historical messages, refresh your timeline.") }
- - { _t("Refresh timeline") } - + + { _t("Refresh timeline") } +
- ) + ); } return null; From eb5e899398364307a7bbaaf2c908cb1fae66cb17 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 13 Apr 2022 02:47:45 -0500 Subject: [PATCH 04/76] Fix room not showing refresh timeline banner if not switched to the room when the marker was sent --- src/components/structures/RoomStatusBar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 08507402d07..840d7135d42 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -94,7 +94,7 @@ export default class RoomStatusBar extends React.PureComponent { syncStateData: this.context.getSyncStateData(), unsentMessages: getUnsentMessages(this.props.room), isResending: false, - timelineNeedsRefresh: false, + timelineNeedsRefresh: this.props.room.getTimelineNeedsRefresh(), }; } @@ -172,7 +172,7 @@ export default class RoomStatusBar extends React.PureComponent { if (room.roomId !== this.props.room.roomId) return; this.setState({ - timelineNeedsRefresh: true, + timelineNeedsRefresh: room.getTimelineNeedsRefresh(), }); }; From a50e011c40a80fea5fa1b1356e1e8802cfa8b50a Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 13 Apr 2022 02:47:53 -0500 Subject: [PATCH 05/76] Fix type lints --- src/components/structures/FilePanel.tsx | 4 +++- src/indexing/EventIndex.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/structures/FilePanel.tsx b/src/components/structures/FilePanel.tsx index d248c6556fd..98f37c9e068 100644 --- a/src/components/structures/FilePanel.tsx +++ b/src/components/structures/FilePanel.tsx @@ -104,7 +104,9 @@ class FilePanel extends React.Component { } if (!this.state.timelineSet.eventIdToTimeline(ev.getId())) { - this.state.timelineSet.addEventToTimeline(ev, timeline, false); + this.state.timelineSet.addEventToTimeline(ev, timeline, { + toStartOfTimeline: false, + }); } } diff --git a/src/indexing/EventIndex.ts b/src/indexing/EventIndex.ts index 85ff7038de0..3a958f2af6b 100644 --- a/src/indexing/EventIndex.ts +++ b/src/indexing/EventIndex.ts @@ -808,7 +808,9 @@ export default class EventIndex extends EventEmitter { // Add the events to the timeline of the file panel. matrixEvents.forEach(e => { if (!timelineSet.eventIdToTimeline(e.getId())) { - timelineSet.addEventToTimeline(e, timeline, direction == EventTimeline.BACKWARDS); + timelineSet.addEventToTimeline(e, timeline, { + toStartOfTimeline: direction == EventTimeline.BACKWARDS, + }); } }); From ed910bb7ec71c7feae90d00ebca9b54263f98fd2 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 14 Apr 2022 01:43:48 -0500 Subject: [PATCH 06/76] Remove parenthesis change --- src/components/structures/RoomStatusBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 840d7135d42..1487b51b9dd 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -211,7 +211,7 @@ export default class RoomStatusBar extends React.PureComponent { this.state.syncStateData.error && this.state.syncStateData.error.name === 'M_RESOURCE_LIMIT_EXCEEDED', ); - return (this.state.syncState === "ERROR" && !errorIsMauError); + return this.state.syncState === "ERROR" && !errorIsMauError; } private getUnsentMessageContent(): JSX.Element { From 8d6122626ce48ba3d84c505a0c451fbb812f1acd Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 16 Apr 2022 02:17:55 -0500 Subject: [PATCH 07/76] Raw refreshLiveTimeline usage that seems to work --- src/components/structures/MessagePanel.tsx | 2 ++ src/components/structures/RoomStatusBar.tsx | 11 +++++++---- src/components/structures/RoomView.tsx | 5 ++++- src/components/structures/TimelinePanel.tsx | 17 ++++++++++++++++- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index a4791a1ec57..2d8543c8b3a 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -1021,6 +1021,8 @@ export default class MessagePanel extends React.Component { "mx_MessagePanel_narrow": this.context.narrow, }); + //console.log('MessagePanel: render', this.props.events.length) + return ( { syncStateData: this.context.getSyncStateData(), unsentMessages: getUnsentMessages(this.props.room), isResending: false, - timelineNeedsRefresh: this.props.room.getTimelineNeedsRefresh(), + timelineNeedsRefresh: true // TODO: Put this back to this.props.room.getTimelineNeedsRefresh(), }; } @@ -153,10 +153,13 @@ export default class RoomStatusBar extends React.PureComponent { // clear the timeline. I also tried to split out // `scrollbackFromPaginationToken` from the `scrollback` method in to // paginate from the beginning of the room but it's just not right. + this.props.room.refreshLiveTimeline(); + //timelinePanel.refreshTimeline(); - this.setState({ - timelineNeedsRefresh: false, - }); + // TODO: Uncomment + // this.setState({ + // timelineNeedsRefresh: false, + // }); }; private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 1d363b649ea..a28faa180e2 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2065,11 +2065,14 @@ export class RoomView extends React.Component { highlightedEventId = this.state.initialEventId; } + const timelineSet = this.state.room.getUnfilteredTimelineSet(); + console.log('RoomView: timelineSet', timelineSet); + // console.info("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview); const messagePanel = ( { const cli = MatrixClientPeg.get(); cli.on(RoomEvent.Timeline, this.onRoomTimeline); cli.on(RoomEvent.TimelineReset, this.onRoomTimelineReset); + this.props.timelineSet.room.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); cli.on(RoomEvent.Redaction, this.onRoomRedaction); if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { // Make sure that events are re-rendered when their visibility-pending-moderation changes. @@ -370,6 +371,8 @@ class TimelinePanel extends React.Component { client.removeListener(MatrixEventEvent.VisibilityChange, this.onEventVisibilityChange); client.removeListener(ClientEvent.Sync, this.onSync); } + + this.props.timelineSet.room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); } private onMessageListUnfillRequest = (backwards: boolean, scrollToken: string): void => { @@ -627,10 +630,18 @@ class TimelinePanel extends React.Component { }); }; + private onRoomTimelineRefresh = (room: Room, timelineSet: EventTimelineSet): void => { + console.log(`onRoomTimelineRefresh skipping=${timelineSet !== this.props.timelineSet}`); + if (timelineSet !== this.props.timelineSet) return; + + this.refreshTimeline(); + }; + private onRoomTimelineReset = (room: Room, timelineSet: EventTimelineSet): void => { + console.log(`onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} skippingBecauseAtBottom=${this.canResetTimeline()}`); if (timelineSet !== this.props.timelineSet) return; - if (this.messagePanel.current && this.messagePanel.current.isAtBottom()) { + if (this.canResetTimeline()) { this.loadTimeline(); } }; @@ -1181,6 +1192,9 @@ class TimelinePanel extends React.Component { * @param {boolean?} scrollIntoView whether to scroll the event into view. */ private loadTimeline(eventId?: string, pixelOffset?: number, offsetBase?: number, scrollIntoView = true): void { + console.log('TimelinePanel: loadTimeline', this.props.timelineSet.getTimelines(), this.props.timelineSet.getTimelines().map((timeline) => { + return timeline.getEvents().length; + })) this.timelineWindow = new TimelineWindow( MatrixClientPeg.get(), this.props.timelineSet, { windowLimit: this.props.timelineCap }); @@ -1319,6 +1333,7 @@ class TimelinePanel extends React.Component { // get the list of events from the timeline window and the pending event list private getEvents(): Pick { const events: MatrixEvent[] = this.timelineWindow.getEvents(); + console.log('TimelinePanel: getEvents', events.length); // `arrayFastClone` performs a shallow copy of the array // we want the last event to be decrypted first but displayed last From d8f94ed2ac9cf018ed57e16bbabda1b55101974d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 18 Apr 2022 18:52:06 -0500 Subject: [PATCH 08/76] Clean up raw commit --- src/components/structures/MessagePanel.tsx | 2 -- src/components/structures/RoomStatusBar.tsx | 17 +++++------------ src/components/structures/RoomView.tsx | 5 +---- src/components/structures/TimelinePanel.tsx | 7 ++----- 4 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 2d8543c8b3a..a4791a1ec57 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -1021,8 +1021,6 @@ export default class MessagePanel extends React.Component { "mx_MessagePanel_narrow": this.context.narrow, }); - //console.log('MessagePanel: render', this.props.events.length) - return ( { syncStateData: this.context.getSyncStateData(), unsentMessages: getUnsentMessages(this.props.room), isResending: false, - timelineNeedsRefresh: true // TODO: Put this back to this.props.room.getTimelineNeedsRefresh(), + timelineNeedsRefresh: this.props.room.getTimelineNeedsRefresh(), }; } @@ -147,19 +147,12 @@ export default class RoomStatusBar extends React.PureComponent { }; private onRefreshTimelineClick = (): void => { - console.log('TODO: Refresh timeline'); - // TODO: What's the best way to refresh the timeline? Something like - // `room.resetLiveTimeline(null, null);` although this just seems to - // clear the timeline. I also tried to split out - // `scrollbackFromPaginationToken` from the `scrollback` method in to - // paginate from the beginning of the room but it's just not right. + // Empty out the current timeline and re-request it this.props.room.refreshLiveTimeline(); - //timelinePanel.refreshTimeline(); - // TODO: Uncomment - // this.setState({ - // timelineNeedsRefresh: false, - // }); + this.setState({ + timelineNeedsRefresh: false, + }); }; private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index a28faa180e2..1d363b649ea 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -2065,14 +2065,11 @@ export class RoomView extends React.Component { highlightedEventId = this.state.initialEventId; } - const timelineSet = this.state.room.getUnfilteredTimelineSet(); - console.log('RoomView: timelineSet', timelineSet); - // console.info("ShowUrlPreview for %s is %s", this.state.room.roomId, this.state.showUrlPreview); const messagePanel = ( { }; private onRoomTimelineRefresh = (room: Room, timelineSet: EventTimelineSet): void => { - console.log(`onRoomTimelineRefresh skipping=${timelineSet !== this.props.timelineSet}`); + debuglog(`onRoomTimelineRefresh skipping=${timelineSet !== this.props.timelineSet}`); if (timelineSet !== this.props.timelineSet) return; this.refreshTimeline(); }; private onRoomTimelineReset = (room: Room, timelineSet: EventTimelineSet): void => { - console.log(`onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} skippingBecauseAtBottom=${this.canResetTimeline()}`); + debuglog(`onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} skippingBecauseAtBottom=${this.canResetTimeline()}`); if (timelineSet !== this.props.timelineSet) return; if (this.canResetTimeline()) { @@ -1192,9 +1192,6 @@ class TimelinePanel extends React.Component { * @param {boolean?} scrollIntoView whether to scroll the event into view. */ private loadTimeline(eventId?: string, pixelOffset?: number, offsetBase?: number, scrollIntoView = true): void { - console.log('TimelinePanel: loadTimeline', this.props.timelineSet.getTimelines(), this.props.timelineSet.getTimelines().map((timeline) => { - return timeline.getEvents().length; - })) this.timelineWindow = new TimelineWindow( MatrixClientPeg.get(), this.props.timelineSet, { windowLimit: this.props.timelineCap }); From 623960b4cfe1ac47f8a5eba6f976e8ec1ab8a808 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 18 Apr 2022 23:20:11 -0500 Subject: [PATCH 09/76] Clean up event usage See https://github.com/matrix-org/matrix-react-sdk/pull/8303#discussion_r850192080 --- src/components/structures/RoomStatusBar.tsx | 15 +++++++++++---- src/components/structures/TimelinePanel.tsx | 8 ++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 7345b184add..d075b621482 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -17,7 +17,7 @@ limitations under the License. import React from 'react'; import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event"; import { SyncState, ISyncStateData } from "matrix-js-sdk/src/sync"; -import { Room } from "matrix-js-sdk/src/models/room"; +import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; import { _t, _td } from '../../languageHandler'; import Resend from '../../Resend'; @@ -102,13 +102,19 @@ export default class RoomStatusBar extends React.PureComponent { const client = this.context; client.on("sync", this.onSyncStateChange); client.on("Room.localEchoUpdated", this.onRoomLocalEchoUpdated); - client.on("Room.historyImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline); + this.props.room.on(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); this.checkSize(); } - public componentDidUpdate(): void { + public componentDidUpdate(prevProps): void { this.checkSize(); + + // When the room changes, setup the new listener + if(prevProps.room !== this.props.room) { + prevProps.room.removeListener("Room.historyImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline); + this.props.room.on(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); + } } public componentWillUnmount(): void { @@ -118,8 +124,9 @@ export default class RoomStatusBar extends React.PureComponent { if (client) { client.removeListener("sync", this.onSyncStateChange); client.removeListener("Room.localEchoUpdated", this.onRoomLocalEchoUpdated); - client.removeListener("Room.historyImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline); } + + this.props.room.removeListener(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); } private onSyncStateChange = (state: SyncState, prevState: SyncState, data: ISyncStateData): void => { diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 28338aaba8f..f37d4ebd36a 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -339,6 +339,14 @@ class TimelinePanel extends React.Component { } } + public componentDidUpdate(prevProps): void { + // When the room changes, setup the new listener + if(prevProps.timelineSet.room !== this.props.timelineSet.room) { + prevProps.timelineSet.room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + this.props.timelineSet.room.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + } + } + componentWillUnmount() { // set a boolean to say we've been unmounted, which any pending // promises can use to throw away their results. From d9001ce19fb4351651a38f5fc06098968a175c5d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 18 Apr 2022 23:28:49 -0500 Subject: [PATCH 10/76] Remove unreadable image descriptions See https://github.com/matrix-org/matrix-react-sdk/pull/8303#discussion_r850188154 --- src/components/structures/RoomStatusBar.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index d075b621482..02c4239e8a8 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -318,8 +318,7 @@ export default class RoomStatusBar extends React.PureComponent { src={require("../../../res/img/feather-customised/warning-triangle.svg").default} width="24" height="24" - title="/!\ " - alt="/!\ " /> + alt="" />
{ _t('Connectivity to the server has been lost.') } @@ -347,8 +346,7 @@ export default class RoomStatusBar extends React.PureComponent { src={require("../../../res/img/feather-customised/warning-triangle.svg").default} width="24" height="24" - title="/!\ " - alt="/!\ " /> + alt="" />
From b4c81e148257f610b76dae800ceb2d5fad87a31b Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 18 Apr 2022 23:50:38 -0500 Subject: [PATCH 11/76] Fix up lints --- src/components/structures/RoomStatusBar.tsx | 12 +++++++++--- src/components/structures/TimelinePanel.tsx | 7 +++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 02c4239e8a8..121f2bb1ac2 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -111,8 +111,11 @@ export default class RoomStatusBar extends React.PureComponent { this.checkSize(); // When the room changes, setup the new listener - if(prevProps.room !== this.props.room) { - prevProps.room.removeListener("Room.historyImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline); + if (prevProps.room !== this.props.room) { + prevProps.room.removeListener( + "Room.historyImportedWithinTimeline", + this.onRoomHistoryImportedWithinTimeline, + ); this.props.room.on(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); } } @@ -126,7 +129,10 @@ export default class RoomStatusBar extends React.PureComponent { client.removeListener("Room.localEchoUpdated", this.onRoomLocalEchoUpdated); } - this.props.room.removeListener(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); + this.props.room.removeListener( + RoomEvent.historyImportedWithinTimeline, + this.onRoomHistoryImportedWithinTimeline, + ); } private onSyncStateChange = (state: SyncState, prevState: SyncState, data: ISyncStateData): void => { diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index f37d4ebd36a..6da54add86b 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -341,7 +341,7 @@ class TimelinePanel extends React.Component { public componentDidUpdate(prevProps): void { // When the room changes, setup the new listener - if(prevProps.timelineSet.room !== this.props.timelineSet.room) { + if (prevProps.timelineSet.room !== this.props.timelineSet.room) { prevProps.timelineSet.room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); this.props.timelineSet.room.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); } @@ -646,7 +646,10 @@ class TimelinePanel extends React.Component { }; private onRoomTimelineReset = (room: Room, timelineSet: EventTimelineSet): void => { - debuglog(`onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} skippingBecauseAtBottom=${this.canResetTimeline()}`); + debuglog( + `onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} ` + + `skippingBecauseAtBottom=${this.canResetTimeline()}`, + ); if (timelineSet !== this.props.timelineSet) return; if (this.canResetTimeline()) { From 361675e0d5acf3aa2a00a1ea4fe23a77e26c2e35 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 19 Apr 2022 02:10:54 -0500 Subject: [PATCH 12/76] Add tests for RoomStatusBar --- .../structures/RoomStatusBar-test.tsx | 151 ++ .../__snapshots__/RoomStatusBar-test.tsx.snap | 1852 +++++++++++++++++ test/test-utils/test-utils.ts | 6 +- 3 files changed, 2008 insertions(+), 1 deletion(-) create mode 100644 test/components/structures/RoomStatusBar-test.tsx create mode 100644 test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap diff --git a/test/components/structures/RoomStatusBar-test.tsx b/test/components/structures/RoomStatusBar-test.tsx new file mode 100644 index 00000000000..d4eb9d8d1e1 --- /dev/null +++ b/test/components/structures/RoomStatusBar-test.tsx @@ -0,0 +1,151 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { shallow, mount } from "enzyme"; +import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; +import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; +import { + ISyncStateData, SyncState +} from 'matrix-js-sdk/src/sync'; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { MatrixError } from "matrix-js-sdk/src/http-api"; + +import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; +import { stubClient } from "../../test-utils"; +import { Action } from "../../../src/dispatcher/actions"; +import dis from "../../../src/dispatcher/dispatcher"; +import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; +import RoomStatusBar from "../../../src/components/structures/RoomStatusBar"; + +// Fake date to give a predictable snapshot +const realDateNow = Date.now; +const realDateToISOString = Date.prototype.toISOString; +Date.now = jest.fn(() => 2345678901234); +// eslint-disable-next-line no-extend-native +Date.prototype.toISOString = jest.fn(() => "2021-11-23T14:35:14.240Z"); + +afterAll(() => { + Date.now = realDateNow; + // eslint-disable-next-line no-extend-native + Date.prototype.toISOString = realDateToISOString; +}); + +describe("RoomStatusBar", () => { + let client; + beforeEach(() => { + stubClient(); + client = MatrixClientPeg.get(); + }) + + it('does not show anything when no sync error or other status', () => { + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + expect(wrapper).toMatchSnapshot(); + }); + + describe('connectivity lost bar', () => { + it('should show connection lost bar when sync has an error', () => { + client.getSyncState = (): SyncState => SyncState.Error, + client.getSyncStateData = (): ISyncStateData => ({ + error: new MatrixError({ + errcode: 'FAKE_ERROR', + error: "Fake sync error", + }) + }); + + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + expect(wrapper).toMatchSnapshot(); + }); + + it('connectivity lost bar has priority over the timeline refresh bar', () => { + // Show connectivity lost bar + client.getSyncState = (): SyncState => SyncState.Error, + client.getSyncStateData = (): ISyncStateData => ({ + error: new MatrixError({ + errcode: 'FAKE_ERROR', + error: "Fake sync error", + }) + }); + + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + + // Show timeline needs refresh bar + r1.setTimelineNeedsRefresh(true); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + expect(wrapper).toMatchSnapshot(); + }); + }); + + describe('timeline needs refresh bar (history import)', () => { + it('should show timeline refresh bar when history import detected', () => { + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + // Show timeline needs refresh bar + r1.setTimelineNeedsRefresh(true); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + expect(wrapper).toMatchSnapshot(); + }); + + it('should refresh timeline for room when button clicked', () => { + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + // Show timeline needs refresh bar + r1.setTimelineNeedsRefresh(true); + + r1.refreshLiveTimeline = jest.fn(); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + + const refreshTimelineButton = wrapper.find('AccessibleButton.mx_RoomStatusBar_refreshTimelineBtn'); + refreshTimelineButton.simulate('click'); + + // Make sure that the SDK was called to refresh the timeline + expect(r1.refreshLiveTimeline).toHaveBeenCalled(); + + // Expect the refresh timeline bar to be hidden now + expect(wrapper).toMatchSnapshot(); + }); + }); +}); diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap new file mode 100644 index 00000000000..7cd78db7303 --- /dev/null +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -0,0 +1,1852 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority over the timeline refresh bar 1`] = ` + +
+
+
+ +
+
+ Connectivity to the server has been lost. +
+
+ Sent messages will be stored until your connection has returned. +
+
+
+
+
+
+`; + +exports[`RoomStatusBar connectivity lost bar should show connection lost bar when sync has an error 1`] = ` + +
+
+
+ +
+
+ Connectivity to the server has been lost. +
+
+ Sent messages will be stored until your connection has returned. +
+
+
+
+
+
+`; + +exports[`RoomStatusBar does not show anything when no sync error or other status 1`] = ` + +`; + +exports[`RoomStatusBar timeline needs refresh bar (history import) should refresh timeline for room when button clicked 1`] = ` + +`; + +exports[`RoomStatusBar timeline needs refresh bar (history import) should show timeline refresh bar when history import detected 1`] = ` + +
+
+
+ +
+
+
+ History import detected. +
+
+ History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. +
+
+
+ +
+ Refresh timeline +
+
+
+
+
+
+`; diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index fc85a825f31..325aa045b5f 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -15,6 +15,9 @@ import { IEventRelation, IUnsigned, } from 'matrix-js-sdk/src/matrix'; +import { + ISyncStateData, SyncState +} from 'matrix-js-sdk/src/sync'; import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; import dis from '../../src/dispatcher/dispatcher'; @@ -102,7 +105,8 @@ export function createTestClient(): MatrixClient { sendTyping: jest.fn().mockResolvedValue({}), sendMessage: () => jest.fn().mockResolvedValue({}), sendStateEvent: jest.fn().mockResolvedValue(undefined), - getSyncState: () => "SYNCING", + getSyncState: (): SyncState => SyncState.Syncing, + getSyncStateData: (): ISyncStateData => ({}), generateClientSecret: () => "t35tcl1Ent5ECr3T", isGuest: jest.fn().mockReturnValue(false), getRoomHierarchy: jest.fn().mockReturnValue({ From bf8555f52641ccb118e7f05a3c69a24c97e16fe0 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 19 Apr 2022 02:13:09 -0500 Subject: [PATCH 13/76] Fix lints --- src/components/structures/TimelinePanel.tsx | 1 - test/components/structures/RoomStatusBar-test.tsx | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 6da54add86b..6159e1724ad 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -1341,7 +1341,6 @@ class TimelinePanel extends React.Component { // get the list of events from the timeline window and the pending event list private getEvents(): Pick { const events: MatrixEvent[] = this.timelineWindow.getEvents(); - console.log('TimelinePanel: getEvents', events.length); // `arrayFastClone` performs a shallow copy of the array // we want the last event to be decrypted first but displayed last diff --git a/test/components/structures/RoomStatusBar-test.tsx b/test/components/structures/RoomStatusBar-test.tsx index d4eb9d8d1e1..ece4d242388 100644 --- a/test/components/structures/RoomStatusBar-test.tsx +++ b/test/components/structures/RoomStatusBar-test.tsx @@ -15,19 +15,16 @@ limitations under the License. */ import React from "react"; -import { shallow, mount } from "enzyme"; -import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; +import { mount } from "enzyme"; +import { Room } from "matrix-js-sdk/src/models/room"; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { ISyncStateData, SyncState } from 'matrix-js-sdk/src/sync'; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixError } from "matrix-js-sdk/src/http-api"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; import { stubClient } from "../../test-utils"; -import { Action } from "../../../src/dispatcher/actions"; -import dis from "../../../src/dispatcher/dispatcher"; import MatrixClientContext from "../../../src/contexts/MatrixClientContext"; import RoomStatusBar from "../../../src/components/structures/RoomStatusBar"; From 886b67633cabcc2d2daabb816bcbeefbdd938697 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 19 Apr 2022 02:24:20 -0500 Subject: [PATCH 14/76] Fix lints --- test/components/structures/RoomStatusBar-test.tsx | 8 ++++---- test/test-utils/test-utils.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/components/structures/RoomStatusBar-test.tsx b/test/components/structures/RoomStatusBar-test.tsx index ece4d242388..bb7ccaf43d7 100644 --- a/test/components/structures/RoomStatusBar-test.tsx +++ b/test/components/structures/RoomStatusBar-test.tsx @@ -19,7 +19,7 @@ import { mount } from "enzyme"; import { Room } from "matrix-js-sdk/src/models/room"; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { - ISyncStateData, SyncState + ISyncStateData, SyncState, } from 'matrix-js-sdk/src/sync'; import { MatrixError } from "matrix-js-sdk/src/http-api"; @@ -46,7 +46,7 @@ describe("RoomStatusBar", () => { beforeEach(() => { stubClient(); client = MatrixClientPeg.get(); - }) + }); it('does not show anything when no sync error or other status', () => { const r1 = new Room("r1", client, "@name:example.com", { @@ -67,7 +67,7 @@ describe("RoomStatusBar", () => { error: new MatrixError({ errcode: 'FAKE_ERROR', error: "Fake sync error", - }) + }), }); const r1 = new Room("r1", client, "@name:example.com", { @@ -88,7 +88,7 @@ describe("RoomStatusBar", () => { error: new MatrixError({ errcode: 'FAKE_ERROR', error: "Fake sync error", - }) + }), }); const r1 = new Room("r1", client, "@name:example.com", { diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 325aa045b5f..8331a8a36f2 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -16,7 +16,7 @@ import { IUnsigned, } from 'matrix-js-sdk/src/matrix'; import { - ISyncStateData, SyncState + ISyncStateData, SyncState, } from 'matrix-js-sdk/src/sync'; import { MatrixClientPeg as peg } from '../../src/MatrixClientPeg'; From 65cacbb66baa955228029cf7d9bf024e4f664db8 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 20 Apr 2022 00:49:58 -0500 Subject: [PATCH 15/76] Match case of other room events See https://github.com/matrix-org/matrix-js-sdk/pull/2299#discussion_r852884948 --- src/components/structures/RoomStatusBar.tsx | 8 ++++---- .../__snapshots__/RoomStatusBar-test.tsx.snap | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 121f2bb1ac2..bd6236bd95f 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -102,7 +102,7 @@ export default class RoomStatusBar extends React.PureComponent { const client = this.context; client.on("sync", this.onSyncStateChange); client.on("Room.localEchoUpdated", this.onRoomLocalEchoUpdated); - this.props.room.on(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); + this.props.room.on(RoomEvent.HistoryImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); this.checkSize(); } @@ -113,10 +113,10 @@ export default class RoomStatusBar extends React.PureComponent { // When the room changes, setup the new listener if (prevProps.room !== this.props.room) { prevProps.room.removeListener( - "Room.historyImportedWithinTimeline", + "Room.HistoryImportedWithinTimeline", this.onRoomHistoryImportedWithinTimeline, ); - this.props.room.on(RoomEvent.historyImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); + this.props.room.on(RoomEvent.HistoryImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); } } @@ -130,7 +130,7 @@ export default class RoomStatusBar extends React.PureComponent { } this.props.room.removeListener( - RoomEvent.historyImportedWithinTimeline, + RoomEvent.HistoryImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline, ); } diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index 7cd78db7303..ef6e0844b86 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -5,7 +5,7 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority room={ Room { "_events": Object { - "Room.historyImportedWithinTimeline": [Function], + "Room.HistoryImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -381,7 +381,7 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe room={ Room { "_events": Object { - "Room.historyImportedWithinTimeline": [Function], + "Room.HistoryImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -757,7 +757,7 @@ exports[`RoomStatusBar does not show anything when no sync error or other status room={ Room { "_events": Object { - "Room.historyImportedWithinTimeline": [Function], + "Room.HistoryImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -1102,7 +1102,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres room={ Room { "_events": Object { - "Room.historyImportedWithinTimeline": [Function], + "Room.HistoryImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -1458,7 +1458,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show t room={ Room { "_events": Object { - "Room.historyImportedWithinTimeline": [Function], + "Room.HistoryImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, From cef6d3ca3bb069d2adee9f4b492c04ae00b61d97 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 20 Apr 2022 01:09:07 -0500 Subject: [PATCH 16/76] Add types and fix up mis-type See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r852896228 --- src/components/structures/RoomStatusBar.tsx | 4 ++-- src/components/structures/TimelinePanel.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index bd6236bd95f..2fc88436da7 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -107,13 +107,13 @@ export default class RoomStatusBar extends React.PureComponent { this.checkSize(); } - public componentDidUpdate(prevProps): void { + public componentDidUpdate(prevProps: IProps): void { this.checkSize(); // When the room changes, setup the new listener if (prevProps.room !== this.props.room) { prevProps.room.removeListener( - "Room.HistoryImportedWithinTimeline", + RoomEvent.HistoryImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline, ); this.props.room.on(RoomEvent.HistoryImportedWithinTimeline, this.onRoomHistoryImportedWithinTimeline); diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 6159e1724ad..e0928d38022 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -339,7 +339,7 @@ class TimelinePanel extends React.Component { } } - public componentDidUpdate(prevProps): void { + public componentDidUpdate(prevProps: IProps): void { // When the room changes, setup the new listener if (prevProps.timelineSet.room !== this.props.timelineSet.room) { prevProps.timelineSet.room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); From f5711075edb7cffe058031fe92b8104a47c64149 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 20 Apr 2022 01:19:03 -0500 Subject: [PATCH 17/76] Fix snapshots with using string value case --- .../__snapshots__/RoomStatusBar-test.tsx.snap | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index ef6e0844b86..7cd78db7303 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -5,7 +5,7 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority room={ Room { "_events": Object { - "Room.HistoryImportedWithinTimeline": [Function], + "Room.historyImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -381,7 +381,7 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe room={ Room { "_events": Object { - "Room.HistoryImportedWithinTimeline": [Function], + "Room.historyImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -757,7 +757,7 @@ exports[`RoomStatusBar does not show anything when no sync error or other status room={ Room { "_events": Object { - "Room.HistoryImportedWithinTimeline": [Function], + "Room.historyImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -1102,7 +1102,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres room={ Room { "_events": Object { - "Room.HistoryImportedWithinTimeline": [Function], + "Room.historyImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, @@ -1458,7 +1458,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show t room={ Room { "_events": Object { - "Room.HistoryImportedWithinTimeline": [Function], + "Room.historyImportedWithinTimeline": [Function], }, "_eventsCount": 1, "_maxListeners": 100, From c2895ff092dba82ac67ed51ef07fbb56e1f7a3d7 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 20 May 2022 02:50:52 -0500 Subject: [PATCH 18/76] WIP: Cypress tests --- .../historical-import.spec.ts | 182 ++++++++++++++++++ .../templates/COPYME/homeserver.yaml | 2 +- .../msc2716-historical-import/README.md | 1 + .../as-registration.yaml | 16 ++ .../msc2716-historical-import/homeserver.yaml | 80 ++++++++ .../msc2716-historical-import/log.config | 50 +++++ cypress/support/bot.ts | 58 ++++-- cypress/support/client.ts | 51 ++++- 8 files changed, 413 insertions(+), 27 deletions(-) create mode 100644 cypress/integration/x-msc2716-historical-import/historical-import.spec.ts create mode 100644 cypress/plugins/synapsedocker/templates/msc2716-historical-import/README.md create mode 100644 cypress/plugins/synapsedocker/templates/msc2716-historical-import/as-registration.yaml create mode 100644 cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml create mode 100644 cypress/plugins/synapsedocker/templates/msc2716-historical-import/log.config diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts new file mode 100644 index 00000000000..4f455ffd4a0 --- /dev/null +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -0,0 +1,182 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/// + +import { SynapseInstance } from "../../plugins/synapsedocker"; +import { MatrixClient } from "../../global"; +import type { UserCredentials } from "../../support/login"; +import type { Room } from "matrix-js-sdk/src/models/room"; +import type { Preset } from "matrix-js-sdk/src/@types/partials"; + + +function createJoinStateEventsForBatchSendRequest( + virtualUserIDs: string[], + insertTimestamp: number, +) { + return virtualUserIDs.map((virtualUserID, index) => { + return { + "content": { + "displayname": `some-display-name-for-${virtualUserID}`, + "membership": "join" + }, + "origin_server_ts": insertTimestamp + index, + "sender": virtualUserID, + "state_key": virtualUserID, + "type": "m.room.member" + } + }); +} + +let batchCount = 0; +function createMessageEventsForBatchSendRequest( + virtualUserIDs: string[], + insertTimestamp: number, + count: number, +) { + const messageEvents = [...Array(count).keys()].map((i) => { + const virtualUserID = virtualUserIDs[i % virtualUserIDs.length]; + + return { + "content": { + "body": `Historical ${i} (batch=${batchCount})`, + "msgtype": "m.text", + "org.matrix.msc2716.historical": true + }, + "origin_server_ts": insertTimestamp + i, + "sender": virtualUserID, + "type": "m.room.message" + }; + }); + + batchCount++; + + return messageEvents; +} + +describe("MSC2716: Historical Import", () => { + let synapse: SynapseInstance; + let asMatrixClient: MatrixClient; + let loggedInUserCreds: UserCredentials; + // let loggedInUserMatrixClient: MatrixClient; + + beforeEach(() => { + cy.window().then(win => { + // Collapse left panel for these tests (get more space in the area we care about) + win.localStorage.setItem("mx_lhs_size", "0"); + }); + // Start Synapse with msc2716_enabled and an application service configured + cy.startSynapse("msc2716-historical-import").then(data => { + synapse = data; + + // This is the person we're logged in as + cy.initTestUser(synapse, "Grace").then(userCreds => { + loggedInUserCreds = userCreds; + }); + // cy.getClient().then((matrixClient) => { + // loggedInUserMatrixClient = matrixClient; + // }); + + // Get a Matrix Client for the application service + cy.newMatrixClient(synapse, { + userId: '@gitter-badger:localhost', + accessToken: 'as_token123', + }).then(matrixClient => { + asMatrixClient = matrixClient; + }); + }); + }); + + afterEach(() => { + cy.stopSynapse(synapse); + }); + + it("asdf", () => { + // As the application service, create the room so it is the room creator + // and proper power_levels to send MSC2716 events. Then join the logged + // in user to the room. + let roomId: string; + cy.window({ log: false }) + .then(async win => { + const resp = await asMatrixClient.createRoom({ + // FIXME: I can't use Preset.PublicChat because Cypress doesn't + // understand Typescript + preset: "public_chat" as Preset, + name: "test-msc2716", + room_version: "org.matrix.msc2716v3", + }); + roomId = resp.room_id; + return roomId; + }) + .as('roomId'); + + cy.get("@roomId").then(roomId => { + // Join the logged in user to the room + cy.joinRoom(roomId); + + // Then visit the room + cy.visit("/#/room/" + roomId); + }); + + // Send 3 live messages as the application service. + // Then make sure they are visible from the perspective of the logged in user. + cy.get("@roomId").then(async (roomId) => { + // Send 3 messages and wait for them to be sent + const messageResponses = await Promise.all([...Array(3).keys()].map((i) => { + return asMatrixClient.sendMessage(roomId, null, { + body: `live_event${i}`, + msgtype: "m.text", + }); + })); + + const messageEventIds: string[] = messageResponses.map((messageResponse) => { + return messageResponse.event_id; + }); + + messageEventIds.forEach((messageEventId) => { + // Wait for the messages to be visible + cy.get(`[data-event-id="${messageEventId}"]`); + }); + + const virtualUserIDs = ['@maria-01234:localhost']; + const insertTimestamp = Date.now(); + await asMatrixClient.batchSend(roomId, messageEventIds[1], null, { + state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), + events: createMessageEventsForBatchSendRequest( + virtualUserIDs, + insertTimestamp, + 3, + ) + }) + }); + + // TODO: Ensure historical messages do not appear yet. Send another live + // event and wait for it to sync back to us. If we're able to see + // eventIDAfterHistoricalImport without any the + // historicalEventIDs/historicalStateEventIDs in between, we're probably + // safe to assume it won't sync. + + // TODO: Send marker and wait for it + + // TODO: Ensure "History import detected" notice is shown + + // TODO: Press "Refresh timeline" + + // TODO: Ensure historical messages are now shown + + }); + +}); diff --git a/cypress/plugins/synapsedocker/templates/COPYME/homeserver.yaml b/cypress/plugins/synapsedocker/templates/COPYME/homeserver.yaml index fab1bc1c451..f616297d9b9 100644 --- a/cypress/plugins/synapsedocker/templates/COPYME/homeserver.yaml +++ b/cypress/plugins/synapsedocker/templates/COPYME/homeserver.yaml @@ -12,7 +12,7 @@ listeners: x_forwarded: true resources: - - names: [client, federation, consent] + - names: [client, federation] compress: false # An sqlite in-memory database is fast & automatically wipes each time diff --git a/cypress/plugins/synapsedocker/templates/msc2716-historical-import/README.md b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/README.md new file mode 100644 index 00000000000..c511585a4cb --- /dev/null +++ b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/README.md @@ -0,0 +1 @@ +Start Synapse with `msc2716_enabled` and an application service configured diff --git a/cypress/plugins/synapsedocker/templates/msc2716-historical-import/as-registration.yaml b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/as-registration.yaml new file mode 100644 index 00000000000..7febb972953 --- /dev/null +++ b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/as-registration.yaml @@ -0,0 +1,16 @@ +id: my_application_service_id +hs_token: hs_token123 +as_token: as_token123 +url: 'http://localhost:0000' +sender_localpart: gitter-badger +namespaces: + users: + - exclusive: false + regex: .* + aliases: + - exclusive: false + regex: .* + rooms: + - exclusive: false + regex: .* +rate_limited: false diff --git a/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml new file mode 100644 index 00000000000..548620b5712 --- /dev/null +++ b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml @@ -0,0 +1,80 @@ +server_name: "localhost" +pid_file: /data/homeserver.pid +# XXX: This won't actually be right: it lets docker allocate an ephemeral port, +# so we have a chicken-and-egg problem +public_baseurl: http://localhost:8008/ +# Listener is always port 8008 (configured in the container) +listeners: + - port: 8008 + tls: false + bind_addresses: ['::'] + type: http + x_forwarded: true + + resources: + - names: [client, federation] + compress: false + +# An sqlite in-memory database is fast & automatically wipes each time +database: + name: "sqlite3" + args: + database: ":memory:" + +# Needs to be configured to log to the console like a good docker process +log_config: "/data/log.config" + +rc_messages_per_second: 10000 +rc_message_burst_count: 10000 +rc_registration: + per_second: 10000 + burst_count: 10000 + +rc_login: + address: + per_second: 10000 + burst_count: 10000 + account: + per_second: 10000 + burst_count: 10000 + failed_attempts: + per_second: 10000 + burst_count: 10000 + +media_store_path: "/data/media_store" +uploads_path: "/data/uploads" +enable_registration: true +enable_registration_without_verification: true +disable_msisdn_registration: false +# These placeholders will be be replaced with values generated at start +registration_shared_secret: "{{REGISTRATION_SECRET}}" +report_stats: false +macaroon_secret_key: "{{MACAROON_SECRET_KEY}}" +form_secret: "{{FORM_SECRET}}" +# Signing key must be here: it will be generated to this file +signing_key_path: "/data/localhost.signing.key" +email: + enable_notifs: false + smtp_host: "localhost" + smtp_port: 25 + smtp_user: "exampleusername" + smtp_pass: "examplepassword" + require_transport_security: False + notif_from: "Your Friendly %(app)s homeserver " + app_name: Matrix + notif_template_html: notif_mail.html + notif_template_text: notif_mail.txt + notif_for_new_users: True + client_base_url: "http://localhost/element" + +trusted_key_servers: + - server_name: "matrix.org" +suppress_key_server_warning: true + +# A list of application service config files to use +# +app_service_config_files: + - /data/as-registration.yaml + +experimental_features: + msc2716_enabled: true diff --git a/cypress/plugins/synapsedocker/templates/msc2716-historical-import/log.config b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/log.config new file mode 100644 index 00000000000..ac232762da3 --- /dev/null +++ b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/log.config @@ -0,0 +1,50 @@ +# Log configuration for Synapse. +# +# This is a YAML file containing a standard Python logging configuration +# dictionary. See [1] for details on the valid settings. +# +# Synapse also supports structured logging for machine readable logs which can +# be ingested by ELK stacks. See [2] for details. +# +# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema +# [2]: https://matrix-org.github.io/synapse/latest/structured_logging.html + +version: 1 + +formatters: + precise: + format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' + +handlers: + # A handler that writes logs to stderr. Unused by default, but can be used + # instead of "buffer" and "file" in the logger handlers. + console: + class: logging.StreamHandler + formatter: precise + +loggers: + synapse.storage.SQL: + # beware: increasing this to DEBUG will make synapse log sensitive + # information such as access tokens. + level: INFO + + twisted: + # We send the twisted logging directly to the file handler, + # to work around https://github.com/matrix-org/synapse/issues/3471 + # when using "buffer" logger. Use "console" to log to stderr instead. + handlers: [console] + propagate: false + +root: + level: INFO + + # Write logs to the `buffer` handler, which will buffer them together in memory, + # then write them to a file. + # + # Replace "buffer" with "console" to log to stderr instead. (Note that you'll + # also need to update the configuration for the `twisted` logger above, in + # this case.) + # + handlers: [console] + +disable_existing_loggers: false diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts index a2488c0081e..4b839d1d46c 100644 --- a/cypress/support/bot.ts +++ b/cypress/support/bot.ts @@ -22,6 +22,12 @@ import type { MatrixClient } from "matrix-js-sdk/src/client"; import { SynapseInstance } from "../plugins/synapsedocker"; import Chainable = Cypress.Chainable; +interface INewMatrixClientOptions { + userId: string; + accessToken: string; + deviceId?: string; +} + declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace Cypress { @@ -32,32 +38,48 @@ declare global { * @param displayName the display name to give to the bot user */ getBot(synapse: SynapseInstance, displayName?: string): Chainable; + /** + * TODO + */ + newMatrixClient(synapse: SynapseInstance, opts: INewMatrixClientOptions): Chainable; } } } + +Cypress.Commands.add("newMatrixClient", ( + synapse: SynapseInstance, + { userId, accessToken, deviceId }: INewMatrixClientOptions +): Chainable => { + return cy.window({ log: false }).then(win => { + const cli = new win.matrixcs.MatrixClient({ + baseUrl: synapse.baseUrl, + userId, + deviceId, + accessToken, + request, + }); + + cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => { + if (member.membership === "invite" && member.userId === cli.getUserId()) { + cli.joinRoom(member.roomId); + } + }); + + cli.startClient(); + + return cli; + }); +}); + Cypress.Commands.add("getBot", (synapse: SynapseInstance, displayName?: string): Chainable => { const username = Cypress._.uniqueId("userId_"); const password = Cypress._.uniqueId("password_"); return cy.registerUser(synapse, username, password, displayName).then(credentials => { - return cy.window({ log: false }).then(win => { - const cli = new win.matrixcs.MatrixClient({ - baseUrl: synapse.baseUrl, - userId: credentials.userId, - deviceId: credentials.deviceId, - accessToken: credentials.accessToken, - request, - }); - - cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => { - if (member.membership === "invite" && member.userId === cli.getUserId()) { - cli.joinRoom(member.roomId); - } - }); - - cli.startClient(); - - return cli; + return cy.newMatrixClient(synapse, { + userId: credentials.userId, + deviceId: credentials.deviceId, + accessToken: credentials.accessToken, }); }); }); diff --git a/cypress/support/client.ts b/cypress/support/client.ts index 682f3ee426c..593f8b96e84 100644 --- a/cypress/support/client.ts +++ b/cypress/support/client.ts @@ -19,6 +19,7 @@ limitations under the License. import type { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests"; import type { MatrixClient } from "matrix-js-sdk/src/client"; import type { Room } from "matrix-js-sdk/src/models/room"; +import type { IJoinRoomOpts } from "matrix-js-sdk/src/@types/requests"; import Chainable = Cypress.Chainable; declare global { @@ -41,6 +42,17 @@ declare global { * @param userId the id of the user to invite */ inviteUser(roomId: string, userId: string): Chainable<{}>; + /** + * Joins the current user to the given room. + * @param roomId the id of the room to join + * @param opts the options when joining a room + */ + joinRoom(roomId: string, opts?: IJoinRoomOpts): Chainable<{}>; + /** + * Waits for the given room to be synced locally + * @param roomId the id of the room to wait for locally + */ + waitForRoom(roomId: string): Chainable; } } } @@ -50,11 +62,40 @@ Cypress.Commands.add("getClient", (): Chainable => { }); Cypress.Commands.add("createRoom", (options: ICreateRoomOpts): Chainable => { + cy.window({ log: false }) + .then(async win => { + const cli = win.mxMatrixClientPeg.matrixClient; + const resp = await cli.createRoom(options); + const roomId = resp.room_id; + return roomId; + }) + .as('roomId'); + + return cy.get("@roomId").then(roomId => { + return cy.waitForRoom(roomId); + }); +}); + +Cypress.Commands.add("inviteUser", (roomId: string, userId: string): Chainable<{}> => { + return cy.getClient().then(async (cli: MatrixClient) => { + return cli.invite(roomId, userId); + }); +}); + +Cypress.Commands.add("joinRoom", (roomId: string, opts?: IJoinRoomOpts): Chainable<{}> => { + cy.getClient().then(async (cli: MatrixClient) => { + return cli.joinRoom(roomId, opts); + }); + + // Wait for the room to be available locally + return cy.waitForRoom(roomId) +}); + +Cypress.Commands.add("waitForRoom", (roomId: string): Chainable => { return cy.window({ log: false }).then(async win => { const cli = win.mxMatrixClientPeg.matrixClient; - const resp = await cli.createRoom(options); - const roomId = resp.room_id; + // Wait for the room to be available locally if (!cli.getRoom(roomId)) { await new Promise(resolve => { const onRoom = (room: Room) => { @@ -70,9 +111,3 @@ Cypress.Commands.add("createRoom", (options: ICreateRoomOpts): Chainable return roomId; }); }); - -Cypress.Commands.add("inviteUser", (roomId: string, userId: string): Chainable<{}> => { - return cy.getClient().then(async (cli: MatrixClient) => { - return cli.invite(roomId, userId); - }); -}); From f58094770d752eee41c21d7562bb41ff0e3281fc Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 20 May 2022 20:39:05 -0500 Subject: [PATCH 19/76] Register virtual users --- cypress/global.d.ts | 3 + .../historical-import.spec.ts | 153 +++++++++++++----- 2 files changed, 117 insertions(+), 39 deletions(-) diff --git a/cypress/global.d.ts b/cypress/global.d.ts index efbb255b081..b1323a47f57 100644 --- a/cypress/global.d.ts +++ b/cypress/global.d.ts @@ -19,6 +19,7 @@ import type { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client"; import type { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member"; import type { MatrixDispatcher } from "../src/dispatcher/dispatcher"; import type PerformanceMonitor from "../src/performance"; +import type SettingsStore from "../src/settings/SettingsStore"; declare global { // eslint-disable-next-line @typescript-eslint/no-namespace @@ -29,6 +30,7 @@ declare global { }; mxDispatcher: MatrixDispatcher; mxPerformanceMonitor: PerformanceMonitor; + mxSettingsStore: SettingsStore; beforeReload?: boolean; // for detecting reloads // Partial type for the matrix-js-sdk module, exported by browser-matrix matrixcs: { @@ -45,6 +47,7 @@ declare global { // to appease the PerformanceMonitor import mxPerformanceMonitor: PerformanceMonitor; mxPerformanceEntryNames: any; + mxSettingsStore: SettingsStore; } } diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 4f455ffd4a0..080c851f155 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -19,6 +19,7 @@ limitations under the License. import { SynapseInstance } from "../../plugins/synapsedocker"; import { MatrixClient } from "../../global"; import type { UserCredentials } from "../../support/login"; +import { SettingLevel } from "../../../src/settings/SettingLevel"; import type { Room } from "matrix-js-sdk/src/models/room"; import type { Preset } from "matrix-js-sdk/src/@types/partials"; @@ -67,11 +68,65 @@ function createMessageEventsForBatchSendRequest( return messageEvents; } +function waitForEventIdsInClient(eventIds: string[]) { + eventIds.forEach((eventId) => { + // Wait for the messages to be visible + cy.get(`[data-event-id="${eventId}"]`); + }); +} + +function ensureVirtualUsersRegistered(synapse: SynapseInstance, applicationServiceToken, virtualUserIds: string[]) { + const url = `${synapse.baseUrl}/_matrix/client/r0/register`; + + const virtualUserLocalparts = virtualUserIds.map((virtualUserId) => { + const userIdWithoutServer = virtualUserId.split(':')[0]; + const localpart = userIdWithoutServer.replace(/^@/, ''); + return localpart; + }); + + console.log('virtualUserLocalparts', virtualUserLocalparts); + virtualUserLocalparts.forEach((virtualUserLocalpart) => { + cy.request<{ error?: string, errcode?: string }>({ + url, + method: "POST", + body: { + type: "m.login.application_service", + username: virtualUserLocalpart + }, + headers: { + 'Authorization': `Bearer ${applicationServiceToken}` + }, + // We'll handle the errors ourselves below + failOnStatusCode: false, + }) + .then((res) => { + // Registration success + if(res.status === 200) { + return; + } + + const errcode = res.body.errcode; + + // User already registered and good to go + if (res.status == 400 && errcode === "M_USER_IN_USE") { + return; + } + + const errorMessage = res.body.error; + throw new Error(`ensureVirtualUserRegistered failed to register: (${errcode}) ${errorMessage}`) + }); + }); +} + describe("MSC2716: Historical Import", () => { let synapse: SynapseInstance; let asMatrixClient: MatrixClient; let loggedInUserCreds: UserCredentials; - // let loggedInUserMatrixClient: MatrixClient; + const virtualUserIDs = ['@maria-01234:localhost']; + + // This corresponds to the application service registration defined in the + // "msc2716-historical-import" Synapse configuration + const AS_TOKEN = 'as_token123'; beforeEach(() => { cy.window().then(win => { @@ -86,17 +141,23 @@ describe("MSC2716: Historical Import", () => { cy.initTestUser(synapse, "Grace").then(userCreds => { loggedInUserCreds = userCreds; }); - // cy.getClient().then((matrixClient) => { - // loggedInUserMatrixClient = matrixClient; - // }); + // After the page is loaded from initializing the logged in user so + // the mxSettingsStore is available + cy.window().then(win => { + // Disable the sound notifications so you're not startled and + // confused where the sound is coming from + win.mxSettingsStore.setValue("audioNotificationsEnabled", null, SettingLevel.DEVICE, false); + }); // Get a Matrix Client for the application service cy.newMatrixClient(synapse, { userId: '@gitter-badger:localhost', - accessToken: 'as_token123', + accessToken: AS_TOKEN, }).then(matrixClient => { asMatrixClient = matrixClient; }); + + ensureVirtualUsersRegistered(synapse, AS_TOKEN, virtualUserIDs); }); }); @@ -109,11 +170,12 @@ describe("MSC2716: Historical Import", () => { // and proper power_levels to send MSC2716 events. Then join the logged // in user to the room. let roomId: string; - cy.window({ log: false }) - .then(async win => { + cy.wrap(true) + .then(async () => { + console.log('using asMatrixClient', asMatrixClient); const resp = await asMatrixClient.createRoom({ // FIXME: I can't use Preset.PublicChat because Cypress doesn't - // understand Typescript + // understand Typescript to import it preset: "public_chat" as Preset, name: "test-msc2716", room_version: "org.matrix.msc2716v3", @@ -133,41 +195,54 @@ describe("MSC2716: Historical Import", () => { // Send 3 live messages as the application service. // Then make sure they are visible from the perspective of the logged in user. - cy.get("@roomId").then(async (roomId) => { - // Send 3 messages and wait for them to be sent - const messageResponses = await Promise.all([...Array(3).keys()].map((i) => { - return asMatrixClient.sendMessage(roomId, null, { - body: `live_event${i}`, - msgtype: "m.text", - }); - })); - - const messageEventIds: string[] = messageResponses.map((messageResponse) => { - return messageResponse.event_id; - }); + cy.get("@roomId") + .then(async (roomId) => { + // Send 3 messages and wait for them to be sent + const messageEventIds = (await Promise.all([...Array(3).keys()].map((i) => { + return asMatrixClient.sendMessage(roomId, null, { + body: `live_event${i}`, + msgtype: "m.text", + }); + }))) + .map((messageResponse) => { + return messageResponse.event_id; + }); - messageEventIds.forEach((messageEventId) => { - // Wait for the messages to be visible - cy.get(`[data-event-id="${messageEventId}"]`); - }); + // Wait for the messages to show up for the logged in user + waitForEventIdsInClient(messageEventIds); - const virtualUserIDs = ['@maria-01234:localhost']; - const insertTimestamp = Date.now(); - await asMatrixClient.batchSend(roomId, messageEventIds[1], null, { - state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), - events: createMessageEventsForBatchSendRequest( - virtualUserIDs, - insertTimestamp, - 3, - ) + console.log('messageEventIds1', messageEventIds); + cy.wrap(messageEventIds); }) - }); + .then(async (messageEventIds) => { + console.log('messageEventIds2', messageEventIds); + // Make sure the right thing was yielded + expect(messageEventIds).to.have.lengthOf(3); + + // Send a batch of historical messages + const insertTimestamp = Date.now(); + await asMatrixClient.batchSend(roomId, messageEventIds[1], null, { + state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), + events: createMessageEventsForBatchSendRequest( + virtualUserIDs, + insertTimestamp, + 3, + ) + }) + + // Ensure historical messages do not appear yet. We can do this by + // sending another live event and wait for it to sync back to us. If + // we're able to see eventIDAfterHistoricalImport without any the + // historicalEventIDs/historicalStateEventIDs in between, we're + // probably safe to assume it won't sync. + const {event_id: eventIDAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { + body: `live_event after`, + msgtype: "m.text", + }); + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIDAfterHistoricalImport]); + }); - // TODO: Ensure historical messages do not appear yet. Send another live - // event and wait for it to sync back to us. If we're able to see - // eventIDAfterHistoricalImport without any the - // historicalEventIDs/historicalStateEventIDs in between, we're probably - // safe to assume it won't sync. // TODO: Send marker and wait for it From 4c53f34ab0c8ea376aa79f101ba0ed619799ff53 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 20 May 2022 22:08:44 -0500 Subject: [PATCH 20/76] All assertions --- .../historical-import.spec.ts | 61 ++++++++++++++----- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 080c851f155..0110c159913 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -147,6 +147,10 @@ describe("MSC2716: Historical Import", () => { // Disable the sound notifications so you're not startled and // confused where the sound is coming from win.mxSettingsStore.setValue("audioNotificationsEnabled", null, SettingLevel.DEVICE, false); + // Show hidden events to make debugging easier. And the state + // events will show up in the timeline to make it the same + // assert as other events. + win.mxSettingsStore.setValue("showHiddenEventsInTimeline", null, SettingLevel.DEVICE, true); }); // Get a Matrix Client for the application service @@ -198,7 +202,7 @@ describe("MSC2716: Historical Import", () => { cy.get("@roomId") .then(async (roomId) => { // Send 3 messages and wait for them to be sent - const messageEventIds = (await Promise.all([...Array(3).keys()].map((i) => { + const liveMessageEventIds = (await Promise.all([...Array(3).keys()].map((i) => { return asMatrixClient.sendMessage(roomId, null, { body: `live_event${i}`, msgtype: "m.text", @@ -208,32 +212,37 @@ describe("MSC2716: Historical Import", () => { return messageResponse.event_id; }); + // Make this available for later chains + cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); + // Wait for the messages to show up for the logged in user - waitForEventIdsInClient(messageEventIds); + waitForEventIdsInClient(liveMessageEventIds); - console.log('messageEventIds1', messageEventIds); - cy.wrap(messageEventIds); + console.log('messageEventIds1', liveMessageEventIds); + cy.wrap(liveMessageEventIds); }) - .then(async (messageEventIds) => { - console.log('messageEventIds2', messageEventIds); + .then(async (liveMessageEventIds) => { // Make sure the right thing was yielded - expect(messageEventIds).to.have.lengthOf(3); + expect(liveMessageEventIds).to.have.lengthOf(3); // Send a batch of historical messages const insertTimestamp = Date.now(); - await asMatrixClient.batchSend(roomId, messageEventIds[1], null, { + const { event_ids, base_insertion_event_id } = await asMatrixClient.batchSend(roomId, liveMessageEventIds[1], null, { state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), events: createMessageEventsForBatchSendRequest( virtualUserIDs, insertTimestamp, 3, - ) - }) + ), + }); + // Make this available for later chains + cy.wrap(event_ids).as('historicalEventIds'); + cy.wrap(base_insertion_event_id).as('baseInsertionEventId'); // Ensure historical messages do not appear yet. We can do this by // sending another live event and wait for it to sync back to us. If // we're able to see eventIDAfterHistoricalImport without any the - // historicalEventIDs/historicalStateEventIDs in between, we're + // historicalEventIds/historicalStateEventIds in between, we're // probably safe to assume it won't sync. const {event_id: eventIDAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { body: `live_event after`, @@ -244,14 +253,36 @@ describe("MSC2716: Historical Import", () => { }); - // TODO: Send marker and wait for it + // Send the marker event which lets the client know there are + // some historical messages back at the given insertion event. + cy.get("@roomId") + .then(async function(roomId) { + assert.exists(this.baseInsertionEventId); - // TODO: Ensure "History import detected" notice is shown + const {event_id: markeEventId } = await asMatrixClient.sendStateEvent(roomId, 'org.matrix.msc2716.marker', { + "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, + }, Cypress._.uniqueId("marker_state_key_")); + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([markeEventId]); + }); - // TODO: Press "Refresh timeline" + // Ensure the "History import detected" notice is shown + cy.get(".mx_RoomStatusBar").should("contain", "History import detected"); - // TODO: Ensure historical messages are now shown + // Press "Refresh timeline" + cy.get(".mx_RoomStatusBar_refreshTimelineBtn").click(); + // Ensure historical messages are now shown + cy.wrap(true) + .then(function() { + // TODO: Assert in the correct order + waitForEventIdsInClient([ + this.liveMessageEventIds[0], + ...this.historicalEventIds, + this.liveMessageEventIds[1], + this.liveMessageEventIds[2] + ]); + }); }); }); From ee10ae2ba627764addbe6fc29bca7f2a5cb9dcb5 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 21 May 2022 00:23:52 -0500 Subject: [PATCH 21/76] Best practice Cypress test selectors --- .../x-msc2716-historical-import/historical-import.spec.ts | 8 +++----- src/components/structures/RoomStatusBar.tsx | 8 ++++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 0110c159913..d3d2ddac16d 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -176,7 +176,6 @@ describe("MSC2716: Historical Import", () => { let roomId: string; cy.wrap(true) .then(async () => { - console.log('using asMatrixClient', asMatrixClient); const resp = await asMatrixClient.createRoom({ // FIXME: I can't use Preset.PublicChat because Cypress doesn't // understand Typescript to import it @@ -218,7 +217,6 @@ describe("MSC2716: Historical Import", () => { // Wait for the messages to show up for the logged in user waitForEventIdsInClient(liveMessageEventIds); - console.log('messageEventIds1', liveMessageEventIds); cy.wrap(liveMessageEventIds); }) .then(async (liveMessageEventIds) => { @@ -267,10 +265,10 @@ describe("MSC2716: Historical Import", () => { }); // Ensure the "History import detected" notice is shown - cy.get(".mx_RoomStatusBar").should("contain", "History import detected"); + cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("contain", "History import detected"); // Press "Refresh timeline" - cy.get(".mx_RoomStatusBar_refreshTimelineBtn").click(); + cy.get(`[data-cy="refresh-timeline-button"]`).click(); // Ensure historical messages are now shown cy.wrap(true) @@ -278,8 +276,8 @@ describe("MSC2716: Historical Import", () => { // TODO: Assert in the correct order waitForEventIdsInClient([ this.liveMessageEventIds[0], - ...this.historicalEventIds, this.liveMessageEventIds[1], + ...this.historicalEventIds, this.liveMessageEventIds[2] ]); }); diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 53a6794e302..b0fe075bb96 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -345,7 +345,7 @@ export default class RoomStatusBar extends React.PureComponent { if (this.state.timelineNeedsRefresh) { return ( -
+
{
- + { _t("Refresh timeline") }
From 2bdb16574d55020a5baed1c348468cd63e952bbe Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 21 May 2022 00:26:08 -0500 Subject: [PATCH 22/76] Don't assert text that could change --- .../x-msc2716-historical-import/historical-import.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index d3d2ddac16d..2ac7049f2e4 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -265,7 +265,7 @@ describe("MSC2716: Historical Import", () => { }); // Ensure the "History import detected" notice is shown - cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("contain", "History import detected"); + cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); // Press "Refresh timeline" cy.get(`[data-cy="refresh-timeline-button"]`).click(); From 64e7e285454887205f0c7cd8cc3dbb9ed6e471e4 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 21 May 2022 02:32:03 -0500 Subject: [PATCH 23/76] Send live events sequentially to avoid them all having the same depth To achieve a nice pretty expected order of messages at the end of the test where the historical events are between the live events. Here is how `/context` was selecting `events_before` before and after this change: Before: ```diff depth stream_ordering type state_key event_id ->10 13 org.matrix.msc2716.marker marker_state_key_1556 $dKxDZQGaIQ_f-gktM4GG0VVFEqC7MFOkzY4IH3xUfy0 + 9 12 m.room.message None $8iyJhbATonshLiqUeHrlfJ5P4N9aTtkvywqLbK6SUx4 + 8 11 m.room.message None $PDjZCIilkqOeVKr7FfR8lcdbJc8W1DCPtMjKepVzFS0 + 8 10 m.room.message None $dIXBcdGT8h6bTnqN7ArbMCyESHUerPOWP07E2SRtlsw + 8 9 m.room.message None $6UQ_Hm_IXHw8-xwJ-lJPD1mp6IoNY9GTaFrnURrhT9I + 8 -3 org.matrix.msc2716.insertion None $D-JpKoB2CJ4MEA64fgRtjb01JLmm30dwW0RiV2rMweg 8 -4 org.matrix.msc2716.batch None $KemKolgMcQ1M-bqA3WVvwNSw-PP6YLoFOlyc9qLsWpA 8 -5 m.room.message None $zTl3QdmPMDMs5P7LE3ntsMv9Nygy6cQPs2zljuXNdAs 8 -6 m.room.message None $PZPoUyaxlSb96gkGJUYmEwyIfMcsRwWLVZAHdr4-gbs 8 -7 m.room.message None $nF1fANamEvmCFGE8eP_chMiqmJlmNtGp6DgRbvh5ZbY 8 -8 org.matrix.msc2716.insertion None $YW2-96D7MACHwahQxBncQS7gPKfjV9oF-J80kEuI9iQ 7 8 m.room.member @userid_1432:localhost $froWZNJQs_Icb5xdJFt0LvRfZtphaGAgEL99cdBM7tQ 6 7 m.room.name $niWX1K2k4muCReFN34Dhp1anHu3q4RFKuUxaeOXST5Y 5 6 m.room.history_visibility $6XACW1IHXv8hSQLsCWNHZMWbbliUaCojbu0POE3VjHQ 4 5 m.room.join_rules $qK7R_YtgzCO9LDZcUoJUSUB9c8mas8GbLyVDZHB8N7A 3 4 m.room.power_levels $BJ1WYUoeWV7Pz3TzVyAi3mu63kRapi-36NlKFzHLZNQ 2 3 m.room.member @gitter-badger:localhost $rIFvO_yuWu6GQjQ5uYJt4vZA8VLxSROfb5fWcIAN4bg 1 2 m.room.create $RFkJUmW_2jZTt73G3YDyI2RjapBLoGzWvj1CXd1bn8g 1 -2 m.room.member @maria-01234:localhost $JgfcZjPbjVHIdu1-eGrMZDYqXBfEZKvfoWZOtC4aSYo ``` After: ```py depth stream_ordering type state_key event_id ->12 13 org.matrix.msc2716.marker marker_state_key_2270 $2a02Y937WilvjgRVstsfwLx4E5OBO3-1iQgLq1yEB5E + 11 12 m.room.message None $DTDay_DW5Jyk0Jgeiab3o-BJpuEYD7lJTjb27X8Gyz4 + 10 11 m.room.message None $ZJh4TUkqKjBQ8NzT7gWUhQcYIGJS-R4M74MxwqIopEc + 10 -3 org.matrix.msc2716.insertion None $K-IOd_7KI4jfvLfGw5fGp_xmB6224D45It90doM-cAE + 10 -4 org.matrix.msc2716.batch None $MsPmhsc8xiYXqjPrqSs6ge-x_bFG9JE6silptAtFkhY + 10 -5 m.room.message None $IkyF2qsxxmARbeQbKU1ccSjJJi4CJZz8r998CYLkj_4 10 -6 m.room.message None $lFU-1ZPB2hIJVmwCoRzL9-4rh1D4AYrCrtTXtxsVcng 10 -7 m.room.message None $9-RXGLnMadETgmAbREfauDbzbOEIOkDKCOsp_JI_NkQ 10 -8 org.matrix.msc2716.insertion None $PffMur-OkTHckcNx7RkhnPxyb5EGimnBFyvszntBtV4 9 10 m.room.message None $OjUi9AlIcL4q6M_p09ktPN0Vwrheve3J2HJ4XRI6RjQ 8 9 m.room.message None $WKit32Eti15ddcOxRcAXIt48p25kBVOUR7pxy72B-II 7 8 m.room.member @userid_2141:localhost $DTGbc38K8mK-UwOqvCmrIAg9hsoSnJkfFaRSUgMmW4k 6 7 m.room.name $iz0-8hXSXdVB-eeFm9uP6_mslSKeT3RBRuU9wnaulQ8 5 6 m.room.history_visibility $Uxvxd3m6IY9zl0n2JNRwO7C1hggEm29MWWdRGrW0OAQ 4 5 m.room.join_rules $cKAvApHSqaWSS9eYCAnbntpwSNtABWFC1R86vWB_HcQ 3 4 m.room.power_levels $icdqTeEsAywRz4w1qkz63iu7ZOfwgW4GFmA6SnygtZI 2 3 m.room.member @gitter-badger:localhost $lxUJoye0uyOYJdyyYN5CKvU8QObwqhE-IagNCxNLU1E 1 2 m.room.create $Xf1FoL0lCbqhuaLwCHwxvqt3QQZdBxmbK32-uogT9sw 1 -2 m.room.member @maria-01234:localhost $aISZQr-_HwRveEJnS3KC1ZF2SuoYRfUSwharge4SlsU ``` Logging code in Synapse to generate the tabulated events from the room in: ```py logger.info( "asdf_get_debug_events_in_room_ordered_by_depth\n%s", await self.store.asdf_get_debug_events_in_room_ordered_by_depth(room_id), ) ``` ```py async def asdf_get_debug_events_in_room_ordered_by_depth(self, room_id: str) -> Any: """Gets the topological token in a room after or at the given stream ordering. Args: room_id """ sql = ( "SELECT depth, stream_ordering, type, state_key, event_id FROM events" " WHERE events.room_id = ?" " ORDER BY depth DESC, stream_ordering DESC;" ) rows = await self.db_pool.execute( "asdf_get_debug_events_in_room_ordered_by_depth", None, sql, room_id ) headerColumnLengthMap = { "depth": 4, "stream_ordering": 12, "type": 30, "state_key": 28, # event_ids are 44 long but we don't need the extra 5 padding # because it's the last item and we're just cheating by building # this into the value instead of the format code. "event_id": 39, } output = "" row_format = "".join( [ "{:<" + str(columnLength + 5) + "}" for columnLength in headerColumnLengthMap.values() ] ) output += row_format.format(*headerColumnLengthMap.keys()) + "\n" for row in rows: output += row_format.format(*[str(x) for x in row]) + "\n" return output ``` --- .../historical-import.spec.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 2ac7049f2e4..845c30ad6b8 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -84,7 +84,6 @@ function ensureVirtualUsersRegistered(synapse: SynapseInstance, applicationServi return localpart; }); - console.log('virtualUserLocalparts', virtualUserLocalparts); virtualUserLocalparts.forEach((virtualUserLocalpart) => { cy.request<{ error?: string, errcode?: string }>({ url, @@ -201,15 +200,18 @@ describe("MSC2716: Historical Import", () => { cy.get("@roomId") .then(async (roomId) => { // Send 3 messages and wait for them to be sent - const liveMessageEventIds = (await Promise.all([...Array(3).keys()].map((i) => { - return asMatrixClient.sendMessage(roomId, null, { + const liveMessageEventIds = []; + for (let i = 0; i < 3; i++) { + // Send the messages sequentially waiting for each request + // to finish before we move onto the next so we don't end up + // with a pile of live messages at the same depth. This + // gives more of an expected order at the end. + const { event_id } = await asMatrixClient.sendMessage(roomId, null, { body: `live_event${i}`, msgtype: "m.text", }); - }))) - .map((messageResponse) => { - return messageResponse.event_id; - }); + liveMessageEventIds.push(event_id); + } // Make this available for later chains cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); From 6dbe331c429df8bdc53f82980917d5c32e1817ed Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 23 May 2022 21:12:13 -0500 Subject: [PATCH 24/76] Better self describing message --- .../x-msc2716-historical-import/historical-import.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 845c30ad6b8..2241c5f60fb 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -245,7 +245,7 @@ describe("MSC2716: Historical Import", () => { // historicalEventIds/historicalStateEventIds in between, we're // probably safe to assume it won't sync. const {event_id: eventIDAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { - body: `live_event after`, + body: `live_event after historical import`, msgtype: "m.text", }); // Wait for the message to show up for the logged in user From 18adde8d47b278b22fd13b3085cb89567c0aebea Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 23 May 2022 23:54:33 -0500 Subject: [PATCH 25/76] Use function scoped to the tests where it is only used See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r878660862 --- .../historical-import.spec.ts | 104 +++++++++++++++--- 1 file changed, 89 insertions(+), 15 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 2241c5f60fb..ef1ac344e1f 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -23,7 +23,6 @@ import { SettingLevel } from "../../../src/settings/SettingLevel"; import type { Room } from "matrix-js-sdk/src/models/room"; import type { Preset } from "matrix-js-sdk/src/@types/partials"; - function createJoinStateEventsForBatchSendRequest( virtualUserIDs: string[], insertTimestamp: number, @@ -75,7 +74,64 @@ function waitForEventIdsInClient(eventIds: string[]) { }); } -function ensureVirtualUsersRegistered(synapse: SynapseInstance, applicationServiceToken, virtualUserIds: string[]) { +interface IBatchSendResponse { + /** List of state event ID's we inserted */ + state_event_ids: string[]; + /** List of historical event ID's we inserted */ + event_ids: string[]; + next_batch_id: string; + insertion_event_id: string; + batch_event_id: string; + /** When `?batch_id` isn't provided, the homeserver automatically creates an + * insertion event as a starting place to hang the history off of. This + * automatic insertion event ID is returned in this field. + * + * When `?batch_id` is provided, this field is not present because we can + * hang the history off the insertion event specified and associated by the + * batch ID. + */ + base_insertion_event_id?: string; +} + +/** + * Import a batch of historical events (MSC2716) + */ +function batchSend({ + synapse, + accessToken, + roomId, + prevEventId, + batchId, + payload, +}: { + synapse: SynapseInstance, + accessToken: string, + roomId: string, + prevEventId: string, + batchId: string | null, + payload: { state_events_at_start?: any[], events: any[] }, +}): Cypress.Chainable> { + const batchSendUrl = new URL(`${synapse.baseUrl}/_matrix/client/unstable/org.matrix.msc2716/rooms/${roomId}/batch_send`); + batchSendUrl.searchParams.set('prev_event_id', prevEventId); + if (batchId !== null) { + batchSendUrl.searchParams.set('batch_id', batchId); + } + + return cy.request({ + url: batchSendUrl.toString(), + method: "POST", + headers: { + 'Authorization': `Bearer ${accessToken}`, + }, + body: payload, + }); +} + +function ensureVirtualUsersRegistered( + synapse: SynapseInstance, + applicationServiceToken: string, + virtualUserIds: string[] +) { const url = `${synapse.baseUrl}/_matrix/client/r0/register`; const virtualUserLocalparts = virtualUserIds.map((virtualUserId) => { @@ -219,26 +275,44 @@ describe("MSC2716: Historical Import", () => { // Wait for the messages to show up for the logged in user waitForEventIdsInClient(liveMessageEventIds); - cy.wrap(liveMessageEventIds); - }) + cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); + }); + + cy.get("@liveMessageEventIds") .then(async (liveMessageEventIds) => { // Make sure the right thing was yielded expect(liveMessageEventIds).to.have.lengthOf(3); // Send a batch of historical messages const insertTimestamp = Date.now(); - const { event_ids, base_insertion_event_id } = await asMatrixClient.batchSend(roomId, liveMessageEventIds[1], null, { - state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), - events: createMessageEventsForBatchSendRequest( - virtualUserIDs, - insertTimestamp, - 3, - ), - }); - // Make this available for later chains - cy.wrap(event_ids).as('historicalEventIds'); - cy.wrap(base_insertion_event_id).as('baseInsertionEventId'); + batchSend({ + synapse, + accessToken: asMatrixClient.getAccessToken(), + roomId, + prevEventId: liveMessageEventIds[1], + batchId: null, + payload: { + state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), + events: createMessageEventsForBatchSendRequest( + virtualUserIDs, + insertTimestamp, + 3, + ), + }, + }) + .then((res) => { + assert.exists(res.body.event_ids); + assert.exists(res.body.base_insertion_event_id); + + // Make this available for later chains + cy.wrap(res.body.event_ids).as('historicalEventIds'); + cy.wrap(res.body.base_insertion_event_id).as('baseInsertionEventId'); + }); + }); + + cy.get("@roomId") + .then(async function(roomId) { // Ensure historical messages do not appear yet. We can do this by // sending another live event and wait for it to sync back to us. If // we're able to see eventIDAfterHistoricalImport without any the From a661bf66cba32c1ecbeacdb6713c4602df2b0251 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 24 May 2022 03:07:11 -0500 Subject: [PATCH 26/76] WIP: Test to make sure racing sync that resolve before /context finishes still works out correctly See https://github.com/matrix-org/matrix-js-sdk/pull/2299#discussion_r852891150 Currently, the cy.intercept throws an error: ``` Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise. ``` --- .../historical-import.spec.ts | 303 +++++++++++------- 1 file changed, 184 insertions(+), 119 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index ef1ac344e1f..2ec5f33bcad 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -22,6 +22,7 @@ import type { UserCredentials } from "../../support/login"; import { SettingLevel } from "../../../src/settings/SettingLevel"; import type { Room } from "matrix-js-sdk/src/models/room"; import type { Preset } from "matrix-js-sdk/src/@types/partials"; +import * as cypress from "cypress"; function createJoinStateEventsForBatchSendRequest( virtualUserIDs: string[], @@ -173,6 +174,133 @@ function ensureVirtualUsersRegistered( }); } +function setupRoomWithHistoricalMessagesAndMarker({ + synapse, + asMatrixClient, + virtualUserIDs +}: { + synapse: SynapseInstance, + asMatrixClient: MatrixClient, + virtualUserIDs: string[] +}) { + // As the application service, create the room so it is the room creator + // and proper power_levels to send MSC2716 events. Then join the logged + // in user to the room. + cy.wrap(true) + .then(async () => { + const resp = await asMatrixClient.createRoom({ + // FIXME: I can't use Preset.PublicChat because Cypress doesn't + // understand Typescript to import it + preset: "public_chat" as Preset, + name: "test-msc2716", + room_version: "org.matrix.msc2716v3", + }); + cy.wrap(resp.room_id) .as('roomId'); + }); + + cy.get("@roomId").then(roomId => { + // Join the logged in user to the room + cy.joinRoom(roomId); + + // Then visit the room + cy.visit("/#/room/" + roomId); + }); + + // Send 3 live messages as the application service. + // Then make sure they are visible from the perspective of the logged in user. + cy.get("@roomId") + .then(async (roomId) => { + // Send 3 messages and wait for them to be sent + const liveMessageEventIds = []; + for (let i = 0; i < 3; i++) { + // Send the messages sequentially waiting for each request + // to finish before we move onto the next so we don't end up + // with a pile of live messages at the same depth. This + // gives more of an expected order at the end. + const { event_id } = await asMatrixClient.sendMessage(roomId, null, { + body: `live_event${i}`, + msgtype: "m.text", + }); + liveMessageEventIds.push(event_id); + } + + // Make this available for later chains + cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); + + // Wait for the messages to show up for the logged in user + waitForEventIdsInClient(liveMessageEventIds); + + cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); + }); + + cy.then(function() { + // Make sure the right thing was yielded + expect(this.liveMessageEventIds).to.have.lengthOf(3); + + // Send a batch of historical messages + const insertTimestamp = Date.now(); + batchSend({ + synapse, + accessToken: asMatrixClient.getAccessToken(), + roomId: this.roomId, + prevEventId: this.liveMessageEventIds[1], + batchId: null, + payload: { + state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), + events: createMessageEventsForBatchSendRequest( + virtualUserIDs, + insertTimestamp, + 3, + ), + }, + }) + .then((res) => { + assert.exists(res.body.event_ids); + assert.exists(res.body.base_insertion_event_id); + + // Make this available for later chains + cy.wrap(res.body.event_ids).as('historicalEventIds'); + cy.wrap(res.body.base_insertion_event_id).as('baseInsertionEventId'); + }); + }); + + cy.get("@roomId") + .then(async function(roomId) { + // Ensure historical messages do not appear yet. We can do this by + // sending another live event and wait for it to sync back to us. If + // we're able to see eventIdAfterHistoricalImport without any the + // historicalEventIds/historicalStateEventIds in between, we're + // probably safe to assume it won't sync. + const {event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { + body: `live_event after historical import`, + msgtype: "m.text", + }); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIdAfterHistoricalImport]); + }); + + + // Send the marker event which lets the client know there are + // some historical messages back at the given insertion event. + cy.get("@roomId") + .then(async function(roomId) { + assert.exists(this.baseInsertionEventId); + + const {event_id: markeEventId } = await asMatrixClient.sendStateEvent(roomId, 'org.matrix.msc2716.marker', { + "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, + }, Cypress._.uniqueId("marker_state_key_")); + + cy.wrap(markeEventId).as('markeEventId'); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([markeEventId]); + }); + + // Ensure the "History import detected" notice is shown + cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); +} + describe("MSC2716: Historical Import", () => { let synapse: SynapseInstance; let asMatrixClient: MatrixClient; @@ -224,139 +352,76 @@ describe("MSC2716: Historical Import", () => { cy.stopSynapse(synapse); }); - it("asdf", () => { - // As the application service, create the room so it is the room creator - // and proper power_levels to send MSC2716 events. Then join the logged - // in user to the room. - let roomId: string; - cy.wrap(true) - .then(async () => { - const resp = await asMatrixClient.createRoom({ - // FIXME: I can't use Preset.PublicChat because Cypress doesn't - // understand Typescript to import it - preset: "public_chat" as Preset, - name: "test-msc2716", - room_version: "org.matrix.msc2716v3", - }); - roomId = resp.room_id; - return roomId; - }) - .as('roomId'); - - cy.get("@roomId").then(roomId => { - // Join the logged in user to the room - cy.joinRoom(roomId); - - // Then visit the room - cy.visit("/#/room/" + roomId); + it("Shows historical messages after refreshing the timeline", () => { + setupRoomWithHistoricalMessagesAndMarker({ + synapse, + asMatrixClient, + virtualUserIDs }); - // Send 3 live messages as the application service. - // Then make sure they are visible from the perspective of the logged in user. - cy.get("@roomId") - .then(async (roomId) => { - // Send 3 messages and wait for them to be sent - const liveMessageEventIds = []; - for (let i = 0; i < 3; i++) { - // Send the messages sequentially waiting for each request - // to finish before we move onto the next so we don't end up - // with a pile of live messages at the same depth. This - // gives more of an expected order at the end. - const { event_id } = await asMatrixClient.sendMessage(roomId, null, { - body: `live_event${i}`, - msgtype: "m.text", - }); - liveMessageEventIds.push(event_id); - } - - // Make this available for later chains - cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); - - // Wait for the messages to show up for the logged in user - waitForEventIdsInClient(liveMessageEventIds); - - cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); - }); + // Press "Refresh timeline" + cy.get(`[data-cy="refresh-timeline-button"]`).click(); - cy.get("@liveMessageEventIds") - .then(async (liveMessageEventIds) => { - // Make sure the right thing was yielded - expect(liveMessageEventIds).to.have.lengthOf(3); - - // Send a batch of historical messages - const insertTimestamp = Date.now(); - batchSend({ - synapse, - accessToken: asMatrixClient.getAccessToken(), - roomId, - prevEventId: liveMessageEventIds[1], - batchId: null, - payload: { - state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), - events: createMessageEventsForBatchSendRequest( - virtualUserIDs, - insertTimestamp, - 3, - ), - }, - }) - .then((res) => { - assert.exists(res.body.event_ids); - assert.exists(res.body.base_insertion_event_id); - - // Make this available for later chains - cy.wrap(res.body.event_ids).as('historicalEventIds'); - cy.wrap(res.body.base_insertion_event_id).as('baseInsertionEventId'); - }); - }); + // Ensure historical messages are now shown + cy.wrap(null).then(function() { + // FIXME: Assert that they appear in the correct order + waitForEventIdsInClient([ + this.liveMessageEventIds[0], + this.liveMessageEventIds[1], + ...this.historicalEventIds, + this.liveMessageEventIds[2] + ]); + }); + }); + it.only("Perfectly merges timelines if a sync happens while refreshig the timeline", () => { + setupRoomWithHistoricalMessagesAndMarker({ + synapse, + asMatrixClient, + virtualUserIDs + }); - cy.get("@roomId") - .then(async function(roomId) { - // Ensure historical messages do not appear yet. We can do this by - // sending another live event and wait for it to sync back to us. If - // we're able to see eventIDAfterHistoricalImport without any the - // historicalEventIds/historicalStateEventIds in between, we're - // probably safe to assume it won't sync. - const {event_id: eventIDAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { - body: `live_event after historical import`, + // 1. Pause the /context from the `getEventTimeline` that happens + // 1. Make sure a sync happens + // 1. Then unpause + + cy.wrap(null).then(function() { + // We're using `this.markeEventId` here because it's the latest event in the room + const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; + cy.intercept(contextUrl, async (req) => { + console.log('intercepted aewfefewafaew'); + const {event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage(this.roomId, null, { + body: `live_event while trying to refresh timeline`, msgtype: "m.text", }); + // Wait for the message to show up for the logged in user - waitForEventIdsInClient([eventIDAfterHistoricalImport]); - }); - + // indicating that a sync happened + waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); - // Send the marker event which lets the client know there are - // some historical messages back at the given insertion event. - cy.get("@roomId") - .then(async function(roomId) { - assert.exists(this.baseInsertionEventId); - - const {event_id: markeEventId } = await asMatrixClient.sendStateEvent(roomId, 'org.matrix.msc2716.marker', { - "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, - }, Cypress._.uniqueId("marker_state_key_")); - // Wait for the message to show up for the logged in user - waitForEventIdsInClient([markeEventId]); - }); - - // Ensure the "History import detected" notice is shown - cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); + // Now continue the request + req.continue(); + //req.reply(); + }).as('contextRequestThatWillMakeNewTimeline'); + }); // Press "Refresh timeline" cy.get(`[data-cy="refresh-timeline-button"]`).click(); + // Make sure the request was intercepted + cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); + + // Ensure historical messages are now shown - cy.wrap(true) - .then(function() { - // TODO: Assert in the correct order - waitForEventIdsInClient([ - this.liveMessageEventIds[0], - this.liveMessageEventIds[1], - ...this.historicalEventIds, - this.liveMessageEventIds[2] - ]); - }); + cy.wrap(null).then(function() { + // FIXME: Assert that they appear in the correct order + waitForEventIdsInClient([ + this.liveMessageEventIds[0], + this.liveMessageEventIds[1], + ...this.historicalEventIds, + this.liveMessageEventIds[2] + ]); + }); }); }); From ae5338d0e5272c279488ba0d8e301cff2c46bd99 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 24 May 2022 03:38:44 -0500 Subject: [PATCH 27/76] The racey sync test does pass, not sure if testing the right thing --- .../historical-import.spec.ts | 33 ++++++++++++++----- src/components/structures/ScrollPanel.tsx | 2 +- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 2ec5f33bcad..811651ec1a2 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -385,11 +385,30 @@ describe("MSC2716: Historical Import", () => { // 1. Make sure a sync happens // 1. Then unpause + let resolveReq; cy.wrap(null).then(function() { // We're using `this.markeEventId` here because it's the latest event in the room const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; cy.intercept(contextUrl, async (req) => { console.log('intercepted aewfefewafaew'); + return new Cypress.Promise(resolve => { + resolveReq = resolve; + }).then(req.reply) + }).as('contextRequestThatWillMakeNewTimeline'); + }); + + // Press "Refresh timeline" + cy.get(`[data-cy="refresh-timeline-button"]`).click(); + + cy.get('[data-cy="message-list"] [data-event-id]') + // Wait for the timeline to go blank (meaning it was reset). + // + // FIXME: This only exists with the extra `RoomEvent.TimelineRefresh` to replace + // the timeline after `resetLiveTimeline(null, null)`. This might be + // fine though as it gives feedback to the user after pressing the + // refresh timeline button. + .should('not.exist') + .then(async function() { const {event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage(this.roomId, null, { body: `live_event while trying to refresh timeline`, msgtype: "m.text", @@ -398,15 +417,11 @@ describe("MSC2716: Historical Import", () => { // Wait for the message to show up for the logged in user // indicating that a sync happened waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); - - // Now continue the request - req.continue(); - //req.reply(); - }).as('contextRequestThatWillMakeNewTimeline'); - }); - - // Press "Refresh timeline" - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + }) + .then(() => { + console.log('trying to resolveReq'); + resolveReq(); + }); // Make sure the request was intercepted cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); diff --git a/src/components/structures/ScrollPanel.tsx b/src/components/structures/ScrollPanel.tsx index 5db5e6daad9..69898be6e04 100644 --- a/src/components/structures/ScrollPanel.tsx +++ b/src/components/structures/ScrollPanel.tsx @@ -937,7 +937,7 @@ export default class ScrollPanel extends React.Component { > { this.props.fixedChildren }
-
    +
      { this.props.children }
From f9a525c201986f20763b8b44c84f2848c623b519 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 24 May 2022 03:43:58 -0500 Subject: [PATCH 28/76] Better comments and state of things --- .../historical-import.spec.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 811651ec1a2..e3cbbad299b 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -392,6 +392,12 @@ describe("MSC2716: Historical Import", () => { cy.intercept(contextUrl, async (req) => { console.log('intercepted aewfefewafaew'); return new Cypress.Promise(resolve => { + // Later, we only resolve this after we detect that the + // timeline was reset(when it goes blank) and force a sync + // to happen in the middle of all of this refresh timeline + // logic. We want to make sure the sync pagination still + // works as expected after messing the refresh timline logic + // messes with the pagination tokens. resolveReq = resolve; }).then(req.reply) }).as('contextRequestThatWillMakeNewTimeline'); @@ -415,7 +421,10 @@ describe("MSC2716: Historical Import", () => { }); // Wait for the message to show up for the logged in user - // indicating that a sync happened + // indicating that a sync happened in the middle of us + // refreshing the timeline. We want to make sure the sync + // pagination still works as expected after messing the refresh + // timline logic messes with the pagination tokens. waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); }) .then(() => { @@ -426,6 +435,7 @@ describe("MSC2716: Historical Import", () => { // Make sure the request was intercepted cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); + // TODO: Does sync pagiantion still work as expected? // Ensure historical messages are now shown cy.wrap(null).then(function() { From b45be5b0c28c8191244f1fdf321043b869a04ee0 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 00:31:51 -0500 Subject: [PATCH 29/76] More robust to failurse and user feedback --- .../historical-import.spec.ts | 68 +++++++- res/css/structures/_RoomStatusBar.scss | 2 + res/css/structures/_RoomView.scss | 2 +- src/components/structures/RoomStatusBar.tsx | 152 +++++++++++++----- src/components/structures/TimelinePanel.tsx | 2 +- src/i18n/strings/en_EN.json | 10 +- 6 files changed, 193 insertions(+), 43 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index e3cbbad299b..5a78ea16267 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -374,7 +374,7 @@ describe("MSC2716: Historical Import", () => { }); }); - it.only("Perfectly merges timelines if a sync happens while refreshig the timeline", () => { + it("Perfectly merges timelines if a sync happens while refreshing the timeline", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, @@ -435,7 +435,7 @@ describe("MSC2716: Historical Import", () => { // Make sure the request was intercepted cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); - // TODO: Does sync pagiantion still work as expected? + // TODO: Does sync pagination still work as expected? // Ensure historical messages are now shown cy.wrap(null).then(function() { @@ -449,4 +449,68 @@ describe("MSC2716: Historical Import", () => { }); }); + it.only("Timeline recovers after `/context` request to generate new timeline fails", () => { + setupRoomWithHistoricalMessagesAndMarker({ + synapse, + asMatrixClient, + virtualUserIDs + }); + + // Make the `/context` fail when we try to refresh the timeline. We want + // to make sure that we are resilient to this type of failure and can + // retry and recover. + cy.wrap(null).then(function() { + // We're using `this.markeEventId` here because it's the latest event in the room + const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; + cy.intercept(contextUrl, { statusCode: 500 }).as('contextRequestThatWillTryToMakeNewTimeline'); + }); + + // Press "Refresh timeline" + cy.get(`[data-cy="refresh-timeline-button"]`).click(); + + // Make sure the request was intercepted and thew an error + cy.wait('@contextRequestThatWillTryToMakeNewTimeline').its('response.statusCode').should('eq', 500); + + // Make sure we tell the user that an error happened + cy.get(`[data-cy="historical-import-detected-error-content"]`).should("exist"); + + // Allow the requests to succeed now + cy.wrap(null).then(function() { + // We're using `this.markeEventId` here because it's the latest event in the room + const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; + cy.intercept(contextUrl, async (req) => { + // Passthrough. We can't just omit this callback because the + // other intercept will take precedent for some reason. + req.reply(); + }).as('contextRequestThatWillMakeNewTimeline'); + }); + + // Press "Refresh timeline" again, this time the network request should succeed + cy.get(`[data-cy="refresh-timeline-button"]`).click(); + + // Make sure the request was intercepted and succeeded + cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); + + // Make sure sync pagination still works by seeing a new message show up + cy.wrap(null).then(async function() { + const {event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(this.roomId, null, { + body: `live_event after refresh`, + msgtype: "m.text", + }); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIdAfterRefresh]); + }); + + // Ensure historical messages are now shown + cy.wrap(null).then(function() { + // FIXME: Assert that they appear in the correct order + waitForEventIdsInClient([ + this.liveMessageEventIds[0], + this.liveMessageEventIds[1], + ...this.historicalEventIds, + this.liveMessageEventIds[2] + ]); + }); + }); }); diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index 8397353eb73..f29c49c0e34 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -76,6 +76,8 @@ limitations under the License. min-height: 70px; margin: 12px; padding-left: 16px; + padding-top: 8px; + padding-bottom: 8px; background-color: $header-panel-bg-color; border-radius: 4px; } diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index eba8ae8f6e8..a18201b8586 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -130,7 +130,7 @@ limitations under the License. } .mx_RoomView_statusArea_expanded { - max-height: 100px; + max-height: 140px; } .mx_RoomView_statusAreaBox { diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index b0fe075bb96..d907eacb712 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event"; import { SyncState, ISyncStateData } from "matrix-js-sdk/src/sync"; import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; +import { logger } from 'matrix-js-sdk/src/logger'; import { _t, _td } from '../../languageHandler'; import Resend from '../../Resend'; @@ -29,6 +30,8 @@ import { StaticNotificationState } from "../../stores/notifications/StaticNotifi import AccessibleButton from "../views/elements/AccessibleButton"; import InlineSpinner from "../views/elements/InlineSpinner"; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import Modal from '../../Modal'; +import BugReportDialog from '../views/dialogs/BugReportDialog'; const STATUS_BAR_HIDDEN = 0; const STATUS_BAR_EXPANDED = 1; @@ -80,6 +83,8 @@ interface IState { unsentMessages: MatrixEvent[]; isResending: boolean; timelineNeedsRefresh: boolean; + isRefreshing: boolean; + refreshError?: Error; } export default class RoomStatusBar extends React.PureComponent { @@ -95,6 +100,8 @@ export default class RoomStatusBar extends React.PureComponent { unsentMessages: getUnsentMessages(this.props.room), isResending: false, timelineNeedsRefresh: this.props.room.getTimelineNeedsRefresh(), + isRefreshing: false, + refreshError: null, }; } @@ -159,13 +166,28 @@ export default class RoomStatusBar extends React.PureComponent { dis.fire(Action.FocusSendMessageComposer); }; - private onRefreshTimelineClick = (): void => { - // Empty out the current timeline and re-request it - this.props.room.refreshLiveTimeline(); - + private onRefreshTimelineClick = async (): Promise => { this.setState({ - timelineNeedsRefresh: false, + isRefreshing: true, + refreshError: null, }); + try { + // Empty out the current timeline and re-request it + await this.props.room.refreshLiveTimeline(); + + this.setState({ + timelineNeedsRefresh: false, + }); + } catch(err) { + logger.error('Error while refresing the timeline:', err); + this.setState({ + refreshError: err, + }); + } finally { + this.setState({ + isRefreshing: false, + }); + } }; private onRoomLocalEchoUpdated = (ev: MatrixEvent, room: Room) => { @@ -314,6 +336,94 @@ export default class RoomStatusBar extends React.PureComponent { ; } + private getRefreshTimelineContent(): JSX.Element { + let buttonRow = <> + + { _t("Refresh timeline") } + + ; + if (this.state.isRefreshing) { + buttonRow = <> + + { /* span for css */ } + { _t("Refreshing") } + ; + } + + let errorContent; + if (this.state.refreshError) { + let errorTextContent; + let submitDebugLogsTextContent; + if (this.state.refreshError.name === "ConnectionError") { + errorTextContent = <> + { _t("A network error occurred while trying to refresh the timeline. " + + "Your homeserver might be down or was just a temporary problem with your " + + "internet connection.") } + ; + } else { + errorTextContent = <> + { _t("An error occurred while trying to refresh the timeline.") } + ; + + // We only give the option to submit logs for actual errors. Not network problem. + submitDebugLogsTextContent = <> + { _t("Please submit debug logs to help us " + + "track down the problem.", {}, { + debugLogsLink: sub => ( + { sub } + ), + }) } + ; + } + + errorContent = <> +
+
+ { errorTextContent } + { submitDebugLogsTextContent } +
+ ; + } + + return ( +
+
+
+ +
+
+
+ { _t("History import detected.") } +
+
+ { _t("History was just imported somewhere in the room. " + + "In order to see the historical messages, refresh your timeline.") } +
+ { errorContent } +
+
+ { buttonRow } +
+
+
+ ); + } + + private onBugReport = (): void => { + Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, { + error: this.state.refreshError, + initialText: 'Error occured while refreshing the timeline', + }); + }; + public render(): JSX.Element { if (this.shouldShowConnectionError()) { return ( @@ -344,37 +454,7 @@ export default class RoomStatusBar extends React.PureComponent { } if (this.state.timelineNeedsRefresh) { - return ( -
-
-
- -
-
-
- { _t("History import detected.") } -
-
- { _t("History was just imported somewhere in the room. " + - "In order to see the historical messages, refresh your timeline.") } -
-
-
- - { _t("Refresh timeline") } - -
-
-
- ); + return this.getRefreshTimelineContent(); } return null; diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 9574a42359a..d1865e48dc4 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -717,7 +717,7 @@ class TimelinePanel extends React.Component { }; private onRoomTimelineReset = (room: Room, timelineSet: EventTimelineSet): void => { - debuglog( + console.log( `onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} ` + `skippingBecauseAtBottom=${this.canResetTimeline()}`, ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 34bee793587..ebfacb8fc6b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -3091,11 +3091,15 @@ "Delete all": "Delete all", "Retry all": "Retry all", "You can select all or individual messages to retry or delete": "You can select all or individual messages to retry or delete", - "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", - "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", + "Refresh timeline": "Refresh timeline", + "Refreshing": "Refreshing", + "A network error occurred while trying to refresh the timeline. Your homeserver might be down or was just a temporary problem with your internet connection.": "A network error occurred while trying to refresh the timeline. Your homeserver might be down or was just a temporary problem with your internet connection.", + "An error occurred while trying to refresh the timeline.": "An error occurred while trying to refresh the timeline.", + "Please submit debug logs to help us track down the problem.": "Please submit debug logs to help us track down the problem.", "History import detected.": "History import detected.", "History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.": "History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.", - "Refresh timeline": "Refresh timeline", + "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", + "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", "You seem to be in a call, are you sure you want to quit?": "You seem to be in a call, are you sure you want to quit?", "Search failed": "Search failed", From c14cc18642ab269dff75867fceb0bcaf9571c334 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 00:46:14 -0500 Subject: [PATCH 30/76] All Cypress tests passing --- .../historical-import.spec.ts | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 5a78ea16267..4a3ed707495 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -374,23 +374,23 @@ describe("MSC2716: Historical Import", () => { }); }); - it("Perfectly merges timelines if a sync happens while refreshing the timeline", () => { + it("Perfectly merges timelines if a sync finishes while refreshing the timeline", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, virtualUserIDs }); - // 1. Pause the /context from the `getEventTimeline` that happens - // 1. Make sure a sync happens - // 1. Then unpause - + // 1. Pause the `/context` request from `getEventTimeline` that happens + // when we refresh the timeline. + // 2. Make sure a sync happens in the middle (simulate a sync racing + // with us). + // 3. Then resume the `/context` request. let resolveReq; cy.wrap(null).then(function() { // We're using `this.markeEventId` here because it's the latest event in the room const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; cy.intercept(contextUrl, async (req) => { - console.log('intercepted aewfefewafaew'); return new Cypress.Promise(resolve => { // Later, we only resolve this after we detect that the // timeline was reset(when it goes blank) and force a sync @@ -406,13 +406,8 @@ describe("MSC2716: Historical Import", () => { // Press "Refresh timeline" cy.get(`[data-cy="refresh-timeline-button"]`).click(); + // Wait for the timeline to go blank (meaning it was reset). cy.get('[data-cy="message-list"] [data-event-id]') - // Wait for the timeline to go blank (meaning it was reset). - // - // FIXME: This only exists with the extra `RoomEvent.TimelineRefresh` to replace - // the timeline after `resetLiveTimeline(null, null)`. This might be - // fine though as it gives feedback to the user after pressing the - // refresh timeline button. .should('not.exist') .then(async function() { const {event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage(this.roomId, null, { @@ -426,16 +421,28 @@ describe("MSC2716: Historical Import", () => { // pagination still works as expected after messing the refresh // timline logic messes with the pagination tokens. waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); + + cy.wrap(eventIdWhileRefrshingTimeline).as('eventIdWhileRefrshingTimeline'); }) .then(() => { - console.log('trying to resolveReq'); resolveReq(); }); // Make sure the request was intercepted cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); - // TODO: Does sync pagination still work as expected? + // Make sure sync pagination still works by seeing a new message show up + cy.wrap(null).then(async function() { + const {event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(this.roomId, null, { + body: `live_event after refresh`, + msgtype: "m.text", + }); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIdAfterRefresh]); + + cy.wrap(eventIdAfterRefresh).as('eventIdAfterRefresh'); + }); // Ensure historical messages are now shown cy.wrap(null).then(function() { @@ -444,12 +451,14 @@ describe("MSC2716: Historical Import", () => { this.liveMessageEventIds[0], this.liveMessageEventIds[1], ...this.historicalEventIds, - this.liveMessageEventIds[2] + this.liveMessageEventIds[2], + this.eventIdWhileRefrshingTimeline, + this.eventIdAfterRefresh, ]); }); }); - it.only("Timeline recovers after `/context` request to generate new timeline fails", () => { + it("Timeline recovers after `/context` request to generate new timeline fails", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, From 52866414213b8feafd19ce1b8beefd702f288fed Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 00:56:04 -0500 Subject: [PATCH 31/76] Some test cleanup --- .../historical-import.spec.ts | 114 +++++++++--------- 1 file changed, 54 insertions(+), 60 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 4a3ed707495..1e57a287a93 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -186,54 +186,52 @@ function setupRoomWithHistoricalMessagesAndMarker({ // As the application service, create the room so it is the room creator // and proper power_levels to send MSC2716 events. Then join the logged // in user to the room. - cy.wrap(true) - .then(async () => { - const resp = await asMatrixClient.createRoom({ - // FIXME: I can't use Preset.PublicChat because Cypress doesn't - // understand Typescript to import it - preset: "public_chat" as Preset, - name: "test-msc2716", - room_version: "org.matrix.msc2716v3", - }); - cy.wrap(resp.room_id) .as('roomId'); + cy.wrap(null).then(async function() { + const resp = await asMatrixClient.createRoom({ + // FIXME: I can't use Preset.PublicChat because Cypress doesn't + // understand Typescript to import it + preset: "public_chat" as Preset, + name: "test-msc2716", + room_version: "org.matrix.msc2716v3", }); + cy.wrap(resp.room_id) .as('roomId'); + }); - cy.get("@roomId").then(roomId => { + cy.wrap(null).then(function() { // Join the logged in user to the room - cy.joinRoom(roomId); + cy.joinRoom(this.roomId); // Then visit the room - cy.visit("/#/room/" + roomId); + cy.visit("/#/room/" + this.roomId); }); // Send 3 live messages as the application service. // Then make sure they are visible from the perspective of the logged in user. - cy.get("@roomId") - .then(async (roomId) => { - // Send 3 messages and wait for them to be sent - const liveMessageEventIds = []; - for (let i = 0; i < 3; i++) { - // Send the messages sequentially waiting for each request - // to finish before we move onto the next so we don't end up - // with a pile of live messages at the same depth. This - // gives more of an expected order at the end. - const { event_id } = await asMatrixClient.sendMessage(roomId, null, { - body: `live_event${i}`, - msgtype: "m.text", - }); - liveMessageEventIds.push(event_id); - } + cy.wrap(null).then(async function() { + // Send 3 messages and wait for them to be sent + const liveMessageEventIds = []; + for (let i = 0; i < 3; i++) { + // Send the messages sequentially waiting for each request + // to finish before we move onto the next so we don't end up + // with a pile of live messages at the same depth. This + // gives more of an expected order at the end. + const { event_id } = await asMatrixClient.sendMessage(this.roomId, null, { + body: `live_event${i}`, + msgtype: "m.text", + }); + liveMessageEventIds.push(event_id); + } - // Make this available for later chains - cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); + // Make this available for later chains + cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); - // Wait for the messages to show up for the logged in user - waitForEventIdsInClient(liveMessageEventIds); + // Wait for the messages to show up for the logged in user + waitForEventIdsInClient(liveMessageEventIds); - cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); - }); + cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); + }); - cy.then(function() { + cy.wrap(null).then(function() { // Make sure the right thing was yielded expect(this.liveMessageEventIds).to.have.lengthOf(3); @@ -264,38 +262,34 @@ function setupRoomWithHistoricalMessagesAndMarker({ }); }); - cy.get("@roomId") - .then(async function(roomId) { - // Ensure historical messages do not appear yet. We can do this by - // sending another live event and wait for it to sync back to us. If - // we're able to see eventIdAfterHistoricalImport without any the - // historicalEventIds/historicalStateEventIds in between, we're - // probably safe to assume it won't sync. - const {event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { - body: `live_event after historical import`, - msgtype: "m.text", - }); - - // Wait for the message to show up for the logged in user - waitForEventIdsInClient([eventIdAfterHistoricalImport]); + cy.wrap(null).then(async function() { + // Ensure historical messages do not appear yet. We can do this by + // sending another live event and wait for it to sync back to us. If + // we're able to see eventIdAfterHistoricalImport without any the + // historicalEventIds/historicalStateEventIds in between, we're + // probably safe to assume it won't sync. + const {event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(this.roomId, null, { + body: `live_event after historical import`, + msgtype: "m.text", }); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIdAfterHistoricalImport]); + }); // Send the marker event which lets the client know there are // some historical messages back at the given insertion event. - cy.get("@roomId") - .then(async function(roomId) { - assert.exists(this.baseInsertionEventId); + cy.wrap(null).then(async function() { + const {event_id: markeEventId } = await asMatrixClient.sendStateEvent(this.roomId, 'org.matrix.msc2716.marker', { + "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, + }, Cypress._.uniqueId("marker_state_key_")); - const {event_id: markeEventId } = await asMatrixClient.sendStateEvent(roomId, 'org.matrix.msc2716.marker', { - "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, - }, Cypress._.uniqueId("marker_state_key_")); + cy.wrap(markeEventId).as('markeEventId'); - cy.wrap(markeEventId).as('markeEventId'); - - // Wait for the message to show up for the logged in user - waitForEventIdsInClient([markeEventId]); - }); + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([markeEventId]); + }); // Ensure the "History import detected" notice is shown cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); From 7848501b90ce1d326fc8dd4f779aec274f1dc285 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 02:11:53 -0500 Subject: [PATCH 32/76] Fix some lints --- .../historical-import.spec.ts | 126 ++++++++++-------- cypress/support/bot.ts | 3 +- cypress/support/client.ts | 2 +- src/components/structures/RoomStatusBar.tsx | 4 +- 4 files changed, 73 insertions(+), 62 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 1e57a287a93..604a274b60a 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -20,33 +20,31 @@ import { SynapseInstance } from "../../plugins/synapsedocker"; import { MatrixClient } from "../../global"; import type { UserCredentials } from "../../support/login"; import { SettingLevel } from "../../../src/settings/SettingLevel"; -import type { Room } from "matrix-js-sdk/src/models/room"; import type { Preset } from "matrix-js-sdk/src/@types/partials"; -import * as cypress from "cypress"; function createJoinStateEventsForBatchSendRequest( virtualUserIDs: string[], - insertTimestamp: number, + insertTimestamp: number, ) { return virtualUserIDs.map((virtualUserID, index) => { return { "content": { "displayname": `some-display-name-for-${virtualUserID}`, - "membership": "join" + "membership": "join", }, "origin_server_ts": insertTimestamp + index, "sender": virtualUserID, "state_key": virtualUserID, - "type": "m.room.member" - } + "type": "m.room.member", + }; }); } let batchCount = 0; function createMessageEventsForBatchSendRequest( virtualUserIDs: string[], - insertTimestamp: number, - count: number, + insertTimestamp: number, + count: number, ) { const messageEvents = [...Array(count).keys()].map((i) => { const virtualUserID = virtualUserIDs[i % virtualUserIDs.length]; @@ -55,11 +53,11 @@ function createMessageEventsForBatchSendRequest( "content": { "body": `Historical ${i} (batch=${batchCount})`, "msgtype": "m.text", - "org.matrix.msc2716.historical": true + "org.matrix.msc2716.historical": true, }, "origin_server_ts": insertTimestamp + i, "sender": virtualUserID, - "type": "m.room.message" + "type": "m.room.message", }; }); @@ -105,14 +103,15 @@ function batchSend({ batchId, payload, }: { - synapse: SynapseInstance, - accessToken: string, - roomId: string, - prevEventId: string, - batchId: string | null, - payload: { state_events_at_start?: any[], events: any[] }, + synapse: SynapseInstance; + accessToken: string; + roomId: string; + prevEventId: string; + batchId: string | null; + payload: { state_events_at_start?: any[], events: any[] }; }): Cypress.Chainable> { - const batchSendUrl = new URL(`${synapse.baseUrl}/_matrix/client/unstable/org.matrix.msc2716/rooms/${roomId}/batch_send`); + const prefix = '/_matrix/client/unstable/org.matrix.msc2716'; + const batchSendUrl = new URL(`${synapse.baseUrl}${prefix}/rooms/${roomId}/batch_send`); batchSendUrl.searchParams.set('prev_event_id', prevEventId); if (batchId !== null) { batchSendUrl.searchParams.set('batch_id', batchId); @@ -131,7 +130,7 @@ function batchSend({ function ensureVirtualUsersRegistered( synapse: SynapseInstance, applicationServiceToken: string, - virtualUserIds: string[] + virtualUserIds: string[], ) { const url = `${synapse.baseUrl}/_matrix/client/r0/register`; @@ -147,17 +146,17 @@ function ensureVirtualUsersRegistered( method: "POST", body: { type: "m.login.application_service", - username: virtualUserLocalpart + username: virtualUserLocalpart, }, headers: { - 'Authorization': `Bearer ${applicationServiceToken}` + 'Authorization': `Bearer ${applicationServiceToken}`, }, // We'll handle the errors ourselves below failOnStatusCode: false, }) .then((res) => { // Registration success - if(res.status === 200) { + if (res.status === 200) { return; } @@ -169,7 +168,7 @@ function ensureVirtualUsersRegistered( } const errorMessage = res.body.error; - throw new Error(`ensureVirtualUserRegistered failed to register: (${errcode}) ${errorMessage}`) + throw new Error(`ensureVirtualUserRegistered failed to register: (${errcode}) ${errorMessage}`); }); }); } @@ -177,11 +176,11 @@ function ensureVirtualUsersRegistered( function setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, - virtualUserIDs + virtualUserIDs, }: { - synapse: SynapseInstance, - asMatrixClient: MatrixClient, - virtualUserIDs: string[] + synapse: SynapseInstance; + asMatrixClient: MatrixClient; + virtualUserIDs: string[]; }) { // As the application service, create the room so it is the room creator // and proper power_levels to send MSC2716 events. Then join the logged @@ -215,11 +214,11 @@ function setupRoomWithHistoricalMessagesAndMarker({ // to finish before we move onto the next so we don't end up // with a pile of live messages at the same depth. This // gives more of an expected order at the end. - const { event_id } = await asMatrixClient.sendMessage(this.roomId, null, { + const { event_id: eventId } = await asMatrixClient.sendMessage(this.roomId, null, { body: `live_event${i}`, msgtype: "m.text", }); - liveMessageEventIds.push(event_id); + liveMessageEventIds.push(eventId); } // Make this available for later chains @@ -268,22 +267,25 @@ function setupRoomWithHistoricalMessagesAndMarker({ // we're able to see eventIdAfterHistoricalImport without any the // historicalEventIds/historicalStateEventIds in between, we're // probably safe to assume it won't sync. - const {event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(this.roomId, null, { + const { event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(this.roomId, null, { body: `live_event after historical import`, msgtype: "m.text", }); - + // Wait for the message to show up for the logged in user waitForEventIdsInClient([eventIdAfterHistoricalImport]); }); - // Send the marker event which lets the client know there are // some historical messages back at the given insertion event. cy.wrap(null).then(async function() { - const {event_id: markeEventId } = await asMatrixClient.sendStateEvent(this.roomId, 'org.matrix.msc2716.marker', { - "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, - }, Cypress._.uniqueId("marker_state_key_")); + const { event_id: markeEventId } = await asMatrixClient.sendStateEvent( + this.roomId, + 'org.matrix.msc2716.marker', { + "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, + }, + Cypress._.uniqueId("marker_state_key_"), + ); cy.wrap(markeEventId).as('markeEventId'); @@ -298,7 +300,6 @@ function setupRoomWithHistoricalMessagesAndMarker({ describe("MSC2716: Historical Import", () => { let synapse: SynapseInstance; let asMatrixClient: MatrixClient; - let loggedInUserCreds: UserCredentials; const virtualUserIDs = ['@maria-01234:localhost']; // This corresponds to the application service registration defined in the @@ -315,9 +316,8 @@ describe("MSC2716: Historical Import", () => { synapse = data; // This is the person we're logged in as - cy.initTestUser(synapse, "Grace").then(userCreds => { - loggedInUserCreds = userCreds; - }); + cy.initTestUser(synapse, "Grace"); + // After the page is loaded from initializing the logged in user so // the mxSettingsStore is available cy.window().then(win => { @@ -350,7 +350,7 @@ describe("MSC2716: Historical Import", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, - virtualUserIDs + virtualUserIDs, }); // Press "Refresh timeline" @@ -363,7 +363,7 @@ describe("MSC2716: Historical Import", () => { this.liveMessageEventIds[0], this.liveMessageEventIds[1], ...this.historicalEventIds, - this.liveMessageEventIds[2] + this.liveMessageEventIds[2], ]); }); }); @@ -372,7 +372,7 @@ describe("MSC2716: Historical Import", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, - virtualUserIDs + virtualUserIDs, }); // 1. Pause the `/context` request from `getEventTimeline` that happens @@ -383,7 +383,9 @@ describe("MSC2716: Historical Import", () => { let resolveReq; cy.wrap(null).then(function() { // We're using `this.markeEventId` here because it's the latest event in the room - const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; + const prefix = '/_matrix/client/r0'; + const path = `/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}`; + const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, async (req) => { return new Cypress.Promise(resolve => { // Later, we only resolve this after we detect that the @@ -393,7 +395,7 @@ describe("MSC2716: Historical Import", () => { // works as expected after messing the refresh timline logic // messes with the pagination tokens. resolveReq = resolve; - }).then(req.reply) + }).then(req.reply); }).as('contextRequestThatWillMakeNewTimeline'); }); @@ -404,11 +406,14 @@ describe("MSC2716: Historical Import", () => { cy.get('[data-cy="message-list"] [data-event-id]') .should('not.exist') .then(async function() { - const {event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage(this.roomId, null, { - body: `live_event while trying to refresh timeline`, - msgtype: "m.text", - }); - + const { event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage( + this.roomId, + null, { + body: `live_event while trying to refresh timeline`, + msgtype: "m.text", + }, + ); + // Wait for the message to show up for the logged in user // indicating that a sync happened in the middle of us // refreshing the timeline. We want to make sure the sync @@ -427,7 +432,7 @@ describe("MSC2716: Historical Import", () => { // Make sure sync pagination still works by seeing a new message show up cy.wrap(null).then(async function() { - const {event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(this.roomId, null, { + const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(this.roomId, null, { body: `live_event after refresh`, msgtype: "m.text", }); @@ -456,7 +461,7 @@ describe("MSC2716: Historical Import", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, - virtualUserIDs + virtualUserIDs, }); // Make the `/context` fail when we try to refresh the timeline. We want @@ -464,7 +469,9 @@ describe("MSC2716: Historical Import", () => { // retry and recover. cy.wrap(null).then(function() { // We're using `this.markeEventId` here because it's the latest event in the room - const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; + const prefix = '/_matrix/client/r0'; + const path = `/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}`; + const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, { statusCode: 500 }).as('contextRequestThatWillTryToMakeNewTimeline'); }); @@ -480,7 +487,9 @@ describe("MSC2716: Historical Import", () => { // Allow the requests to succeed now cy.wrap(null).then(function() { // We're using `this.markeEventId` here because it's the latest event in the room - const contextUrl = `${synapse.baseUrl}/_matrix/client/r0/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}*`; + const prefix = '/_matrix/client/r0'; + const path = `/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}`; + const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, async (req) => { // Passthrough. We can't just omit this callback because the // other intercept will take precedent for some reason. @@ -496,10 +505,13 @@ describe("MSC2716: Historical Import", () => { // Make sure sync pagination still works by seeing a new message show up cy.wrap(null).then(async function() { - const {event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(this.roomId, null, { - body: `live_event after refresh`, - msgtype: "m.text", - }); + const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage( + this.roomId, + null, { + body: `live_event after refresh`, + msgtype: "m.text", + }, + ); // Wait for the message to show up for the logged in user waitForEventIdsInClient([eventIdAfterRefresh]); @@ -512,7 +524,7 @@ describe("MSC2716: Historical Import", () => { this.liveMessageEventIds[0], this.liveMessageEventIds[1], ...this.historicalEventIds, - this.liveMessageEventIds[2] + this.liveMessageEventIds[2], ]); }); }); diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts index 4b839d1d46c..cd421310609 100644 --- a/cypress/support/bot.ts +++ b/cypress/support/bot.ts @@ -46,10 +46,9 @@ declare global { } } - Cypress.Commands.add("newMatrixClient", ( synapse: SynapseInstance, - { userId, accessToken, deviceId }: INewMatrixClientOptions + { userId, accessToken, deviceId }: INewMatrixClientOptions, ): Chainable => { return cy.window({ log: false }).then(win => { const cli = new win.matrixcs.MatrixClient({ diff --git a/cypress/support/client.ts b/cypress/support/client.ts index 593f8b96e84..2245b3263f0 100644 --- a/cypress/support/client.ts +++ b/cypress/support/client.ts @@ -88,7 +88,7 @@ Cypress.Commands.add("joinRoom", (roomId: string, opts?: IJoinRoomOpts): Chainab }); // Wait for the room to be available locally - return cy.waitForRoom(roomId) + return cy.waitForRoom(roomId); }); Cypress.Commands.add("waitForRoom", (roomId: string): Chainable => { diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index d907eacb712..3b6973fb9e1 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -178,7 +178,7 @@ export default class RoomStatusBar extends React.PureComponent { this.setState({ timelineNeedsRefresh: false, }); - } catch(err) { + } catch (err) { logger.error('Error while refresing the timeline:', err); this.setState({ refreshError: err, @@ -381,7 +381,7 @@ export default class RoomStatusBar extends React.PureComponent { } errorContent = <> -
+
{ errorTextContent } { submitDebugLogsTextContent } From 47ecf3b8a4fbd2711c6c5a1726dd6ba0680fe2e2 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 02:16:58 -0500 Subject: [PATCH 33/76] Remove unused import --- .../x-msc2716-historical-import/historical-import.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 604a274b60a..69d5b32acdf 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -18,7 +18,6 @@ limitations under the License. import { SynapseInstance } from "../../plugins/synapsedocker"; import { MatrixClient } from "../../global"; -import type { UserCredentials } from "../../support/login"; import { SettingLevel } from "../../../src/settings/SettingLevel"; import type { Preset } from "matrix-js-sdk/src/@types/partials"; From 2ef47f9c46b21c017f4e6ec08f7f39e49a432e45 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 19:32:02 -0500 Subject: [PATCH 34/76] Fix unexpected 'this' lints See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r881316177 --- .../historical-import.spec.ts | 194 +++++++++++------- cypress/support/index.ts | 1 + cypress/support/util.ts | 82 ++++++++ 3 files changed, 200 insertions(+), 77 deletions(-) create mode 100644 cypress/support/util.ts diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 69d5b32acdf..313deec9e02 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -195,17 +195,17 @@ function setupRoomWithHistoricalMessagesAndMarker({ cy.wrap(resp.room_id) .as('roomId'); }); - cy.wrap(null).then(function() { + cy.get("@roomId").then((roomId) => { // Join the logged in user to the room - cy.joinRoom(this.roomId); + cy.joinRoom(roomId); // Then visit the room - cy.visit("/#/room/" + this.roomId); + cy.visit("/#/room/" + roomId); }); // Send 3 live messages as the application service. // Then make sure they are visible from the perspective of the logged in user. - cy.wrap(null).then(async function() { + cy.get("@roomId").then(async (roomId) => { // Send 3 messages and wait for them to be sent const liveMessageEventIds = []; for (let i = 0; i < 3; i++) { @@ -213,7 +213,7 @@ function setupRoomWithHistoricalMessagesAndMarker({ // to finish before we move onto the next so we don't end up // with a pile of live messages at the same depth. This // gives more of an expected order at the end. - const { event_id: eventId } = await asMatrixClient.sendMessage(this.roomId, null, { + const { event_id: eventId } = await asMatrixClient.sendMessage(roomId, null, { body: `live_event${i}`, msgtype: "m.text", }); @@ -225,21 +225,22 @@ function setupRoomWithHistoricalMessagesAndMarker({ // Wait for the messages to show up for the logged in user waitForEventIdsInClient(liveMessageEventIds); - - cy.wrap(liveMessageEventIds).as('liveMessageEventIds'); }); - cy.wrap(null).then(function() { + cy.all([ + cy.get("@roomId"), + cy.get("@liveMessageEventIds"), + ]).then(([roomId, liveMessageEventIds]) => { // Make sure the right thing was yielded - expect(this.liveMessageEventIds).to.have.lengthOf(3); + expect(liveMessageEventIds).to.have.lengthOf(3); // Send a batch of historical messages const insertTimestamp = Date.now(); batchSend({ synapse, accessToken: asMatrixClient.getAccessToken(), - roomId: this.roomId, - prevEventId: this.liveMessageEventIds[1], + roomId: roomId, + prevEventId: liveMessageEventIds[1], batchId: null, payload: { state_events_at_start: createJoinStateEventsForBatchSendRequest(virtualUserIDs, insertTimestamp), @@ -249,24 +250,23 @@ function setupRoomWithHistoricalMessagesAndMarker({ 3, ), }, - }) - .then((res) => { - assert.exists(res.body.event_ids); - assert.exists(res.body.base_insertion_event_id); + }).then((res) => { + assert.exists(res.body.event_ids); + assert.exists(res.body.base_insertion_event_id); - // Make this available for later chains - cy.wrap(res.body.event_ids).as('historicalEventIds'); - cy.wrap(res.body.base_insertion_event_id).as('baseInsertionEventId'); - }); + // Make this available for later chains + cy.wrap(res.body.event_ids).as('historicalEventIds'); + cy.wrap(res.body.base_insertion_event_id).as('baseInsertionEventId'); + }); }); - cy.wrap(null).then(async function() { + cy.get("@roomId").then(async (roomId) => { // Ensure historical messages do not appear yet. We can do this by // sending another live event and wait for it to sync back to us. If // we're able to see eventIdAfterHistoricalImport without any the // historicalEventIds/historicalStateEventIds in between, we're // probably safe to assume it won't sync. - const { event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(this.roomId, null, { + const { event_id: eventIdAfterHistoricalImport } = await asMatrixClient.sendMessage(roomId, null, { body: `live_event after historical import`, msgtype: "m.text", }); @@ -277,11 +277,14 @@ function setupRoomWithHistoricalMessagesAndMarker({ // Send the marker event which lets the client know there are // some historical messages back at the given insertion event. - cy.wrap(null).then(async function() { + cy.all([ + cy.get("@roomId"), + cy.get("@baseInsertionEventId"), + ]).then(async ([roomId, baseInsertionEventId]) => { const { event_id: markeEventId } = await asMatrixClient.sendStateEvent( - this.roomId, + roomId, 'org.matrix.msc2716.marker', { - "org.matrix.msc2716.marker.insertion": this.baseInsertionEventId, + "org.matrix.msc2716.marker.insertion": baseInsertionEventId, }, Cypress._.uniqueId("marker_state_key_"), ); @@ -356,13 +359,16 @@ describe("MSC2716: Historical Import", () => { cy.get(`[data-cy="refresh-timeline-button"]`).click(); // Ensure historical messages are now shown - cy.wrap(null).then(function() { + cy.all([ + cy.get("@liveMessageEventIds"), + cy.get("@historicalEventIds"), + ]).then(([liveMessageEventIds, historicalEventIds]) => { // FIXME: Assert that they appear in the correct order waitForEventIdsInClient([ - this.liveMessageEventIds[0], - this.liveMessageEventIds[1], - ...this.historicalEventIds, - this.liveMessageEventIds[2], + liveMessageEventIds[0], + liveMessageEventIds[1], + ...historicalEventIds, + liveMessageEventIds[2], ]); }); }); @@ -376,14 +382,17 @@ describe("MSC2716: Historical Import", () => { // 1. Pause the `/context` request from `getEventTimeline` that happens // when we refresh the timeline. - // 2. Make sure a sync happens in the middle (simulate a sync racing + // 2. Make sure a /sync happens in the middle (simulate a sync racing // with us). // 3. Then resume the `/context` request. let resolveReq; - cy.wrap(null).then(function() { - // We're using `this.markeEventId` here because it's the latest event in the room + cy.all([ + cy.get("@roomId"), + cy.get("@markeEventId"), + ]).then(([roomId, markeEventId]) => { + // We're using `markeEventId` here because it's the latest event in the room const prefix = '/_matrix/client/r0'; - const path = `/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}`; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, async (req) => { return new Cypress.Promise(resolve => { @@ -401,37 +410,41 @@ describe("MSC2716: Historical Import", () => { // Press "Refresh timeline" cy.get(`[data-cy="refresh-timeline-button"]`).click(); - // Wait for the timeline to go blank (meaning it was reset). + // Wait for the timeline to go blank (meaning it was reset) + // and in the middle of the refrsehing timeline function. cy.get('[data-cy="message-list"] [data-event-id]') - .should('not.exist') - .then(async function() { - const { event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage( - this.roomId, - null, { - body: `live_event while trying to refresh timeline`, - msgtype: "m.text", - }, - ); - - // Wait for the message to show up for the logged in user - // indicating that a sync happened in the middle of us - // refreshing the timeline. We want to make sure the sync - // pagination still works as expected after messing the refresh - // timline logic messes with the pagination tokens. - waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); - - cy.wrap(eventIdWhileRefrshingTimeline).as('eventIdWhileRefrshingTimeline'); - }) - .then(() => { - resolveReq(); - }); + .should('not.exist'); - // Make sure the request was intercepted + // Then make a `/sync` happen by sending a message and seeing that it + // shows up (simulate a /sync naturally racing with us). + cy.get("@roomId").then(async (roomId) => { + const { event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage( + roomId, + null, { + body: `live_event while trying to refresh timeline`, + msgtype: "m.text", + }, + ); + + // Wait for the message to show up for the logged in user + // indicating that a sync happened in the middle of us + // refreshing the timeline. We want to make sure the sync + // pagination still works as expected after messing the refresh + // timline logic messes with the pagination tokens. + waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); + + cy.wrap(eventIdWhileRefrshingTimeline).as('eventIdWhileRefrshingTimeline'); + }).then(() => { + // Now we can resume the `/context` request + resolveReq(); + }); + + // Make sure the `/context` request was intercepted cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); // Make sure sync pagination still works by seeing a new message show up - cy.wrap(null).then(async function() { - const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(this.roomId, null, { + cy.get("@roomId").then(async (roomId) => { + const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(roomId, null, { body: `live_event after refresh`, msgtype: "m.text", }); @@ -443,15 +456,25 @@ describe("MSC2716: Historical Import", () => { }); // Ensure historical messages are now shown - cy.wrap(null).then(function() { + cy.all([ + cy.get("@liveMessageEventIds"), + cy.get("@historicalEventIds"), + cy.get("@eventIdWhileRefrshingTimeline"), + cy.get("@eventIdAfterRefresh"), + ]).then(async ([ + liveMessageEventIds, + historicalEventIds, + eventIdWhileRefrshingTimeline, + eventIdAfterRefresh, + ]) => { // FIXME: Assert that they appear in the correct order waitForEventIdsInClient([ - this.liveMessageEventIds[0], - this.liveMessageEventIds[1], - ...this.historicalEventIds, - this.liveMessageEventIds[2], - this.eventIdWhileRefrshingTimeline, - this.eventIdAfterRefresh, + liveMessageEventIds[0], + liveMessageEventIds[1], + ...historicalEventIds, + liveMessageEventIds[2], + eventIdWhileRefrshingTimeline, + eventIdAfterRefresh, ]); }); }); @@ -466,10 +489,13 @@ describe("MSC2716: Historical Import", () => { // Make the `/context` fail when we try to refresh the timeline. We want // to make sure that we are resilient to this type of failure and can // retry and recover. - cy.wrap(null).then(function() { + cy.all([ + cy.get("@roomId"), + cy.get("@markeEventId"), + ]).then(async ([roomId, markeEventId]) => { // We're using `this.markeEventId` here because it's the latest event in the room const prefix = '/_matrix/client/r0'; - const path = `/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}`; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, { statusCode: 500 }).as('contextRequestThatWillTryToMakeNewTimeline'); }); @@ -484,10 +510,13 @@ describe("MSC2716: Historical Import", () => { cy.get(`[data-cy="historical-import-detected-error-content"]`).should("exist"); // Allow the requests to succeed now - cy.wrap(null).then(function() { + cy.all([ + cy.get("@roomId"), + cy.get("@markeEventId"), + ]).then(async ([roomId, markeEventId]) => { // We're using `this.markeEventId` here because it's the latest event in the room const prefix = '/_matrix/client/r0'; - const path = `/rooms/${encodeURIComponent(this.roomId)}/context/${encodeURIComponent(this.markeEventId)}`; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, async (req) => { // Passthrough. We can't just omit this callback because the @@ -503,9 +532,9 @@ describe("MSC2716: Historical Import", () => { cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); // Make sure sync pagination still works by seeing a new message show up - cy.wrap(null).then(async function() { + cy.get("@roomId").then(async (roomId) => { const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage( - this.roomId, + roomId, null, { body: `live_event after refresh`, msgtype: "m.text", @@ -514,16 +543,27 @@ describe("MSC2716: Historical Import", () => { // Wait for the message to show up for the logged in user waitForEventIdsInClient([eventIdAfterRefresh]); + + cy.wrap(eventIdAfterRefresh).as('eventIdAfterRefresh'); }); // Ensure historical messages are now shown - cy.wrap(null).then(function() { + cy.all([ + cy.get("@liveMessageEventIds"), + cy.get("@historicalEventIds"), + cy.get("@eventIdAfterRefresh"), + ]).then(async ([ + liveMessageEventIds, + historicalEventIds, + eventIdAfterRefresh, + ]) => { // FIXME: Assert that they appear in the correct order waitForEventIdsInClient([ - this.liveMessageEventIds[0], - this.liveMessageEventIds[1], - ...this.historicalEventIds, - this.liveMessageEventIds[2], + liveMessageEventIds[0], + liveMessageEventIds[1], + ...historicalEventIds, + liveMessageEventIds[2], + eventIdAfterRefresh, ]); }); }); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index dd8e5cab991..54c1704e110 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -24,3 +24,4 @@ import "./login"; import "./client"; import "./settings"; import "./bot"; +import "./util"; diff --git a/cypress/support/util.ts b/cypress/support/util.ts new file mode 100644 index 00000000000..e8f48b4bcc1 --- /dev/null +++ b/cypress/support/util.ts @@ -0,0 +1,82 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/// + +// @see https://github.com/cypress-io/cypress/issues/915#issuecomment-475862672 +// Modified due to changes to `cy.queue` https://github.com/cypress-io/cypress/pull/17448 +// Note: this DOES NOT run Promises in parallel like `Promise.all` due to the nature +// of Cypress promise-like objects and command queue. This only makes it convenient to use the same +// API but runs the commands sequentially. + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + type ChainableValue = T extends Cypress.Chainable ? V : T; + + interface cy { + all( + commands: T + ): Cypress.Chainable<{ [P in keyof T]: ChainableValue }>; + queue: any; + } + + interface Chainable { + chainerId: string; + } + } +} + +const chainStart = Symbol("chainStart"); + +/** + * @description Returns a single Chainable that resolves when all of the Chainables pass. + * @param {Cypress.Chainable[]} commands - List of Cypress.Chainable to resolve. + * @returns {Cypress.Chainable} Cypress when all Chainables are resolved. + */ +cy.all = function all(commands): Cypress.Chainable { + const chain = cy.wrap(null, { log: false }); + const stopCommand = Cypress._.find(cy.queue.get(), { + attributes: { chainerId: chain.chainerId }, + }); + const startCommand = Cypress._.find(cy.queue.get(), { + attributes: { chainerId: commands[0].chainerId }, + }); + const p = chain.then(() => { + return cy.wrap( + // @see https://lodash.com/docs/4.17.15#lodash + Cypress._(commands) + .map(cmd => { + return cmd[chainStart] + ? cmd[chainStart].attributes + : Cypress._.find(cy.queue.get(), { + attributes: { chainerId: cmd.chainerId }, + }).attributes; + }) + .concat(stopCommand.attributes) + .slice(1) + .map(cmd => { + return cmd.prev.get("subject"); + }) + .value(), + ); + }); + p[chainStart] = startCommand; + return p; +}; + +// Needed to make this file a module +export { }; From e9861c7d5a932677db6dade5b402870338b9b2b1 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 19:54:21 -0500 Subject: [PATCH 35/76] Smaller padding --- res/css/structures/_RoomStatusBar.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index f29c49c0e34..719dfce3307 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -76,8 +76,8 @@ limitations under the License. min-height: 70px; margin: 12px; padding-left: 16px; - padding-top: 8px; - padding-bottom: 8px; + padding-top: 4px; + padding-bottom: 4px; background-color: $header-panel-bg-color; border-radius: 4px; } From 54268ba995dfe43f69bca7dc5aee5c8b9add6412 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 20:11:14 -0500 Subject: [PATCH 36/76] Better comment --- src/components/structures/RoomStatusBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 3b6973fb9e1..bbe341d62f5 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -369,7 +369,7 @@ export default class RoomStatusBar extends React.PureComponent { { _t("An error occurred while trying to refresh the timeline.") } ; - // We only give the option to submit logs for actual errors. Not network problem. + // We only give the option to submit logs for actual errors, not network problems. submitDebugLogsTextContent = <> { _t("Please submit debug logs to help us " + "track down the problem.", {}, { From 3defe30f481ad240829bce9eabb01d773a0440f1 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 25 May 2022 20:11:24 -0500 Subject: [PATCH 37/76] Update snapshots --- .../__snapshots__/RoomStatusBar-test.tsx.snap | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index 7cd78db7303..91e002e7841 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -27,6 +27,7 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority "getCapabilities": [MockFunction], "getClientWellKnown": [MockFunction], "getDeviceId": [MockFunction], + "getDevices": [MockFunction], "getDomain": [MockFunction], "getHomeserverUrl": [MockFunction], "getIdentityAccount": [MockFunction], @@ -176,7 +177,6 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority "summary": null, "summaryHeroes": null, "tags": Object {}, - "threadPromises": Map {}, "threadTimelineSetsPromise": null, "threads": Map {}, "threadsReady": false, @@ -403,6 +403,7 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe "getCapabilities": [MockFunction], "getClientWellKnown": [MockFunction], "getDeviceId": [MockFunction], + "getDevices": [MockFunction], "getDomain": [MockFunction], "getHomeserverUrl": [MockFunction], "getIdentityAccount": [MockFunction], @@ -552,7 +553,6 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe "summary": null, "summaryHeroes": null, "tags": Object {}, - "threadPromises": Map {}, "threadTimelineSetsPromise": null, "threads": Map {}, "threadsReady": false, @@ -779,6 +779,7 @@ exports[`RoomStatusBar does not show anything when no sync error or other status "getCapabilities": [MockFunction], "getClientWellKnown": [MockFunction], "getDeviceId": [MockFunction], + "getDevices": [MockFunction], "getDomain": [MockFunction], "getHomeserverUrl": [MockFunction], "getIdentityAccount": [MockFunction], @@ -928,7 +929,6 @@ exports[`RoomStatusBar does not show anything when no sync error or other status "summary": null, "summaryHeroes": null, "tags": Object {}, - "threadPromises": Map {}, "threadTimelineSetsPromise": null, "threads": Map {}, "threadsReady": false, @@ -1124,6 +1124,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres "getCapabilities": [MockFunction], "getClientWellKnown": [MockFunction], "getDeviceId": [MockFunction], + "getDevices": [MockFunction], "getDomain": [MockFunction], "getHomeserverUrl": [MockFunction], "getIdentityAccount": [MockFunction], @@ -1284,7 +1285,6 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres "summary": null, "summaryHeroes": null, "tags": Object {}, - "threadPromises": Map {}, "threadTimelineSetsPromise": null, "threads": Map {}, "threadsReady": false, @@ -1450,7 +1450,65 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres Symbol(kCapture): false, } } -/> +> +
+
+
+ +
+
+
+ History import detected. +
+
+ History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. +
+
+
+ +
+
+
+ + + Refreshing + +
+
+
+ `; exports[`RoomStatusBar timeline needs refresh bar (history import) should show timeline refresh bar when history import detected 1`] = ` @@ -1480,6 +1538,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show t "getCapabilities": [MockFunction], "getClientWellKnown": [MockFunction], "getDeviceId": [MockFunction], + "getDevices": [MockFunction], "getDomain": [MockFunction], "getHomeserverUrl": [MockFunction], "getIdentityAccount": [MockFunction], @@ -1629,7 +1688,6 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show t "summary": null, "summaryHeroes": null, "tags": Object {}, - "threadPromises": Map {}, "threadTimelineSetsPromise": null, "threads": Map {}, "threadsReady": false, @@ -1798,6 +1856,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show t >
Date: Wed, 25 May 2022 23:30:27 -0500 Subject: [PATCH 38/76] Add test for refreshing the timeline multiple times --- .../historical-import.spec.ts | 95 ++++++++++++++----- 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 313deec9e02..8f858d6ee04 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -172,6 +172,31 @@ function ensureVirtualUsersRegistered( }); } +function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { + // Send the marker event which lets the client know there are + // some historical messages back at the given insertion event. + cy.all([ + cy.get("@roomId"), + cy.get("@baseInsertionEventId"), + ]).then(async ([roomId, baseInsertionEventId]) => { + const { event_id: markeEventId } = await asMatrixClient.sendStateEvent( + roomId, + 'org.matrix.msc2716.marker', { + "org.matrix.msc2716.marker.insertion": baseInsertionEventId, + }, + Cypress._.uniqueId("marker_state_key_"), + ); + + cy.wrap(markeEventId).as('markeEventId'); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([markeEventId]); + }); + + // Ensure the "History import detected" notice is shown + cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); +} + function setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, @@ -275,28 +300,7 @@ function setupRoomWithHistoricalMessagesAndMarker({ waitForEventIdsInClient([eventIdAfterHistoricalImport]); }); - // Send the marker event which lets the client know there are - // some historical messages back at the given insertion event. - cy.all([ - cy.get("@roomId"), - cy.get("@baseInsertionEventId"), - ]).then(async ([roomId, baseInsertionEventId]) => { - const { event_id: markeEventId } = await asMatrixClient.sendStateEvent( - roomId, - 'org.matrix.msc2716.marker', { - "org.matrix.msc2716.marker.insertion": baseInsertionEventId, - }, - Cypress._.uniqueId("marker_state_key_"), - ); - - cy.wrap(markeEventId).as('markeEventId'); - - // Wait for the message to show up for the logged in user - waitForEventIdsInClient([markeEventId]); - }); - - // Ensure the "History import detected" notice is shown - cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); + sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient); } describe("MSC2716: Historical Import", () => { @@ -373,6 +377,53 @@ describe("MSC2716: Historical Import", () => { }); }); + it("Able to refresh the timeline multiple times", () => { + setupRoomWithHistoricalMessagesAndMarker({ + synapse, + asMatrixClient, + virtualUserIDs, + }); + + // Press "Refresh timeline" + cy.get(`[data-cy="refresh-timeline-button"]`).click(); + + // Ensure historical messages are now shown + cy.all([ + cy.get("@liveMessageEventIds"), + cy.get("@historicalEventIds"), + ]).then(([liveMessageEventIds, historicalEventIds]) => { + // FIXME: Assert that they appear in the correct order + waitForEventIdsInClient([ + liveMessageEventIds[0], + liveMessageEventIds[1], + ...historicalEventIds, + liveMessageEventIds[2], + ]); + }); + + // Send another marker event. We're making sure that the history status + // bar appears again and works (this is the special differentiator we're + // testing in this test) + sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient); + + // Press "Refresh timeline" + cy.get(`[data-cy="refresh-timeline-button"]`).click(); + + // Ensure all of the messages still show afterwards + cy.all([ + cy.get("@liveMessageEventIds"), + cy.get("@historicalEventIds"), + ]).then(([liveMessageEventIds, historicalEventIds]) => { + // FIXME: Assert that they appear in the correct order + waitForEventIdsInClient([ + liveMessageEventIds[0], + liveMessageEventIds[1], + ...historicalEventIds, + liveMessageEventIds[2], + ]); + }); + }); + it("Perfectly merges timelines if a sync finishes while refreshing the timeline", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, From 4af71c275d1c99c100b615baf64b3f1175cdd625 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 00:29:55 -0500 Subject: [PATCH 39/76] Add context into intercepted request error so it's more obvious why you see this failed request in the console --- .../historical-import.spec.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 8f858d6ee04..ff0e16662ad 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -548,7 +548,14 @@ describe("MSC2716: Historical Import", () => { const prefix = '/_matrix/client/r0'; const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; - cy.intercept(contextUrl, { statusCode: 500 }).as('contextRequestThatWillTryToMakeNewTimeline'); + cy.intercept(contextUrl, { + statusCode: 500, + body: { + errcode: 'CYPRESS_FAKE_ERROR', + error: 'We purposely intercepted this /context request to make it fail ' + + 'in order to test whether the refresh timeline code is resilient', + }, + }).as('contextRequestThatWillTryToMakeNewTimeline'); }); // Press "Refresh timeline" From 0dae43ef3db9d9bc9af9ef1a244607bd334286c4 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 00:57:00 -0500 Subject: [PATCH 40/76] Fill in comment doc --- cypress/support/bot.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts index cd421310609..26210bf2864 100644 --- a/cypress/support/bot.ts +++ b/cypress/support/bot.ts @@ -39,7 +39,11 @@ declare global { */ getBot(synapse: SynapseInstance, displayName?: string): Chainable; /** - * TODO + * Create a new Matrix client to interact with the API as user + * separate from the one logged in + * @param synapse the instance on which to register the bot user + * @param opts Options to pass when creating a new Matrix client + * like `userId` and `accessToken` */ newMatrixClient(synapse: SynapseInstance, opts: INewMatrixClientOptions): Chainable; } From e75d92abb54706dc21634c568f4cc511c38d0da5 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 01:08:09 -0500 Subject: [PATCH 41/76] Update spapshots after removing last marker processed from js-sdk --- .../structures/__snapshots__/RoomStatusBar-test.tsx.snap | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index 91e002e7841..84da8d74d04 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -128,7 +128,6 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority "filteredTimelineSets": Object {}, "getTypeWarning": false, "getVersionWarning": false, - "lastMarkerEventIdProcessed": null, "lastThread": undefined, "membersPromise": Promise {}, "myUserId": "@name:example.com", @@ -504,7 +503,6 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe "filteredTimelineSets": Object {}, "getTypeWarning": false, "getVersionWarning": false, - "lastMarkerEventIdProcessed": null, "lastThread": undefined, "membersPromise": Promise {}, "myUserId": "@name:example.com", @@ -880,7 +878,6 @@ exports[`RoomStatusBar does not show anything when no sync error or other status "filteredTimelineSets": Object {}, "getTypeWarning": false, "getVersionWarning": false, - "lastMarkerEventIdProcessed": null, "lastThread": undefined, "membersPromise": Promise {}, "myUserId": "@name:example.com", @@ -1225,7 +1222,6 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres "filteredTimelineSets": Object {}, "getTypeWarning": false, "getVersionWarning": false, - "lastMarkerEventIdProcessed": null, "lastThread": undefined, "membersPromise": Promise {}, "myUserId": "@name:example.com", @@ -1639,7 +1635,6 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show t "filteredTimelineSets": Object {}, "getTypeWarning": false, "getVersionWarning": false, - "lastMarkerEventIdProcessed": null, "lastThread": undefined, "membersPromise": Promise {}, "myUserId": "@name:example.com", From 7eb0576ecc77c80cfda125c250286cf235254dcd Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 22:36:29 -0500 Subject: [PATCH 42/76] Add comments describing why mxSettingsStore is useful See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r878768589 --- cypress/global.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cypress/global.d.ts b/cypress/global.d.ts index b1323a47f57..965d406f401 100644 --- a/cypress/global.d.ts +++ b/cypress/global.d.ts @@ -30,7 +30,7 @@ declare global { }; mxDispatcher: MatrixDispatcher; mxPerformanceMonitor: PerformanceMonitor; - mxSettingsStore: SettingsStore; + mxSettingsStore: SettingsStore; // to allow for adjusting settings in tests beforeReload?: boolean; // for detecting reloads // Partial type for the matrix-js-sdk module, exported by browser-matrix matrixcs: { @@ -47,6 +47,7 @@ declare global { // to appease the PerformanceMonitor import mxPerformanceMonitor: PerformanceMonitor; mxPerformanceEntryNames: any; + // to allow for adjusting settings in tests mxSettingsStore: SettingsStore; } } From 8ed948d6998a63d103c914a3eb3af5056f401a2d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 22:46:57 -0500 Subject: [PATCH 43/76] Fix being able to reference Preset See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r882339509 --- .../x-msc2716-historical-import/historical-import.spec.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index ff0e16662ad..1722ee91971 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -19,7 +19,6 @@ limitations under the License. import { SynapseInstance } from "../../plugins/synapsedocker"; import { MatrixClient } from "../../global"; import { SettingLevel } from "../../../src/settings/SettingLevel"; -import type { Preset } from "matrix-js-sdk/src/@types/partials"; function createJoinStateEventsForBatchSendRequest( virtualUserIDs: string[], @@ -209,11 +208,9 @@ function setupRoomWithHistoricalMessagesAndMarker({ // As the application service, create the room so it is the room creator // and proper power_levels to send MSC2716 events. Then join the logged // in user to the room. - cy.wrap(null).then(async function() { + cy.window().then(async (win) => { const resp = await asMatrixClient.createRoom({ - // FIXME: I can't use Preset.PublicChat because Cypress doesn't - // understand Typescript to import it - preset: "public_chat" as Preset, + preset: win.matrixcs.Preset.PublicChat, name: "test-msc2716", room_version: "org.matrix.msc2716v3", }); From 75fc3d4729ccfbacce71111c54e4a88e5e434bac Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 22:53:07 -0500 Subject: [PATCH 44/76] Save the file --- cypress/global.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cypress/global.d.ts b/cypress/global.d.ts index 965d406f401..8b89acf5336 100644 --- a/cypress/global.d.ts +++ b/cypress/global.d.ts @@ -17,6 +17,7 @@ limitations under the License. import "matrix-js-sdk/src/@types/global"; import type { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client"; import type { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member"; +import type { Preset } from "matrix-js-sdk/src/@types/partials"; import type { MatrixDispatcher } from "../src/dispatcher/dispatcher"; import type PerformanceMonitor from "../src/performance"; import type SettingsStore from "../src/settings/SettingsStore"; @@ -37,6 +38,7 @@ declare global { MatrixClient: typeof MatrixClient; ClientEvent: typeof ClientEvent; RoomMemberEvent: typeof RoomMemberEvent; + Preset: typeof Preset; }; } } From 1f4d3b5cf8ad849ec91f7bbe665560569657b242 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 23:30:13 -0500 Subject: [PATCH 45/76] Comment out so typescript doesn't go as crazy. Still need to solve this though --- cypress/global.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cypress/global.d.ts b/cypress/global.d.ts index 8b89acf5336..386c49bfb6d 100644 --- a/cypress/global.d.ts +++ b/cypress/global.d.ts @@ -20,7 +20,7 @@ import type { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member"; import type { Preset } from "matrix-js-sdk/src/@types/partials"; import type { MatrixDispatcher } from "../src/dispatcher/dispatcher"; import type PerformanceMonitor from "../src/performance"; -import type SettingsStore from "../src/settings/SettingsStore"; +//import type SettingsStore from "../src/settings/SettingsStore"; declare global { // eslint-disable-next-line @typescript-eslint/no-namespace @@ -31,7 +31,7 @@ declare global { }; mxDispatcher: MatrixDispatcher; mxPerformanceMonitor: PerformanceMonitor; - mxSettingsStore: SettingsStore; // to allow for adjusting settings in tests + //mxSettingsStore: SettingsStore; // to allow for adjusting settings in tests beforeReload?: boolean; // for detecting reloads // Partial type for the matrix-js-sdk module, exported by browser-matrix matrixcs: { @@ -50,7 +50,7 @@ declare global { mxPerformanceMonitor: PerformanceMonitor; mxPerformanceEntryNames: any; // to allow for adjusting settings in tests - mxSettingsStore: SettingsStore; + //mxSettingsStore: SettingsStore; } } From 17d3203bb5dbd433faf01bb35033f092187baba5 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 26 May 2022 23:44:48 -0500 Subject: [PATCH 46/76] Remove debug logging --- src/components/structures/TimelinePanel.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index ff2c6a86a90..ddee25669aa 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -725,10 +725,6 @@ class TimelinePanel extends React.Component { }; private onRoomTimelineReset = (room: Room, timelineSet: EventTimelineSet): void => { - console.log( - `onRoomTimelineReset skipping=${timelineSet !== this.props.timelineSet} ` + - `skippingBecauseAtBottom=${this.canResetTimeline()}`, - ); if (timelineSet !== this.props.timelineSet) return; if (this.canResetTimeline()) { From 0c5c0b5b490ea686006ab6a20ab32a33c8a31ae8 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 27 May 2022 00:05:58 -0500 Subject: [PATCH 47/76] Add comment doc to test functions --- .../historical-import.spec.ts | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 1722ee91971..2ade9915245 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -20,6 +20,12 @@ import { SynapseInstance } from "../../plugins/synapsedocker"; import { MatrixClient } from "../../global"; import { SettingLevel } from "../../../src/settings/SettingLevel"; +/** + * Create the join state events necessary for the given virtual user IDs to send + * messages in the room. Usuable in a /batch_send requests. + * @param {string[]} virtualUserIDs A list of virtualUserIds to create join events for + * @param {number} insertTimestamp A unix timestamp when the join events should be marked as sent + */ function createJoinStateEventsForBatchSendRequest( virtualUserIDs: string[], insertTimestamp: number, @@ -39,6 +45,12 @@ function createJoinStateEventsForBatchSendRequest( } let batchCount = 0; +/** + * Create a number of message events that are usuable in a /batch_send request + * @param {string[]} virtualUserIDs A list of virtualUserIds to send historical messages from + * @param {number} insertTimestamp A unix timestamp when the messages should start from + * @param {number} count The number of messages to create + */ function createMessageEventsForBatchSendRequest( virtualUserIDs: string[], insertTimestamp: number, @@ -64,6 +76,10 @@ function createMessageEventsForBatchSendRequest( return messageEvents; } +/** + * Wait for the given event IDs to show up in the UI + * @param {string[]} eventIds The event IDs we ensure are visible in the UI + */ function waitForEventIdsInClient(eventIds: string[]) { eventIds.forEach((eventId) => { // Wait for the messages to be visible @@ -92,17 +108,26 @@ interface IBatchSendResponse { /** * Import a batch of historical events (MSC2716) + * @param {object} opts + * @param {SynapseInstance} opts.synapse The given Synapse instance to `/batch_send` against + * @param {string} opts.applicationServiceToken The given application service token to register + * the virtual users from + * @param {string} opts.roomId The room to import the historical messages in + * @param {string} opts.prevEventId The event ID to import the history next to + * @param {string} opts.batchId The batch ID from a previous `/batch_send` request to connect + * them all together into one big chain of history. + * @param {object} opts.payload The events and state to send in the batch */ function batchSend({ synapse, - accessToken, + applicationServiceToken, roomId, prevEventId, batchId, payload, }: { synapse: SynapseInstance; - accessToken: string; + applicationServiceToken: string; roomId: string; prevEventId: string; batchId: string | null; @@ -119,12 +144,20 @@ function batchSend({ url: batchSendUrl.toString(), method: "POST", headers: { - 'Authorization': `Bearer ${accessToken}`, + 'Authorization': `Bearer ${applicationServiceToken}`, }, body: payload, }); } +/** + * Make sure all of the given virtual user IDs are registered and ready to be + * used in a `/batch_send` request. + * @param {SynapseInstance} synapse The given Synapse instance to `/batch_send` against + * @param {string} applicationServiceToken The given application service token to register + * the virtual users from + * @param {string[]} virtualUserIDs A list of virtualUserIds to send historical messages from + */ function ensureVirtualUsersRegistered( synapse: SynapseInstance, applicationServiceToken: string, @@ -166,11 +199,17 @@ function ensureVirtualUsersRegistered( } const errorMessage = res.body.error; - throw new Error(`ensureVirtualUserRegistered failed to register: (${errcode}) ${errorMessage}`); + throw new Error(`ensureVirtualUserRegistered failed to register ${virtualUserLocalpart}: (${errcode}) ${errorMessage}`); }); }); } +/** + * Send a marker event and ensure that the "History import detected" status bar is shown + * which indicates that the client received the event. + * @param {MatrixClient} asMatrixClient The given application service client to send + * marker event from. + */ function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { // Send the marker event which lets the client know there are // some historical messages back at the given insertion event. @@ -196,6 +235,15 @@ function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); } +/** + * Bootstrap a room with some messages and a historically imported batch that is + * ready to be seen after refreshing the timeline. + * @param {object} opts + * @param {SynapseInstance} opts.synapse The given Synapse instance to `/batch_send` against + * @param {MatrixClient} opts.asMatrixClient The given application service client to create + * the room and messages. + * @param {string[]} opts.virtualUserIDs A list of virtualUserIds to send historical messages from + */ function setupRoomWithHistoricalMessagesAndMarker({ synapse, asMatrixClient, @@ -260,7 +308,7 @@ function setupRoomWithHistoricalMessagesAndMarker({ const insertTimestamp = Date.now(); batchSend({ synapse, - accessToken: asMatrixClient.getAccessToken(), + applicationServiceToken: asMatrixClient.getAccessToken(), roomId: roomId, prevEventId: liveMessageEventIds[1], batchId: null, From 641d37c44ab0a06cb692d153eacebc4f504b4998 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Fri, 27 May 2022 00:18:55 -0500 Subject: [PATCH 48/76] Add snapshot tests for error states --- .../structures/RoomStatusBar-test.tsx | 44 + .../__snapshots__/RoomStatusBar-test.tsx.snap | 836 ++++++++++++++++++ 2 files changed, 880 insertions(+) diff --git a/test/components/structures/RoomStatusBar-test.tsx b/test/components/structures/RoomStatusBar-test.tsx index bb7ccaf43d7..06cb4922642 100644 --- a/test/components/structures/RoomStatusBar-test.tsx +++ b/test/components/structures/RoomStatusBar-test.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import { mount } from "enzyme"; +import { act } from 'react-dom/test-utils'; import { Room } from "matrix-js-sdk/src/models/room"; import { PendingEventOrdering } from 'matrix-js-sdk/src/matrix'; import { @@ -144,5 +145,48 @@ describe("RoomStatusBar", () => { // Expect the refresh timeline bar to be hidden now expect(wrapper).toMatchSnapshot(); }); + + it('should show error state with option to submit debug logs ' + + 'in timeline refresh bar when something went wrong while refreshing', () => { + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + // Show timeline needs refresh bar + r1.setTimelineNeedsRefresh(true); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + act(() => { + wrapper.setState({ + refreshError: new Error('Fake error in test'), + }); + }); + expect(wrapper).toMatchSnapshot(); + }); + + + it('should show error state without submit debug logs option ' + + 'in timeline refresh bar when ConnectionError while refreshing', () => { + const r1 = new Room("r1", client, "@name:example.com", { + pendingEventOrdering: PendingEventOrdering.Detached, + }); + // Show timeline needs refresh bar + r1.setTimelineNeedsRefresh(true); + + const wrapper = mount(, { + wrappingComponent: MatrixClientContext.Provider, + wrappingComponentProps: { value: client }, + }); + act(() => { + const connectionError = new Error('Fake connection error in test'); + connectionError.name = "ConnectionError"; + wrapper.setState({ + refreshError: connectionError, + }); + }); + expect(wrapper).toMatchSnapshot(); + }); }); }); diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index 84da8d74d04..2b3ba7f3458 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -1507,6 +1507,842 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres `; +exports[`RoomStatusBar timeline needs refresh bar (history import) should show error state with option to submit debug logs in timeline refresh bar when something went wrong while refreshing 1`] = ` + +
+
+
+ +
+
+
+ History import detected. +
+
+ History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. +
+
+
+ An error occurred while trying to refresh the timeline. + + Please submit + +
+ debug logs +
+
+ to help us track down the problem. +
+
+
+
+ +
+ Refresh timeline +
+
+
+
+
+
+`; + +exports[`RoomStatusBar timeline needs refresh bar (history import) should show error state without submit debug logs option in timeline refresh bar when ConnectionError while refreshing 1`] = ` + +
+
+
+ +
+
+
+ History import detected. +
+
+ History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. +
+
+
+ A network error occurred while trying to refresh the timeline. Your homeserver might be down or was just a temporary problem with your internet connection. +
+
+
+ +
+ Refresh timeline +
+
+
+
+
+
+`; + exports[`RoomStatusBar timeline needs refresh bar (history import) should show timeline refresh bar when history import detected 1`] = ` Date: Fri, 27 May 2022 00:21:51 -0500 Subject: [PATCH 49/76] Fix lints --- .../x-msc2716-historical-import/historical-import.spec.ts | 5 ++++- test/components/structures/RoomStatusBar-test.tsx | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 2ade9915245..4742573fc13 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -199,7 +199,10 @@ function ensureVirtualUsersRegistered( } const errorMessage = res.body.error; - throw new Error(`ensureVirtualUserRegistered failed to register ${virtualUserLocalpart}: (${errcode}) ${errorMessage}`); + throw new Error( + `ensureVirtualUserRegistered failed to register ` + + `${virtualUserLocalpart}: (${errcode}) ${errorMessage}`, + ); }); }); } diff --git a/test/components/structures/RoomStatusBar-test.tsx b/test/components/structures/RoomStatusBar-test.tsx index 06cb4922642..2a211926ddb 100644 --- a/test/components/structures/RoomStatusBar-test.tsx +++ b/test/components/structures/RoomStatusBar-test.tsx @@ -166,7 +166,6 @@ describe("RoomStatusBar", () => { expect(wrapper).toMatchSnapshot(); }); - it('should show error state without submit debug logs option ' + 'in timeline refresh bar when ConnectionError while refreshing', () => { const r1 = new Room("r1", client, "@name:example.com", { From 6c7df4ef1b8f46b41cf9fbcc20591a70853e84f5 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 28 May 2022 01:06:36 -0500 Subject: [PATCH 50/76] Use correct public_baseurl (COPYME template is wrong) See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r883510154 --- .../templates/msc2716-historical-import/homeserver.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml index 548620b5712..e6cf07dd138 100644 --- a/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml +++ b/cypress/plugins/synapsedocker/templates/msc2716-historical-import/homeserver.yaml @@ -2,7 +2,7 @@ server_name: "localhost" pid_file: /data/homeserver.pid # XXX: This won't actually be right: it lets docker allocate an ephemeral port, # so we have a chicken-and-egg problem -public_baseurl: http://localhost:8008/ +public_baseurl: "{{PUBLIC_BASEURL}}" # Listener is always port 8008 (configured in the container) listeners: - port: 8008 From 0fac6b252bc36d0c8c35b5028c9354171b44ab65 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 28 May 2022 01:17:22 -0500 Subject: [PATCH 51/76] Only getBot should respond to invites by joining the room See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r883555047 --- cypress/support/bot.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts index 26210bf2864..6d445b83542 100644 --- a/cypress/support/bot.ts +++ b/cypress/support/bot.ts @@ -63,12 +63,6 @@ Cypress.Commands.add("newMatrixClient", ( request, }); - cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => { - if (member.membership === "invite" && member.userId === cli.getUserId()) { - cli.joinRoom(member.roomId); - } - }); - cli.startClient(); return cli; @@ -79,10 +73,21 @@ Cypress.Commands.add("getBot", (synapse: SynapseInstance, displayName?: string): const username = Cypress._.uniqueId("userId_"); const password = Cypress._.uniqueId("password_"); return cy.registerUser(synapse, username, password, displayName).then(credentials => { - return cy.newMatrixClient(synapse, { - userId: credentials.userId, - deviceId: credentials.deviceId, - accessToken: credentials.accessToken, + return cy.all([ + cy.newMatrixClient(synapse, { + userId: credentials.userId, + deviceId: credentials.deviceId, + accessToken: credentials.accessToken, + }), + cy.window(), + ]).then(([cli, win]) => { + cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => { + if (member.membership === "invite" && member.userId === cli.getUserId()) { + cli.joinRoom(member.roomId); + } + }); + + return cli; }); }); }); From fc0d4747b3820d19369b0e7810b1caa8e798f06c Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 28 May 2022 01:19:41 -0500 Subject: [PATCH 52/76] Use spacing variables --- res/css/structures/_RoomStatusBar.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index 719dfce3307..6fed6a506ea 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -76,8 +76,8 @@ limitations under the License. min-height: 70px; margin: 12px; padding-left: 16px; - padding-top: 4px; - padding-bottom: 4px; + padding-top: $spacing-4; + padding-bottom: $spacing-4; background-color: $header-panel-bg-color; border-radius: 4px; } From 0c89bcb3b27d17c2b2792d3f7bd121e727caaeae Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Sat, 28 May 2022 01:23:58 -0500 Subject: [PATCH 53/76] Type unintitialized variable --- src/components/structures/RoomStatusBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index bbe341d62f5..40ef23945f2 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -354,7 +354,7 @@ export default class RoomStatusBar extends React.PureComponent { ; } - let errorContent; + let errorContent: JSX.Element; if (this.state.refreshError) { let errorTextContent; let submitDebugLogsTextContent; From 20086966cf94c9279f3005f32a61c38dd963cbb7 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 1 Jun 2022 16:50:50 -0500 Subject: [PATCH 54/76] Fix minor spacing typo in comments --- .../x-msc2716-historical-import/historical-import.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts index 4742573fc13..ba8719c7e27 100644 --- a/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/integration/x-msc2716-historical-import/historical-import.spec.ts @@ -500,7 +500,7 @@ describe("MSC2716: Historical Import", () => { // to happen in the middle of all of this refresh timeline // logic. We want to make sure the sync pagination still // works as expected after messing the refresh timline logic - // messes with the pagination tokens. + // messes with the pagination tokens. resolveReq = resolve; }).then(req.reply); }).as('contextRequestThatWillMakeNewTimeline'); @@ -529,7 +529,7 @@ describe("MSC2716: Historical Import", () => { // indicating that a sync happened in the middle of us // refreshing the timeline. We want to make sure the sync // pagination still works as expected after messing the refresh - // timline logic messes with the pagination tokens. + // timeline logic messes with the pagination tokens. waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); cy.wrap(eventIdWhileRefrshingTimeline).as('eventIdWhileRefrshingTimeline'); From 34ebd08e823430c35029617f090164196d543be8 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 1 Jun 2022 16:51:05 -0500 Subject: [PATCH 55/76] Make sure sentences are properly spaced apart --- src/components/structures/RoomStatusBar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 40ef23945f2..8ad54070100 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -384,6 +384,7 @@ export default class RoomStatusBar extends React.PureComponent {
{ errorTextContent } + { " " } { submitDebugLogsTextContent }
; From b9c86ca94fad21e4bec5742eb12330c49fc6dd61 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 11 Jul 2022 18:23:28 -0500 Subject: [PATCH 56/76] Some type cleanup No need to re-use `newMatrixClient` either, https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r918410590 --- .../historical-import.spec.ts | 3 ++- cypress/support/bot.ts | 18 ++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index ba8719c7e27..23dc85a65cb 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -265,7 +265,7 @@ function setupRoomWithHistoricalMessagesAndMarker({ name: "test-msc2716", room_version: "org.matrix.msc2716v3", }); - cy.wrap(resp.room_id) .as('roomId'); + cy.wrap(resp.room_id).as('roomId'); }); cy.get("@roomId").then((roomId) => { @@ -386,6 +386,7 @@ describe("MSC2716: Historical Import", () => { // Get a Matrix Client for the application service cy.newMatrixClient(synapse, { + baseUrl: synapse.baseUrl, userId: '@gitter-badger:localhost', accessToken: AS_TOKEN, }).then(matrixClient => { diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts index aafd88fe0ec..125ccce91c4 100644 --- a/cypress/support/bot.ts +++ b/cypress/support/bot.ts @@ -18,16 +18,10 @@ limitations under the License. import request from "browser-request"; -import type { MatrixClient, Room } from "matrix-js-sdk/src/matrix"; +import type { MatrixClient, Room, IMatrixClientCreateOpts } from "matrix-js-sdk/src/matrix"; import { SynapseInstance } from "../plugins/synapsedocker"; import Chainable = Cypress.Chainable; -interface INewMatrixClientOptions { - userId: string; - accessToken: string; - deviceId?: string; -} - interface CreateBotOpts { /** * Whether the bot should automatically accept all invites. @@ -60,7 +54,7 @@ declare global { * @param opts Options to pass when creating a new Matrix client * like `userId` and `accessToken` */ - newMatrixClient(synapse: SynapseInstance, opts: INewMatrixClientOptions): Chainable; + newMatrixClient(synapse: SynapseInstance, opts: IMatrixClientCreateOpts): Chainable; /** * Let a bot join a room * @param cli The bot's MatrixClient @@ -79,15 +73,12 @@ declare global { Cypress.Commands.add("newMatrixClient", ( synapse: SynapseInstance, - { userId, accessToken, deviceId }: INewMatrixClientOptions, + opts: IMatrixClientCreateOpts, ): Chainable => { return cy.window({ log: false }).then(win => { const cli = new win.matrixcs.MatrixClient({ - baseUrl: synapse.baseUrl, - userId, - deviceId, - accessToken, request, + ...opts, }); cli.startClient(); @@ -96,7 +87,6 @@ Cypress.Commands.add("newMatrixClient", ( }); }); -// TODO: Can we re-use `newMatrixClient` again here? Cypress.Commands.add("getBot", (synapse: SynapseInstance, opts: CreateBotOpts): Chainable => { opts = Object.assign({}, defaultCreateBotOptions, opts); const username = Cypress._.uniqueId("userId_"); From 9d7eec39d25eca5051a5afd6552af1da40387462 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 11 Jul 2022 18:32:15 -0500 Subject: [PATCH 57/76] Update from Modal.createTrackedDialog to Modal.createDialog Modal refactor happened in https://github.com/matrix-org/matrix-react-sdk/commit/3c5c2bef6dbac51ce6e1864056523815ca4c38d9 --- src/components/structures/RoomStatusBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 8ad54070100..c2de7788089 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -419,7 +419,7 @@ export default class RoomStatusBar extends React.PureComponent { } private onBugReport = (): void => { - Modal.createTrackedDialog('Bug Report Dialog', '', BugReportDialog, { + Modal.createDialog(BugReportDialog, { error: this.state.refreshError, initialText: 'Error occured while refreshing the timeline', }); From 32952e3503928d4af4b40c1d029db5e06c4b2f82 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 11 Jul 2022 18:35:30 -0500 Subject: [PATCH 58/76] Update snapshots with Matrix client changes --- .../__snapshots__/RoomStatusBar-test.tsx.snap | 1577 +++++++++++++++-- 1 file changed, 1437 insertions(+), 140 deletions(-) diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index 2b3ba7f3458..d005141da32 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -53,8 +53,10 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority "getUser": [MockFunction], "getUserId": [MockFunction], "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], "isCryptoEnabled": [MockFunction], "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], "isRoomEncrypted": [MockFunction], "isUserIgnored": [MockFunction], "loginFlows": [MockFunction], @@ -71,30 +73,30 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority "sendReadReceipt": [MockFunction], "sendStateEvent": [MockFunction], "sendTyping": [MockFunction], - "sessionStore": Object { - "store": Object { - "getItem": [MockFunction] { - "calls": Array [ - Array [ - "mx_pending_events_r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "setItem": [MockFunction], - }, - }, "setAccountData": [MockFunction], "setPowerLevel": [MockFunction], "setPushRuleActions": [MockFunction], "setPushRuleEnabled": [MockFunction], "setPusher": [MockFunction], "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, "supportsExperimentalThreads": [Function], "supportsVoip": [MockFunction], }, @@ -170,6 +172,98 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority }, "receiptCacheByEventId": Object {}, "receipts": Object {}, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "roomId": "r1", "selfMembership": null, "storageToken": undefined, @@ -260,8 +354,100 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority Symbol(kCapture): false, }, }, - "relations": undefined, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "room": [Circular], + "thread": undefined, "timelineSupport": false, "timelines": Array [ EventTimeline { @@ -332,7 +518,6 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority }, }, ], - "unstableClientRelationAggregation": false, Symbol(kCapture): false, }, ], @@ -428,8 +613,10 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe "getUser": [MockFunction], "getUserId": [MockFunction], "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], "isCryptoEnabled": [MockFunction], "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], "isRoomEncrypted": [MockFunction], "isUserIgnored": [MockFunction], "loginFlows": [MockFunction], @@ -446,30 +633,30 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe "sendReadReceipt": [MockFunction], "sendStateEvent": [MockFunction], "sendTyping": [MockFunction], - "sessionStore": Object { - "store": Object { - "getItem": [MockFunction] { - "calls": Array [ - Array [ - "mx_pending_events_r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "setItem": [MockFunction], - }, - }, "setAccountData": [MockFunction], "setPowerLevel": [MockFunction], "setPushRuleActions": [MockFunction], "setPushRuleEnabled": [MockFunction], "setPusher": [MockFunction], "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, "supportsExperimentalThreads": [Function], "supportsVoip": [MockFunction], }, @@ -545,6 +732,98 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe }, "receiptCacheByEventId": Object {}, "receipts": Object {}, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "roomId": "r1", "selfMembership": null, "storageToken": undefined, @@ -635,8 +914,100 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe Symbol(kCapture): false, }, }, - "relations": undefined, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "room": [Circular], + "thread": undefined, "timelineSupport": false, "timelines": Array [ EventTimeline { @@ -707,7 +1078,6 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe }, }, ], - "unstableClientRelationAggregation": false, Symbol(kCapture): false, }, ], @@ -803,8 +1173,10 @@ exports[`RoomStatusBar does not show anything when no sync error or other status "getUser": [MockFunction], "getUserId": [MockFunction], "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], "isCryptoEnabled": [MockFunction], "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], "isRoomEncrypted": [MockFunction], "isUserIgnored": [MockFunction], "loginFlows": [MockFunction], @@ -821,30 +1193,30 @@ exports[`RoomStatusBar does not show anything when no sync error or other status "sendReadReceipt": [MockFunction], "sendStateEvent": [MockFunction], "sendTyping": [MockFunction], - "sessionStore": Object { - "store": Object { - "getItem": [MockFunction] { - "calls": Array [ - Array [ - "mx_pending_events_r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "setItem": [MockFunction], - }, - }, "setAccountData": [MockFunction], "setPowerLevel": [MockFunction], "setPushRuleActions": [MockFunction], "setPushRuleEnabled": [MockFunction], "setPusher": [MockFunction], "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, "supportsExperimentalThreads": [Function], "supportsVoip": [MockFunction], }, @@ -920,6 +1292,98 @@ exports[`RoomStatusBar does not show anything when no sync error or other status }, "receiptCacheByEventId": Object {}, "receipts": Object {}, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "roomId": "r1", "selfMembership": null, "storageToken": undefined, @@ -1010,8 +1474,100 @@ exports[`RoomStatusBar does not show anything when no sync error or other status Symbol(kCapture): false, }, }, - "relations": undefined, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "room": [Circular], + "thread": undefined, "timelineSupport": false, "timelines": Array [ EventTimeline { @@ -1082,7 +1638,6 @@ exports[`RoomStatusBar does not show anything when no sync error or other status }, }, ], - "unstableClientRelationAggregation": false, Symbol(kCapture): false, }, ], @@ -1147,8 +1702,10 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres "getUser": [MockFunction], "getUserId": [MockFunction], "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], "isCryptoEnabled": [MockFunction], "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], "isRoomEncrypted": [MockFunction], "isUserIgnored": [MockFunction], "loginFlows": [MockFunction], @@ -1165,30 +1722,30 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres "sendReadReceipt": [MockFunction], "sendStateEvent": [MockFunction], "sendTyping": [MockFunction], - "sessionStore": Object { - "store": Object { - "getItem": [MockFunction] { - "calls": Array [ - Array [ - "mx_pending_events_r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "setItem": [MockFunction], - }, - }, "setAccountData": [MockFunction], "setPowerLevel": [MockFunction], "setPushRuleActions": [MockFunction], "setPushRuleEnabled": [MockFunction], "setPusher": [MockFunction], "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, "supportsExperimentalThreads": [Function], "supportsVoip": [MockFunction], }, @@ -1275,6 +1832,98 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres }, ], }, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "roomId": "r1", "selfMembership": null, "storageToken": undefined, @@ -1365,8 +2014,100 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres Symbol(kCapture): false, }, }, - "relations": undefined, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "room": [Circular], + "thread": undefined, "timelineSupport": false, "timelines": Array [ EventTimeline { @@ -1437,7 +2178,6 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres }, }, ], - "unstableClientRelationAggregation": false, Symbol(kCapture): false, }, ], @@ -1560,8 +2300,10 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e "getUser": [MockFunction], "getUserId": [MockFunction], "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], "isCryptoEnabled": [MockFunction], "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], "isRoomEncrypted": [MockFunction], "isUserIgnored": [MockFunction], "loginFlows": [MockFunction], @@ -1578,30 +2320,30 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e "sendReadReceipt": [MockFunction], "sendStateEvent": [MockFunction], "sendTyping": [MockFunction], - "sessionStore": Object { - "store": Object { - "getItem": [MockFunction] { - "calls": Array [ - Array [ - "mx_pending_events_r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "setItem": [MockFunction], - }, - }, "setAccountData": [MockFunction], "setPowerLevel": [MockFunction], "setPushRuleActions": [MockFunction], "setPushRuleEnabled": [MockFunction], "setPusher": [MockFunction], "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, "supportsExperimentalThreads": [Function], "supportsVoip": [MockFunction], }, @@ -1677,6 +2419,98 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e }, "receiptCacheByEventId": Object {}, "receipts": Object {}, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "roomId": "r1", "selfMembership": null, "storageToken": undefined, @@ -1767,8 +2601,100 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e Symbol(kCapture): false, }, }, - "relations": undefined, + "relations": RelationsContainer { + "client": Object { + "createRoom": [MockFunction], + "credentials": Object { + "userId": "@userId:matrix.rog", + }, + "decryptEventIfNeeded": [Function], + "doesServerSupportUnstableFeature": [MockFunction], + "downloadKeys": [MockFunction], + "emit": [Function], + "fetchRoomEvent": [MockFunction], + "generateClientSecret": [Function], + "getAccountData": [Function], + "getCapabilities": [MockFunction], + "getClientWellKnown": [MockFunction], + "getDeviceId": [MockFunction], + "getDevices": [MockFunction], + "getDomain": [MockFunction], + "getHomeserverUrl": [MockFunction], + "getIdentityAccount": [MockFunction], + "getIdentityServerUrl": [MockFunction], + "getOpenIdToken": [MockFunction], + "getProfileInfo": [MockFunction], + "getPushActionsForEvent": [MockFunction], + "getPushRules": [MockFunction], + "getPushers": [MockFunction], + "getRoom": [MockFunction], + "getRoomDirectoryVisibility": [MockFunction], + "getRoomHierarchy": [MockFunction], + "getRoomIdForAlias": [MockFunction], + "getRoomUpgradeHistory": [MockFunction], + "getRooms": [MockFunction], + "getSyncState": [Function], + "getSyncStateData": [Function], + "getTerms": [MockFunction], + "getThirdpartyProtocols": [MockFunction], + "getThirdpartyUser": [MockFunction], + "getThreePids": [MockFunction], + "getTurnServersExpiry": [MockFunction], + "getUser": [MockFunction], + "getUserId": [MockFunction], + "getVisibleRooms": [MockFunction], + "hasLazyLoadMembersEnabled": [MockFunction], + "isCryptoEnabled": [MockFunction], + "isGuest": [MockFunction], + "isInitialSyncComplete": [MockFunction], + "isRoomEncrypted": [MockFunction], + "isUserIgnored": [MockFunction], + "loginFlows": [MockFunction], + "mxcUrlToHttp": [Function], + "off": [Function], + "on": [Function], + "paginateEventTimeline": [MockFunction], + "peekInRoom": [MockFunction], + "pushRules": Object {}, + "registerWithIdentityServer": [MockFunction], + "relations": [MockFunction], + "removeListener": [Function], + "sendMessage": [Function], + "sendReadReceipt": [MockFunction], + "sendStateEvent": [MockFunction], + "sendTyping": [MockFunction], + "setAccountData": [MockFunction], + "setPowerLevel": [MockFunction], + "setPushRuleActions": [MockFunction], + "setPushRuleEnabled": [MockFunction], + "setPusher": [MockFunction], + "setRoomAccountData": [MockFunction], + "setRoomTopic": [MockFunction], + "stopPeeking": [MockFunction], + "store": Object { + "getPendingEvents": [MockFunction] { + "calls": Array [ + Array [ + "r1", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": Promise {}, + }, + ], + }, + "setPendingEvents": [MockFunction], + }, + "supportsExperimentalThreads": [Function], + "supportsVoip": [MockFunction], + }, + "relations": Object {}, + "room": [Circular], + }, "room": [Circular], + "thread": undefined, "timelineSupport": false, "timelines": Array [ EventTimeline { @@ -1839,7 +2765,6 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e }, }, ], - "unstableClientRelationAggregation": false, Symbol(kCapture): false, }, ], @@ -1883,6 +2808,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e data-cy="historical-import-detected-error-content" > An error occurred while trying to refresh the timeline. + Please submit A network error occurred while trying to refresh the timeline. Your homeserver might be down or was just a temporary problem with your internet connection. +
Date: Mon, 11 Jul 2022 20:12:52 -0500 Subject: [PATCH 59/76] Fix markerEventId typo --- .../historical-import.spec.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index 23dc85a65cb..9e1446d71df 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -220,7 +220,7 @@ function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { cy.get("@roomId"), cy.get("@baseInsertionEventId"), ]).then(async ([roomId, baseInsertionEventId]) => { - const { event_id: markeEventId } = await asMatrixClient.sendStateEvent( + const { event_id: markerEventId } = await asMatrixClient.sendStateEvent( roomId, 'org.matrix.msc2716.marker', { "org.matrix.msc2716.marker.insertion": baseInsertionEventId, @@ -228,10 +228,10 @@ function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { Cypress._.uniqueId("marker_state_key_"), ); - cy.wrap(markeEventId).as('markeEventId'); + cy.wrap(markerEventId).as('markerEventId'); // Wait for the message to show up for the logged in user - waitForEventIdsInClient([markeEventId]); + waitForEventIdsInClient([markerEventId]); }); // Ensure the "History import detected" notice is shown @@ -488,11 +488,11 @@ describe("MSC2716: Historical Import", () => { let resolveReq; cy.all([ cy.get("@roomId"), - cy.get("@markeEventId"), - ]).then(([roomId, markeEventId]) => { - // We're using `markeEventId` here because it's the latest event in the room + cy.get("@markerEventId"), + ]).then(([roomId, markerEventId]) => { + // We're using `markerEventId` here because it's the latest event in the room const prefix = '/_matrix/client/r0'; - const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markerEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, async (req) => { return new Cypress.Promise(resolve => { @@ -591,11 +591,11 @@ describe("MSC2716: Historical Import", () => { // retry and recover. cy.all([ cy.get("@roomId"), - cy.get("@markeEventId"), - ]).then(async ([roomId, markeEventId]) => { - // We're using `this.markeEventId` here because it's the latest event in the room + cy.get("@markerEventId"), + ]).then(async ([roomId, markerEventId]) => { + // We're using `this.markerEventId` here because it's the latest event in the room const prefix = '/_matrix/client/r0'; - const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markerEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, { statusCode: 500, @@ -619,11 +619,11 @@ describe("MSC2716: Historical Import", () => { // Allow the requests to succeed now cy.all([ cy.get("@roomId"), - cy.get("@markeEventId"), - ]).then(async ([roomId, markeEventId]) => { - // We're using `this.markeEventId` here because it's the latest event in the room + cy.get("@markerEventId"), + ]).then(async ([roomId, markerEventId]) => { + // We're using `this.markerEventId` here because it's the latest event in the room const prefix = '/_matrix/client/r0'; - const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markeEventId)}`; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(markerEventId)}`; const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; cy.intercept(contextUrl, async (req) => { // Passthrough. We can't just omit this callback because the From 0e923b756ce8095d8e5232cd5f0a5cff20f25b7b Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 11 Jul 2022 20:19:46 -0500 Subject: [PATCH 60/76] Fix eventIdWhileRefrshingTimeline typo --- .../historical-import.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index 9e1446d71df..b37ad3f3188 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -518,7 +518,7 @@ describe("MSC2716: Historical Import", () => { // Then make a `/sync` happen by sending a message and seeing that it // shows up (simulate a /sync naturally racing with us). cy.get("@roomId").then(async (roomId) => { - const { event_id: eventIdWhileRefrshingTimeline } = await asMatrixClient.sendMessage( + const { event_id: eventIdWhileRefreshingTimeline } = await asMatrixClient.sendMessage( roomId, null, { body: `live_event while trying to refresh timeline`, @@ -531,9 +531,9 @@ describe("MSC2716: Historical Import", () => { // refreshing the timeline. We want to make sure the sync // pagination still works as expected after messing the refresh // timeline logic messes with the pagination tokens. - waitForEventIdsInClient([eventIdWhileRefrshingTimeline]); + waitForEventIdsInClient([eventIdWhileRefreshingTimeline]); - cy.wrap(eventIdWhileRefrshingTimeline).as('eventIdWhileRefrshingTimeline'); + cy.wrap(eventIdWhileRefreshingTimeline).as('eventIdWhileRefreshingTimeline'); }).then(() => { // Now we can resume the `/context` request resolveReq(); @@ -559,12 +559,12 @@ describe("MSC2716: Historical Import", () => { cy.all([ cy.get("@liveMessageEventIds"), cy.get("@historicalEventIds"), - cy.get("@eventIdWhileRefrshingTimeline"), + cy.get("@eventIdWhileRefreshingTimeline"), cy.get("@eventIdAfterRefresh"), ]).then(async ([ liveMessageEventIds, historicalEventIds, - eventIdWhileRefrshingTimeline, + eventIdWhileRefreshingTimeline, eventIdAfterRefresh, ]) => { // FIXME: Assert that they appear in the correct order @@ -573,7 +573,7 @@ describe("MSC2716: Historical Import", () => { liveMessageEventIds[1], ...historicalEventIds, liveMessageEventIds[2], - eventIdWhileRefrshingTimeline, + eventIdWhileRefreshingTimeline, eventIdAfterRefresh, ]); }); From c9270d8dcb1205617d5995f40c8b39ff0e6df374 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 12 Jul 2022 19:12:28 -0500 Subject: [PATCH 61/76] Add test when we fail to refresh and latest event is a threaded message See https://github.com/matrix-org/matrix-react-sdk/pull/8354#discussion_r892481473 --- .../historical-import.spec.ts | 139 ++++++++++++++++-- src/components/structures/RoomStatusBar.tsx | 6 +- src/components/structures/ScrollPanel.tsx | 2 +- src/components/views/rooms/ThreadSummary.tsx | 1 + .../__snapshots__/RoomStatusBar-test.tsx.snap | 24 +-- 5 files changed, 147 insertions(+), 25 deletions(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index b37ad3f3188..af480cfbdfb 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -235,7 +235,7 @@ function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { }); // Ensure the "History import detected" notice is shown - cy.get(`[data-cy="historical-import-detected-status-bar"]`).should("exist"); + cy.get(`[data-test-id="historical-import-detected-status-bar"]`).should("exist"); } /** @@ -361,6 +361,9 @@ describe("MSC2716: Historical Import", () => { const AS_TOKEN = 'as_token123'; beforeEach(() => { + // Default threads to ON for this spec + cy.enableLabsFeature("feature_thread"); + cy.window().then(win => { // Collapse left panel for these tests (get more space in the area we care about) win.localStorage.setItem("mx_lhs_size", "0"); @@ -409,7 +412,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); // Ensure historical messages are now shown cy.all([ @@ -434,7 +437,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); // Ensure historical messages are now shown cy.all([ @@ -456,7 +459,7 @@ describe("MSC2716: Historical Import", () => { sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient); // Press "Refresh timeline" - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); // Ensure all of the messages still show afterwards cy.all([ @@ -508,11 +511,11 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); // Wait for the timeline to go blank (meaning it was reset) // and in the middle of the refrsehing timeline function. - cy.get('[data-cy="message-list"] [data-event-id]') + cy.get('[data-test-id="message-list"] [data-event-id]') .should('not.exist'); // Then make a `/sync` happen by sending a message and seeing that it @@ -608,13 +611,13 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); // Make sure the request was intercepted and thew an error cy.wait('@contextRequestThatWillTryToMakeNewTimeline').its('response.statusCode').should('eq', 500); // Make sure we tell the user that an error happened - cy.get(`[data-cy="historical-import-detected-error-content"]`).should("exist"); + cy.get(`[data-test-id="historical-import-detected-error-content"]`).should("exist"); // Allow the requests to succeed now cy.all([ @@ -633,7 +636,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" again, this time the network request should succeed - cy.get(`[data-cy="refresh-timeline-button"]`).click(); + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); // Make sure the request was intercepted and succeeded cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); @@ -674,4 +677,122 @@ describe("MSC2716: Historical Import", () => { ]); }); }); + + it.only("Perfectly resolves timelines when refresh fails and then another refresh causes `getLatestTimeline()` " + + "finds a threaded event", () => { + setupRoomWithHistoricalMessagesAndMarker({ + synapse, + asMatrixClient, + virtualUserIDs, + }); + + // Send a threaded message so it's the latest message in the room + cy.get("@roomId").then(async (roomId) => { + const { event_id: eventIdToThreadFrom } = await asMatrixClient.sendMessage(roomId, null, { + body: `event to thread from (root)`, + msgtype: "m.text", + }); + const { event_id: eventIdThreadedMessage } = await asMatrixClient.sendMessage(roomId, null, { + "body": `threaded message1`, + "msgtype": "m.text", + "m.relates_to": { + "rel_type": "m.thread", + "event_id": eventIdToThreadFrom, + "is_falling_back": true, + "m.in_reply_to": { + "event_id": eventIdToThreadFrom, + }, + }, + }); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIdToThreadFrom]); + cy.wrap(eventIdToThreadFrom).as('eventIdToThreadFrom'); + // We don't wait for this event in the client because it will be + // hidden away in a thread. + cy.wrap(eventIdThreadedMessage).as('eventIdThreadedMessage'); + + // Wait for the thread summary to appear which indicates that + // `eventIdThreadedMessage` made it to the client + cy.get(`[data-event-id="${eventIdToThreadFrom}"] [data-test-id="thread-summary"]`); + }); + + // Make the `/context` fail when we try to refresh the timeline. We want + // to make sure that we are resilient to this type of failure and can + // retry and recover. + cy.all([ + cy.get("@roomId"), + cy.get("@eventIdToThreadFrom"), + ]).then(async ([roomId, eventIdToThreadFrom]) => { + // We're using `eventIdToThreadFrom` here because it's the latest + // event in the rooms main timeline which the refresh timeline logic + // will use if available. + const prefix = '/_matrix/client/r0'; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(eventIdToThreadFrom)}`; + const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; + cy.intercept(contextUrl, { + statusCode: 500, + body: { + errcode: 'CYPRESS_FAKE_ERROR', + error: 'We purposely intercepted this /context request to make it fail ' + + 'in order to test whether the refresh timeline code is resilient', + }, + }).as('contextRequestThatWillTryToMakeNewTimeline'); + }); + + // Press "Refresh timeline" + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + + // Make sure the request was intercepted and thew an error + cy.wait('@contextRequestThatWillTryToMakeNewTimeline').its('response.statusCode').should('eq', 500); + + // Wait for the timeline to go blank (meaning it was reset) + // and refreshing the timeline failed. + cy.get('[data-test-id="message-list"] [data-event-id]') + .should('not.exist'); + + // Press "Refresh timeline" again, this time the network request should succeed. + // + // Since the timeline is now blank, we have no most recent event to + // draw from locally. So `MatrixClient::getLatestTimeline` will + // fetch the latest from `/messages` which will return + // `eventIdThreadedMessage` as the latest event in the room. + cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + + // Make sure sync pagination still works by seeing a new message show up + cy.get("@roomId").then(async (roomId) => { + const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(roomId, null, { + body: `live_event after refresh`, + msgtype: "m.text", + }); + + // Wait for the message to show up for the logged in user + waitForEventIdsInClient([eventIdAfterRefresh]); + + cy.wrap(eventIdAfterRefresh).as('eventIdAfterRefresh'); + }); + + // Ensure historical messages are now shown + cy.all([ + cy.get("@liveMessageEventIds"), + cy.get("@historicalEventIds"), + cy.get("@eventIdToThreadFrom"), + cy.get("@eventIdAfterRefresh"), + ]).then(async ([ + liveMessageEventIds, + historicalEventIds, + eventIdToThreadFrom, + eventIdAfterRefresh, + ]) => { + // FIXME: Assert that they appear in the correct order + waitForEventIdsInClient([ + liveMessageEventIds[0], + liveMessageEventIds[1], + ...historicalEventIds, + liveMessageEventIds[2], + eventIdToThreadFrom, + eventIdAfterRefresh, + ]); + }); + }); }); diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index c2de7788089..21ab72541f6 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -341,7 +341,7 @@ export default class RoomStatusBar extends React.PureComponent { { _t("Refresh timeline") } @@ -382,7 +382,7 @@ export default class RoomStatusBar extends React.PureComponent { errorContent = <>
-
+
{ errorTextContent } { " " } { submitDebugLogsTextContent } @@ -391,7 +391,7 @@ export default class RoomStatusBar extends React.PureComponent { } return ( -
+
{ > { this.props.fixedChildren }
-
    +
      { this.props.children }
diff --git a/src/components/views/rooms/ThreadSummary.tsx b/src/components/views/rooms/ThreadSummary.tsx index 968727022f9..1b525fa6943 100644 --- a/src/components/views/rooms/ThreadSummary.tsx +++ b/src/components/views/rooms/ThreadSummary.tsx @@ -49,6 +49,7 @@ const ThreadSummary = ({ mxEvent, thread }: IProps) => { return ( { showThread({ rootEvent: mxEvent, diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index d005141da32..10dcb6bac9f 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -2189,7 +2189,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should refres >
An error occurred while trying to refresh the timeline. @@ -2838,7 +2838,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e >
A network error occurred while trying to refresh the timeline. Your homeserver might be down or was just a temporary problem with your internet connection. @@ -3431,7 +3431,7 @@ exports[`RoomStatusBar timeline needs refresh bar (history import) should show e >
Date: Tue, 12 Jul 2022 21:57:49 -0500 Subject: [PATCH 62/76] Remove the test only --- .../e2e/x-msc2716-historical-import/historical-import.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index af480cfbdfb..4c19f5a77c2 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -678,7 +678,7 @@ describe("MSC2716: Historical Import", () => { }); }); - it.only("Perfectly resolves timelines when refresh fails and then another refresh causes `getLatestTimeline()` " + + it("Perfectly resolves timelines when refresh fails and then another refresh causes `getLatestTimeline()` " + "finds a threaded event", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, From ac998bd85326667522dae20a6572d7f0e69cd6f6 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 19 Jul 2022 18:06:01 -0500 Subject: [PATCH 63/76] Use fire-forget pattern See https://github.com/matrix-org/matrix-js-sdk/pull/2521#discussion_r920214132 --- src/components/structures/LoggedInView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index 87869b65511..33beec5ccdd 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -353,8 +353,8 @@ class LoggedInView extends React.Component { const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM); for (const eventId of pinnedEventIds) { - const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId); - const event = timeline.getEvents().find(ev => ev.getId() === eventId); + await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId); + const event = room.findEventById(eventId); if (event) events.push(event); } } From 8c78dd5faf89d8362e47557e9cf8b249a5fc2e9d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 18:34:40 -0600 Subject: [PATCH 64/76] Make test more robust --- .../historical-import.spec.ts | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index 4c19f5a77c2..8830fddbcb7 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -678,7 +678,7 @@ describe("MSC2716: Historical Import", () => { }); }); - it("Perfectly resolves timelines when refresh fails and then another refresh causes `getLatestTimeline()` " + + it("Perfectly resolves timelines when refresh fails and then another refresh causes `fetchLatestLiveTimeline()` " + "finds a threaded event", () => { setupRoomWithHistoricalMessagesAndMarker({ synapse, @@ -751,14 +751,35 @@ describe("MSC2716: Historical Import", () => { cy.get('[data-test-id="message-list"] [data-event-id]') .should('not.exist'); + // Allow the requests to succeed now + cy.all([ + cy.get("@roomId"), + cy.get("@eventIdThreadedMessage"), + ]).then(async ([roomId, eventIdThreadedMessage]) => { + // We're using `eventIdThreadedMessage` here because it's the latest event in + // the room which `/messages?dir=b` will find from the refresh timeline -> + // `client.fetchLatestLiveTimeline(...)` logic. + const prefix = '/_matrix/client/r0'; + const path = `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(eventIdThreadedMessage)}`; + const contextUrl = `${synapse.baseUrl}${prefix}${path}*`; + cy.intercept(contextUrl, async (req) => { + // Passthrough. We can't just omit this callback because the + // other intercept will take precedent for some reason. + req.reply(); + }).as('contextRequestThatWillMakeNewTimeline'); + }); + // Press "Refresh timeline" again, this time the network request should succeed. // // Since the timeline is now blank, we have no most recent event to - // draw from locally. So `MatrixClient::getLatestTimeline` will - // fetch the latest from `/messages` which will return + // draw from locally. So `MatrixClient::fetchLatestLiveTimeline()` will + // fetch the latest from `/messages?dir=b` which will return // `eventIdThreadedMessage` as the latest event in the room. cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + // Make sure the request was intercepted and succeeded + cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); + // Make sure sync pagination still works by seeing a new message show up cy.get("@roomId").then(async (roomId) => { const { event_id: eventIdAfterRefresh } = await asMatrixClient.sendMessage(roomId, null, { From 3d259def77d1b596e94ac986b01ae0f3b55a935f Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 19:03:02 -0600 Subject: [PATCH 65/76] Fix joinRoom duplication --- cypress/support/client.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cypress/support/client.ts b/cypress/support/client.ts index 86c74ae7e5a..1d649515acc 100644 --- a/cypress/support/client.ts +++ b/cypress/support/client.ts @@ -52,10 +52,10 @@ declare global { inviteUser(roomId: string, userId: string): Chainable<{}>; /** * Joins the current user to the given room. - * @param roomId the id of the room to join + * @param roomIdOrAlias the id or alias of the room to join * @param opts the options when joining a room */ - joinRoom(roomId: string, opts?: IJoinRoomOpts): Chainable<{}>; + joinRoom(roomIdOrAlias: string, opts?: IJoinRoomOpts): Chainable<{}>; /** * Waits for the given room to be synced locally * @param roomId the id of the room to wait for locally @@ -135,11 +135,6 @@ declare global { * Boostraps cross-signing. */ bootstrapCrossSigning(): Chainable; - /** - * Joins the given room by alias or ID - * @param roomIdOrAlias the id or alias of the room to join - */ - joinRoom(roomIdOrAlias: string): Chainable; } } } From e64e59b2a30e005d3804f2a915cdc5147abd70ed Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 19:03:44 -0600 Subject: [PATCH 66/76] Fix duplicate command --- cypress/support/client.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cypress/support/client.ts b/cypress/support/client.ts index 1d649515acc..9a94a3807f7 100644 --- a/cypress/support/client.ts +++ b/cypress/support/client.ts @@ -170,13 +170,13 @@ Cypress.Commands.add("inviteUser", (roomId: string, userId: string): Chainable<{ }); }); -Cypress.Commands.add("joinRoom", (roomId: string, opts?: IJoinRoomOpts): Chainable<{}> => { +Cypress.Commands.add("joinRoom", (roomIdOrAlias: string, opts?: IJoinRoomOpts): Chainable<{}> => { cy.getClient().then(async (cli: MatrixClient) => { - return cli.joinRoom(roomId, opts); + return cli.joinRoom(roomIdOrAlias, opts); }); // Wait for the room to be available locally - return cy.waitForRoom(roomId); + return cy.waitForRoom(roomIdOrAlias); }); Cypress.Commands.add("waitForRoom", (roomId: string): Chainable => { @@ -257,7 +257,3 @@ Cypress.Commands.add("bootstrapCrossSigning", () => { }); }); }); - -Cypress.Commands.add("joinRoom", (roomIdOrAlias: string): Chainable => { - return cy.getClient().then(cli => cli.joinRoom(roomIdOrAlias)); -}); From 1ff2c78b6acfc9efbf73783ee8f8e7854d4982e1 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 19:51:36 -0600 Subject: [PATCH 67/76] Fix some lints --- src/components/structures/RoomStatusBar.tsx | 44 +++++++++++++-------- src/components/structures/TimelinePanel.tsx | 34 ++++++++++------ 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index cdb29275b4d..9bf4aac2179 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -19,6 +19,7 @@ import { EventStatus, MatrixEvent } from "matrix-js-sdk/src/models/event"; import { SyncState, ISyncStateData } from "matrix-js-sdk/src/sync"; import { Room, RoomEvent } from "matrix-js-sdk/src/models/room"; import { logger } from 'matrix-js-sdk/src/logger'; +import { MatrixError } from "matrix-js-sdk/src/http-api"; import { _t, _td } from '../../languageHandler'; import Resend from '../../Resend'; @@ -103,7 +104,7 @@ export default class RoomStatusBar extends React.PureComponent { isResending: false, timelineNeedsRefresh: this.props.room.getTimelineNeedsRefresh(), isRefreshing: false, - refreshError: null, + refreshError: undefined, }; } @@ -171,7 +172,7 @@ export default class RoomStatusBar extends React.PureComponent { private onRefreshTimelineClick = async (): Promise => { this.setState({ isRefreshing: true, - refreshError: null, + refreshError: undefined, }); try { // Empty out the current timeline and re-request it @@ -183,7 +184,7 @@ export default class RoomStatusBar extends React.PureComponent { } catch (err) { logger.error('Error while refresing the timeline:', err); this.setState({ - refreshError: err, + refreshError: err as Error, }); } finally { this.setState({ @@ -252,8 +253,8 @@ export default class RoomStatusBar extends React.PureComponent { let title; - let consentError = null; - let resourceLimitError = null; + let consentError: MatrixError | undefined = null; + let resourceLimitError: MatrixError | undefined = null; for (const m of unsentMessages) { if (m.error && m.error.errcode === 'M_CONSENT_NOT_GIVEN') { consentError = m.error; @@ -264,17 +265,26 @@ export default class RoomStatusBar extends React.PureComponent { } } if (consentError) { - title = _t( - "You can't send any messages until you review and agree to " + - "our terms and conditions.", - {}, - { - 'consentLink': (sub) => - - { sub } - , - }, - ); + const consentUri = consentError.data.consent_uri; + if (consentUri) { + title = _t( + "You can't send any messages until you review and agree to " + + "the terms and conditions.", + {}, + { + 'consentLink': (sub) => + + { sub } + , + }, + ); + } else { + title = _t( + "You can't send any messages until you review and agree to " + + "the terms and conditions but the homeserver did not provide " + + "a link to consent. Contact your homeserver administrator.", + ); + } } else if (resourceLimitError) { title = messageForResourceLimitError( resourceLimitError.data.limit_type, @@ -340,7 +350,7 @@ export default class RoomStatusBar extends React.PureComponent { ; } - let errorContent: JSX.Element; + let errorContent: JSX.Element = <>; if (this.state.refreshError) { let errorTextContent; let submitDebugLogsTextContent; diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 9630b3cc13c..2472b04f519 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -186,7 +186,7 @@ interface IState { forwardPaginating: boolean; // cache of matrixClient.getSyncState() (but from the 'sync' event) - clientSyncState: SyncState; + clientSyncState: SyncState | null; // should the event tiles have twelve hour times isTwelveHour: boolean; @@ -237,8 +237,8 @@ class TimelinePanel extends React.Component { private readonly dispatcherRef: string; private timelineWindow?: TimelineWindow; private unmounted = false; - private readReceiptActivityTimer: Timer; - private readMarkerActivityTimer: Timer; + private readReceiptActivityTimer?: Timer; + private readMarkerActivityTimer?: Timer; // A map of private callEventGroupers = new Map(); @@ -253,7 +253,7 @@ class TimelinePanel extends React.Component { // but for now we just do it per room for simplicity. let initialReadMarker: string | null = null; if (this.props.manageReadMarkers) { - const readmarker = this.props.timelineSet.room.getAccountData('m.fully_read'); + const readmarker = this.props.timelineSet.room?.getAccountData('m.fully_read'); if (readmarker) { initialReadMarker = readmarker.getContent().event_id; } else { @@ -283,7 +283,10 @@ class TimelinePanel extends React.Component { const cli = MatrixClientPeg.get(); cli.on(RoomEvent.Timeline, this.onRoomTimeline); cli.on(RoomEvent.TimelineReset, this.onRoomTimelineReset); - this.props.timelineSet.room.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + const room = this.props.timelineSet.room; + if (room) { + room.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + } cli.on(RoomEvent.Redaction, this.onRoomRedaction); if (SettingsStore.getValue("feature_msc3531_hide_messages_pending_moderation")) { // Make sure that events are re-rendered when their visibility-pending-moderation changes. @@ -345,8 +348,14 @@ class TimelinePanel extends React.Component { public componentDidUpdate(prevProps: IProps): void { // When the room changes, setup the new listener if (prevProps.timelineSet.room !== this.props.timelineSet.room) { - prevProps.timelineSet.room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); - this.props.timelineSet.room.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + const prevRoom = prevProps.timelineSet.room; + if (prevRoom) { + prevRoom.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + } + const newRoom = this.props.timelineSet.room; + if (newRoom) { + newRoom.on(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + } } } @@ -383,7 +392,10 @@ class TimelinePanel extends React.Component { client.removeListener(ClientEvent.Sync, this.onSync); } - this.props.timelineSet.room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + const room = this.props.timelineSet.room; + if (room) { + room.removeListener(RoomEvent.TimelineRefresh, this.onRoomTimelineRefresh); + } } /** @@ -457,13 +469,13 @@ class TimelinePanel extends React.Component { let timelineWindowEventIds: string[]; try { - timelineWindowEventIds = this.timelineWindow.getEvents().map(ev => ev.getId()); + timelineWindowEventIds = this.timelineWindow?.getEvents().map(ev => ev.getId()!) ?? []; } catch (err) { logger.error(`onDumpDebugLogs: Failed to get event IDs from the timelineWindow`, err); } let pendingEventIds: string[]; try { - pendingEventIds = this.props.timelineSet.getPendingEvents().map(ev => ev.getId()); + pendingEventIds = this.props.timelineSet.getPendingEvents().map(ev => ev.getId()!); } catch (err) { logger.error(`onDumpDebugLogs: Failed to get pending event IDs`, err); } @@ -753,7 +765,7 @@ class TimelinePanel extends React.Component { } }; - public canResetTimeline = () => this.messagePanel?.current.isAtBottom(); + public canResetTimeline = () => this.messagePanel?.current?.isAtBottom(); private onRoomRedaction = (ev: MatrixEvent, room: Room): void => { if (this.unmounted) return; From ef58f454eb128085e5ced416b8d91f8addee68c9 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 20:38:39 -0600 Subject: [PATCH 68/76] Migrate away from enzyme --- .../historical-import.spec.ts | 20 +- src/components/structures/RoomStatusBar.tsx | 10 +- .../structures/RoomStatusBar-test.tsx | 104 +- .../__snapshots__/RoomStatusBar-test.tsx.snap | 7248 +---------------- 4 files changed, 96 insertions(+), 7286 deletions(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index 8830fddbcb7..83a056ecbd9 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -235,7 +235,7 @@ function sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient) { }); // Ensure the "History import detected" notice is shown - cy.get(`[data-test-id="historical-import-detected-status-bar"]`).should("exist"); + cy.get(`[data-testid="historical-import-detected-status-bar"]`).should("exist"); } /** @@ -412,7 +412,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Ensure historical messages are now shown cy.all([ @@ -437,7 +437,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Ensure historical messages are now shown cy.all([ @@ -459,7 +459,7 @@ describe("MSC2716: Historical Import", () => { sendMarkerEventAndEnsureHistoryDetectedStatusBar(asMatrixClient); // Press "Refresh timeline" - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Ensure all of the messages still show afterwards cy.all([ @@ -511,7 +511,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Wait for the timeline to go blank (meaning it was reset) // and in the middle of the refrsehing timeline function. @@ -611,13 +611,13 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Make sure the request was intercepted and thew an error cy.wait('@contextRequestThatWillTryToMakeNewTimeline').its('response.statusCode').should('eq', 500); // Make sure we tell the user that an error happened - cy.get(`[data-test-id="historical-import-detected-error-content"]`).should("exist"); + cy.get(`[data-testid="historical-import-detected-error-content"]`).should("exist"); // Allow the requests to succeed now cy.all([ @@ -636,7 +636,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" again, this time the network request should succeed - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Make sure the request was intercepted and succeeded cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); @@ -741,7 +741,7 @@ describe("MSC2716: Historical Import", () => { }); // Press "Refresh timeline" - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Make sure the request was intercepted and thew an error cy.wait('@contextRequestThatWillTryToMakeNewTimeline').its('response.statusCode').should('eq', 500); @@ -775,7 +775,7 @@ describe("MSC2716: Historical Import", () => { // draw from locally. So `MatrixClient::fetchLatestLiveTimeline()` will // fetch the latest from `/messages?dir=b` which will return // `eventIdThreadedMessage` as the latest event in the room. - cy.get(`[data-test-id="refresh-timeline-button"]`).click(); + cy.get(`[data-testid="refresh-timeline-button"]`).click(); // Make sure the request was intercepted and succeeded cy.wait('@contextRequestThatWillMakeNewTimeline').its('response.statusCode').should('eq', 200); diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 9bf4aac2179..bc2f4cc8179 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -337,7 +337,7 @@ export default class RoomStatusBar extends React.PureComponent { { _t("Refresh timeline") } @@ -370,7 +370,9 @@ export default class RoomStatusBar extends React.PureComponent { { _t("Please submit debug logs to help us " + "track down the problem.", {}, { debugLogsLink: sub => ( - { sub } + + { sub } + ), }) } ; @@ -378,7 +380,7 @@ export default class RoomStatusBar extends React.PureComponent { errorContent = <>
-
+
{ errorTextContent } { " " } { submitDebugLogsTextContent } @@ -387,7 +389,7 @@ export default class RoomStatusBar extends React.PureComponent { } return ( -
+
{ client = MatrixClientPeg.get(); }); + const customRender = (room: Room) => { + return render( + + + , + ); + }; + describe("getUnsentMessages", () => { const ROOM_ID = "!roomId:example.org"; let room: Room; @@ -119,11 +128,8 @@ describe("RoomStatusBar", () => { pendingEventOrdering: PendingEventOrdering.Detached, }); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); - expect(wrapper).toMatchSnapshot(); + const wrapper = customRender(r1); + expect(wrapper.asFragment()).toMatchSnapshot(); }); describe('connectivity lost bar', () => { @@ -140,11 +146,8 @@ describe("RoomStatusBar", () => { pendingEventOrdering: PendingEventOrdering.Detached, }); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); - expect(wrapper).toMatchSnapshot(); + const wrapper = customRender(r1); + expect(wrapper.asFragment()).toMatchSnapshot(); }); it('connectivity lost bar has priority over the timeline refresh bar', () => { @@ -164,11 +167,8 @@ describe("RoomStatusBar", () => { // Show timeline needs refresh bar r1.setTimelineNeedsRefresh(true); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); - expect(wrapper).toMatchSnapshot(); + const wrapper = customRender(r1); + expect(wrapper.asFragment()).toMatchSnapshot(); }); }); @@ -180,11 +180,8 @@ describe("RoomStatusBar", () => { // Show timeline needs refresh bar r1.setTimelineNeedsRefresh(true); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); - expect(wrapper).toMatchSnapshot(); + const wrapper = customRender(r1); + expect(wrapper.asFragment()).toMatchSnapshot(); }); it('should refresh timeline for room when button clicked', () => { @@ -196,61 +193,68 @@ describe("RoomStatusBar", () => { r1.refreshLiveTimeline = jest.fn(); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); + const wrapper = customRender(r1); - const refreshTimelineButton = wrapper.find('AccessibleButton.mx_RoomStatusBar_refreshTimelineBtn'); - refreshTimelineButton.simulate('click'); + act(() => { + fireEvent.click(wrapper.getByTestId('refresh-timeline-button')); + }); // Make sure that the SDK was called to refresh the timeline expect(r1.refreshLiveTimeline).toHaveBeenCalled(); - - // Expect the refresh timeline bar to be hidden now - expect(wrapper).toMatchSnapshot(); }); it('should show error state with option to submit debug logs ' + - 'in timeline refresh bar when something went wrong while refreshing', () => { + 'in timeline refresh bar when something went wrong while refreshing', async () => { const r1 = new Room("r1", client, "@name:example.com", { pendingEventOrdering: PendingEventOrdering.Detached, }); // Show timeline needs refresh bar r1.setTimelineNeedsRefresh(true); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); + const wrapper = customRender(r1); + + r1.refreshLiveTimeline = jest.fn().mockRejectedValue(new Error('Fake error in test')); act(() => { - wrapper.setState({ - refreshError: new Error('Fake error in test'), - }); + fireEvent.click(wrapper.getByTestId('refresh-timeline-button')); }); - expect(wrapper).toMatchSnapshot(); + + // Make sure that the SDK was called to refresh the timeline + expect(r1.refreshLiveTimeline).toHaveBeenCalled(); + + // Expect error to be shown. We have to wait for the UI to transition. + await waitFor(() => expect(wrapper.getByTestId('historical-import-detected-error-content')).toBeDefined()); + + // Expect an option to submit debug logs to be shown + expect(wrapper.getByTestId('historical-import-detected-error-submit-debug-logs-button')).toBeDefined(); }); it('should show error state without submit debug logs option ' + - 'in timeline refresh bar when ConnectionError while refreshing', () => { + 'in timeline refresh bar when ConnectionError while refreshing', async () => { const r1 = new Room("r1", client, "@name:example.com", { pendingEventOrdering: PendingEventOrdering.Detached, }); // Show timeline needs refresh bar r1.setTimelineNeedsRefresh(true); - const wrapper = mount(, { - wrappingComponent: MatrixClientContext.Provider, - wrappingComponentProps: { value: client }, - }); + const wrapper = customRender(r1); + + const connectionError = new Error('Fake connection error in test'); + connectionError.name = "ConnectionError"; + r1.refreshLiveTimeline = jest.fn().mockRejectedValue(connectionError); act(() => { - const connectionError = new Error('Fake connection error in test'); - connectionError.name = "ConnectionError"; - wrapper.setState({ - refreshError: connectionError, - }); + fireEvent.click(wrapper.getByTestId('refresh-timeline-button')); }); - expect(wrapper).toMatchSnapshot(); + + // Make sure that the SDK was called to refresh the timeline + expect(r1.refreshLiveTimeline).toHaveBeenCalled(); + + // Expect error to be shown + await waitFor(() => expect(wrapper.getByTestId('historical-import-detected-error-content')).toBeDefined()); + + // The submit debug logs option should *NOT* be shown. + // + // We have to use `queryBy` so that it can return `null` for something that does not exist. + expect(wrapper.queryByTestId('historical-import-detected-error-submit-debug-logs-button]')).toBeNull(); }); }); }); diff --git a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap index 32552938a2d..65bbf66ad1e 100644 --- a/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomStatusBar-test.tsx.snap @@ -1,1008 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority over the timeline refresh bar 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": true, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -> +
Connectivity to the server has been lost.
Sent messages will be stored until your connection has returned.
@@ -1025,1012 +32,19 @@ exports[`RoomStatusBar connectivity lost bar connectivity lost bar has priority
- + `; exports[`RoomStatusBar connectivity lost bar should show connection lost bar when sync has an error 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": false, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -> +
Connectivity to the server has been lost.
Sent messages will be stored until your connection has returned.
@@ -2053,2021 +67,22 @@ exports[`RoomStatusBar connectivity lost bar should show connection lost bar whe
- + `; -exports[`RoomStatusBar does not show anything when no sync error or other status 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": false, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -/> -`; +exports[`RoomStatusBar does not show anything when no sync error or other status 1`] = ``; -exports[`RoomStatusBar timeline needs refresh bar (history import) should refresh timeline for room when button clicked 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "refreshLiveTimeline": [MockFunction] { - "calls": Array [ - Array [], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": true, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -> +exports[`RoomStatusBar timeline needs refresh bar (history import) should show timeline refresh bar when history import detected 1`] = ` +
History import detected.
History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline.
- -
-
-
- - - Refreshing - -
-
-
- -`; - -exports[`RoomStatusBar timeline needs refresh bar (history import) should show error state with option to submit debug logs in timeline refresh bar when something went wrong while refreshing 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": true, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -> -
-
-
- -
-
-
- History import detected. -
- History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. -
-
-
- An error occurred while trying to refresh the timeline. - - - Please submit - -
- debug logs -
-
- to help us track down the problem. -
-
-
-
- -
- Refresh timeline -
-
-
-
-
-
-`; - -exports[`RoomStatusBar timeline needs refresh bar (history import) should show error state without submit debug logs option in timeline refresh bar when ConnectionError while refreshing 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": true, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -> -
-
-
- -
-
-
- History import detected. -
-
- History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. -
-
-
- A network error occurred while trying to refresh the timeline. Your homeserver might be down or was just a temporary problem with your internet connection. - -
-
-
- -
- Refresh timeline -
-
-
-
-
-
-`; - -exports[`RoomStatusBar timeline needs refresh bar (history import) should show timeline refresh bar when history import detected 1`] = ` - 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "currentState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "filteredTimelineSets": Object {}, - "getTypeWarning": false, - "getVersionWarning": false, - "lastThread": undefined, - "membersPromise": Promise {}, - "myUserId": "@name:example.com", - "name": "r1", - "normalizedName": "r1", - "notificationCounts": Object {}, - "oldState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "opts": Object { - "pendingEventOrdering": "detached", - }, - "pendingEventList": Array [], - "reEmitter": TypedReEmitter { - "reEmitters": Map { - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - } => Map { - "Room.timeline" => [Function], - "Room.timelineReset" => [Function], - }, - RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - } => Map { - "RoomState.events" => [Function], - "RoomState.members" => [Function], - "RoomState.newMember" => [Function], - "RoomState.update" => [Function], - "RoomState.Marker" => [Function], - "Beacon.new" => [Function], - "Beacon.update" => [Function], - "Beacon.Destroy" => [Function], - "Beacon.LivenessChange" => [Function], - }, - }, - "target": [Circular], - }, - "receiptCacheByEventId": Object {}, - "receipts": Object {}, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "roomId": "r1", - "selfMembership": undefined, - "summary": null, - "summaryHeroes": null, - "tags": Object {}, - "threadNotifications": Map {}, - "threadTimelineSetsPromise": null, - "threads": Map {}, - "threadsReady": false, - "threadsTimelineSets": Array [], - "timeline": Array [], - "timelineNeedsRefresh": true, - "timelineSets": Array [ - EventTimelineSet { - "_eventIdToTimeline": Map {}, - "_events": Object { - "Room.timeline": [Function], - "Room.timelineReset": [Function], - }, - "_eventsCount": 2, - "_maxListeners": undefined, - "displayPendingEvents": true, - "filter": undefined, - "liveTimeline": EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - "relations": RelationsContainer { - "client": Object { - "canSupport": Map { - "Thread" => 0, - "ThreadUnreadNotifications" => 0, - "LoginTokenRequest" => 0, - }, - "cancelPendingEvent": [MockFunction], - "createRoom": [MockFunction], - "credentials": Object { - "userId": "@userId:matrix.org", - }, - "crypto": Object { - "deviceList": Object { - "downloadKeys": [MockFunction], - }, - }, - "decryptEventIfNeeded": [Function], - "doesServerSupportUnstableFeature": [MockFunction], - "downloadKeys": [MockFunction], - "emit": [Function], - "encryptAndSendToDevices": [MockFunction], - "fetchRoomEvent": [MockFunction], - "generateClientSecret": [Function], - "getAccountData": [Function], - "getCapabilities": [MockFunction], - "getClientWellKnown": [MockFunction], - "getDeviceId": [MockFunction], - "getDevices": [MockFunction], - "getDomain": [MockFunction], - "getEventMapper": [Function], - "getHomeserverUrl": [MockFunction], - "getIdentityAccount": [MockFunction], - "getIdentityServerUrl": [MockFunction], - "getMediaHandler": [MockFunction], - "getOpenIdToken": [MockFunction], - "getProfileInfo": [MockFunction], - "getPushActionsForEvent": [MockFunction], - "getPushRules": [MockFunction], - "getPushers": [MockFunction], - "getRoom": [MockFunction], - "getRoomDirectoryVisibility": [MockFunction], - "getRoomHierarchy": [MockFunction], - "getRoomIdForAlias": [MockFunction], - "getRoomUpgradeHistory": [MockFunction], - "getRooms": [MockFunction], - "getSyncState": [Function], - "getSyncStateData": [Function], - "getTerms": [MockFunction], - "getThirdpartyProtocols": [MockFunction], - "getThirdpartyUser": [MockFunction], - "getThreePids": [MockFunction], - "getTurnServers": [MockFunction], - "getTurnServersExpiry": [MockFunction], - "getUser": [MockFunction], - "getUserId": [MockFunction], - "getVisibleRooms": [MockFunction], - "hasLazyLoadMembersEnabled": [MockFunction], - "isCryptoEnabled": [MockFunction], - "isGuest": [MockFunction], - "isInitialSyncComplete": [MockFunction], - "isRoomEncrypted": [MockFunction], - "isUserIgnored": [MockFunction], - "isVersionSupported": [MockFunction], - "loginFlows": [MockFunction], - "makeTxnId": [MockFunction], - "mxcUrlToHttp": [Function], - "off": [Function], - "on": [Function], - "paginateEventTimeline": [MockFunction], - "peekInRoom": [MockFunction], - "pushRules": Object {}, - "queueToDevice": [MockFunction], - "reEmitter": ReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "registerWithIdentityServer": [MockFunction], - "relations": [MockFunction], - "removeListener": [Function], - "sendMessage": [MockFunction], - "sendReadReceipt": [MockFunction], - "sendStateEvent": [MockFunction], - "sendToDevice": [MockFunction], - "sendTyping": [MockFunction], - "setAccountData": [MockFunction], - "setPowerLevel": [MockFunction], - "setPushRuleActions": [MockFunction], - "setPushRuleEnabled": [MockFunction], - "setPusher": [MockFunction], - "setRoomAccountData": [MockFunction], - "setRoomReadMarkers": [MockFunction], - "setRoomTopic": [MockFunction], - "stopPeeking": [MockFunction], - "store": Object { - "getPendingEvents": [MockFunction] { - "calls": Array [ - Array [ - "r1", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": Promise {}, - }, - ], - }, - "removeRoom": [MockFunction], - "setPendingEvents": [MockFunction], - "storeRoom": [MockFunction], - }, - "supportsExperimentalThreads": [Function], - "supportsVoip": [MockFunction], - "uploadContent": [MockFunction], - }, - "relations": Map {}, - "room": [Circular], - }, - "room": [Circular], - "thread": undefined, - "threadListType": null, - "timelineSupport": false, - "timelines": Array [ - EventTimeline { - "baseIndex": 0, - "endState": RoomState { - "_events": Object { - "Beacon.Destroy": [Function], - "Beacon.LivenessChange": [Function], - "Beacon.new": [Function], - "Beacon.update": [Function], - "RoomState.Marker": [Function], - "RoomState.events": [Function], - "RoomState.members": [Function], - "RoomState.newMember": [Function], - "RoomState.update": [Function], - }, - "_eventsCount": 9, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - "eventTimelineSet": [Circular], - "events": Array [], - "name": "r1:2021-11-23T14:35:14.240Z", - "nextTimeline": null, - "paginationRequests": Object { - "b": null, - "f": null, - }, - "prevTimeline": null, - "roomId": "r1", - "startState": RoomState { - "_events": Object {}, - "_eventsCount": 0, - "_liveBeaconIds": Array [], - "_maxListeners": undefined, - "beacons": Map {}, - "displayNameToUserIds": Map {}, - "events": Map {}, - "invitedMemberCount": null, - "joinedMemberCount": null, - "members": Object {}, - "modified": 2345678901234, - "oobMemberFlags": Object { - "status": 0, - }, - "paginationToken": null, - "reEmitter": TypedReEmitter { - "reEmitters": Map {}, - "target": [Circular], - }, - "roomId": "r1", - "sentinels": Object {}, - "summaryInvitedMemberCount": null, - "summaryJoinedMemberCount": null, - "tokenToInvite": Object {}, - "userIdsToDisplayNames": Object {}, - Symbol(kCapture): false, - }, - }, - ], - Symbol(kCapture): false, - }, - ], - "txnToEvent": Object {}, - "updateThreadRootEvent": [Function], - "updateThreadRootEvents": [Function], - "visibilityEvents": Map {}, - Symbol(kCapture): false, - } - } -> -
-
-
- -
-
-
- History import detected. + Refresh timeline
-
- History was just imported somewhere in the room. In order to see the historical messages, refresh your timeline. -
-
-
- -
- Refresh timeline -
-
-
+ `; From 012d27fdaaab53853c2ec01fabc2fe8c6b8ed6c6 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 20:53:57 -0600 Subject: [PATCH 69/76] Fix more strict errors --- src/components/structures/RoomStatusBar.tsx | 52 +++++++++++-------- src/components/structures/TimelinePanel.tsx | 25 +++++---- src/utils/ErrorUtils.tsx | 2 +- .../structures/RoomStatusBar-test.tsx | 1 - 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index bc2f4cc8179..17d42ceee8e 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -253,8 +253,8 @@ export default class RoomStatusBar extends React.PureComponent { let title; - let consentError: MatrixError | undefined = null; - let resourceLimitError: MatrixError | undefined = null; + let consentError: MatrixError | undefined; + let resourceLimitError: MatrixError | undefined; for (const m of unsentMessages) { if (m.error && m.error.errcode === 'M_CONSENT_NOT_GIVEN') { consentError = m.error; @@ -286,24 +286,34 @@ export default class RoomStatusBar extends React.PureComponent { ); } } else if (resourceLimitError) { - title = messageForResourceLimitError( - resourceLimitError.data.limit_type, - resourceLimitError.data.admin_contact, - { - 'monthly_active_user': _td( - "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " + - "Please contact your service administrator to continue using the service.", - ), - 'hs_disabled': _td( - "Your message wasn't sent because this homeserver has been blocked by its administrator. " + - "Please contact your service administrator to continue using the service.", - ), - '': _td( - "Your message wasn't sent because this homeserver has exceeded a resource limit. " + - "Please contact your service administrator to continue using the service.", - ), - }, - ); + const limitType = resourceLimitError.data.limit_type; + if (limitType) { + const adminContact = resourceLimitError.data.admin_contact; + title = messageForResourceLimitError( + limitType, + adminContact, + { + 'monthly_active_user': _td( + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " + + "Please contact your service administrator to continue using the service.", + ), + 'hs_disabled': _td( + "Your message wasn't sent because this homeserver has been blocked by its administrator. " + + "Please contact your service administrator to continue using the service.", + ), + '': _td( + "Your message wasn't sent because this homeserver has exceeded a resource limit. " + + "Please contact your service administrator to continue using the service.", + ), + }, + ); + } else { + title = _t( + "Your message wasn't sent because it ran into a M_RESOURCE_LIMIT_EXCEEDED error. " + + "We were unable to determine the exact type of error because the response did not include it." + + "Contact your homeserver administrator.", + ); + } } else { title = _t('Some of your messages have not been sent'); } @@ -423,7 +433,7 @@ export default class RoomStatusBar extends React.PureComponent { }); }; - public render(): JSX.Element { + public render(): JSX.Element | null { if (this.shouldShowConnectionError()) { return (
diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 2472b04f519..ada7555778f 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -237,8 +237,8 @@ class TimelinePanel extends React.Component { private readonly dispatcherRef: string; private timelineWindow?: TimelineWindow; private unmounted = false; - private readReceiptActivityTimer?: Timer; - private readMarkerActivityTimer?: Timer; + private readReceiptActivityTimer: Timer | null = null; + private readMarkerActivityTimer: Timer | null = null; // A map of private callEventGroupers = new Map(); @@ -416,7 +416,7 @@ class TimelinePanel extends React.Component { // Get the list of actually rendered events seen in the DOM. // This is useful to know for sure what's being shown on screen. // And we can suss out any corrupted React `key` problems. - let renderedEventIds: string[]; + let renderedEventIds: string[] = []; try { const messagePanel = this.messagePanel.current; if (messagePanel) { @@ -434,8 +434,8 @@ class TimelinePanel extends React.Component { // Get the list of events and threads for the room as seen by the // matrix-js-sdk. - let serializedEventIdsFromTimelineSets: { [key: string]: string[] }[]; - let serializedEventIdsFromThreadsTimelineSets: { [key: string]: string[] }[]; + let serializedEventIdsFromTimelineSets: { [key: string]: string[] }[] = []; + let serializedEventIdsFromThreadsTimelineSets: { [key: string]: string[] }[] = []; const serializedThreadsMap: { [key: string]: any } = {}; if (room) { const timelineSets = room.getTimelineSets(); @@ -467,13 +467,13 @@ class TimelinePanel extends React.Component { } } - let timelineWindowEventIds: string[]; + let timelineWindowEventIds: string[] = []; try { timelineWindowEventIds = this.timelineWindow?.getEvents().map(ev => ev.getId()!) ?? []; } catch (err) { logger.error(`onDumpDebugLogs: Failed to get event IDs from the timelineWindow`, err); } - let pendingEventIds: string[]; + let pendingEventIds: string[] = []; try { pendingEventIds = this.props.timelineSet.getPendingEvents().map(ev => ev.getId()!); } catch (err) { @@ -765,7 +765,7 @@ class TimelinePanel extends React.Component { } }; - public canResetTimeline = () => this.messagePanel?.current?.isAtBottom(); + public canResetTimeline = () => !!this.messagePanel?.current?.isAtBottom(); private onRoomRedaction = (ev: MatrixEvent, room: Room): void => { if (this.unmounted) return; @@ -791,9 +791,14 @@ class TimelinePanel extends React.Component { return; } + const eventId = ev.getId(); + if (!eventId) { + return; + } + // we could skip an update if the event isn't in our timeline, // but that's probably an early optimisation. - const tile = this.messagePanel.current?.getTileForEventId(ev.getId()); + const tile = this.messagePanel.current?.getTileForEventId(eventId); if (tile) { tile.forceUpdate(); } @@ -1800,7 +1805,7 @@ class TimelinePanel extends React.Component { // the HS and fetch the latest events, so we are effectively forward paginating. const forwardPaginating = ( this.state.forwardPaginating || - ['PREPARED', 'CATCHUP'].includes(this.state.clientSyncState) + ['PREPARED', 'CATCHUP'].includes(this.state.clientSyncState!) ); const events = this.state.firstVisibleEventIndex ? this.state.events.slice(this.state.firstVisibleEventIndex) diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index ff78fe076c4..3beb77bb3d3 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -35,7 +35,7 @@ import { _t, _td, Tags, TranslatedString } from '../languageHandler'; */ export function messageForResourceLimitError( limitType: string, - adminContact: string, + adminContact?: string, strings: Record, extraTranslations?: Tags, ): TranslatedString { diff --git a/test/components/structures/RoomStatusBar-test.tsx b/test/components/structures/RoomStatusBar-test.tsx index 13bc3dc4bbf..432f8729909 100644 --- a/test/components/structures/RoomStatusBar-test.tsx +++ b/test/components/structures/RoomStatusBar-test.tsx @@ -31,7 +31,6 @@ import { getUnsentMessages } from "../../../src/components/structures/RoomStatus import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; import { mkEvent, stubClient } from "../../test-utils/test-utils"; import { mkThread } from "../../test-utils/threads"; -import { sleep } from "matrix-js-sdk/src/utils"; // Fake date to give a predictable snapshot const realDateNow = Date.now; From d2e300be6b26a1575282f7bf30ed9ab0a01bf583 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 20:58:57 -0600 Subject: [PATCH 70/76] Update i18n --- src/components/structures/RoomStatusBar.tsx | 2 +- src/i18n/strings/en_EN.json | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 17d42ceee8e..6b8db9b1084 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -310,7 +310,7 @@ export default class RoomStatusBar extends React.PureComponent { } else { title = _t( "Your message wasn't sent because it ran into a M_RESOURCE_LIMIT_EXCEEDED error. " + - "We were unable to determine the exact type of error because the response did not include it." + + "We were unable to determine the exact type of error because the response did not include it. " + "Contact your homeserver administrator.", ); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1a5b8691bd5..ce11b9f9ed0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -3307,10 +3307,12 @@ "Find a room…": "Find a room…", "Find a room… (e.g. %(exampleRoom)s)": "Find a room… (e.g. %(exampleRoom)s)", "If you can't find the room you're looking for, ask for an invite or create a new room.": "If you can't find the room you're looking for, ask for an invite or create a new room.", - "You can't send any messages until you review and agree to our terms and conditions.": "You can't send any messages until you review and agree to our terms and conditions.", + "You can't send any messages until you review and agree to the terms and conditions.": "You can't send any messages until you review and agree to the terms and conditions.", + "You can't send any messages until you review and agree to the terms and conditions but the homeserver did not provide a link to consent. Contact your homeserver administrator.": "You can't send any messages until you review and agree to the terms and conditions but the homeserver did not provide a link to consent. Contact your homeserver administrator.", "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.": "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. Please contact your service administrator to continue using the service.", "Your message wasn't sent because this homeserver has been blocked by its administrator. Please contact your service administrator to continue using the service.": "Your message wasn't sent because this homeserver has been blocked by its administrator. Please contact your service administrator to continue using the service.", "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.": "Your message wasn't sent because this homeserver has exceeded a resource limit. Please contact your service administrator to continue using the service.", + "Your message wasn't sent because it ran into a M_RESOURCE_LIMIT_EXCEEDED error. We were unable to determine the exact type of error because the response did not include it. Contact your homeserver administrator.": "Your message wasn't sent because it ran into a M_RESOURCE_LIMIT_EXCEEDED error. We were unable to determine the exact type of error because the response did not include it. Contact your homeserver administrator.", "Some of your messages have not been sent": "Some of your messages have not been sent", "Delete all": "Delete all", "Retry all": "Retry all", From eb815cc6d983c629894be565991bf8f8c2358a74 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 20:59:49 -0600 Subject: [PATCH 71/76] Workaround lint See: ``` Error: src/utils/ErrorUtils.tsx(39,5): error TS1016: A required parameter cannot follow an optional parameter. ``` --- src/components/structures/RoomStatusBar.tsx | 2 +- src/utils/ErrorUtils.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 6b8db9b1084..51cc4d72878 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -291,7 +291,7 @@ export default class RoomStatusBar extends React.PureComponent { const adminContact = resourceLimitError.data.admin_contact; title = messageForResourceLimitError( limitType, - adminContact, + adminContact ?? null, { 'monthly_active_user': _td( "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " + diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index 3beb77bb3d3..e357d14c75e 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -35,7 +35,7 @@ import { _t, _td, Tags, TranslatedString } from '../languageHandler'; */ export function messageForResourceLimitError( limitType: string, - adminContact?: string, + adminContact: string | null, strings: Record, extraTranslations?: Tags, ): TranslatedString { From b9cd0a69eae855bf3c7075f65190758095ae6cad Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 22:14:44 -0600 Subject: [PATCH 72/76] More strict lints --- src/components/structures/MessagePanel.tsx | 6 +++--- src/components/structures/RoomStatusBar.tsx | 2 +- src/components/structures/TimelinePanel.tsx | 9 +++++++-- src/components/views/rooms/EventTile.tsx | 2 +- src/utils/ErrorUtils.tsx | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 56c396750ff..f6ac0dd58a6 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -145,7 +145,7 @@ interface IProps { // the userid of our user. This is used to suppress the read marker // for pending messages. - ourUserId?: string; + ourUserId: string | null | undefined; // whether the timeline can visually go back any further canBackPaginate?: boolean; @@ -159,7 +159,7 @@ interface IProps { stickyBottom?: boolean; // className for the panel - className: string; + className?: string; // show twelve hour timestamps isTwelveHour?: boolean; @@ -173,7 +173,7 @@ interface IProps { // which layout to use layout?: Layout; - resizeNotifier: ResizeNotifier; + resizeNotifier?: ResizeNotifier; permalinkCreator?: RoomPermalinkCreator; editState?: EditorStateTransfer; diff --git a/src/components/structures/RoomStatusBar.tsx b/src/components/structures/RoomStatusBar.tsx index 51cc4d72878..6b8db9b1084 100644 --- a/src/components/structures/RoomStatusBar.tsx +++ b/src/components/structures/RoomStatusBar.tsx @@ -291,7 +291,7 @@ export default class RoomStatusBar extends React.PureComponent { const adminContact = resourceLimitError.data.admin_contact; title = messageForResourceLimitError( limitType, - adminContact ?? null, + adminContact, { 'monthly_active_user': _td( "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " + diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index ada7555778f..05d64e48653 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -424,7 +424,7 @@ class TimelinePanel extends React.Component { if (messagePanelNode) { const actuallyRenderedEvents = messagePanelNode.querySelectorAll('[data-event-id]'); renderedEventIds = [...actuallyRenderedEvents].map((renderedEvent) => { - return renderedEvent.getAttribute('data-event-id'); + return renderedEvent.getAttribute('data-event-id')!; }); } } @@ -816,7 +816,12 @@ class TimelinePanel extends React.Component { // We could skip an update if the power level change didn't cross the // threshold for `VISIBILITY_CHANGE_TYPE`. for (const event of this.state.events) { - const tile = this.messagePanel.current?.getTileForEventId(event.getId()); + const stateEventId = event.getId(); + if (!stateEventId) { + continue; + } + + const tile = this.messagePanel.current?.getTileForEventId(stateEventId); if (!tile) { // The event is not visible, nothing to re-render. continue; diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index f6b249b2913..0b57895a77c 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -87,7 +87,7 @@ import { isLocalRoom } from '../../../utils/localRoom/isLocalRoom'; import { ElementCall } from "../../../models/Call"; import { UnreadNotificationBadge } from './NotificationBadge/UnreadNotificationBadge'; -export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: string) => Relations; +export type GetRelationsForEvent = (eventId: string, relationType: string, eventType: EventType | string) => Relations; // Our component structure for EventTiles on the timeline is: // diff --git a/src/utils/ErrorUtils.tsx b/src/utils/ErrorUtils.tsx index e357d14c75e..3c2dae317aa 100644 --- a/src/utils/ErrorUtils.tsx +++ b/src/utils/ErrorUtils.tsx @@ -35,7 +35,7 @@ import { _t, _td, Tags, TranslatedString } from '../languageHandler'; */ export function messageForResourceLimitError( limitType: string, - adminContact: string | null, + adminContact: string | null | undefined, strings: Record, extraTranslations?: Tags, ): TranslatedString { From 43f90f6923d4df85dfbea4dfcb23074840165ea9 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 7 Nov 2022 22:18:07 -0600 Subject: [PATCH 73/76] Use supported room version --- .../e2e/x-msc2716-historical-import/historical-import.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts index 83a056ecbd9..94a1d17322b 100644 --- a/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts +++ b/cypress/e2e/x-msc2716-historical-import/historical-import.spec.ts @@ -263,7 +263,7 @@ function setupRoomWithHistoricalMessagesAndMarker({ const resp = await asMatrixClient.createRoom({ preset: win.matrixcs.Preset.PublicChat, name: "test-msc2716", - room_version: "org.matrix.msc2716v3", + room_version: "org.matrix.msc2716v4", }); cy.wrap(resp.room_id).as('roomId'); }); From 131af45c97034c0dba419e860293e462f1439983 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 8 Nov 2022 00:57:30 -0600 Subject: [PATCH 74/76] Fix lints --- src/components/structures/MessagePanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index f6ac0dd58a6..ab4309e3dc9 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -145,7 +145,7 @@ interface IProps { // the userid of our user. This is used to suppress the read marker // for pending messages. - ourUserId: string | null | undefined; + ourUserId?: string | null | undefined; // whether the timeline can visually go back any further canBackPaginate?: boolean; @@ -186,7 +186,7 @@ interface IProps { // helper function to access relations for an event onUnfillRequest?(backwards: boolean, scrollToken: string): void; - getRelationsForEvent?(eventId: string, relationType: string, eventType: string): Relations; + getRelationsForEvent?(eventId: string, relationType: string, eventType: EventType | string): Relations; hideThreadedMessages?: boolean; disableGrouping?: boolean; From 280ddb5faeb2db82d456e0c94956574d0799bfe4 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 8 Nov 2022 01:12:07 -0600 Subject: [PATCH 75/76] Fix `Error: TypeError: (0 , _jestMock.mocked)(...).mockReturnValue is not a function` See https://github.com/matrix-org/matrix-react-sdk/actions/runs/3416332427/jobs/5686363049#step:6:142 --- test/test-utils/test-utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 6ad7520bfb9..7f18aa745ec 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -34,7 +34,7 @@ import { RoomType, } from 'matrix-js-sdk/src/matrix'; import { - ISyncStateData, SyncState, + SyncState, } from 'matrix-js-sdk/src/sync'; import { normalize } from "matrix-js-sdk/src/utils"; import { ReEmitter } from "matrix-js-sdk/src/ReEmitter"; @@ -146,8 +146,8 @@ export function createTestClient(): MatrixClient { sendTyping: jest.fn().mockResolvedValue({}), sendMessage: jest.fn().mockResolvedValue({}), sendStateEvent: jest.fn().mockResolvedValue(undefined), - getSyncState: (): SyncState => SyncState.Syncing, - getSyncStateData: (): ISyncStateData => ({}), + getSyncState: jest.fn().mockReturnValue(SyncState.Syncing), + getSyncStateData: jest.fn().mockReturnValue({}), generateClientSecret: () => "t35tcl1Ent5ECr3T", isGuest: jest.fn().mockReturnValue(false), getRoomHierarchy: jest.fn().mockReturnValue({ From 1726830462151419ef9cd36a9eb0e21b718da4ba Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Tue, 8 Nov 2022 01:13:26 -0600 Subject: [PATCH 76/76] Update snapshots with small change and lots of quote escaping differences --- .../structures/__snapshots__/RoomView-test.tsx.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/components/structures/__snapshots__/RoomView-test.tsx.snap b/test/components/structures/__snapshots__/RoomView-test.tsx.snap index 33f44f9a371..54e05d6a625 100644 --- a/test/components/structures/__snapshots__/RoomView-test.tsx.snap +++ b/test/components/structures/__snapshots__/RoomView-test.tsx.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RoomView for a local room in state CREATING should match the snapshot 1`] = `"
@user:example.com
We're creating a room with @user:example.com
"`; +exports[`RoomView for a local room in state CREATING should match the snapshot 1`] = `"
U\\"\\"
@user:example.com
We're creating a room with @user:example.com
"`; -exports[`RoomView for a local room in state ERROR should match the snapshot 1`] = `"
@user:example.com
  1. End-to-end encryption isn't enabled
    Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.

    @user:example.com

    Send your first message to invite @user:example.com to chat

!
Some of your messages have not been sent
Retry
"`; +exports[`RoomView for a local room in state ERROR should match the snapshot 1`] = `"
U\\"\\"
@user:example.com
  1. End-to-end encryption isn't enabled
    Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.
    U\\"\\"

    @user:example.com

    Send your first message to invite @user:example.com to chat

!
Some of your messages have not been sent
Retry
"`; -exports[`RoomView for a local room in state NEW should match the snapshot 1`] = `"
@user:example.com
  1. End-to-end encryption isn't enabled
    Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.

    @user:example.com

    Send your first message to invite @user:example.com to chat


"`; +exports[`RoomView for a local room in state NEW should match the snapshot 1`] = `"
U\\"\\"
@user:example.com
  1. End-to-end encryption isn't enabled
    Your private messages are normally encrypted, but this room isn't. Usually this is due to an unsupported device or method being used, like email invites.
    U\\"\\"

    @user:example.com

    Send your first message to invite @user:example.com to chat


"`; -exports[`RoomView for a local room in state NEW that is encrypted should match the snapshot 1`] = `"
@user:example.com
    Encryption enabled
    Messages in this chat will be end-to-end encrypted.
  1. @user:example.com

    Send your first message to invite @user:example.com to chat


"`; +exports[`RoomView for a local room in state NEW that is encrypted should match the snapshot 1`] = `"
U\\"\\"
@user:example.com
    Encryption enabled
    Messages in this chat will be end-to-end encrypted.
  1. U\\"\\"

    @user:example.com

    Send your first message to invite @user:example.com to chat


"`;