@@ -57,6 +57,7 @@ import {
5757 Room ,
5858 RuleId ,
5959 TweakName ,
60+ UpdateDelayedEventAction ,
6061} from "../../src" ;
6162import { supportsMatrixCall } from "../../src/webrtc/call" ;
6263import { makeBeaconEvent } from "../test-utils/beacon" ;
@@ -97,7 +98,7 @@ type HttpLookup = {
9798 method : string ;
9899 path : string ;
99100 prefix ?: string ;
100- data ?: Record < string , any > ;
101+ data ?: Record < string , any > | Record < string , any > [ ] ;
101102 error ?: object ;
102103 expectBody ?: Record < string , any > ;
103104 expectQueryParams ?: QueryDict ;
@@ -704,6 +705,328 @@ describe("MatrixClient", function () {
704705 } ) ;
705706 } ) ;
706707
708+ describe ( "_unstable_sendDelayedEvent" , ( ) => {
709+ const unstableMSC4140Prefix = `${ ClientPrefix . Unstable } /org.matrix.msc4140` ;
710+
711+ const roomId = "!room:example.org" ;
712+ const body = "This is the body" ;
713+ const content = { body, msgtype : MsgType . Text } satisfies RoomMessageEventContent ;
714+ const timeoutDelayOpts = { delay : 2000 } ;
715+ const realTimeoutDelayOpts = { "org.matrix.msc4140.delay" : 2000 } ;
716+
717+ beforeEach ( ( ) => {
718+ unstableFeatures [ "org.matrix.msc4140" ] = true ;
719+ } ) ;
720+
721+ it ( "throws when unsupported by server" , async ( ) => {
722+ unstableFeatures [ "org.matrix.msc4140" ] = false ;
723+ const errorMessage = "Server does not support" ;
724+
725+ await expect (
726+ client . _unstable_sendDelayedEvent (
727+ roomId ,
728+ timeoutDelayOpts ,
729+ null ,
730+ EventType . RoomMessage ,
731+ { ...content } ,
732+ client . makeTxnId ( ) ,
733+ ) ,
734+ ) . rejects . toThrow ( errorMessage ) ;
735+
736+ await expect (
737+ client . _unstable_sendDelayedStateEvent ( roomId , timeoutDelayOpts , EventType . RoomTopic , {
738+ topic : "topic" ,
739+ } ) ,
740+ ) . rejects . toThrow ( errorMessage ) ;
741+
742+ await expect ( client . _unstable_getDelayedEvents ( ) ) . rejects . toThrow ( errorMessage ) ;
743+
744+ await expect (
745+ client . _unstable_updateDelayedEvent ( "anyDelayId" , UpdateDelayedEventAction . Send ) ,
746+ ) . rejects . toThrow ( errorMessage ) ;
747+ } ) ;
748+
749+ it ( "works with null threadId" , async ( ) => {
750+ httpLookups = [ ] ;
751+
752+ const timeoutDelayTxnId = client . makeTxnId ( ) ;
753+ httpLookups . push ( {
754+ method : "PUT" ,
755+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ timeoutDelayTxnId } ` ,
756+ expectQueryParams : realTimeoutDelayOpts ,
757+ data : { delay_id : "id1" } ,
758+ expectBody : content ,
759+ } ) ;
760+
761+ const { delay_id : timeoutDelayId } = await client . _unstable_sendDelayedEvent (
762+ roomId ,
763+ timeoutDelayOpts ,
764+ null ,
765+ EventType . RoomMessage ,
766+ { ...content } ,
767+ timeoutDelayTxnId ,
768+ ) ;
769+
770+ const actionDelayTxnId = client . makeTxnId ( ) ;
771+ httpLookups . push ( {
772+ method : "PUT" ,
773+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ actionDelayTxnId } ` ,
774+ expectQueryParams : { "org.matrix.msc4140.parent_delay_id" : timeoutDelayId } ,
775+ data : { delay_id : "id2" } ,
776+ expectBody : content ,
777+ } ) ;
778+
779+ await client . _unstable_sendDelayedEvent (
780+ roomId ,
781+ { parent_delay_id : timeoutDelayId } ,
782+ null ,
783+ EventType . RoomMessage ,
784+ { ...content } ,
785+ actionDelayTxnId ,
786+ ) ;
787+ } ) ;
788+
789+ it ( "works with non-null threadId" , async ( ) => {
790+ httpLookups = [ ] ;
791+ const threadId = "$threadId:server" ;
792+ const expectBody = {
793+ ...content ,
794+ "m.relates_to" : {
795+ event_id : threadId ,
796+ is_falling_back : true ,
797+ rel_type : "m.thread" ,
798+ } ,
799+ } ;
800+
801+ const timeoutDelayTxnId = client . makeTxnId ( ) ;
802+ httpLookups . push ( {
803+ method : "PUT" ,
804+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ timeoutDelayTxnId } ` ,
805+ expectQueryParams : realTimeoutDelayOpts ,
806+ data : { delay_id : "id1" } ,
807+ expectBody,
808+ } ) ;
809+
810+ const { delay_id : timeoutDelayId } = await client . _unstable_sendDelayedEvent (
811+ roomId ,
812+ timeoutDelayOpts ,
813+ threadId ,
814+ EventType . RoomMessage ,
815+ { ...content } ,
816+ timeoutDelayTxnId ,
817+ ) ;
818+
819+ const actionDelayTxnId = client . makeTxnId ( ) ;
820+ httpLookups . push ( {
821+ method : "PUT" ,
822+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ actionDelayTxnId } ` ,
823+ expectQueryParams : { "org.matrix.msc4140.parent_delay_id" : timeoutDelayId } ,
824+ data : { delay_id : "id2" } ,
825+ expectBody,
826+ } ) ;
827+
828+ await client . _unstable_sendDelayedEvent (
829+ roomId ,
830+ { parent_delay_id : timeoutDelayId } ,
831+ threadId ,
832+ EventType . RoomMessage ,
833+ { ...content } ,
834+ actionDelayTxnId ,
835+ ) ;
836+ } ) ;
837+
838+ it ( "should add thread relation if threadId is passed and the relation is missing" , async ( ) => {
839+ httpLookups = [ ] ;
840+ const threadId = "$threadId:server" ;
841+ const expectBody = {
842+ ...content ,
843+ "m.relates_to" : {
844+ "m.in_reply_to" : {
845+ event_id : threadId ,
846+ } ,
847+ "event_id" : threadId ,
848+ "is_falling_back" : true ,
849+ "rel_type" : "m.thread" ,
850+ } ,
851+ } ;
852+
853+ const room = new Room ( roomId , client , userId ) ;
854+ mocked ( store . getRoom ) . mockReturnValue ( room ) ;
855+
856+ const rootEvent = new MatrixEvent ( { event_id : threadId } ) ;
857+ room . createThread ( threadId , rootEvent , [ rootEvent ] , false ) ;
858+
859+ const timeoutDelayTxnId = client . makeTxnId ( ) ;
860+ httpLookups . push ( {
861+ method : "PUT" ,
862+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ timeoutDelayTxnId } ` ,
863+ expectQueryParams : realTimeoutDelayOpts ,
864+ data : { delay_id : "id1" } ,
865+ expectBody,
866+ } ) ;
867+
868+ const { delay_id : timeoutDelayId } = await client . _unstable_sendDelayedEvent (
869+ roomId ,
870+ timeoutDelayOpts ,
871+ threadId ,
872+ EventType . RoomMessage ,
873+ { ...content } ,
874+ timeoutDelayTxnId ,
875+ ) ;
876+
877+ const actionDelayTxnId = client . makeTxnId ( ) ;
878+ httpLookups . push ( {
879+ method : "PUT" ,
880+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ actionDelayTxnId } ` ,
881+ expectQueryParams : { "org.matrix.msc4140.parent_delay_id" : timeoutDelayId } ,
882+ data : { delay_id : "id2" } ,
883+ expectBody,
884+ } ) ;
885+
886+ await client . _unstable_sendDelayedEvent (
887+ roomId ,
888+ { parent_delay_id : timeoutDelayId } ,
889+ threadId ,
890+ EventType . RoomMessage ,
891+ { ...content } ,
892+ actionDelayTxnId ,
893+ ) ;
894+ } ) ;
895+
896+ it ( "should add thread relation if threadId is passed and the relation is missing with reply" , async ( ) => {
897+ httpLookups = [ ] ;
898+ const threadId = "$threadId:server" ;
899+
900+ const content = {
901+ body,
902+ "msgtype" : MsgType . Text ,
903+ "m.relates_to" : {
904+ "m.in_reply_to" : {
905+ event_id : "$other:event" ,
906+ } ,
907+ } ,
908+ } satisfies RoomMessageEventContent ;
909+ const expectBody = {
910+ ...content ,
911+ "m.relates_to" : {
912+ "m.in_reply_to" : {
913+ event_id : "$other:event" ,
914+ } ,
915+ "event_id" : threadId ,
916+ "is_falling_back" : false ,
917+ "rel_type" : "m.thread" ,
918+ } ,
919+ } ;
920+
921+ const room = new Room ( roomId , client , userId ) ;
922+ mocked ( store . getRoom ) . mockReturnValue ( room ) ;
923+
924+ const rootEvent = new MatrixEvent ( { event_id : threadId } ) ;
925+ room . createThread ( threadId , rootEvent , [ rootEvent ] , false ) ;
926+
927+ const timeoutDelayTxnId = client . makeTxnId ( ) ;
928+ httpLookups . push ( {
929+ method : "PUT" ,
930+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ timeoutDelayTxnId } ` ,
931+ expectQueryParams : realTimeoutDelayOpts ,
932+ data : { delay_id : "id1" } ,
933+ expectBody,
934+ } ) ;
935+
936+ const { delay_id : timeoutDelayId } = await client . _unstable_sendDelayedEvent (
937+ roomId ,
938+ timeoutDelayOpts ,
939+ threadId ,
940+ EventType . RoomMessage ,
941+ { ...content } ,
942+ timeoutDelayTxnId ,
943+ ) ;
944+
945+ const actionDelayTxnId = client . makeTxnId ( ) ;
946+ httpLookups . push ( {
947+ method : "PUT" ,
948+ path : `/rooms/${ encodeURIComponent ( roomId ) } /send/m.room.message/${ actionDelayTxnId } ` ,
949+ expectQueryParams : { "org.matrix.msc4140.parent_delay_id" : timeoutDelayId } ,
950+ data : { delay_id : "id2" } ,
951+ expectBody,
952+ } ) ;
953+
954+ await client . _unstable_sendDelayedEvent (
955+ roomId ,
956+ { parent_delay_id : timeoutDelayId } ,
957+ threadId ,
958+ EventType . RoomMessage ,
959+ { ...content } ,
960+ actionDelayTxnId ,
961+ ) ;
962+ } ) ;
963+
964+ it ( "can send a delayed state event" , async ( ) => {
965+ httpLookups = [ ] ;
966+ const content = { topic : "The year 2000" } ;
967+
968+ httpLookups . push ( {
969+ method : "PUT" ,
970+ path : `/rooms/${ encodeURIComponent ( roomId ) } /state/m.room.topic/` ,
971+ expectQueryParams : realTimeoutDelayOpts ,
972+ data : { delay_id : "id1" } ,
973+ expectBody : content ,
974+ } ) ;
975+
976+ const { delay_id : timeoutDelayId } = await client . _unstable_sendDelayedStateEvent (
977+ roomId ,
978+ timeoutDelayOpts ,
979+ EventType . RoomTopic ,
980+ { ...content } ,
981+ ) ;
982+
983+ httpLookups . push ( {
984+ method : "PUT" ,
985+ path : `/rooms/${ encodeURIComponent ( roomId ) } /state/m.room.topic/` ,
986+ expectQueryParams : { "org.matrix.msc4140.parent_delay_id" : timeoutDelayId } ,
987+ data : { delay_id : "id2" } ,
988+ expectBody : content ,
989+ } ) ;
990+
991+ await client . _unstable_sendDelayedStateEvent (
992+ roomId ,
993+ { parent_delay_id : timeoutDelayId } ,
994+ EventType . RoomTopic ,
995+ { ...content } ,
996+ ) ;
997+ } ) ;
998+
999+ it ( "can look up delayed events" , async ( ) => {
1000+ httpLookups = [
1001+ {
1002+ method : "GET" ,
1003+ prefix : unstableMSC4140Prefix ,
1004+ path : "/delayed_events" ,
1005+ data : [ ] ,
1006+ } ,
1007+ ] ;
1008+
1009+ await client . _unstable_getDelayedEvents ( ) ;
1010+ } ) ;
1011+
1012+ it ( "can update delayed events" , async ( ) => {
1013+ const delayId = "id" ;
1014+ const action = UpdateDelayedEventAction . Restart ;
1015+ httpLookups = [
1016+ {
1017+ method : "POST" ,
1018+ prefix : unstableMSC4140Prefix ,
1019+ path : `/delayed_events/${ encodeURIComponent ( delayId ) } ` ,
1020+ data : {
1021+ action,
1022+ } ,
1023+ } ,
1024+ ] ;
1025+
1026+ await client . _unstable_updateDelayedEvent ( delayId , action ) ;
1027+ } ) ;
1028+ } ) ;
1029+
7071030 it ( "should create (unstable) file trees" , async ( ) => {
7081031 const userId = "@test:example.org" ;
7091032 const roomId = "!room:example.org" ;
@@ -963,7 +1286,7 @@ describe("MatrixClient", function () {
9631286 const filter = new Filter ( client . credentials . userId ) ;
9641287
9651288 const filterId = await client . getOrCreateFilter ( filterName , filter ) ;
966- expect ( filterId ) . toEqual ( FILTER_RESPONSE . data ?. filter_id ) ;
1289+ expect ( filterId ) . toEqual ( ! Array . isArray ( FILTER_RESPONSE . data ) && FILTER_RESPONSE . data ?. filter_id ) ;
9671290 } ) ;
9681291 } ) ;
9691292
0 commit comments