@@ -18,8 +18,22 @@ import "fake-indexeddb/auto";
18
18
19
19
import HttpBackend from "matrix-mock-request" ;
20
20
21
- import { Category , ISyncResponse , MatrixClient , NotificationCountType , Room } from "../../src" ;
21
+ import {
22
+ Category ,
23
+ ClientEvent ,
24
+ EventType ,
25
+ IStartClientOpts ,
26
+ ISyncResponse ,
27
+ MatrixClient ,
28
+ MatrixEvent ,
29
+ NotificationCountType ,
30
+ RelationType ,
31
+ Room ,
32
+ } from "../../src" ;
22
33
import { TestClient } from "../TestClient" ;
34
+ import { logger } from "../../src/logger" ;
35
+ import { ReceiptType , WrappedReceipt } from "../../src/@types/read_receipts" ;
36
+ import { mkThread } from "../test-utils/thread" ;
23
37
24
38
describe ( "MatrixClient syncing" , ( ) => {
25
39
const userA = "@alice:localhost" ;
@@ -51,6 +65,92 @@ describe("MatrixClient syncing", () => {
51
65
return httpBackend ! . stop ( ) ;
52
66
} ) ;
53
67
68
+ it ( "reactions in thread set the correct timeline to unread" , async ( ) => {
69
+ // start the client, and wait for it to initialise
70
+ function startClient ( httpBackend : HttpBackend , client : MatrixClient , opts ?: IStartClientOpts ) {
71
+ httpBackend . when ( "GET" , "/sync" ) . respond ( 200 , {
72
+ next_batch : "s_5_3" ,
73
+ rooms : {
74
+ [ Category . Join ] : { } ,
75
+ [ Category . Leave ] : { } ,
76
+ [ Category . Invite ] : { } ,
77
+ } ,
78
+ } ) ;
79
+
80
+ client . startClient ( opts ) ;
81
+
82
+ // set up a promise which will resolve once the client is initialised
83
+ const prom = new Promise < void > ( ( resolve ) => {
84
+ client . on ( ClientEvent . Sync , function ( state ) {
85
+ logger . log ( "sync" , state ) ;
86
+ if ( state != "SYNCING" ) {
87
+ return ;
88
+ }
89
+ resolve ( ) ;
90
+ } ) ;
91
+ } ) ;
92
+
93
+ return Promise . all ( [ httpBackend . flushAllExpected ( ) , prom ] ) ;
94
+ }
95
+
96
+ const roomId = "!room:localhost" ;
97
+ await startClient ( httpBackend ! , client ! , { threadSupport : true } ) ;
98
+ const room = new Room ( roomId , client ! , selfUserId ) ;
99
+ jest . spyOn ( client ! , "getRoom" ) . mockImplementation ( ( id ) => ( id === roomId ? room : null ) ) ;
100
+ const thread = mkThread ( { room, client : client ! , authorId : selfUserId , participantUserIds : [ selfUserId ] } ) ;
101
+ const threadReply = thread . events . at ( - 1 ) ! ;
102
+ room . addLiveEvents ( [ thread . rootEvent ] ) ;
103
+
104
+ const roomReceipt : WrappedReceipt = {
105
+ eventId : thread . rootEvent . getId ( ) ! ,
106
+ data : {
107
+ ts : 1 ,
108
+ } ,
109
+ } ;
110
+
111
+ const threadReceipt : WrappedReceipt = {
112
+ eventId : threadReply . getId ( ) ! ,
113
+ data : {
114
+ thread_id : thread . thread . id ,
115
+ ts : 1 ,
116
+ } ,
117
+ } ;
118
+
119
+ room . addReceiptToStructure ( roomReceipt . eventId , ReceiptType . Read , selfUserId , roomReceipt . data , false ) ;
120
+ thread . thread . addReceiptToStructure (
121
+ threadReceipt . eventId ,
122
+ ReceiptType . Read ,
123
+ selfUserId ,
124
+ threadReceipt . data ,
125
+ false ,
126
+ ) ;
127
+
128
+ expect ( room . getReadReceiptForUserId ( selfUserId , false ) ?. eventId ) . toEqual ( thread . rootEvent . getId ( ) ) ;
129
+ expect ( thread . thread . getReadReceiptForUserId ( selfUserId , false ) ?. eventId ) . toEqual ( threadReply . getId ( ) ) ;
130
+
131
+ const reactionEventId = `$9-${ Math . random ( ) } -${ Math . random ( ) } ` ;
132
+ let lastEvent : MatrixEvent | null = null ;
133
+ jest . spyOn ( client ! as any , "sendEventHttpRequest" ) . mockImplementation ( ( event ) => {
134
+ lastEvent = event as MatrixEvent ;
135
+ return { event_id : reactionEventId } ;
136
+ } ) ;
137
+
138
+ // we currently don't handle the case of a non-detached pending event list well!
139
+ await client ! . sendEvent ( roomId , EventType . Reaction , {
140
+ "m.relates_to" : {
141
+ rel_type : RelationType . Annotation ,
142
+ event_id : threadReply . getId ( ) ,
143
+ key : "" ,
144
+ } ,
145
+ } ) ;
146
+
147
+ expect ( lastEvent ! . getId ( ) ) . toEqual ( reactionEventId ) ;
148
+ room . handleRemoteEcho ( new MatrixEvent ( lastEvent ! . event ) , lastEvent ! ) ;
149
+
150
+ expect ( room . getReadReceiptForUserId ( selfUserId , false ) ?. eventId ) . toEqual ( thread . rootEvent . getId ( ) ) ;
151
+ expect ( thread . thread . getReadReceiptForUserId ( selfUserId , false ) ?. eventId ) . toEqual ( reactionEventId ) ;
152
+ } ) ;
153
+
54
154
describe ( "Stuck unread notifications integration tests" , ( ) => {
55
155
const ROOM_ID = "!room:localhost" ;
56
156
0 commit comments