@@ -45,23 +45,23 @@ describe("DmkNetworkClientHelpers", () => {
4545 describe ( "buildUrl" , ( ) => {
4646 it ( "should keep an absolute URL as-is" , ( ) => {
4747 const url = buildUrl ( { url : "https://api.example.com/items" } ) ;
48- expect ( url . toString ( ) ) . toBe ( "https://api.example.com/items" ) ;
48+ expect ( url ) . toBe ( "https://api.example.com/items" ) ;
4949 } ) ;
5050
5151 it ( "should prepend the base URL to a relative path" , ( ) => {
5252 const url = buildUrl ( {
5353 url : "/items" ,
5454 baseUrl : "https://api.example.com/" ,
5555 } ) ;
56- expect ( url . toString ( ) ) . toBe ( "https://api.example.com/items" ) ;
56+ expect ( url ) . toBe ( "https://api.example.com/items" ) ;
5757 } ) ;
5858
5959 it ( "should ignore the base URL when the input URL is absolute" , ( ) => {
6060 const url = buildUrl ( {
6161 url : "https://other.example.com/items" ,
6262 baseUrl : "https://api.example.com" ,
6363 } ) ;
64- expect ( url . toString ( ) ) . toBe ( "https://other.example.com/items" ) ;
64+ expect ( url ) . toBe ( "https://other.example.com/items" ) ;
6565 } ) ;
6666
6767 it ( "should append query params and skip null/undefined entries" , ( ) => {
@@ -75,36 +75,56 @@ describe("DmkNetworkClientHelpers", () => {
7575 alsoSkip : undefined ,
7676 } ,
7777 } ) ;
78- expect ( url . searchParams . get ( "chain" ) ) . toBe ( "1" ) ;
79- expect ( url . searchParams . get ( "contract" ) ) . toBe ( "0xabc" ) ;
80- expect ( url . searchParams . get ( "active" ) ) . toBe ( "true" ) ;
81- expect ( url . searchParams . has ( "skip" ) ) . toBe ( false ) ;
82- expect ( url . searchParams . has ( "alsoSkip" ) ) . toBe ( false ) ;
78+ expect ( typeof url ) . toBe ( "string" ) ;
79+ const parsed = new URL ( url ) ;
80+ expect ( parsed . searchParams . get ( "chain" ) ) . toBe ( "1" ) ;
81+ expect ( parsed . searchParams . get ( "contract" ) ) . toBe ( "0xabc" ) ;
82+ expect ( parsed . searchParams . get ( "active" ) ) . toBe ( "true" ) ;
83+ expect ( parsed . searchParams . has ( "skip" ) ) . toBe ( false ) ;
84+ expect ( parsed . searchParams . has ( "alsoSkip" ) ) . toBe ( false ) ;
8385 } ) ;
8486
8587 it ( "should preserve a pre-existing query string in the input URL" , ( ) => {
8688 const url = buildUrl ( {
8789 url : "https://api.example.com/items?keep=1" ,
8890 params : { chain : 2 } ,
8991 } ) ;
90- expect ( url . searchParams . get ( "keep" ) ) . toBe ( "1" ) ;
91- expect ( url . searchParams . get ( "chain" ) ) . toBe ( "2" ) ;
92+ const parsed = new URL ( url ) ;
93+ expect ( parsed . searchParams . get ( "keep" ) ) . toBe ( "1" ) ;
94+ expect ( parsed . searchParams . get ( "chain" ) ) . toBe ( "2" ) ;
9295 } ) ;
9396
9497 it ( "should percent-encode keys and values" , ( ) => {
9598 const url = buildUrl ( {
9699 url : "https://api.example.com/items" ,
97100 params : { "a key" : "a value&b" } ,
98101 } ) ;
99- expect ( url . toString ( ) ) . toBe (
100- "https://api.example.com/items?a%20key=a%20value%26b" ,
102+ expect ( url ) . toBe ( "https://api.example.com/items?a%20key=a%20value%26b" ) ;
103+ } ) ;
104+
105+ it ( "should not append a trailing slash after the last query value (facebook/react-native#54242)" , ( ) => {
106+ const url = buildUrl ( {
107+ url : "https://manager.api.live.ledger.com/api/get_device_version" ,
108+ params : { target_id : 858783748 , provider : 1 } ,
109+ } ) ;
110+ expect ( typeof url ) . toBe ( "string" ) ;
111+ expect ( url ) . toBe (
112+ "https://manager.api.live.ledger.com/api/get_device_version?target_id=858783748&provider=1" ,
101113 ) ;
114+ expect ( url . endsWith ( "/" ) ) . toBe ( false ) ;
115+ } ) ;
116+
117+ it ( "should return a plain string (not a URL instance) so RN URL serialization is bypassed" , ( ) => {
118+ const url = buildUrl ( {
119+ url : "https://api.example.com/items" ,
120+ params : { chain : 1 } ,
121+ } ) ;
122+ expect ( typeof url ) . toBe ( "string" ) ;
123+ expect ( url ) . not . toBeInstanceOf ( URL ) ;
102124 } ) ;
103125
104126 it ( "should still build the URL when URLSearchParams.set is unavailable (React Native regression)" , ( ) => {
105127 const original = URLSearchParams . prototype . set ;
106- // Simulate a runtime (e.g. some React Native versions) where
107- // URLSearchParams exists but `set` is not implemented.
108128 URLSearchParams . prototype . set = function notImplemented ( ) : never {
109129 throw new Error ( "URLSearchParams.set is not implemented" ) ;
110130 } ;
@@ -113,10 +133,8 @@ describe("DmkNetworkClientHelpers", () => {
113133 url : "https://api.example.com/items" ,
114134 params : { chain : 1 , contract : "0xabc" } ,
115135 } ) ;
116- // Reading `searchParams.get` in jsdom does not call `set`, so it is
117- // safe to assert against the parsed URL here.
118- expect ( url . toString ( ) ) . toContain ( "chain=1" ) ;
119- expect ( url . toString ( ) ) . toContain ( "contract=0xabc" ) ;
136+ expect ( url ) . toContain ( "chain=1" ) ;
137+ expect ( url ) . toContain ( "contract=0xabc" ) ;
120138 } finally {
121139 URLSearchParams . prototype . set = original ;
122140 }
0 commit comments