@@ -32,6 +32,7 @@ import { PostmessageTransport } from '../src/transport/PostmessageTransport';
3232import  { 
3333    IDownloadFileActionFromWidgetActionRequest , 
3434    IMatrixApiError , 
35+     INavigateActionRequest , 
3536    IReadEventFromWidgetActionRequest , 
3637    ISendEventFromWidgetActionRequest , 
3738    ISendToDeviceFromWidgetActionRequest , 
@@ -113,6 +114,7 @@ describe('ClientWidgetApi', () => {
113114        document . body . appendChild ( iframe ) ; 
114115
115116        driver  =  { 
117+             navigate : jest . fn ( ) , 
116118            readStateEvents : jest . fn ( ) , 
117119            readEventRelations : jest . fn ( ) , 
118120            sendEvent : jest . fn ( ) , 
@@ -159,6 +161,155 @@ describe('ClientWidgetApi', () => {
159161        expect ( clientWidgetApi . hasCapability ( 'm.sticker' ) ) . toBe ( false ) ; 
160162    } ) ; 
161163
164+     describe ( 'navigate action' ,  ( )  =>  { 
165+         it ( 'navigates' ,  async  ( )  =>  { 
166+             driver . navigate . mockResolvedValue ( Promise . resolve ( ) ) ; 
167+ 
168+             const  event : INavigateActionRequest  =  { 
169+                 api : WidgetApiDirection . FromWidget , 
170+                 widgetId : 'test' , 
171+                 requestId : '0' , 
172+                 action : WidgetApiFromWidgetAction . MSC2931Navigate , 
173+                 data : { 
174+                     uri : 'https://matrix.to/#/#room:example.net' , 
175+                 } , 
176+             } ; 
177+ 
178+             await  loadIframe ( [ 'org.matrix.msc2931.navigate' ] ) ; 
179+ 
180+             emitEvent ( new  CustomEvent ( '' ,  {  detail : event  } ) ) ; 
181+ 
182+             await  waitFor ( ( )  =>  { 
183+                 expect ( transport . reply ) . toHaveBeenCalledWith ( event ,  { } ) ; 
184+             } ) ; 
185+ 
186+             expect ( driver . navigate ) . toHaveBeenCalledWith ( 
187+                 event . data . uri , 
188+             ) ; 
189+         } ) ; 
190+ 
191+         it ( 'fails to navigate' ,  async  ( )  =>  { 
192+             const  event : INavigateActionRequest  =  { 
193+                 api : WidgetApiDirection . FromWidget , 
194+                 widgetId : 'test' , 
195+                 requestId : '0' , 
196+                 action : WidgetApiFromWidgetAction . MSC2931Navigate , 
197+                 data : { 
198+                     uri : 'https://matrix.to/#/#room:example.net' , 
199+                 } , 
200+             } ; 
201+ 
202+             await  loadIframe ( [ ] ) ;  // Without the required capability 
203+ 
204+             emitEvent ( new  CustomEvent ( '' ,  {  detail : event  } ) ) ; 
205+ 
206+             await  waitFor ( ( )  =>  { 
207+                 expect ( transport . reply ) . toBeCalledWith ( event ,  { 
208+                     error : {  message : 'Missing capability'  } , 
209+                 } ) ; 
210+             } ) ; 
211+ 
212+             expect ( driver . navigate ) . not . toBeCalled ( ) ; 
213+         } ) ; 
214+ 
215+         it ( 'fails to navigate to an unsupported URI' ,  async  ( )  =>  { 
216+             const  event : INavigateActionRequest  =  { 
217+                 api : WidgetApiDirection . FromWidget , 
218+                 widgetId : 'test' , 
219+                 requestId : '0' , 
220+                 action : WidgetApiFromWidgetAction . MSC2931Navigate , 
221+                 data : { 
222+                     uri : 'https://example.net' , 
223+                 } , 
224+             } ; 
225+ 
226+             await  loadIframe ( [ 'org.matrix.msc2931.navigate' ] ) ; 
227+ 
228+             emitEvent ( new  CustomEvent ( '' ,  {  detail : event  } ) ) ; 
229+ 
230+             await  waitFor ( ( )  =>  { 
231+                 expect ( transport . reply ) . toBeCalledWith ( event ,  { 
232+                     error : {  message : 'Invalid matrix.to URI'  } , 
233+                 } ) ; 
234+             } ) ; 
235+ 
236+             expect ( driver . navigate ) . not . toBeCalled ( ) ; 
237+         } ) ; 
238+ 
239+         it ( 'should reject requests when the driver throws an exception' ,  async  ( )  =>  { 
240+             driver . navigate . mockRejectedValue ( 
241+                 new  Error ( "M_UNKNOWN: Unknown error" ) , 
242+             ) ; 
243+ 
244+             const  event : INavigateActionRequest  =  { 
245+                 api : WidgetApiDirection . FromWidget , 
246+                 widgetId : 'test' , 
247+                 requestId : '0' , 
248+                 action : WidgetApiFromWidgetAction . MSC2931Navigate , 
249+                 data : { 
250+                     uri : 'https://matrix.to/#/#room:example.net' , 
251+                 } , 
252+             } ; 
253+ 
254+             await  loadIframe ( [ 'org.matrix.msc2931.navigate' ] ) ; 
255+ 
256+             emitEvent ( new  CustomEvent ( '' ,  {  detail : event  } ) ) ; 
257+ 
258+             await  waitFor ( ( )  =>  { 
259+                 expect ( transport . reply ) . toBeCalledWith ( event ,  { 
260+                     error : {  message : 'Error handling navigation'  } , 
261+                 } ) ; 
262+             } ) ; 
263+         } ) ; 
264+ 
265+         it ( 'should reject with Matrix API error response thrown by driver' ,  async  ( )  =>  { 
266+             driver . processError . mockImplementation ( processCustomMatrixError ) ; 
267+ 
268+             driver . navigate . mockRejectedValue ( 
269+                 new  CustomMatrixError ( 
270+                     'failed to navigate' , 
271+                     400 , 
272+                     'M_UNKNOWN' , 
273+                     { 
274+                         reason : 'Unknown error' , 
275+                     } , 
276+                 ) , 
277+             ) ; 
278+ 
279+             const  event : INavigateActionRequest  =  { 
280+                 api : WidgetApiDirection . FromWidget , 
281+                 widgetId : 'test' , 
282+                 requestId : '0' , 
283+                 action : WidgetApiFromWidgetAction . MSC2931Navigate , 
284+                 data : { 
285+                     uri : 'https://matrix.to/#/#room:example.net' , 
286+                 } , 
287+             } ; 
288+ 
289+             await  loadIframe ( [ 'org.matrix.msc2931.navigate' ] ) ; 
290+ 
291+             emitEvent ( new  CustomEvent ( '' ,  {  detail : event  } ) ) ; 
292+ 
293+             await  waitFor ( ( )  =>  { 
294+                 expect ( transport . reply ) . toBeCalledWith ( event ,  { 
295+                     error : { 
296+                         message : 'Error handling navigation' , 
297+                         matrix_api_error : { 
298+                             http_status : 400 , 
299+                             http_headers : { } , 
300+                             url : '' , 
301+                             response : { 
302+                                 errcode : 'M_UNKNOWN' , 
303+                                 error : 'failed to navigate' , 
304+                                 reason : 'Unknown error' , 
305+                             } , 
306+                         }  satisfies  IMatrixApiError , 
307+                     } , 
308+                 } ) ; 
309+             } ) ; 
310+         } ) ; 
311+     } ) ; 
312+ 
162313    describe ( 'send_event action' ,  ( )  =>  { 
163314        it ( 'sends message events' ,  async  ( )  =>  { 
164315            const  roomId  =  '!room:example.org' ; 
0 commit comments