@@ -20,7 +20,7 @@ import { waitFor } from "@testing-library/dom";
2020import { ClientWidgetApi } from "../src/ClientWidgetApi" ;
2121import { WidgetDriver } from "../src/driver/WidgetDriver" ;
2222import { CurrentApiVersions , UnstableApiVersion } from "../src/interfaces/ApiVersion" ;
23- import { Capability } from "../src/interfaces/Capabilities" ;
23+ import { Capability , MatrixCapabilities } from "../src/interfaces/Capabilities" ;
2424import { IRoomEvent } from "../src/interfaces/IRoomEvent" ;
2525import { IWidgetApiRequest } from "../src/interfaces/IWidgetApiRequest" ;
2626import { IReadRelationsFromWidgetActionRequest } from "../src/interfaces/ReadRelationsAction" ;
@@ -141,6 +141,8 @@ describe("ClientWidgetApi", () => {
141141 downloadFile : jest . fn ( ) ,
142142 getKnownRooms : jest . fn ( ( ) => [ ] ) ,
143143 processError : jest . fn ( ) ,
144+ sendStickyEvent : jest . fn ( ) ,
145+ sendDelayedStickyEvent : jest . fn ( ) ,
144146 } as Partial < WidgetDriver > as jest . Mocked < WidgetDriver > ;
145147
146148 clientWidgetApi = new ClientWidgetApi (
@@ -704,6 +706,190 @@ describe("ClientWidgetApi", () => {
704706 } ) ;
705707 } ) ;
706708
709+ describe ( "send_event action for sticky events" , ( ) => {
710+ it ( "fails to send delayed events" , async ( ) => {
711+ const roomId = "!room:example.org" ;
712+
713+ const event : ISendEventFromWidgetActionRequest = {
714+ api : WidgetApiDirection . FromWidget ,
715+ widgetId : "test" ,
716+ requestId : "0" ,
717+ action : WidgetApiFromWidgetAction . SendEvent ,
718+ data : {
719+ type : "m.room.message" ,
720+ content : {
721+ sticky_key : "foobar" ,
722+ } ,
723+ delay : 5000 ,
724+ room_id : roomId ,
725+ sticky_duration_ms : 5000 ,
726+ } ,
727+ } ;
728+
729+ await loadIframe ( [
730+ `org.matrix.msc2762.timeline:${ event . data . room_id } ` ,
731+ `org.matrix.msc2762.send.event:${ event . data . type } ` ,
732+ // Without the required capability
733+ ] ) ;
734+
735+ emitEvent ( new CustomEvent ( "" , { detail : event } ) ) ;
736+
737+ await waitFor ( ( ) => {
738+ expect ( transport . reply ) . toHaveBeenCalledWith ( event , {
739+ error : { message : expect . any ( String ) } ,
740+ } ) ;
741+ } ) ;
742+
743+ expect ( driver . sendDelayedEvent ) . not . toHaveBeenCalled ( ) ;
744+ } ) ;
745+
746+ it ( "can send a sticky message event" , async ( ) => {
747+ const roomId = "!room:example.org" ;
748+ const eventId = "$evt:example.org" ;
749+
750+ driver . sendStickyEvent . mockResolvedValue ( {
751+ roomId,
752+ eventId,
753+ } ) ;
754+
755+ const event : ISendEventFromWidgetActionRequest = {
756+ api : WidgetApiDirection . FromWidget ,
757+ widgetId : "test" ,
758+ requestId : "0" ,
759+ action : WidgetApiFromWidgetAction . SendEvent ,
760+ data : {
761+ type : "m.room.message" ,
762+ content : {
763+ sticky_key : "12345" ,
764+ } ,
765+ room_id : roomId ,
766+ sticky_duration_ms : 5000 ,
767+ } ,
768+ } ;
769+
770+ await loadIframe ( [
771+ `org.matrix.msc2762.timeline:${ event . data . room_id } ` ,
772+ `org.matrix.msc2762.send.event:${ event . data . type } ` ,
773+ MatrixCapabilities . MSC4354SendStickyEvent ,
774+ ] ) ;
775+
776+ emitEvent ( new CustomEvent ( "" , { detail : event } ) ) ;
777+
778+ await waitFor ( ( ) => {
779+ expect ( transport . reply ) . toHaveBeenCalledWith ( event , {
780+ room_id : roomId ,
781+ event_id : eventId ,
782+ } ) ;
783+ } ) ;
784+
785+ expect ( driver . sendStickyEvent ) . toHaveBeenCalledWith (
786+ 5000 ,
787+ event . data . type ,
788+ event . data . content ,
789+ null ,
790+ roomId ,
791+ ) ;
792+ } ) ;
793+
794+ it . each ( [
795+ { hasDelay : true , hasParent : false } ,
796+ { hasDelay : false , hasParent : true } ,
797+ { hasDelay : true , hasParent : true } ,
798+ ] ) (
799+ "sends sticky message events with a delay (withDelay = $hasDelay, hasParent = $hasParent)" ,
800+ async ( { hasDelay, hasParent } ) => {
801+ const roomId = "!room:example.org" ;
802+ const timeoutDelayId = "ft" ;
803+
804+ driver . sendDelayedStickyEvent . mockResolvedValue ( {
805+ roomId,
806+ delayId : timeoutDelayId ,
807+ } ) ;
808+
809+ const event : ISendEventFromWidgetActionRequest = {
810+ api : WidgetApiDirection . FromWidget ,
811+ widgetId : "test" ,
812+ requestId : "0" ,
813+ action : WidgetApiFromWidgetAction . SendEvent ,
814+ data : {
815+ type : "m.room.message" ,
816+ content : {
817+ sticky_key : "12345" ,
818+ } ,
819+ room_id : roomId ,
820+ ...( hasDelay && { delay : 5000 } ) ,
821+ ...( hasParent && { parent_delay_id : "fp" } ) ,
822+ sticky_duration_ms : 5000 ,
823+ } ,
824+ } ;
825+
826+ await loadIframe ( [
827+ `org.matrix.msc2762.timeline:${ event . data . room_id } ` ,
828+ `org.matrix.msc2762.send.event:${ event . data . type } ` ,
829+ MatrixCapabilities . MSC4157SendDelayedEvent ,
830+ MatrixCapabilities . MSC4354SendStickyEvent ,
831+ ] ) ;
832+
833+ emitEvent ( new CustomEvent ( "" , { detail : event } ) ) ;
834+
835+ await waitFor ( ( ) => {
836+ expect ( transport . reply ) . toHaveBeenCalledWith ( event , {
837+ room_id : roomId ,
838+ delay_id : timeoutDelayId ,
839+ } ) ;
840+ } ) ;
841+
842+ expect ( driver . sendDelayedStickyEvent ) . toHaveBeenCalledWith (
843+ event . data . delay ?? null ,
844+ event . data . parent_delay_id ?? null ,
845+ 5000 ,
846+ event . data . type ,
847+ event . data . content ,
848+ null ,
849+ roomId ,
850+ ) ;
851+ } ,
852+ ) ;
853+
854+ it ( "does not allow sticky state events" , async ( ) => {
855+ const roomId = "!room:example.org" ;
856+ const timeoutDelayId = "ft" ;
857+
858+ driver . sendDelayedEvent . mockResolvedValue ( {
859+ roomId,
860+ delayId : timeoutDelayId ,
861+ } ) ;
862+
863+ const event : ISendEventFromWidgetActionRequest = {
864+ api : WidgetApiDirection . FromWidget ,
865+ widgetId : "test" ,
866+ requestId : "0" ,
867+ action : WidgetApiFromWidgetAction . SendEvent ,
868+ data : {
869+ type : "m.room.topic" ,
870+ content : { } ,
871+ state_key : "" ,
872+ room_id : roomId ,
873+ sticky_duration_ms : 5000 ,
874+ } ,
875+ } ;
876+
877+ await loadIframe ( [
878+ `org.matrix.msc2762.timeline:${ event . data . room_id } ` ,
879+ `org.matrix.msc2762.send.state_event:${ event . data . type } ` ,
880+ MatrixCapabilities . MSC4354SendStickyEvent ,
881+ ] ) ;
882+
883+ emitEvent ( new CustomEvent ( "" , { detail : event } ) ) ;
884+
885+ await waitFor ( ( ) => {
886+ expect ( transport . reply ) . toHaveBeenCalledWith ( event , {
887+ error : { message : "Cannot send a state event with a sticky duration" } ,
888+ } ) ;
889+ } ) ;
890+ } ) ;
891+ } ) ;
892+
707893 describe ( "receiving events" , ( ) => {
708894 const roomId = "!room:example.org" ;
709895 const otherRoomId = "!other-room:example.org" ;
0 commit comments