@@ -16,35 +16,23 @@ describe("XMPP URI Query Actions (XEP-0147)", function () {
1616 await mock . waitForRoster ( _converse , 'current' , 1 ) ;
1717
1818 // Save original globals to restore them later
19- const originalLocationDescriptor = Object . getOwnPropertyDescriptor ( window , ' location' ) ;
19+ const originalHash = window . location . hash ;
2020 const originalReplaceState = window . history . replaceState ;
2121
22- // Mock window.location to simulate a protocol handler URI
23- // This simulates: ?uri=xmpp:[email protected] 24- Object . defineProperty ( window , "location" , {
25- value : {
26- search :
'?uri=xmpp%3Aromeo%40montague.lit' , // URL-encoded: xmpp:[email protected] 27- hash : '' ,
28- origin : 'http://localhost' ,
29- pathname : '/' ,
30- } ,
31- configurable : true ,
32- } ) ;
33-
3422 // Spy on history.replaceState to verify URL cleanup
3523 const replaceStateSpy = jasmine . createSpy ( 'replaceState' ) ;
3624 window . history . replaceState = replaceStateSpy ;
3725
26+ // Simulate a protocol handler URI by setting the hash
27+ window . location . hash = '#converse/action?uri=xmpp%3Aromeo%40montague.lit' ;
28+
3829 try {
3930 // Call the function - this should parse URI and open chat
4031 await u . routeToQueryAction ( ) ;
4132
4233 // Verify that the URL was cleaned up (protocol handler removes ?uri=...)
43- expect ( replaceStateSpy ) . toHaveBeenCalledWith (
44- { } ,
45- document . title ,
46- 'http://localhost/'
47- ) ;
34+ const expected_url = `${ window . location . origin } ${ window . location . pathname } ` ;
35+ expect ( replaceStateSpy ) . toHaveBeenCalledWith ( { } , document . title , expected_url ) ;
4836
4937 // Wait for and verify that a chatbox was created
5038 await u . waitUntil ( ( ) => _converse . chatboxes . get ( '[email protected] ' ) ) ; @@ -53,11 +41,7 @@ describe("XMPP URI Query Actions (XEP-0147)", function () {
5341 expect ( chatbox . get ( 'jid' ) ) . toBe ( '[email protected] ' ) ; 5442 } finally {
5543 // Restore original globals to avoid test pollution
56- if ( originalLocationDescriptor ) {
57- Object . defineProperty ( window , 'location' , originalLocationDescriptor ) ;
58- } else {
59- delete window . location ;
60- }
44+ window . location . hash = originalHash ;
6145 window . history . replaceState = originalReplaceState ;
6246 }
6347 } ) ) ;
@@ -66,36 +50,26 @@ describe("XMPP URI Query Actions (XEP-0147)", function () {
6650 * Test message sending functionality when action=message
6751 * This tests URI parsing, chat opening, and message sending
6852 */
69- it ( "sends a message when action=message with body" ,
53+ fit ( "sends a message when action=message with body" ,
7054 mock . initConverse ( [ 'chatBoxesFetched' ] , { } , async function ( _converse ) {
7155
7256 const { api } = _converse ;
7357 await mock . waitForRoster ( _converse , 'current' , 1 ) ;
7458
75- const originalLocationDescriptor = Object . getOwnPropertyDescriptor ( window , ' location' ) ;
59+ const originalHash = window . location . hash ;
7660 const originalReplaceState = window . history . replaceState ;
7761
78- // Mock URI with message action: ?uri=xmpp:[email protected] ?action=message&body=Hello 79- Object . defineProperty ( window , "location" , {
80- value : {
81- search : '?uri=xmpp%3Aromeo%40montague.lit%3Faction%3Dmessage%26body%3DHello' ,
82- hash : '' ,
83- origin : 'http://localhost' ,
84- pathname : '/' ,
85- } ,
86- configurable : true ,
87- } ) ;
88-
8962 window . history . replaceState = jasmine . createSpy ( 'replaceState' ) ;
9063
91- try {
92- const { routeToQueryAction } = await import ( '../utils.js' ) ;
64+ // Mock URI with message action
65+ window . location . hash = '#converse/action?uri=xmpp%3Aromeo%40montague.lit%3Faction%3Dmessage%26body%3DHello' ;
9366
67+ try {
9468 // Spy on the connection send method to verify XMPP stanza sending
9569 spyOn ( api . connection . get ( ) , 'send' ) ;
9670
9771 // Execute the function
98- await routeToQueryAction ( ) ;
72+ await u . routeToQueryAction ( ) ;
9973
10074 // Verify chat was opened
10175 await u . waitUntil ( ( ) => _converse . chatboxes . get ( '[email protected] ' ) ) ; @@ -108,11 +82,85 @@ describe("XMPP URI Query Actions (XEP-0147)", function () {
10882 expect ( message . get ( 'message' ) ) . toBe ( 'Hello' ) ;
10983 expect ( message . get ( 'type' ) ) . toBe ( 'chat' ) ;
11084 } finally {
111- if ( originalLocationDescriptor ) {
112- Object . defineProperty ( window , 'location' , originalLocationDescriptor ) ;
113- } else {
114- delete window . location ;
115- }
85+ window . location . hash = originalHash ;
86+ window . history . replaceState = originalReplaceState ;
87+ }
88+ } ) ) ;
89+
90+ /**
91+ * Test roster add functionality when action=add-roster
92+ * This tests URI parsing and adding a contact to the roster
93+ */
94+ fit ( "adds a contact to roster when action=add-roster" ,
95+ mock . initConverse ( [ 'chatBoxesFetched' ] , { } , async function ( _converse ) {
96+
97+ const { api } = _converse ;
98+ await mock . waitForRoster ( _converse , 'current' , 1 ) ;
99+
100+ const originalHash = window . location . hash ;
101+ const originalReplaceState = window . history . replaceState ;
102+
103+ window . history . replaceState = jasmine . createSpy ( 'replaceState' ) ;
104+
105+ // Mock URI with add-roster action: ?uri=xmpp:[email protected] ?action=add-roster&name=Juliet&group=Friends 106+ window . location . hash = '#converse/action?uri=xmpp%3Ajuliet%40capulet.lit%3Faction%3Dadd-roster%26name%3DJuliet%26group%3DFriends' ;
107+
108+ try {
109+ // Spy on the contacts.add API method - return a resolved promise to avoid network calls
110+ spyOn ( api . contacts , 'add' ) . and . returnValue ( Promise . resolve ( ) ) ;
111+
112+ // Execute the function
113+ await u . routeToQueryAction ( ) ;
114+
115+ // Verify that contacts.add was called with correct parameters
116+ expect ( api . contacts . add ) . toHaveBeenCalledWith (
117+ {
118+ 119+ name : 'Juliet' ,
120+ groups : [ 'Friends' ]
121+ } ,
122+ true , // persist on server
123+ true , // subscribe to presence
124+ '' // no custom message
125+ ) ;
126+ } finally {
127+ window . location . hash = originalHash ;
128+ window . history . replaceState = originalReplaceState ;
129+ }
130+ } ) ) ;
131+
132+ /**
133+ * Test handling of invalid JIDs
134+ * This ensures the function gracefully handles malformed JIDs
135+ */
136+ fit ( "handles invalid JID gracefully" ,
137+ mock . initConverse ( [ 'chatBoxesFetched' ] , { } , async function ( _converse ) {
138+
139+ const { api } = _converse ;
140+ await mock . waitForRoster ( _converse , 'current' , 1 ) ;
141+
142+ const originalHash = window . location . hash ;
143+ const originalReplaceState = window . history . replaceState ;
144+
145+ window . history . replaceState = jasmine . createSpy ( 'replaceState' ) ;
146+
147+ // Mock URI with invalid JID (missing domain)
148+ window . location . hash = '#converse/action?uri=xmpp%3Ainvalid-jid' ;
149+
150+ try {
151+ // Spy on api.chats.open to ensure it's NOT called for invalid JID
152+ spyOn ( api . chats , 'open' ) ;
153+
154+ // Execute the function
155+ await u . routeToQueryAction ( ) ;
156+
157+ // Verify that no chat was opened for the invalid JID
158+ expect ( api . chats . open ) . not . toHaveBeenCalled ( ) ;
159+
160+ // Verify no chatbox was created
161+ expect ( _converse . chatboxes . get ( 'invalid-jid' ) ) . toBeUndefined ( ) ;
162+ } finally {
163+ window . location . hash = originalHash ;
116164 window . history . replaceState = originalReplaceState ;
117165 }
118166 } ) ) ;
0 commit comments