@@ -342,8 +342,14 @@ describe("MatrixClient event timelines", function() {
342342 httpBackend . verifyNoOutstandingExpectation ( ) ;
343343 client . stopClient ( ) ;
344344 Thread . setServerSideSupport ( FeatureSupport . None ) ;
345+ Thread . setServerSideListSupport ( FeatureSupport . None ) ;
346+ Thread . setServerSideFwdPaginationSupport ( FeatureSupport . None ) ;
345347 } ) ;
346348
349+ async function flushHttp < T > ( promise : Promise < T > ) : Promise < T > {
350+ return Promise . all ( [ promise , httpBackend . flushAllExpected ( ) ] ) . then ( ( [ result ] ) => result ) ;
351+ }
352+
347353 describe ( "getEventTimeline" , function ( ) {
348354 it ( "should create a new timeline for new events" , function ( ) {
349355 const room = client . getRoom ( roomId ) ! ;
@@ -595,31 +601,51 @@ describe("MatrixClient event timelines", function() {
595601 // @ts -ignore
596602 client . clientOpts . experimentalThreadSupport = true ;
597603 Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
598- client . stopClient ( ) ; // we don't need the client to be syncing at this time
604+ await client . stopClient ( ) ; // we don't need the client to be syncing at this time
599605 const room = client . getRoom ( roomId ) ! ;
600- const thread = room . createThread ( THREAD_ROOT . event_id ! , undefined , [ ] , false ) ;
601- const timelineSet = thread . timelineSet ;
602606
603- httpBackend . when ( "GET" , "/rooms/!foo%3Abar/context/" + encodeURIComponent ( THREAD_REPLY . event_id ! ) )
607+ httpBackend . when ( "GET" , "/rooms/!foo%3Abar/event/" + encodeURIComponent ( THREAD_ROOT . event_id ! ) )
608+ . respond ( 200 , function ( ) {
609+ return THREAD_ROOT ;
610+ } ) ;
611+
612+ httpBackend . when ( "GET" , "/rooms/!foo%3Abar/relations/" +
613+ encodeURIComponent ( THREAD_ROOT . event_id ! ) + "/" +
614+ encodeURIComponent ( THREAD_RELATION_TYPE . name ) + "?dir=b&limit=1" )
604615 . respond ( 200 , function ( ) {
605616 return {
606- start : "start_token0" ,
607- events_before : [ ] ,
608- event : THREAD_REPLY ,
609- events_after : [ ] ,
610- end : "end_token0" ,
611- state : [ ] ,
617+ original_event : THREAD_ROOT ,
618+ chunk : [ THREAD_REPLY ] ,
619+ // no next batch as this is the oldest end of the timeline
612620 } ;
613621 } ) ;
614622
623+ const thread = room . createThread ( THREAD_ROOT . event_id ! , undefined , [ ] , false ) ;
624+ await httpBackend . flushAllExpected ( ) ;
625+ const timelineSet = thread . timelineSet ;
626+
627+ const timelinePromise = client . getEventTimeline ( timelineSet , THREAD_REPLY . event_id ! ) ;
628+ const timeline = await timelinePromise ;
629+
630+ expect ( timeline ! . getEvents ( ) . find ( e => e . getId ( ) === THREAD_ROOT . event_id ! ) ) . toBeTruthy ( ) ;
631+ expect ( timeline ! . getEvents ( ) . find ( e => e . getId ( ) === THREAD_REPLY . event_id ! ) ) . toBeTruthy ( ) ;
632+ } ) ;
633+
634+ it ( "should handle thread replies with server support by fetching a contiguous thread timeline" , async ( ) => {
635+ // @ts -ignore
636+ client . clientOpts . experimentalThreadSupport = true ;
637+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
638+ await client . stopClient ( ) ; // we don't need the client to be syncing at this time
639+ const room = client . getRoom ( roomId ) ! ;
640+
615641 httpBackend . when ( "GET" , "/rooms/!foo%3Abar/event/" + encodeURIComponent ( THREAD_ROOT . event_id ! ) )
616642 . respond ( 200 , function ( ) {
617643 return THREAD_ROOT ;
618644 } ) ;
619645
620646 httpBackend . when ( "GET" , "/rooms/!foo%3Abar/relations/" +
621647 encodeURIComponent ( THREAD_ROOT . event_id ! ) + "/" +
622- encodeURIComponent ( THREAD_RELATION_TYPE . name ) + "?limit=20 " )
648+ encodeURIComponent ( THREAD_RELATION_TYPE . name ) + "?dir=b& limit=1 " )
623649 . respond ( 200 , function ( ) {
624650 return {
625651 original_event : THREAD_ROOT ,
@@ -628,9 +654,11 @@ describe("MatrixClient event timelines", function() {
628654 } ;
629655 } ) ;
630656
631- const timelinePromise = client . getEventTimeline ( timelineSet , THREAD_REPLY . event_id ! ) ;
657+ const thread = room . createThread ( THREAD_ROOT . event_id ! , undefined , [ ] , false ) ;
632658 await httpBackend . flushAllExpected ( ) ;
659+ const timelineSet = thread . timelineSet ;
633660
661+ const timelinePromise = client . getEventTimeline ( timelineSet , THREAD_REPLY . event_id ! ) ;
634662 const timeline = await timelinePromise ;
635663
636664 expect ( timeline ! . getEvents ( ) . find ( e => e . getId ( ) === THREAD_ROOT . event_id ! ) ) . toBeTruthy ( ) ;
@@ -1025,10 +1053,6 @@ describe("MatrixClient event timelines", function() {
10251053 } ) ;
10261054
10271055 describe ( "paginateEventTimeline for thread list timeline" , function ( ) {
1028- async function flushHttp < T > ( promise : Promise < T > ) : Promise < T > {
1029- return Promise . all ( [ promise , httpBackend . flushAllExpected ( ) ] ) . then ( ( [ result ] ) => result ) ;
1030- }
1031-
10321056 const RANDOM_TOKEN = "7280349c7bee430f91defe2a38a0a08c" ;
10331057
10341058 function respondToFilter ( ) : ExpectedHttpRequest {
@@ -1050,7 +1074,7 @@ describe("MatrixClient event timelines", function() {
10501074 next_batch : RANDOM_TOKEN as string | null ,
10511075 } ,
10521076 ) : ExpectedHttpRequest {
1053- const request = httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/r0 /rooms/$roomId/threads" , {
1077+ const request = httpBackend . when ( "GET" , encodeUri ( "/_matrix/client/v1 /rooms/$roomId/threads" , {
10541078 $roomId : roomId ,
10551079 } ) ) ;
10561080 request . respond ( 200 , response ) ;
@@ -1089,8 +1113,9 @@ describe("MatrixClient event timelines", function() {
10891113 beforeEach ( ( ) => {
10901114 // @ts -ignore
10911115 client . clientOpts . experimentalThreadSupport = true ;
1092- Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1116+ Thread . setServerSideSupport ( FeatureSupport . Stable ) ;
10931117 Thread . setServerSideListSupport ( FeatureSupport . Stable ) ;
1118+ Thread . setServerSideFwdPaginationSupport ( FeatureSupport . Stable ) ;
10941119 } ) ;
10951120
10961121 async function testPagination ( timelineSet : EventTimelineSet , direction : Direction ) {
@@ -1111,7 +1136,7 @@ describe("MatrixClient event timelines", function() {
11111136
11121137 it ( "should allow you to paginate all threads backwards" , async function ( ) {
11131138 const room = client . getRoom ( roomId ) ;
1114- const timelineSets = await ( room ? .createThreadsTimelineSets ( ) ) ;
1139+ const timelineSets = await room ! . createThreadsTimelineSets ( ) ;
11151140 expect ( timelineSets ) . not . toBeNull ( ) ;
11161141 const [ allThreads , myThreads ] = timelineSets ! ;
11171142 await testPagination ( allThreads , Direction . Backward ) ;
@@ -1120,7 +1145,7 @@ describe("MatrixClient event timelines", function() {
11201145
11211146 it ( "should allow you to paginate all threads forwards" , async function ( ) {
11221147 const room = client . getRoom ( roomId ) ;
1123- const timelineSets = await ( room ? .createThreadsTimelineSets ( ) ) ;
1148+ const timelineSets = await room ! . createThreadsTimelineSets ( ) ;
11241149 expect ( timelineSets ) . not . toBeNull ( ) ;
11251150 const [ allThreads , myThreads ] = timelineSets ! ;
11261151
@@ -1130,7 +1155,7 @@ describe("MatrixClient event timelines", function() {
11301155
11311156 it ( "should allow fetching all threads" , async function ( ) {
11321157 const room = client . getRoom ( roomId ) ! ;
1133- const timelineSets = await room . createThreadsTimelineSets ( ) ;
1158+ const timelineSets = await room ! . createThreadsTimelineSets ( ) ;
11341159 expect ( timelineSets ) . not . toBeNull ( ) ;
11351160 respondToThreads ( ) ;
11361161 respondToThreads ( ) ;
@@ -1418,74 +1443,115 @@ describe("MatrixClient event timelines", function() {
14181443 } ) ;
14191444 } ) ;
14201445
1421- it ( "should re-insert room IDs for bundled thread relation events" , async ( ) => {
1422- // @ts -ignore
1423- client . clientOpts . experimentalThreadSupport = true ;
1424- Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1425-
1426- httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , {
1427- next_batch : "s_5_4" ,
1428- rooms : {
1429- join : {
1430- [ roomId ] : {
1431- timeline : {
1432- events : [
1433- SYNC_THREAD_ROOT ,
1434- ] ,
1435- prev_batch : "f_1_1" ,
1446+ describe ( "should re-insert room IDs for bundled thread relation events" , ( ) => {
1447+ async function doTest ( ) {
1448+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , {
1449+ next_batch : "s_5_4" ,
1450+ rooms : {
1451+ join : {
1452+ [ roomId ] : {
1453+ timeline : {
1454+ events : [
1455+ SYNC_THREAD_ROOT ,
1456+ ] ,
1457+ prev_batch : "f_1_1" ,
1458+ } ,
14361459 } ,
14371460 } ,
14381461 } ,
1439- } ,
1440- } ) ;
1441- await Promise . all ( [ httpBackend . flushAllExpected ( ) , utils . syncPromise ( client ) ] ) ;
1462+ } ) ;
1463+ await Promise . all ( [ httpBackend . flushAllExpected ( ) , utils . syncPromise ( client ) ] ) ;
14421464
1443- const room = client . getRoom ( roomId ) ! ;
1444- const thread = room . getThread ( THREAD_ROOT . event_id ! ) ! ;
1445- const timelineSet = thread . timelineSet ;
1465+ const room = client . getRoom ( roomId ) ! ;
1466+ const thread = room . getThread ( THREAD_ROOT . event_id ! ) ! ;
1467+ const timelineSet = thread . timelineSet ;
14461468
1447- httpBackend . when ( "GET" , "/rooms/!foo%3Abar/context/" + encodeURIComponent ( THREAD_ROOT . event_id ! ) )
1448- . respond ( 200 , {
1449- start : "start_token" ,
1450- events_before : [ ] ,
1451- event : THREAD_ROOT ,
1452- events_after : [ ] ,
1453- state : [ ] ,
1454- end : "end_token" ,
1455- } ) ;
1456- httpBackend . when ( "GET" , "/rooms/!foo%3Abar/relations/" +
1457- encodeURIComponent ( THREAD_ROOT . event_id ! ) + "/" +
1458- encodeURIComponent ( THREAD_RELATION_TYPE . name ) + "?limit=20" )
1459- . respond ( 200 , function ( ) {
1460- return {
1461- original_event : THREAD_ROOT ,
1462- chunk : [ THREAD_REPLY ] ,
1463- // no next batch as this is the oldest end of the timeline
1464- } ;
1465- } ) ;
1466- await Promise . all ( [
1467- client . getEventTimeline ( timelineSet , THREAD_ROOT . event_id ! ) ,
1468- httpBackend . flushAllExpected ( ) ,
1469- ] ) ;
1469+ const buildParams = ( direction : Direction , token : string ) : string => {
1470+ if ( Thread . hasServerSideFwdPaginationSupport === FeatureSupport . Experimental ) {
1471+ return `?from=${ token } &org.matrix.msc3715.dir=${ direction } ` ;
1472+ } else {
1473+ return `?dir=${ direction } &from=${ token } ` ;
1474+ }
1475+ } ;
14701476
1471- httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , {
1472- next_batch : "s_5_5" ,
1473- rooms : {
1474- join : {
1475- [ roomId ] : {
1476- timeline : {
1477- events : [
1478- SYNC_THREAD_REPLY ,
1479- ] ,
1480- prev_batch : "f_1_2" ,
1477+ httpBackend . when ( "GET" , "/rooms/!foo%3Abar/context/" + encodeURIComponent ( THREAD_ROOT . event_id ! ) )
1478+ . respond ( 200 , {
1479+ start : "start_token" ,
1480+ events_before : [ ] ,
1481+ event : THREAD_ROOT ,
1482+ events_after : [ ] ,
1483+ state : [ ] ,
1484+ end : "end_token" ,
1485+ } ) ;
1486+ httpBackend . when ( "GET" , "/rooms/!foo%3Abar/relations/" +
1487+ encodeURIComponent ( THREAD_ROOT . event_id ! ) + "/" +
1488+ encodeURIComponent ( THREAD_RELATION_TYPE . name ) + buildParams ( Direction . Backward , "start_token" ) )
1489+ . respond ( 200 , function ( ) {
1490+ return {
1491+ original_event : THREAD_ROOT ,
1492+ chunk : [ ] ,
1493+ } ;
1494+ } ) ;
1495+ httpBackend . when ( "GET" , "/rooms/!foo%3Abar/relations/" +
1496+ encodeURIComponent ( THREAD_ROOT . event_id ! ) + "/" +
1497+ encodeURIComponent ( THREAD_RELATION_TYPE . name ) + buildParams ( Direction . Forward , "end_token" ) )
1498+ . respond ( 200 , function ( ) {
1499+ return {
1500+ original_event : THREAD_ROOT ,
1501+ chunk : [ THREAD_REPLY ] ,
1502+ } ;
1503+ } ) ;
1504+ const timeline = await flushHttp ( client . getEventTimeline ( timelineSet , THREAD_ROOT . event_id ! ) ) ;
1505+
1506+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , {
1507+ next_batch : "s_5_5" ,
1508+ rooms : {
1509+ join : {
1510+ [ roomId ] : {
1511+ timeline : {
1512+ events : [
1513+ SYNC_THREAD_REPLY ,
1514+ ] ,
1515+ prev_batch : "f_1_2" ,
1516+ } ,
14811517 } ,
14821518 } ,
14831519 } ,
1484- } ,
1520+ } ) ;
1521+
1522+ await Promise . all ( [ httpBackend . flushAllExpected ( ) , utils . syncPromise ( client ) ] ) ;
1523+
1524+ expect ( timeline ! . getEvents ( ) [ 1 ] ! . event ) . toEqual ( THREAD_REPLY ) ;
1525+ }
1526+
1527+ it ( "in stable mode" , async ( ) => {
1528+ // @ts -ignore
1529+ client . clientOpts . experimentalThreadSupport = true ;
1530+ Thread . setServerSideSupport ( FeatureSupport . Stable ) ;
1531+ Thread . setServerSideListSupport ( FeatureSupport . Stable ) ;
1532+ Thread . setServerSideFwdPaginationSupport ( FeatureSupport . Stable ) ;
1533+
1534+ return doTest ( ) ;
14851535 } ) ;
14861536
1487- await Promise . all ( [ httpBackend . flushAllExpected ( ) , utils . syncPromise ( client ) ] ) ;
1537+ it ( "in backwards compatible unstable mode" , async ( ) => {
1538+ // @ts -ignore
1539+ client . clientOpts . experimentalThreadSupport = true ;
1540+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1541+ Thread . setServerSideListSupport ( FeatureSupport . Experimental ) ;
1542+ Thread . setServerSideFwdPaginationSupport ( FeatureSupport . Experimental ) ;
14881543
1489- expect ( thread . liveTimeline . getEvents ( ) [ 1 ] . event ) . toEqual ( THREAD_REPLY ) ;
1544+ return doTest ( ) ;
1545+ } ) ;
1546+
1547+ it ( "in backwards compatible mode" , async ( ) => {
1548+ // @ts -ignore
1549+ client . clientOpts . experimentalThreadSupport = true ;
1550+ Thread . setServerSideSupport ( FeatureSupport . Experimental ) ;
1551+ Thread . setServerSideListSupport ( FeatureSupport . None ) ;
1552+ Thread . setServerSideFwdPaginationSupport ( FeatureSupport . None ) ;
1553+
1554+ return doTest ( ) ;
1555+ } ) ;
14901556 } ) ;
14911557} ) ;
0 commit comments