@@ -15,8 +15,19 @@ limitations under the License.
15
15
*/
16
16
17
17
import * as utils from "../test-utils/test-utils" ;
18
- import { ClientEvent , EventTimeline , Filter , IEvent , MatrixClient , MatrixEvent , Room } from "../../src/matrix" ;
18
+ import {
19
+ ClientEvent ,
20
+ Direction ,
21
+ EventTimeline ,
22
+ EventTimelineSet ,
23
+ Filter ,
24
+ IEvent ,
25
+ MatrixClient ,
26
+ MatrixEvent ,
27
+ Room ,
28
+ } from "../../src/matrix" ;
19
29
import { logger } from "../../src/logger" ;
30
+ import { encodeUri } from "../../src/utils" ;
20
31
import { TestClient } from "../TestClient" ;
21
32
import { FeatureSupport , Thread , THREAD_RELATION_TYPE } from "../../src/models/thread" ;
22
33
@@ -133,6 +144,44 @@ const THREAD_REPLY = utils.mkEvent({
133
144
134
145
THREAD_ROOT . unsigned [ "m.relations" ] [ "io.element.thread" ] . latest_event = THREAD_REPLY ;
135
146
147
+ const STABLE_THREAD_ROOT = utils . mkEvent ( {
148
+ room : roomId ,
149
+ user : userId ,
150
+ type : "m.room.message" ,
151
+ content : {
152
+ "body" : "thread root" ,
153
+ "msgtype" : "m.text" ,
154
+ } ,
155
+ unsigned : {
156
+ "m.relations" : {
157
+ "m.thread" : {
158
+ //"latest_event": undefined,
159
+ "count" : 1 ,
160
+ "current_user_participated" : true ,
161
+ } ,
162
+ } ,
163
+ } ,
164
+ event : false ,
165
+ } ) ;
166
+
167
+ const STABLE_THREAD_REPLY = utils . mkEvent ( {
168
+ room : roomId ,
169
+ user : userId ,
170
+ type : "m.room.message" ,
171
+ content : {
172
+ "body" : "thread reply" ,
173
+ "msgtype" : "m.text" ,
174
+ "m.relates_to" : {
175
+ // We can't use the const here because we change server support mode for test
176
+ rel_type : "m.thread" ,
177
+ event_id : THREAD_ROOT . event_id ,
178
+ } ,
179
+ } ,
180
+ event : false ,
181
+ } ) ;
182
+
183
+ STABLE_THREAD_ROOT . unsigned [ "m.relations" ] [ "m.thread" ] . latest_event = STABLE_THREAD_REPLY ;
184
+
136
185
const SYNC_THREAD_ROOT = withoutRoomId ( THREAD_ROOT ) ;
137
186
const SYNC_THREAD_REPLY = withoutRoomId ( THREAD_REPLY ) ;
138
187
SYNC_THREAD_ROOT . unsigned = {
@@ -925,6 +974,231 @@ describe("MatrixClient event timelines", function() {
925
974
} ) ;
926
975
} ) ;
927
976
977
+ describe ( "paginateEventTimeline for thread list timeline" , function ( ) {
978
+ async function flushHttp < T > ( promise : Promise < T > ) : Promise < T > {
979
+ return Promise . all ( [ promise , httpBackend . flushAllExpected ( ) ] ) . then ( ( [ result ] ) => result ) ;
980
+ }
981
+
982
+ describe ( "with server compatibility" , function ( ) {
983
+ async function testPagination ( timelineSet : EventTimelineSet , direction : Direction ) {
984
+ const RANDOM_TOKEN = "7280349c7bee430f91defe2a38a0a08c" ;
985
+ function respondToThreads ( ) {
986
+ httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0/rooms/$roomId/threads" , {
987
+ $roomId : roomId ,
988
+ } ) ) . respond ( 200 , {
989
+ chunk : [ STABLE_THREAD_ROOT ] ,
990
+ state : [ ] ,
991
+ next_batch : RANDOM_TOKEN ,
992
+ } ) ;
993
+ }
994
+ function respondToContext ( ) {
995
+ httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0/rooms/$roomId/context/$eventId" , {
996
+ $roomId : roomId ,
997
+ $eventId : STABLE_THREAD_ROOT . event_id ! ,
998
+ } ) ) . respond ( 200 , {
999
+ end : "" ,
1000
+ start : "" ,
1001
+ state : [ ] ,
1002
+ events_before : [ ] ,
1003
+ events_after : [ ] ,
1004
+ event : STABLE_THREAD_ROOT ,
1005
+ } ) ;
1006
+ }
1007
+
1008
+ respondToContext ( ) ;
1009
+ await flushHttp ( client . getEventTimeline ( timelineSet , STABLE_THREAD_ROOT . event_id ! ) ) ;
1010
+ respondToThreads ( ) ;
1011
+ const timeline = await flushHttp ( client . getLatestTimeline ( timelineSet ) ) ;
1012
+ expect ( timeline ) . not . toBeNull ( ) ;
1013
+
1014
+ respondToThreads ( ) ;
1015
+ const success = await flushHttp ( client . paginateEventTimeline ( timeline ! , {
1016
+ backwards : direction === Direction . Backward ,
1017
+ } ) ) ;
1018
+ expect ( success ) . toBeTruthy ( ) ;
1019
+ expect ( timeline ! . getEvents ( ) . length ) . toEqual ( 1 ) ;
1020
+ expect ( timeline ! . getEvents ( ) [ 0 ] . event ) . toEqual ( STABLE_THREAD_ROOT ) ;
1021
+ expect ( timeline ! . getPaginationToken ( direction ) ) . toEqual ( RANDOM_TOKEN ) ;
1022
+ }
1023
+
1024
+ it ( "should allow you to paginate all threads backwards" , async function ( ) {
1025
+ // @ts -ignore
1026
+ client . clientOpts . experimentalThreadSupport = true ;
1027
+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1028
+ Thread . setServerSideListSupport ( FeatureSupport . Stable ) ;
1029
+
1030
+ const room = client . getRoom ( roomId ) ;
1031
+ const timelineSets = await ( room ?. createThreadsTimelineSets ( ) ) ;
1032
+ expect ( timelineSets ) . not . toBeNull ( ) ;
1033
+ const [ allThreads , myThreads ] = timelineSets ! ;
1034
+ await testPagination ( allThreads , Direction . Backward ) ;
1035
+ await testPagination ( myThreads , Direction . Backward ) ;
1036
+ } ) ;
1037
+
1038
+ it ( "should allow you to paginate all threads forwards" , async function ( ) {
1039
+ // @ts -ignore
1040
+ client . clientOpts . experimentalThreadSupport = true ;
1041
+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1042
+ Thread . setServerSideListSupport ( FeatureSupport . Stable ) ;
1043
+
1044
+ const room = client . getRoom ( roomId ) ;
1045
+ const timelineSets = await ( room ?. createThreadsTimelineSets ( ) ) ;
1046
+ expect ( timelineSets ) . not . toBeNull ( ) ;
1047
+ const [ allThreads , myThreads ] = timelineSets ! ;
1048
+
1049
+ await testPagination ( allThreads , Direction . Forward ) ;
1050
+ await testPagination ( myThreads , Direction . Forward ) ;
1051
+ } ) ;
1052
+
1053
+ it ( "should allow fetching all threads" , async function ( ) {
1054
+ // @ts -ignore
1055
+ client . clientOpts . experimentalThreadSupport = true ;
1056
+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1057
+ Thread . setServerSideListSupport ( FeatureSupport . Stable ) ;
1058
+
1059
+ const RANDOM_TOKEN = "7280349c7bee430f91defe2a38a0a08c" ;
1060
+ function respondToThreads ( ) {
1061
+ httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0/rooms/$roomId/threads" , {
1062
+ $roomId : roomId ,
1063
+ } ) ) . respond ( 200 , {
1064
+ chunk : [ STABLE_THREAD_ROOT ] ,
1065
+ state : [ ] ,
1066
+ next_batch : RANDOM_TOKEN ,
1067
+ } ) ;
1068
+ }
1069
+ const room = client . getRoom ( roomId ) ;
1070
+ const timelineSets = await room ?. createThreadsTimelineSets ( ) ;
1071
+ expect ( timelineSets ) . not . toBeNull ( ) ;
1072
+ respondToThreads ( ) ;
1073
+ respondToThreads ( ) ;
1074
+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , INITIAL_SYNC_DATA ) ;
1075
+ await flushHttp ( room . fetchRoomThreads ( ) ) ;
1076
+ } ) ;
1077
+ } ) ;
1078
+
1079
+ describe ( "without server compatibility" , function ( ) {
1080
+ async function testPagination ( timelineSet : EventTimelineSet , direction : Direction ) {
1081
+ const RANDOM_TOKEN = "7280349c7bee430f91defe2a38a0a08c" ;
1082
+ function respondToMessagesRequest ( ) {
1083
+ httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0/rooms/$roomId/messages" , {
1084
+ $roomId : roomId ,
1085
+ } ) ) . respond ( 200 , {
1086
+ chunk : [ THREAD_ROOT ] ,
1087
+ state : [ ] ,
1088
+ start : `${ Direction . Forward } ${ RANDOM_TOKEN } 2` ,
1089
+ end : `${ Direction . Backward } ${ RANDOM_TOKEN } 2` ,
1090
+ } ) ;
1091
+ }
1092
+ function respondToContext ( ) {
1093
+ httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0/rooms/$roomId/context/$eventId" , {
1094
+ $roomId : roomId ,
1095
+ $eventId : THREAD_ROOT . event_id ! ,
1096
+ } ) ) . respond ( 200 , {
1097
+ end : `${ Direction . Forward } ${ RANDOM_TOKEN } 1` ,
1098
+ start : `${ Direction . Backward } ${ RANDOM_TOKEN } 1` ,
1099
+ state : [ ] ,
1100
+ events_before : [ ] ,
1101
+ events_after : [ ] ,
1102
+ event : THREAD_ROOT ,
1103
+ } ) ;
1104
+ }
1105
+ function respondToSync ( ) {
1106
+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , INITIAL_SYNC_DATA ) ;
1107
+ }
1108
+
1109
+ respondToContext ( ) ;
1110
+ respondToSync ( ) ;
1111
+ await flushHttp ( client . getEventTimeline ( timelineSet , THREAD_ROOT . event_id ! ) ) ;
1112
+
1113
+ respondToMessagesRequest ( ) ;
1114
+ const timeline = await flushHttp ( client . getLatestTimeline ( timelineSet ) ) ;
1115
+ expect ( timeline ) . not . toBeNull ( ) ;
1116
+
1117
+ respondToMessagesRequest ( ) ;
1118
+ const success = await flushHttp ( client . paginateEventTimeline ( timeline ! , {
1119
+ backwards : direction === Direction . Backward ,
1120
+ } ) ) ;
1121
+
1122
+ expect ( success ) . toBeTruthy ( ) ;
1123
+ expect ( timeline ! . getEvents ( ) . length ) . toEqual ( 1 ) ;
1124
+ expect ( timeline ! . getEvents ( ) [ 0 ] . event ) . toEqual ( THREAD_ROOT ) ;
1125
+ expect ( timeline ! . getPaginationToken ( direction ) ) . toEqual ( `${ direction } ${ RANDOM_TOKEN } 2` ) ;
1126
+ }
1127
+
1128
+ it ( "should allow you to paginate all threads" , async function ( ) {
1129
+ // @ts -ignore
1130
+ client . clientOpts . experimentalThreadSupport = true ;
1131
+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1132
+ Thread . setServerSideListSupport ( FeatureSupport . None ) ;
1133
+
1134
+ function respondToFilter ( ) {
1135
+ httpBackend . when ( "POST" , "/filter" ) . respond ( 200 , { filter_id : "fid" } ) ;
1136
+ }
1137
+ function respondToSync ( ) {
1138
+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , INITIAL_SYNC_DATA ) ;
1139
+ }
1140
+
1141
+ const room = client . getRoom ( roomId ) ;
1142
+
1143
+ respondToFilter ( ) ;
1144
+ respondToSync ( ) ;
1145
+ respondToFilter ( ) ;
1146
+ respondToSync ( ) ;
1147
+
1148
+ const timelineSetsPromise = room ?. createThreadsTimelineSets ( ) ;
1149
+ expect ( timelineSetsPromise ) . not . toBeNull ( ) ;
1150
+ const timelineSets = await flushHttp ( timelineSetsPromise ! ) ;
1151
+ expect ( timelineSets ) . not . toBeNull ( ) ;
1152
+ const [ allThreads , myThreads ] = timelineSets ! ;
1153
+
1154
+ await testPagination ( allThreads , Direction . Backward ) ;
1155
+ await testPagination ( myThreads , Direction . Backward ) ;
1156
+ } ) ;
1157
+
1158
+ it ( "should allow fetching all threads" , async function ( ) {
1159
+ // @ts -ignore
1160
+ client . clientOpts . experimentalThreadSupport = true ;
1161
+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1162
+ Thread . setServerSideListSupport ( FeatureSupport . None ) ;
1163
+
1164
+ const room = client . getRoom ( roomId ) ;
1165
+
1166
+ const RANDOM_TOKEN = "7280349c7bee430f91defe2a38a0a08c" ;
1167
+ function respondToMessagesRequest ( ) {
1168
+ httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0/rooms/$roomId/messages" , {
1169
+ $roomId : roomId ,
1170
+ } ) ) . respond ( 200 , {
1171
+ chunk : [ STABLE_THREAD_ROOT ] ,
1172
+ state : [ ] ,
1173
+ start : `${ Direction . Forward } ${ RANDOM_TOKEN } 2` ,
1174
+ end : `${ Direction . Backward } ${ RANDOM_TOKEN } 2` ,
1175
+ } ) ;
1176
+ }
1177
+ function respondToFilter ( ) {
1178
+ httpBackend . when ( "POST" , "/filter" ) . respond ( 200 , { filter_id : "fid" } ) ;
1179
+ }
1180
+ function respondToSync ( ) {
1181
+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , INITIAL_SYNC_DATA ) ;
1182
+ }
1183
+
1184
+ respondToFilter ( ) ;
1185
+ respondToSync ( ) ;
1186
+ respondToFilter ( ) ;
1187
+ respondToSync ( ) ;
1188
+
1189
+ const timelineSetsPromise = room ?. createThreadsTimelineSets ( ) ;
1190
+ expect ( timelineSetsPromise ) . not . toBeNull ( ) ;
1191
+ await flushHttp ( timelineSetsPromise ! ) ;
1192
+ respondToFilter ( ) ;
1193
+ respondToSync ( ) ;
1194
+ respondToSync ( ) ;
1195
+ respondToSync ( ) ;
1196
+ respondToMessagesRequest ( ) ;
1197
+ await flushHttp ( room . fetchRoomThreads ( ) ) ;
1198
+ } ) ;
1199
+ } ) ;
1200
+ } ) ;
1201
+
928
1202
describe ( "event timeline for sent events" , function ( ) {
929
1203
const TXN_ID = "txn1" ;
930
1204
const event = utils . mkMessage ( {
0 commit comments