View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.htmlunit.junit.annotation.HtmlUnitNYI;
21  import org.junit.Test;
22  import org.junit.runner.RunWith;
23  
24  /**
25   * Tests for {@link URLSearchParams}.
26   *
27   * @author Ronald Brill
28   * @author cd alexndr
29   * @author Lai Quang Duong
30   */
31  @RunWith(BrowserRunner.class)
32  public class URLSearchParamsTest extends WebDriverTestCase {
33  
34      /**
35       * @throws Exception if an error occurs
36       */
37      @Test
38      @Alerts({"foo=1&bar=2", ""})
39      public void ctor() throws Exception {
40          final String html = DOCTYPE_HTML
41              + "<html>\n"
42              + "<head>\n"
43              + "  <script>\n"
44              + LOG_TITLE_FUNCTION
45              + "    function test() {\n"
46              + "      if (self.URLSearchParams) {\n"
47              + "        log(new URLSearchParams('?foo=1&bar=2'));\n"
48              + "        log(new URLSearchParams());\n"
49              + "      }\n"
50              + "    }\n"
51              + "  </script>\n"
52              + "</head>\n"
53              + "<body onload='test()'>\n"
54              + "</body>\n"
55              + "</html>";
56  
57          loadPageVerifyTitle2(html);
58      }
59  
60      /**
61       * @throws Exception if an error occurs
62       */
63      @Test
64      @Alerts({"",
65               "Failed to construct 'URLSearchParams': The provided value cannot be converted to a sequence",
66               "foo=1&bar=2&null=null",
67               "Failed to construct 'URLSearchParams': Sequence initializer must only contain pair elements",
68               "a%2Cb=1%2C2%2C3",
69               "Failed to construct 'URLSearchParams': The object must have a callable @@iterator property"})
70      public void ctorArray() throws Exception {
71          final String html = DOCTYPE_HTML
72              + "<html>\n"
73              + "<head>\n"
74              + "  <script>\n"
75              + LOG_TITLE_FUNCTION
76              + "    function test() {\n"
77              + "      if (self.URLSearchParams) {\n"
78              + "        log(new URLSearchParams(Array(0)));\n"
79              + "        try {\n"
80              + "          new URLSearchParams(Array(1));\n"
81              + "        } catch (ex) {\n"
82              + "          log(\"Failed to construct 'URLSearchParams': "
83                                  + "The provided value cannot be converted to a sequence\");\n"
84              + "        }\n"
85              + "\n"
86              + "        log(new URLSearchParams([\n"
87              + "          ['foo', '1'],\n"
88              + "          ['bar', '2'],\n"
89              + "          [null, null],\n"
90              + "        ]));\n"
91              + "\n"
92              + "        try {\n"
93              + "          new URLSearchParams([\n"
94              + "            ['foo', '1', '2'],\n"
95              + "          ]);\n"
96              + "        } catch (ex) {\n"
97              + "          log(\"Failed to construct 'URLSearchParams': "
98                                  + "Sequence initializer must only contain pair elements\");\n"
99              + "        }\n"
100             + "\n"
101             + "        log(new URLSearchParams([\n"
102             + "          [\n"
103             + "            ['a', 'b'],\n"
104             + "            ['1', '2', '3']\n"
105             + "          ],\n"
106             + "        ]));\n"
107             + "\n"
108             + "        try {\n"
109             + "          new URLSearchParams([\n"
110             + "            {'foo': 1},\n"
111             + "            {'bar': 2},\n"
112             + "          ]);\n"
113             + "        } catch (ex) {\n"
114             + "          log(\"Failed to construct 'URLSearchParams': "
115                                 + "The object must have a callable @@iterator property\");\n"
116             + "        }\n"
117             + "      }\n"
118             + "    }\n"
119             + "  </script>\n"
120             + "</head>\n"
121             + "<body onload='test()'>\n"
122             + "</body>\n"
123             + "</html>";
124 
125         loadPageVerifyTitle2(html);
126     }
127 
128     /**
129      * @throws Exception if an error occurs
130      */
131     @Test
132     @Alerts({"foo=1&bar=2", "foo=%5Bobject+Object%5D&bar=3"})
133     public void ctorObject() throws Exception {
134         final String html = DOCTYPE_HTML
135             + "<html>\n"
136             + "<head>\n"
137             + "  <script>\n"
138             + LOG_TITLE_FUNCTION
139             + "    function test() {\n"
140             + "      if (self.URLSearchParams) {\n"
141             + "        log(new URLSearchParams({\n"
142             + "          foo: '1',\n"
143             + "          bar: '2'\n"
144             + "        }));\n"
145             + "\n"
146             + "        log(new URLSearchParams({\n"
147             + "          'foo': {\n"
148             + "            'x': '1',\n"
149             + "            'y': '2'\n"
150             + "          },\n"
151             + "          'bar': '3',\n"
152             + "        }))\n;"
153             + "      }\n"
154             + "    }\n"
155             + "  </script>\n"
156             + "</head>\n"
157             + "<body onload='test()'>\n"
158             + "</body>\n"
159             + "</html>";
160 
161         loadPageVerifyTitle2(html);
162     }
163 
164     /**
165      * @throws Exception if an error occurs
166      */
167     @Test
168     @Alerts({"foo=1&bar=%5Bobject+Object%5D&foobar=4%2C5%2C6",
169              "foo=1&bar=2", "foo=1&bar=2",
170              "Failed to construct 'URLSearchParams': Iterator object must be an object",
171              "Failed to construct 'URLSearchParams': @@iterator must be a callable",
172              "Failed to construct 'URLSearchParams': Expected next() function on iterator",
173              "foo=1&bar=2",
174              "Failed to construct 'URLSearchParams': The provided value cannot be converted to a sequence"})
175     public void ctorIterable() throws Exception {
176         final String html = DOCTYPE_HTML
177             + "<html>\n"
178             + "<head>\n"
179             + "  <script>\n"
180             + LOG_TITLE_FUNCTION
181             + "    function test() {\n"
182             + "      if (self.URLSearchParams) {\n"
183             + "        var map = new Map();\n"
184             + "        map.set('foo', 1);\n"
185             + "        map.set('bar', {\n"
186             + "          'x': 1,\n"
187             + "          'y': 2,\n"
188             + "        });\n"
189             + "        map.set('foobar', [4, 5, 6]);\n"
190             + "        log(new URLSearchParams(map));\n"
191             + "\n"
192             + "        var formData = new FormData();\n"
193             + "        formData.append('foo', '1');\n"
194             + "        formData.append('bar', '2');\n"
195             + "        log(new URLSearchParams(formData));\n"
196             + "\n"
197             + "        var searchParams = new URLSearchParams('foo=1&bar=2');\n"
198             + "        log(new URLSearchParams(searchParams));\n"
199             + "\n"
200             + "        try {\n"
201             + "          var brokenIterable = {};\n"
202             + "          brokenIterable[Symbol.iterator] = function (){};\n"
203             + "          new URLSearchParams(brokenIterable);\n"
204             + "        } catch (ex) {\n"
205             + "          log(\"Failed to construct 'URLSearchParams': Iterator object must be an object\");\n"
206             + "        }\n"
207             + "\n"
208             + "        try {\n"
209             + "          var brokenIterable = {};\n"
210             + "          brokenIterable[Symbol.iterator] = 1;\n"
211             + "          new URLSearchParams(brokenIterable);\n"
212             + "        } catch (ex) {\n"
213             + "          log(\"Failed to construct 'URLSearchParams': @@iterator must be a callable\");\n"
214             + "        }\n"
215             + "\n"
216             + "        try {\n"
217             + "          var brokenIterable = {};\n"
218             + "          brokenIterable[Symbol.iterator] = function (){ return {} };\n"
219             + "          new URLSearchParams(brokenIterable);\n"
220             + "        } catch (ex) {\n"
221             + "          log(\"Failed to construct 'URLSearchParams': Expected next() function on iterator\");\n"
222             + "        }\n"
223             + "\n"
224             + "        var generatorObject = (function* () {\n"
225             + "          yield ['foo', 1];\n"
226             + "          yield ['bar', 2];\n"
227             + "        })();\n"
228             + "        log(new URLSearchParams(generatorObject));\n"
229             + "\n"
230             + "        try {\n"
231             + "          var generatorObject = (function* () {\n"
232             + "            yield 1;\n"
233             + "            yield 2;\n"
234             + "          })();\n"
235             + "          new URLSearchParams(generatorObject);\n"
236             + "        } catch (ex) {\n"
237             + "          log(\"Failed to construct 'URLSearchParams': "
238                                 + "The provided value cannot be converted to a sequence\");\n"
239             + "        }\n"
240             + "      }\n"
241             + "    }\n"
242             + "  </script>\n"
243             + "</head>\n"
244             + "<body onload='test()'>\n"
245             + "</body>\n"
246             + "</html>";
247 
248         loadPageVerifyTitle2(html);
249     }
250 
251     /**
252      * @throws Exception if an error occurs
253      */
254     @Test
255     @Alerts({"", "foo=1&bar=2", "q=Html+Unit&unml=%C3%A4%C3%9C", "q=HtmlUnit&u=%3F%3F"})
256     public void string() throws Exception {
257         final String html = DOCTYPE_HTML
258             + "<html>\n"
259             + "<head>\n"
260             + "  <script>\n"
261             + LOG_TITLE_FUNCTION
262             + "    function test() {\n"
263             + "      if (self.URLSearchParams) {\n"
264             + "        log(new URLSearchParams());\n"
265             + "        log(new URLSearchParams('?foo=1&bar=2'));\n"
266 
267             + "        searchParams = new URLSearchParams();\n"
268             + "        searchParams.append('q', 'Html Unit');\n"
269             + "        searchParams.append('unml', '\u00E4\u00DC');\n"
270             + "        log(searchParams);\n"
271 
272             + "        searchParams = new URLSearchParams();\n"
273             + "        searchParams.append('q', 'HtmlUnit');\n"
274             + "        searchParams.append('u', '\u043B\u0189');\n"
275             + "        log(searchParams);\n"
276             + "      }\n"
277             + "    }\n"
278             + "  </script>\n"
279             + "</head>\n"
280             + "<body onload='test()'>\n"
281             + "</body>\n"
282             + "</html>";
283 
284         loadPageVerifyTitle2(html);
285     }
286 
287     /**
288      * @throws Exception if an error occurs
289      */
290     @Test
291     @Alerts({"=emptyKey", "null=nullKey", "undefined=undefinedKey"})
292     public void stringKeys() throws Exception {
293         final String html = DOCTYPE_HTML
294             + "<html>\n"
295             + "<head>\n"
296             + "  <script>\n"
297             + LOG_TITLE_FUNCTION
298             + "    function test() {\n"
299             + "      if (self.URLSearchParams) {\n"
300             + "        searchParams = new URLSearchParams();\n"
301             + "        searchParams.append('', 'emptyKey');\n"
302             + "        log(searchParams);\n"
303 
304             + "        searchParams = new URLSearchParams();\n"
305             + "        searchParams.append(null, 'nullKey');\n"
306             + "        log(searchParams);\n"
307 
308             + "        searchParams = new URLSearchParams();\n"
309             + "        searchParams.append(undefined, 'undefinedKey');\n"
310             + "        log(searchParams);\n"
311             + "      }\n"
312             + "    }\n"
313             + "  </script>\n"
314             + "</head>\n"
315             + "<body onload='test()'>\n"
316             + "</body>\n"
317             + "</html>";
318 
319         loadPageVerifyTitle2(html);
320     }
321 
322     /**
323      * @throws Exception if an error occurs
324      */
325     @Test
326     @Alerts({"emptyValue=", "nullValue=null", "undefinedValue=undefined"})
327     public void stringValues() throws Exception {
328         final String html = DOCTYPE_HTML
329             + "<html>\n"
330             + "<head>\n"
331             + "  <script>\n"
332             + LOG_TITLE_FUNCTION
333             + "    function test() {\n"
334             + "      if (self.URLSearchParams) {\n"
335             + "        searchParams = new URLSearchParams();\n"
336             + "        searchParams.append('emptyValue', '');\n"
337             + "        log(searchParams);\n"
338 
339             + "        searchParams = new URLSearchParams();\n"
340             + "        searchParams.append('nullValue', null);\n"
341             + "        log(searchParams);\n"
342 
343             + "        searchParams = new URLSearchParams();\n"
344             + "        searchParams.append('undefinedValue', undefined);\n"
345             + "        log(searchParams);\n"
346             + "      }\n"
347             + "    }\n"
348             + "  </script>\n"
349             + "</head>\n"
350             + "<body onload='test()'>\n"
351             + "</body>\n"
352             + "</html>";
353 
354         loadPageVerifyTitle2(html);
355     }
356 
357     /**
358      * @throws Exception if an error occurs
359      */
360     @Test
361     @Alerts("TypeError")
362     @HtmlUnitNYI(CHROME = "noValue=undefined",
363             EDGE = "noValue=undefined",
364             FF = "noValue=undefined",
365             FF_ESR = "noValue=undefined")
366     public void stringMissingParam() throws Exception {
367         final String html = DOCTYPE_HTML
368             + "<html>\n"
369             + "<head>\n"
370             + "  <script>\n"
371             + LOG_TITLE_FUNCTION
372             + "    function test() {\n"
373             + "      if (self.URLSearchParams) {\n"
374             + "        try {\n"
375             + "          searchParams = new URLSearchParams();\n"
376             + "          searchParams.append('noValue');\n"
377             + "          log(searchParams);\n"
378             + "        } catch(e) { logEx(e); }\n"
379             + "      }\n"
380             + "    }\n"
381             + "  </script>\n"
382             + "</head>\n"
383             + "<body onload='test()'>\n"
384             + "</body>\n"
385             + "</html>";
386 
387         loadPageVerifyTitle2(html);
388     }
389 
390     /**
391      * @throws Exception if an error occurs
392      */
393     @Test
394     @Alerts({"key=value", "key=value&empty-key=undefined",
395              "key=value&empty-key=undefined&key=overwrite",
396              "key=value&empty-key=undefined&key=overwrite&key-null=null"})
397     public void append() throws Exception {
398         final String html = DOCTYPE_HTML
399             + "<html>\n"
400             + "<head>\n"
401             + "  <script>\n"
402             + LOG_TITLE_FUNCTION
403             + "    function test() {\n"
404             + "      if (self.URLSearchParams) {\n"
405             + "        var param = new URLSearchParams();\n"
406             + "        param.append('key', 'value');\n"
407             + "        log(param);\n"
408             + "        param.append('empty-key', undefined);\n"
409             + "        log(param);\n"
410             + "        param.append('key', 'overwrite');\n"
411             + "        log(param);\n"
412             + "        param.append('key-null', null);\n"
413             + "        log(param);\n"
414             + "      }\n"
415             + "    }\n"
416             + "  </script>\n"
417             + "</head>\n"
418             + "<body onload='test()'>\n"
419             + "</body>\n"
420             + "</html>";
421 
422         loadPageVerifyTitle2(html);
423     }
424 
425     /**
426      * @throws Exception if an error occurs
427      */
428     @Test
429     @Alerts({"%3Fkey%3D%26=value", "true",
430              "%3Fkey%3D%26=value&url=http%3A%2F%2Ffoo.com%2F%3Fx%3D1%26y%3D2%26z%3D3",
431              "http://foo.com/?x=1&y=2&z=3"})
432     public void appendSpecialChars() throws Exception {
433         final String html = DOCTYPE_HTML
434                 + "<html>\n"
435                 + "<head>\n"
436                 + "  <script>\n"
437                 + LOG_TITLE_FUNCTION
438                 + "    function test() {\n"
439                 + "      if (self.URLSearchParams) {\n"
440                 + "        var param = new URLSearchParams();\n"
441                 + "        param.append('?key=&', 'value');\n"
442                 + "        log(param);\n"
443                 + "        log(param.has('?key=&'));\n"
444                 + "        param.append('url', 'http://foo.com/?x=1&y=2&z=3');\n"
445                 + "        log(param);\n"
446                 + "        log(param.get('url'));\n"
447                 + "      }\n"
448                 + "    }\n"
449                 + "  </script>\n"
450                 + "</head>\n"
451                 + "<body onload='test()'>\n"
452                 + "</body>\n"
453                 + "</html>";
454 
455         loadPageVerifyTitle2(html);
456     }
457 
458     /**
459      * @throws Exception if an error occurs
460      */
461     @Test
462     @Alerts({"key=value", "key=value&empty-key=undefined",
463              "key=value&empty-key=undefined&key=overwrite",
464              "key=value&empty-key=undefined&key=overwrite&key-null=null",
465              "http://test.com/p?key=value&empty-key=undefined&key=overwrite&key-null=null"})
466     public void appendFromUrl() throws Exception {
467         final String html = DOCTYPE_HTML
468             + "<html>\n"
469             + "<head>\n"
470             + "  <script>\n"
471             + LOG_TITLE_FUNCTION
472             + "    function test() {\n"
473             + "      if (self.URLSearchParams) {\n"
474             + "        var url = new URL('http://test.com/p');\n"
475             + "        var param = url.searchParams;\n"
476             + "        param.append('key', 'value');\n"
477             + "        log(param);\n"
478             + "        param.append('empty-key', undefined);\n"
479             + "        log(param);\n"
480             + "        param.append('key', 'overwrite');\n"
481             + "        log(param);\n"
482             + "        param.append('key-null', null);\n"
483             + "        log(param);\n"
484 
485             + "        log(url);\n"
486             + "      }\n"
487             + "    }\n"
488             + "  </script>\n"
489             + "</head>\n"
490             + "<body onload='test()'>\n"
491             + "</body>\n"
492             + "</html>";
493 
494         loadPageVerifyTitle2(html);
495     }
496 
497     /**
498      * @throws Exception if an error occurs
499      */
500     @Test
501     @Alerts({"key2=val2&key2=val3", "", "", "", ""})
502     public void delete() throws Exception {
503         final String html = DOCTYPE_HTML
504             + "<html>\n"
505             + "<head>\n"
506             + "  <script>\n"
507             + LOG_TITLE_FUNCTION
508             + "    function test() {\n"
509             + "      if (self.URLSearchParams) {\n"
510             + "        var param = new URLSearchParams('key1=val1&key2=val2&key2=val3');\n"
511             + "        param.delete('key1');\n"
512             + "        log(param);\n"
513             + "        param.delete('key2');\n"
514             + "        log(param);\n"
515             + "        param.delete('key3');\n"
516             + "        log(param);\n"
517             + "        param.delete(undefined);\n"
518             + "        log(param);\n"
519             + "        param.delete(null);\n"
520             + "        log(param);\n"
521             + "      }\n"
522             + "    }\n"
523             + "  </script>\n"
524             + "</head>\n"
525             + "<body onload='test()'>\n"
526             + "</body>\n"
527             + "</html>";
528 
529         loadPageVerifyTitle2(html);
530     }
531 
532     /**
533      * @throws Exception if an error occurs
534      */
535     @Test
536     @Alerts({"key2=val2&key2=val3", "", "", "", "", "http://test.com/p"})
537     public void deleteFromUrl() throws Exception {
538         final String html = DOCTYPE_HTML
539             + "<html>\n"
540             + "<head>\n"
541             + "  <script>\n"
542             + LOG_TITLE_FUNCTION
543             + "    function test() {\n"
544             + "      if (self.URLSearchParams) {\n"
545             + "        var url = new URL('http://test.com/p?key1=val1&key2=val2&key2=val3');\n"
546             + "        var param = url.searchParams;\n"
547             + "        param.delete('key1');\n"
548             + "        log(param);\n"
549             + "        param.delete('key2');\n"
550             + "        log(param);\n"
551             + "        param.delete('key3');\n"
552             + "        log(param);\n"
553             + "        param.delete(undefined);\n"
554             + "        log(param);\n"
555             + "        param.delete(null);\n"
556             + "        log(param);\n"
557 
558             + "        log(url);\n"
559             + "      }\n"
560             + "    }\n"
561             + "  </script>\n"
562             + "</head>\n"
563             + "<body onload='test()'>\n"
564             + "</body>\n"
565             + "</html>";
566 
567         loadPageVerifyTitle2(html);
568     }
569 
570     /**
571      * @throws Exception if an error occurs
572      */
573     @Test
574     @Alerts({"key+1=val1&key2=val2", "http://test.com/p?key%201=val1&key2=val2",
575              "key2=val2", "http://test.com/p?key2=val2"})
576     @HtmlUnitNYI(CHROME = {"key+1=val1&key2=val2", "http://test.com/p?key 1=val1&key2=val2",
577                            "key2=val2", "http://test.com/p?key2=val2"},
578                  EDGE = {"key+1=val1&key2=val2", "http://test.com/p?key 1=val1&key2=val2",
579                          "key2=val2", "http://test.com/p?key2=val2"},
580                  FF = {"key+1=val1&key2=val2", "http://test.com/p?key 1=val1&key2=val2",
581                        "key2=val2", "http://test.com/p?key2=val2"},
582                  FF_ESR = {"key+1=val1&key2=val2", "http://test.com/p?key 1=val1&key2=val2",
583                            "key2=val2", "http://test.com/p?key2=val2"})
584     public void deleteFromUrlSpecialChars() throws Exception {
585         final String html = DOCTYPE_HTML
586             + "<html>\n"
587             + "<head>\n"
588             + "  <script>\n"
589             + LOG_TITLE_FUNCTION
590             + "    function test() {\n"
591             + "      if (self.URLSearchParams) {\n"
592             + "        var url = new URL('http://test.com/p?key 1=val1&key2=val2');\n"
593             + "        var param = url.searchParams;\n"
594             + "        log(param);\n"
595             + "        log(url);\n"
596 
597             + "        param.delete('key 1');\n"
598             + "        log(param);\n"
599             + "        log(url);\n"
600             + "      }\n"
601             + "    }\n"
602             + "  </script>\n"
603             + "</head>\n"
604             + "<body onload='test()'>\n"
605             + "</body>\n"
606             + "</html>";
607 
608         loadPageVerifyTitle2(html);
609     }
610 
611     /**
612      * @throws Exception if an error occurs
613      */
614     @Test
615     @Alerts({"val1", "val2", "null", "null", "null"})
616     public void get() throws Exception {
617         final String html = DOCTYPE_HTML
618             + "<html>\n"
619             + "<head>\n"
620             + "  <script>\n"
621             + LOG_TITLE_FUNCTION
622             + "    function test() {\n"
623             + "      if (self.URLSearchParams) {\n"
624             + "        var param = new URLSearchParams('key1=val1&key2=val2&key1=val3');\n"
625             + "        log(param.get('key1'));\n"
626             + "        log(param.get('key2'));\n"
627             + "        log(param.get('key3'));\n"
628             + "        log(param.get(undefined));\n"
629             + "        log(param.get(null));\n"
630             + "      }\n"
631             + "    }\n"
632             + "  </script>\n"
633             + "</head>\n"
634             + "<body onload='test()'>\n"
635             + "</body>\n"
636             + "</html>";
637 
638         loadPageVerifyTitle2(html);
639     }
640 
641     /**
642      * @throws Exception if an error occurs
643      */
644     @Test
645     @Alerts({"true", "true", "false", "false", "false"})
646     public void has() throws Exception {
647         final String html = DOCTYPE_HTML
648             + "<html>\n"
649             + "<head>\n"
650             + "  <script>\n"
651             + LOG_TITLE_FUNCTION
652             + "    function test() {\n"
653             + "      if (self.URLSearchParams) {\n"
654             + "        var param = new URLSearchParams('key1=val1&key2=val2&key1=val3');\n"
655             + "        log(param.has('key1'));\n"
656             + "        log(param.has('key2'));\n"
657             + "        log(param.has('key3'));\n"
658             + "        log(param.has(undefined));\n"
659             + "        log(param.has(null));\n"
660             + "      }\n"
661             + "    }\n"
662             + "  </script>\n"
663             + "</head>\n"
664             + "<body onload='test()'>\n"
665             + "</body>\n"
666             + "</html>";
667 
668         loadPageVerifyTitle2(html);
669     }
670 
671     /**
672      * @throws Exception if an error occurs
673      */
674     @Test
675     @Alerts({"val1,val3", "val2", "", "", ""})
676     public void getAll() throws Exception {
677         final String html = DOCTYPE_HTML
678             + "<html>\n"
679             + "<head>\n"
680             + "  <script>\n"
681             + LOG_TITLE_FUNCTION
682             + "    function test() {\n"
683             + "      if (self.URLSearchParams) {\n"
684             + "        var param = new URLSearchParams('key1=val1&key2=val2&key1=val3');\n"
685             + "        log(param.getAll('key1'));\n"
686             + "        log(param.getAll('key2'));\n"
687             + "        log(param.getAll('key3'));\n"
688             + "        log(param.getAll(undefined));\n"
689             + "        log(param.getAll(null));\n"
690             + "      }\n"
691             + "    }\n"
692             + "  </script>\n"
693             + "</head>\n"
694             + "<body onload='test()'>\n"
695             + "</body>\n"
696             + "</html>";
697 
698         loadPageVerifyTitle2(html);
699     }
700 
701     /**
702      * @throws Exception if an error occurs
703      */
704     @Test
705     @Alerts({"key1=val1&key2=val2&key2=val3&key4=val4",
706              "key1=new1&key2=val2&key2=val3&key4=val4",
707              "key1=new1&key2=new2&key4=val4",
708              "key1=new1&key2=new2&key4=val4&key3=undefined",
709              "key1=new1&key2=new2&key4=null&key3=undefined"})
710     public void set() throws Exception {
711         final String html = DOCTYPE_HTML
712             + "<html>\n"
713             + "<head>\n"
714             + "  <script>\n"
715             + LOG_TITLE_FUNCTION
716             + "    function test() {\n"
717             + "      if (self.URLSearchParams) {\n"
718             + "        var param = new URLSearchParams('key1=val1&key2=val2&key2=val3');\n"
719             + "        param.set('key4', 'val4');\n"
720             + "        log(param);\n"
721             + "        param.set('key1', 'new1');\n"
722             + "        log(param);\n"
723             + "        param.set('key2', 'new2');\n"
724             + "        log(param);\n"
725             + "        param.set('key3', undefined);\n"
726             + "        log(param);\n"
727             + "        param.set('key4', null);\n"
728             + "        log(param);\n"
729             + "      }\n"
730             + "    }\n"
731             + "  </script>\n"
732             + "</head>\n"
733             + "<body onload='test()'>\n"
734             + "</body>\n"
735             + "</html>";
736 
737         loadPageVerifyTitle2(html);
738     }
739 
740 
741     /**
742      * @throws Exception if an error occurs
743      */
744     @Test
745     @Alerts({"key1=val1&key2=val2&key2=val3&key4=val4",
746              "key1=new1&key2=val2&key2=val3&key4=val4",
747              "key1=new1&key2=new2&key4=val4",
748              "key1=new1&key2=new2&key4=val4&key3=undefined",
749              "key1=new1&key2=new2&key4=null&key3=undefined",
750              "http://test.com/p?key1=new1&key2=new2&key4=null&key3=undefined"})
751     public void setFromUrl() throws Exception {
752         final String html = DOCTYPE_HTML
753             + "<html>\n"
754             + "<head>\n"
755             + "  <script>\n"
756             + LOG_TITLE_FUNCTION
757             + "    function test() {\n"
758             + "      if (self.URLSearchParams) {\n"
759             + "        var url = new URL('http://test.com/p?key1=val1&key2=val2&key2=val3');\n"
760             + "        var param = url.searchParams;\n"
761             + "        param.set('key4', 'val4');\n"
762             + "        log(param);\n"
763             + "        param.set('key1', 'new1');\n"
764             + "        log(param);\n"
765             + "        param.set('key2', 'new2');\n"
766             + "        log(param);\n"
767             + "        param.set('key3', undefined);\n"
768             + "        log(param);\n"
769             + "        param.set('key4', null);\n"
770             + "        log(param);\n"
771 
772             + "        log(url);\n"
773             + "      }\n"
774             + "    }\n"
775             + "  </script>\n"
776             + "</head>\n"
777             + "<body onload='test()'>\n"
778             + "</body>\n"
779             + "</html>";
780 
781         loadPageVerifyTitle2(html);
782     }
783 
784     /**
785      * @throws Exception if an error occurs
786      */
787     @Test
788     @Alerts({"function keys() { [native code] }", "[object URLSearchParams Iterator]",
789              "key1", "key2", "key1", "", "true"})
790     public void keys() throws Exception {
791         final String html = DOCTYPE_HTML
792             + "<html>\n"
793             + "<head>\n"
794             + "  <script>\n"
795             + LOG_TITLE_FUNCTION
796             + "    function test() {\n"
797             + "      if (self.URLSearchParams) {\n"
798             + "        var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n"
799 
800             + "        log(param.keys);\n"
801             + "        var iter = param.keys();\n"
802             + "        log(iter);\n"
803 
804             + "        var entry = iter.next().value;\n"
805             + "        log(entry);\n"
806             + "        entry = iter.next().value;\n"
807             + "        log(entry);\n"
808             + "        entry = iter.next().value;\n"
809             + "        log(entry);\n"
810             + "        entry = iter.next().value;\n"
811             + "        log(entry);\n"
812 
813             + "        log(iter.next().done);\n"
814             + "      }\n"
815             + "    }\n"
816             + "  </script>\n"
817             + "</head>\n"
818             + "<body onload='test()'>\n"
819             + "</body>\n"
820             + "</html>";
821 
822         loadPageVerifyTitle2(html);
823     }
824 
825     /**
826      * @throws Exception if an error occurs
827      */
828     @Test
829     @Alerts({"function values() { [native code] }", "[object URLSearchParams Iterator]",
830              "val1", "", "val3", "val4", "true"})
831     public void values() throws Exception {
832         final String html = DOCTYPE_HTML
833             + "<html>\n"
834             + "<head>\n"
835             + "  <script>\n"
836             + LOG_TITLE_FUNCTION
837             + "    function test() {\n"
838             + "      if (self.URLSearchParams) {\n"
839             + "        var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n"
840 
841             + "        log(param.values);\n"
842             + "        var iter = param.values();\n"
843             + "        log(iter);\n"
844 
845             + "        var entry = iter.next().value;\n"
846             + "        log(entry);\n"
847             + "        entry = iter.next().value;\n"
848             + "        log(entry);\n"
849             + "        entry = iter.next().value;\n"
850             + "        log(entry);\n"
851             + "        entry = iter.next().value;\n"
852             + "        log(entry);\n"
853 
854             + "        log(iter.next().done);\n"
855             + "      }\n"
856             + "    }\n"
857             + "  </script>\n"
858             + "</head>\n"
859             + "<body onload='test()'>\n"
860             + "</body>\n"
861             + "</html>";
862 
863         loadPageVerifyTitle2(html);
864     }
865 
866     /**
867      * @throws Exception if an error occurs
868      */
869     @Test
870     @Alerts({"val1", "", "val3", "val4"})
871     public void valuesForOf() throws Exception {
872         final String html = DOCTYPE_HTML
873             + "<html>\n"
874             + "<head>\n"
875             + "  <script>\n"
876             + LOG_TITLE_FUNCTION
877             + "    function test() {\n"
878             + "      if (self.URLSearchParams) {\n"
879             + "        var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n"
880 
881             + "        for (var i of param.values()) {\n"
882             + "          log(i);\n"
883             + "        }\n"
884             + "      }\n"
885             + "    }\n"
886             + "  </script>\n"
887             + "</head>\n"
888             + "<body onload='test()'>\n"
889             + "</body>\n"
890             + "</html>";
891 
892         loadPageVerifyTitle2(html);
893     }
894 
895     /**
896      * @throws Exception if an error occurs
897      */
898     @Test
899     @Alerts({"key1-val1", "key2-val2", "key3-val3",
900              "key1-val1", "key3-val3",
901              "key2-val2", "key3-val3"})
902     public void forEach() throws Exception {
903         final String html = DOCTYPE_HTML
904             + "<html>\n"
905                 + "<head>\n"
906                 + "  <script>\n"
907                 + LOG_TITLE_FUNCTION
908                 + "    function test() {\n"
909                 + "      if (self.URLSearchParams) {\n"
910                 + "        var param = new URLSearchParams('key1=val1&key2=val2&key3=val3');\n"
911                 + "        param.forEach((value, key) => {\n"
912                 + "          log(key + '-' + value);\n"
913                 + "        });\n"
914                 + "        param.forEach((value, key) => {\n"
915                 + "          log(key + '-' + value);\n"
916                 + "          if (value == 'val1' || value == 'val2') {\n"
917                 + "            param.delete(key);\n"
918                 + "          }\n"
919                 + "        });\n"
920                 + "        param.forEach((value, key) => {\n"
921                 + "          log(key + '-' + value);\n"
922                 + "        });\n"
923                 + "      }\n"
924                 + "    }\n"
925                 + "  </script>\n"
926                 + "</head>\n"
927                 + "<body onload='test()'>\n"
928                 + "</body>\n"
929                 + "</html>";
930 
931         loadPageVerifyTitle2(html);
932     }
933 
934     /**
935      * @throws Exception if the test fails
936      */
937     @Test
938     @Alerts({"TypeError", "TypeError"})
939     public void forEachWrongParam() throws Exception {
940         final String html = DOCTYPE_HTML
941                 + "<html><head><script>\n"
942                 + LOG_TITLE_FUNCTION
943                 + "function test() {\n"
944                 + "  if (self.URLSearchParams) {\n"
945                 + "    var param = new URLSearchParams('key1=val1&key2=val2&key3=val3');\n"
946                 + "    try {\n"
947                 + "      param.forEach();\n"
948                 + "    } catch(e) { logEx(e); }\n"
949                 + "    try {\n"
950                 + "      param.forEach('wrong');\n"
951                 + "    } catch(e) { logEx(e); }\n"
952                 + "  }\n"
953                 + "}\n"
954                 + "</script></head><body onload='test()'>\n"
955                 + "  <div id='d1' class=' a b \t c \n d \u000B e \u000C f \r g'></div>\n"
956                 + "</body></html>";
957 
958         loadPageVerifyTitle2(html);
959     }
960 
961     /**
962      * @throws Exception if an error occurs
963      */
964     @Test
965     @Alerts({"true", "function entries() { [native code] }", "[object URLSearchParams Iterator]",
966              "key1-val1", "key2-", "key1-val3", "-val4", "true"})
967     public void entries() throws Exception {
968         final String html = DOCTYPE_HTML
969             + "<html>\n"
970             + "<head>\n"
971             + "  <script>\n"
972             + LOG_TITLE_FUNCTION
973             + "    function test() {\n"
974             + "      if (self.URLSearchParams) {\n"
975             + "        var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n"
976 
977             + "        if (typeof Symbol != 'undefined') {\n"
978             + "          log(param[Symbol.iterator] === param.entries);\n"
979             + "        }\n"
980 
981             + "        log(param.entries);\n"
982             + "        var iter = param.entries();\n"
983             + "        log(iter);\n"
984 
985             + "        var entry = iter.next().value;\n"
986             + "        log(entry[0] + '-' + entry[1]);\n"
987             + "        entry = iter.next().value;\n"
988             + "        log(entry[0] + '-' + entry[1]);\n"
989             + "        entry = iter.next().value;\n"
990             + "        log(entry[0] + '-' + entry[1]);\n"
991             + "        entry = iter.next().value;\n"
992             + "        log(entry[0] + '-' + entry[1]);\n"
993 
994             + "        log(iter.next().done);\n"
995             + "      }\n"
996             + "    }\n"
997             + "  </script>\n"
998             + "</head>\n"
999             + "<body onload='test()'>\n"
1000             + "</body>\n"
1001             + "</html>";
1002 
1003         loadPageVerifyTitle2(html);
1004     }
1005 
1006     /**
1007      * @throws Exception if an error occurs
1008      */
1009     @Test
1010     @Alerts({"key1,val1", "key2,", "key1,val3", ",val4"})
1011     public void entriesForOf() throws Exception {
1012         final String html = DOCTYPE_HTML
1013             + "<html>\n"
1014             + "<head>\n"
1015             + "  <script>\n"
1016             + LOG_TITLE_FUNCTION
1017             + "    function test() {\n"
1018             + "      if (self.URLSearchParams) {\n"
1019             + "        var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n"
1020 
1021             + "        for (var i of param.entries()) {\n"
1022             + "          log(i);\n"
1023             + "        }\n"
1024             + "      }\n"
1025             + "    }\n"
1026             + "  </script>\n"
1027             + "</head>\n"
1028             + "<body onload='test()'>\n"
1029             + "</body>\n"
1030             + "</html>";
1031 
1032         loadPageVerifyTitle2(html);
1033     }
1034 
1035     /**
1036      * @throws Exception if an error occurs
1037      */
1038     @Test
1039     @Alerts({"4", "0", "1"})
1040     public void size() throws Exception {
1041         final String html = DOCTYPE_HTML
1042             + "<html>\n"
1043             + "<head>\n"
1044             + "  <script>\n"
1045             + LOG_TITLE_FUNCTION
1046             + "    function test() {\n"
1047             + "      if (self.URLSearchParams) {\n"
1048             + "        var param = new URLSearchParams('key1=val1&key2=&key1=val3&=val4');\n"
1049             + "        log(param.size);\n"
1050 
1051             + "        param = new URLSearchParams('');\n"
1052             + "        log(param.size);\n"
1053 
1054             + "        param = new URLSearchParams('key1=val1');\n"
1055             + "        log(param.size);\n"
1056             + "      }\n"
1057             + "    }\n"
1058             + "  </script>\n"
1059             + "</head>\n"
1060             + "<body onload='test()'>\n"
1061             + "</body>\n"
1062             + "</html>";
1063 
1064         loadPageVerifyTitle2(html);
1065     }
1066 
1067     /**
1068      * @throws Exception if the test fails
1069      */
1070     @Test
1071     @Alerts({"function URLSearchParams() { [native code] }",
1072              "function URLSearchParams() { [native code] }",
1073              "function URLSearchParams() { [native code] }",
1074              "key1=val1", "key1=val1", "key1=val1"})
1075     public void testToString() throws Exception {
1076         final String html = DOCTYPE_HTML
1077             + "<html><body>\n"
1078             + "<script>\n"
1079             + LOG_TITLE_FUNCTION
1080             + "  if (self.URLSearchParams) {\n"
1081             + "    log(URLSearchParams);\n"
1082             + "    log('' + URLSearchParams);\n"
1083             + "    log(URLSearchParams.toString());\n"
1084 
1085             + "    var p = new URLSearchParams('key1=val1');\n"
1086             + "    log(p);\n"
1087             + "    log('' + p);\n"
1088             + "    log(p.toString());\n"
1089             + "  }"
1090             + "</script>\n"
1091             + "</body></html>";
1092 
1093         loadPageVerifyTitle2(html);
1094     }
1095 }