@@ -32,7 +32,7 @@ import {
3232 IOpenIDCredentials ,
3333} from "matrix-widget-api" ;
3434
35- import { createRoomWidgetClient , MsgType } from "../../src/matrix" ;
35+ import { createRoomWidgetClient , MsgType , UpdateDelayedEventAction } from "../../src/matrix" ;
3636import { MatrixClient , ClientEvent , ITurnServer as IClientTurnServer } from "../../src/client" ;
3737import { SyncState } from "../../src/sync" ;
3838import { ICapabilities } from "../../src/embedded" ;
@@ -59,8 +59,26 @@ class MockWidgetApi extends EventEmitter {
5959 public requestCapabilityToReceiveState = jest . fn ( ) ;
6060 public requestCapabilityToSendToDevice = jest . fn ( ) ;
6161 public requestCapabilityToReceiveToDevice = jest . fn ( ) ;
62- public sendRoomEvent = jest . fn ( ( ) => ( { event_id : `$${ Math . random ( ) } ` } ) ) ;
63- public sendStateEvent = jest . fn ( ) ;
62+ public sendRoomEvent = jest . fn (
63+ ( eventType : string , content : unknown , roomId ?: string , delay ?: number , parentDelayId ?: string ) =>
64+ delay === undefined && parentDelayId === undefined
65+ ? { event_id : `$${ Math . random ( ) } ` }
66+ : { delay_id : `id-${ Math . random ( ) } ` } ,
67+ ) ;
68+ public sendStateEvent = jest . fn (
69+ (
70+ eventType : string ,
71+ stateKey : string ,
72+ content : unknown ,
73+ roomId ?: string ,
74+ delay ?: number ,
75+ parentDelayId ?: string ,
76+ ) =>
77+ delay === undefined && parentDelayId === undefined
78+ ? { event_id : `$${ Math . random ( ) } ` }
79+ : { delay_id : `id-${ Math . random ( ) } ` } ,
80+ ) ;
81+ public updateDelayedEvent = jest . fn ( ) ;
6482 public sendToDevice = jest . fn ( ) ;
6583 public requestOpenIDConnectToken = jest . fn ( ( ) => {
6684 return testOIDCToken ;
@@ -125,6 +143,17 @@ describe("RoomWidgetClient", () => {
125143 ) ;
126144 } ) ;
127145
146+ it ( "send handles wrong field in response" , async ( ) => {
147+ await makeClient ( { sendEvent : [ "org.matrix.rageshake_request" ] } ) ;
148+ widgetApi . sendRoomEvent . mockResolvedValueOnce ( {
149+ room_id : "!1:example.org" ,
150+ delay_id : `id-${ Math . random } ` ,
151+ } ) ;
152+ await expect (
153+ client . sendEvent ( "!1:example.org" , "org.matrix.rageshake_request" , { request_id : 123 } ) ,
154+ ) . rejects . toThrow ( ) ;
155+ } ) ;
156+
128157 it ( "receives" , async ( ) => {
129158 const event = new MatrixEvent ( {
130159 type : "org.matrix.rageshake_request" ,
@@ -160,6 +189,199 @@ describe("RoomWidgetClient", () => {
160189 } ) ;
161190 } ) ;
162191
192+ describe ( "delayed events" , ( ) => {
193+ describe ( "when supported" , ( ) => {
194+ const doesServerSupportUnstableFeatureMock = jest . fn ( ( feature ) =>
195+ Promise . resolve ( feature === "org.matrix.msc4140" ) ,
196+ ) ;
197+
198+ beforeAll ( ( ) => {
199+ MatrixClient . prototype . doesServerSupportUnstableFeature = doesServerSupportUnstableFeatureMock ;
200+ } ) ;
201+
202+ afterAll ( ( ) => {
203+ doesServerSupportUnstableFeatureMock . mockReset ( ) ;
204+ } ) ;
205+
206+ it ( "sends delayed message events" , async ( ) => {
207+ await makeClient ( { sendDelayedEvents : true , sendEvent : [ "org.matrix.rageshake_request" ] } ) ;
208+ expect ( widgetApi . requestCapability ) . toHaveBeenCalledWith ( MatrixCapabilities . MSC4157SendDelayedEvent ) ;
209+ await client . _unstable_sendDelayedEvent (
210+ "!1:example.org" ,
211+ { delay : 2000 } ,
212+ null ,
213+ "org.matrix.rageshake_request" ,
214+ { request_id : 123 } ,
215+ ) ;
216+ expect ( widgetApi . sendRoomEvent ) . toHaveBeenCalledWith (
217+ "org.matrix.rageshake_request" ,
218+ { request_id : 123 } ,
219+ "!1:example.org" ,
220+ 2000 ,
221+ undefined ,
222+ ) ;
223+ } ) ;
224+
225+ it ( "sends child action delayed message events" , async ( ) => {
226+ await makeClient ( { sendDelayedEvents : true , sendEvent : [ "org.matrix.rageshake_request" ] } ) ;
227+ expect ( widgetApi . requestCapability ) . toHaveBeenCalledWith ( MatrixCapabilities . MSC4157SendDelayedEvent ) ;
228+ const parentDelayId = `id-${ Math . random ( ) } ` ;
229+ await client . _unstable_sendDelayedEvent (
230+ "!1:example.org" ,
231+ { parent_delay_id : parentDelayId } ,
232+ null ,
233+ "org.matrix.rageshake_request" ,
234+ { request_id : 123 } ,
235+ ) ;
236+ expect ( widgetApi . sendRoomEvent ) . toHaveBeenCalledWith (
237+ "org.matrix.rageshake_request" ,
238+ { request_id : 123 } ,
239+ "!1:example.org" ,
240+ undefined ,
241+ parentDelayId ,
242+ ) ;
243+ } ) ;
244+
245+ it ( "sends delayed state events" , async ( ) => {
246+ await makeClient ( {
247+ sendDelayedEvents : true ,
248+ sendState : [ { eventType : "org.example.foo" , stateKey : "bar" } ] ,
249+ } ) ;
250+ expect ( widgetApi . requestCapability ) . toHaveBeenCalledWith ( MatrixCapabilities . MSC4157SendDelayedEvent ) ;
251+ await client . _unstable_sendDelayedStateEvent (
252+ "!1:example.org" ,
253+ { delay : 2000 } ,
254+ "org.example.foo" ,
255+ { hello : "world" } ,
256+ "bar" ,
257+ ) ;
258+ expect ( widgetApi . sendStateEvent ) . toHaveBeenCalledWith (
259+ "org.example.foo" ,
260+ "bar" ,
261+ { hello : "world" } ,
262+ "!1:example.org" ,
263+ 2000 ,
264+ undefined ,
265+ ) ;
266+ } ) ;
267+
268+ it ( "sends child action delayed state events" , async ( ) => {
269+ await makeClient ( {
270+ sendDelayedEvents : true ,
271+ sendState : [ { eventType : "org.example.foo" , stateKey : "bar" } ] ,
272+ } ) ;
273+ expect ( widgetApi . requestCapability ) . toHaveBeenCalledWith ( MatrixCapabilities . MSC4157SendDelayedEvent ) ;
274+ const parentDelayId = `fg-${ Math . random ( ) } ` ;
275+ await client . _unstable_sendDelayedStateEvent (
276+ "!1:example.org" ,
277+ { parent_delay_id : parentDelayId } ,
278+ "org.example.foo" ,
279+ { hello : "world" } ,
280+ "bar" ,
281+ ) ;
282+ expect ( widgetApi . sendStateEvent ) . toHaveBeenCalledWith (
283+ "org.example.foo" ,
284+ "bar" ,
285+ { hello : "world" } ,
286+ "!1:example.org" ,
287+ undefined ,
288+ parentDelayId ,
289+ ) ;
290+ } ) ;
291+
292+ it ( "send delayed message events handles wrong field in response" , async ( ) => {
293+ await makeClient ( { sendDelayedEvents : true , sendEvent : [ "org.matrix.rageshake_request" ] } ) ;
294+ widgetApi . sendRoomEvent . mockResolvedValueOnce ( {
295+ room_id : "!1:example.org" ,
296+ event_id : `$${ Math . random ( ) } ` ,
297+ } ) ;
298+ await expect (
299+ client . _unstable_sendDelayedEvent (
300+ "!1:example.org" ,
301+ { delay : 2000 } ,
302+ null ,
303+ "org.matrix.rageshake_request" ,
304+ { request_id : 123 } ,
305+ ) ,
306+ ) . rejects . toThrow ( ) ;
307+ } ) ;
308+
309+ it ( "send delayed state events handles wrong field in response" , async ( ) => {
310+ await makeClient ( {
311+ sendDelayedEvents : true ,
312+ sendState : [ { eventType : "org.example.foo" , stateKey : "bar" } ] ,
313+ } ) ;
314+ widgetApi . sendStateEvent . mockResolvedValueOnce ( {
315+ room_id : "!1:example.org" ,
316+ event_id : `$${ Math . random ( ) } ` ,
317+ } ) ;
318+ await expect (
319+ client . _unstable_sendDelayedStateEvent (
320+ "!1:example.org" ,
321+ { delay : 2000 } ,
322+ "org.example.foo" ,
323+ { hello : "world" } ,
324+ "bar" ,
325+ ) ,
326+ ) . rejects . toThrow ( ) ;
327+ } ) ;
328+
329+ it ( "updates delayed events" , async ( ) => {
330+ await makeClient ( { updateDelayedEvents : true , sendEvent : [ "org.matrix.rageshake_request" ] } ) ;
331+ expect ( widgetApi . requestCapability ) . toHaveBeenCalledWith ( MatrixCapabilities . MSC4157UpdateDelayedEvent ) ;
332+ for ( const action of [
333+ UpdateDelayedEventAction . Cancel ,
334+ UpdateDelayedEventAction . Restart ,
335+ UpdateDelayedEventAction . Send ,
336+ ] ) {
337+ await client . _unstable_updateDelayedEvent ( "id" , action ) ;
338+ expect ( widgetApi . updateDelayedEvent ) . toHaveBeenCalledWith ( "id" , action ) ;
339+ }
340+ } ) ;
341+ } ) ;
342+
343+ describe ( "when unsupported" , ( ) => {
344+ it ( "fails to send delayed message events" , async ( ) => {
345+ await makeClient ( { sendEvent : [ "org.matrix.rageshake_request" ] } ) ;
346+ await expect (
347+ client . _unstable_sendDelayedEvent (
348+ "!1:example.org" ,
349+ { delay : 2000 } ,
350+ null ,
351+ "org.matrix.rageshake_request" ,
352+ { request_id : 123 } ,
353+ ) ,
354+ ) . rejects . toThrow ( "Server does not support" ) ;
355+ } ) ;
356+
357+ it ( "fails to send delayed state events" , async ( ) => {
358+ await makeClient ( { sendState : [ { eventType : "org.example.foo" , stateKey : "bar" } ] } ) ;
359+ await expect (
360+ client . _unstable_sendDelayedStateEvent (
361+ "!1:example.org" ,
362+ { delay : 2000 } ,
363+ "org.example.foo" ,
364+ { hello : "world" } ,
365+ "bar" ,
366+ ) ,
367+ ) . rejects . toThrow ( "Server does not support" ) ;
368+ } ) ;
369+
370+ it ( "fails to update delayed state events" , async ( ) => {
371+ await makeClient ( { } ) ;
372+ for ( const action of [
373+ UpdateDelayedEventAction . Cancel ,
374+ UpdateDelayedEventAction . Restart ,
375+ UpdateDelayedEventAction . Send ,
376+ ] ) {
377+ await expect ( client . _unstable_updateDelayedEvent ( "id" , action ) ) . rejects . toThrow (
378+ "Server does not support" ,
379+ ) ;
380+ }
381+ } ) ;
382+ } ) ;
383+ } ) ;
384+
163385 describe ( "initialization" , ( ) => {
164386 it ( "requests permissions for specific message types" , async ( ) => {
165387 await makeClient ( { sendMessage : [ MsgType . Text ] , receiveMessage : [ MsgType . Text ] } ) ;
@@ -211,6 +433,17 @@ describe("RoomWidgetClient", () => {
211433 ) ;
212434 } ) ;
213435
436+ it ( "send handles incorrect response" , async ( ) => {
437+ await makeClient ( { sendState : [ { eventType : "org.example.foo" , stateKey : "bar" } ] } ) ;
438+ widgetApi . sendStateEvent . mockResolvedValueOnce ( {
439+ room_id : "!1:example.org" ,
440+ delay_id : `id-${ Math . random } ` ,
441+ } ) ;
442+ await expect (
443+ client . sendStateEvent ( "!1:example.org" , "org.example.foo" , { hello : "world" } , "bar" ) ,
444+ ) . rejects . toThrow ( ) ;
445+ } ) ;
446+
214447 it ( "receives" , async ( ) => {
215448 await makeClient ( { receiveState : [ { eventType : "org.example.foo" , stateKey : "bar" } ] } ) ;
216449 expect ( widgetApi . requestCapabilityForRoomTimeline ) . toHaveBeenCalledWith ( "!1:example.org" ) ;
0 commit comments