@@ -1453,7 +1453,7 @@ describe("MatrixClient event timelines", function () {
1453
1453
expect ( room . getPendingEvents ( ) ) . toHaveLength ( 1 ) ;
1454
1454
} ) ;
1455
1455
1456
- it ( "should handle thread updates by reordering the thread list" , async ( ) => {
1456
+ it ( "should handle new thread replies by reordering the thread list" , async ( ) => {
1457
1457
// Test data for a second thread
1458
1458
const THREAD2_ROOT = utils . mkEvent ( {
1459
1459
room : roomId ,
@@ -1568,7 +1568,8 @@ describe("MatrixClient event timelines", function () {
1568
1568
// Test adding a second event to the first thread
1569
1569
const thread = room . getThread ( THREAD_ROOT . event_id ! ) ! ;
1570
1570
thread . initialEventsFetched = true ;
1571
- const prom = emitPromise ( room , ThreadEvent . Update ) ;
1571
+ const prom = emitPromise ( room , ThreadEvent . NewReply ) ;
1572
+ respondToEvent ( THREAD_ROOT_UPDATED ) ;
1572
1573
respondToEvent ( THREAD_ROOT_UPDATED ) ;
1573
1574
respondToEvent ( THREAD_ROOT_UPDATED ) ;
1574
1575
respondToEvent ( THREAD_ROOT_UPDATED ) ;
@@ -1583,6 +1584,134 @@ describe("MatrixClient event timelines", function () {
1583
1584
THREAD_ROOT . event_id ,
1584
1585
] ) ;
1585
1586
} ) ;
1587
+
1588
+ it ( "should not reorder the thread list on other thread updates" , async ( ) => {
1589
+ // Test data for a second thread
1590
+ const THREAD2_ROOT = utils . mkEvent ( {
1591
+ room : roomId ,
1592
+ user : userId ,
1593
+ type : "m.room.message" ,
1594
+ content : {
1595
+ body : "thread root" ,
1596
+ msgtype : "m.text" ,
1597
+ } ,
1598
+ unsigned : {
1599
+ "m.relations" : {
1600
+ "io.element.thread" : {
1601
+ //"latest_event": undefined,
1602
+ count : 1 ,
1603
+ current_user_participated : true ,
1604
+ } ,
1605
+ } ,
1606
+ } ,
1607
+ event : false ,
1608
+ } ) ;
1609
+
1610
+ const THREAD2_REPLY = utils . mkEvent ( {
1611
+ room : roomId ,
1612
+ user : userId ,
1613
+ type : "m.room.message" ,
1614
+ content : {
1615
+ "body" : "thread2 reply" ,
1616
+ "msgtype" : "m.text" ,
1617
+ "m.relates_to" : {
1618
+ // We can't use the const here because we change server support mode for test
1619
+ rel_type : "io.element.thread" ,
1620
+ event_id : THREAD_ROOT . event_id ,
1621
+ } ,
1622
+ } ,
1623
+ event : false ,
1624
+ } ) ;
1625
+
1626
+ // @ts -ignore we know this is a defined path for THREAD ROOT
1627
+ THREAD2_ROOT . unsigned [ "m.relations" ] [ "io.element.thread" ] . latest_event = THREAD2_REPLY ;
1628
+
1629
+ const THREAD_REPLY_REACTION = utils . mkEvent ( {
1630
+ room : roomId ,
1631
+ user : userId ,
1632
+ type : "m.reaction" ,
1633
+ content : {
1634
+ "m.relates_to" : {
1635
+ rel_type : RelationType . Annotation ,
1636
+ event_id : THREAD_REPLY . event_id ,
1637
+ key : "🪿" ,
1638
+ } ,
1639
+ } ,
1640
+ event : true ,
1641
+ } ) ;
1642
+ THREAD_REPLY_REACTION . localTimestamp += 1000 ;
1643
+
1644
+ // Modified thread root event containing latest thread reply in its unsigned
1645
+ const THREAD_ROOT_UPDATED = {
1646
+ ...THREAD_ROOT ,
1647
+ unsigned : {
1648
+ ...THREAD_ROOT . unsigned ,
1649
+ "m.relations" : {
1650
+ ...THREAD_ROOT . unsigned ! [ "m.relations" ] ,
1651
+ "io.element.thread" : {
1652
+ ...THREAD_ROOT . unsigned ! [ "m.relations" ] ! [ "io.element.thread" ] ,
1653
+ count : 2 ,
1654
+ latest_event : THREAD_REPLY ,
1655
+ } ,
1656
+ } ,
1657
+ } ,
1658
+ } ;
1659
+
1660
+ // Response with test data for the thread list request
1661
+ const threadsResponse = {
1662
+ chunk : [ THREAD2_ROOT , THREAD_ROOT ] ,
1663
+ state : [ ] ,
1664
+ next_batch : RANDOM_TOKEN as string | null ,
1665
+ } ;
1666
+
1667
+ // @ts -ignore
1668
+ client . clientOpts . threadSupport = true ;
1669
+ Thread . setServerSideSupport ( FeatureSupport . Stable ) ;
1670
+ Thread . setServerSideListSupport ( FeatureSupport . Stable ) ;
1671
+ Thread . setServerSideFwdPaginationSupport ( FeatureSupport . Stable ) ;
1672
+
1673
+ await client . stopClient ( ) ; // we don't need the client to be syncing at this time
1674
+ const room = client . getRoom ( roomId ) ! ;
1675
+
1676
+ // Set up room threads
1677
+ const timelineSets = await room ! . createThreadsTimelineSets ( ) ;
1678
+ expect ( timelineSets ) . not . toBeNull ( ) ;
1679
+ respondToThreads ( threadsResponse ) ;
1680
+ respondToThreads ( threadsResponse ) ;
1681
+ respondToEvent ( THREAD_ROOT ) ;
1682
+ respondToEvent ( THREAD2_ROOT ) ;
1683
+ respondToThread ( THREAD_ROOT , [ THREAD_REPLY ] ) ;
1684
+ respondToThread ( THREAD2_ROOT , [ THREAD2_REPLY ] ) ;
1685
+ await flushHttp ( room . fetchRoomThreads ( ) ) ;
1686
+ const threadIds = room . getThreads ( ) . map ( ( thread ) => thread . id ) ;
1687
+ expect ( threadIds ) . toContain ( THREAD_ROOT . event_id ) ;
1688
+ expect ( threadIds ) . toContain ( THREAD2_ROOT . event_id ) ;
1689
+ const [ allThreads ] = timelineSets ! ;
1690
+ const timeline = allThreads . getLiveTimeline ( ) ! ;
1691
+ // Test threads are in chronological order
1692
+ expect ( timeline . getEvents ( ) . map ( ( it ) => it . event . event_id ) ) . toEqual ( [
1693
+ THREAD_ROOT . event_id ,
1694
+ THREAD2_ROOT . event_id ,
1695
+ ] ) ;
1696
+
1697
+ // Test adding a second event to the first thread
1698
+ const thread = room . getThread ( THREAD_ROOT . event_id ! ) ! ;
1699
+ thread . initialEventsFetched = true ;
1700
+ const prom = emitPromise ( room , ThreadEvent . Update ) ;
1701
+ respondToEvent ( THREAD_ROOT_UPDATED ) ;
1702
+ respondToEvent ( THREAD_ROOT_UPDATED ) ;
1703
+ respondToEvent ( THREAD_ROOT_UPDATED ) ;
1704
+ respondToEvent ( THREAD2_ROOT ) ;
1705
+ await room . addLiveEvents ( [ THREAD_REPLY_REACTION ] ) ;
1706
+ await httpBackend . flushAllExpected ( ) ;
1707
+ await prom ;
1708
+ expect ( thread . length ) . toBe ( 2 ) ;
1709
+ // Test thread order is unchanged
1710
+ expect ( timeline ! . getEvents ( ) . map ( ( it ) => it . event . event_id ) ) . toEqual ( [
1711
+ THREAD_ROOT . event_id ,
1712
+ THREAD2_ROOT . event_id ,
1713
+ ] ) ;
1714
+ } ) ;
1586
1715
} ) ;
1587
1716
1588
1717
describe ( "without server compatibility" , function ( ) {
0 commit comments