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.html;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.junit.Test;
21  import org.junit.runner.RunWith;
22  import org.openqa.selenium.By;
23  import org.openqa.selenium.WebDriver;
24  import org.openqa.selenium.WebElement;
25  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
26  
27  /**
28   * Tests for {@link HtmlUrlInput}.
29   *
30   * @author Ahmed Ashour
31   * @author Ronald Brill
32   * @author Anton Demydenko
33   */
34  @RunWith(BrowserRunner.class)
35  public class HtmlUrlInputTest extends WebDriverTestCase {
36  
37      /**
38       * @throws Exception if the test fails
39       */
40      @Test
41      @Alerts({"--null", "--null", "--null"})
42      public void defaultValues() throws Exception {
43          final String html = DOCTYPE_HTML
44              + "<html><head>\n"
45              + "<script>\n"
46              + LOG_TITLE_FUNCTION
47              + "  function test() {\n"
48              + "    var input = document.getElementById('text1');\n"
49              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
50  
51              + "    try {\n"
52              + "      input = document.createElement('input');\n"
53              + "      input.type = 'url';\n"
54              + "      log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
55              + "    } catch(e)  { logEx(e); }\n"
56  
57              + "    var builder = document.createElement('div');\n"
58              + "    builder.innerHTML = '<input type=\"url\">';\n"
59              + "    input = builder.firstChild;\n"
60              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
61              + "  }\n"
62              + "</script>\n"
63              + "</head><body onload='test()'>\n"
64              + "<form>\n"
65              + "  <input type='url' id='text1'>\n"
66              + "</form>\n"
67              + "</body></html>";
68  
69          loadPageVerifyTitle2(html);
70      }
71  
72      /**
73       * @throws Exception if the test fails
74       */
75      @Test
76      @Alerts({"--null", "--null", "--null"})
77      public void defaultValuesAfterClone() throws Exception {
78          final String html = DOCTYPE_HTML
79              + "<html><head>\n"
80              + "<script>\n"
81              + LOG_TITLE_FUNCTION
82              + "  function test() {\n"
83              + "    var input = document.getElementById('text1');\n"
84              + "    input = input.cloneNode(false);\n"
85              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
86  
87              + "    try {\n"
88              + "      input = document.createElement('input');\n"
89              + "      input.type = 'url';\n"
90              + "      input = input.cloneNode(false);\n"
91              + "      log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
92              + "    } catch(e)  { logEx(e); }\n"
93  
94              + "    var builder = document.createElement('div');\n"
95              + "    builder.innerHTML = '<input type=\"url\">';\n"
96              + "    input = builder.firstChild;\n"
97              + "    input = input.cloneNode(false);\n"
98              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
99              + "  }\n"
100             + "</script>\n"
101             + "</head><body onload='test()'>\n"
102             + "<form>\n"
103             + "  <input type='url' id='text1'>\n"
104             + "</form>\n"
105             + "</body></html>";
106 
107         loadPageVerifyTitle2(html);
108     }
109 
110     /**
111      * Verifies getVisibleText().
112      * @throws Exception if the test fails
113      */
114     @Test
115     @Alerts("")
116     public void getVisibleText() throws Exception {
117         final String htmlContent = DOCTYPE_HTML
118             + "<html>\n"
119             + "<head></head>\n"
120             + "<body>\n"
121             + "<form id='form1'>\n"
122             + "  <input type='url' id='tester' value='http://htmlunit.sourceforge.net'>\n"
123             + "</form>\n"
124             + "</body></html>";
125 
126         final WebDriver driver = loadPage2(htmlContent);
127         final String text = driver.findElement(By.id("tester")).getText();
128         assertEquals(getExpectedAlerts()[0], text);
129 
130         if (driver instanceof HtmlUnitDriver) {
131             final HtmlPage page = (HtmlPage) getEnclosedPage();
132             assertEquals(getExpectedAlerts()[0], page.getBody().getVisibleText());
133         }
134     }
135 
136     /**
137      * Verifies clear().
138      * @throws Exception if the test fails
139      */
140     @Test
141     @Alerts({"https://htmlunit.org", ""})
142     public void clearInput() throws Exception {
143         final String htmlContent = DOCTYPE_HTML
144                 + "<html>\n"
145                 + "<head></head>\n"
146                 + "<body>\n"
147                 + "<form id='form1'>\n"
148                 + "  <input type='url' name='tester' id='tester' value='https://htmlunit.org'>\n"
149                 + "</form>\n"
150                 + "</body></html>";
151 
152         final WebDriver driver = loadPage2(htmlContent);
153         final WebElement element = driver.findElement(By.id("tester"));
154 
155         assertEquals(getExpectedAlerts()[0], element.getDomAttribute("value"));
156         assertEquals(getExpectedAlerts()[0], element.getDomProperty("value"));
157 
158         element.clear();
159         assertEquals(getExpectedAlerts()[0], element.getDomAttribute("value"));
160         assertEquals(getExpectedAlerts()[1], element.getDomProperty("value"));
161     }
162 
163     /**
164      * @throws Exception if the test fails
165      */
166     @Test
167     public void typing() throws Exception {
168         final String htmlContent = DOCTYPE_HTML
169             + "<html><head><title>foo</title></head><body>\n"
170             + "<form id='form1'>\n"
171             + "  <input type='url' id='foo'>\n"
172             + "</form></body></html>";
173 
174         final WebDriver driver = loadPage2(htmlContent);
175 
176         final WebElement input = driver.findElement(By.id("foo"));
177 
178         input.sendKeys("hello");
179         assertNull(input.getDomAttribute("value"));
180         assertEquals("hello", input.getDomProperty("value"));
181     }
182 
183     /**
184      * @throws Exception if the test fails
185      */
186     @Test
187     @Alerts("--")
188     public void minMaxStep() throws Exception {
189         final String html = DOCTYPE_HTML
190             + "<html>\n"
191             + "<head>\n"
192             + "<script>\n"
193             + LOG_TITLE_FUNCTION
194             + "  function test() {\n"
195             + "    var input = document.getElementById('tester');\n"
196             + "    log(input.min + '-' + input.max + '-' + input.step);\n"
197             + "  }\n"
198             + "</script>\n"
199             + "</head>\n"
200             + "<body onload='test()'>\n"
201             + "<form>\n"
202             + "  <input type='url' id='tester'>\n"
203             + "</form>\n"
204             + "</body>\n"
205             + "</html>";
206 
207         loadPageVerifyTitle2(html);
208     }
209 
210     /**
211      * @throws Exception if an error occurs
212      */
213     @Test
214     @Alerts({"http://example.com",
215              "http://example.com",
216              "false",
217              "false-false-true-false-false-false-false-false-false-false-false",
218              "true",
219              "§§URL§§", "1"})
220     public void patternValidationInvalid() throws Exception {
221         validation("<input type='url' pattern='.*test.*' id='e1' value='http://example.com' name='k'>\n",
222                     "", null);
223     }
224 
225     /**
226      * @throws Exception if an error occurs
227      */
228     @Test
229     @Alerts({"http://test.com",
230              "http://test.com",
231              "true",
232              "false-false-false-false-false-false-false-false-false-true-false",
233              "true",
234              "§§URL§§?k=http%3A%2F%2Ftest.com", "2"})
235     public void patternValidationValid() throws Exception {
236         validation("<input type='url' pattern='.*test.*' id='e1' value='http://test.com' name='k'>\n", "", null);
237     }
238 
239     /**
240      * @throws Exception if an error occurs
241      */
242     @Test
243     @Alerts({"",
244              "",
245              "true",
246              "false-false-false-false-false-false-false-false-false-true-false",
247              "true",
248              "§§URL§§?k=", "2"})
249     public void patternValidationEmpty() throws Exception {
250         validation("<input type='url' pattern='.*test.*' id='e1' name='k' value=''>\n", "", null);
251     }
252 
253     /**
254      * @throws Exception if an error occurs
255      */
256     @Test
257     @Alerts({" ",
258              "",
259              "true",
260              "false-false-false-false-false-false-false-false-false-true-false",
261              "true",
262              "§§URL§§?k=", "2"})
263     public void patternValidationBlank() throws Exception {
264         validation("<input type='url' pattern='.*test.*' id='e1' name='k' value=' '>\n", "", null);
265     }
266 
267     /**
268      * @throws Exception if an error occurs
269      */
270     @Test
271     @Alerts({"  \t",
272              "",
273              "true",
274              "false-false-false-false-false-false-false-false-false-true-false",
275              "true",
276              "§§URL§§?k=", "2"})
277     public void patternValidationWhitespace() throws Exception {
278         validation("<input type='url' pattern='.*test.*' id='e1' name='k' value='  \t'>\n", "", null);
279     }
280 
281     /**
282      * @throws Exception if an error occurs
283      */
284     @Test
285     @Alerts({" http://test.com ",
286              "http://test.com",
287              "true",
288              "false-false-false-false-false-false-false-false-false-true-false",
289              "true",
290              "§§URL§§?k=http%3A%2F%2Ftest.com", "2"})
291     public void patternValidationTrimInitial() throws Exception {
292         validation("<input type='url' pattern='.*test.*' id='e1' name='k' value=' http://test.com '>\n", "", null);
293     }
294 
295     /**
296      * @throws Exception if an error occurs
297      */
298     @Test
299     @Alerts({"null",
300              " http://test.com ",
301              "true",
302              "false-false-false-false-false-false-false-false-false-true-false",
303              "true",
304              "§§URL§§?k=+http%3A%2F%2Ftest.com+", "2"})
305     public void patternValidationTrimType() throws Exception {
306         validation("<input type='url' pattern='.*test.*' id='e1' name='k'>\n", "", " http://test.com ");
307     }
308 
309     /**
310      * @throws Exception if an error occurs
311      */
312     @Test
313     @Alerts({"null",
314              "http://example.com",
315              "false",
316              "false-false-false-false-false-false-false-true-false-false-false",
317              "true",
318              "§§URL§§", "1"})
319     public void minLengthValidationInvalid() throws Exception {
320         validation("<input type='url' minlength='20' id='e1' name='k'>\n", "", "http://example.com");
321     }
322 
323     /**
324      * @throws Exception if an error occurs
325      */
326     @Test
327     @Alerts({"http://example.com",
328              "http://example.com",
329              "true",
330              "false-false-false-false-false-false-false-false-false-true-false",
331              "true",
332              "§§URL§§?k=http%3A%2F%2Fexample.com", "2"})
333     public void minLengthValidationInvalidInitial() throws Exception {
334         validation("<input type='url' minlength='20' id='e1' name='k' value='http://example.com'>\n", "", null);
335     }
336 
337     /**
338      * @throws Exception if an error occurs
339      */
340     @Test
341     @Alerts({"null",
342              "",
343              "true",
344              "false-false-false-false-false-false-false-false-false-true-false",
345              "true",
346              "§§URL§§?k=", "2"})
347     public void minLengthValidationInvalidNoInitial() throws Exception {
348         validation("<input type='url' minlength='20' id='e1' name='k'>\n", "", null);
349     }
350 
351     /**
352      * @throws Exception if an error occurs
353      */
354     @Test
355     @Alerts({"null",
356              "http://example.com/test",
357              "true",
358              "false-false-false-false-false-false-false-false-false-true-false",
359              "true",
360              "§§URL§§?k=http%3A%2F%2Fexample.com%2Ftest", "2"})
361     public void minLengthValidationValid() throws Exception {
362         validation("<input type='url' minlength='20' id='e1' name='k'>\n", "", "http://example.com/test");
363     }
364 
365     /**
366      * @throws Exception if an error occurs
367      */
368     @Test
369     @Alerts({"null",
370              "http://example.com",
371              "true",
372              "false-false-false-false-false-false-false-false-false-true-false",
373              "true",
374              "§§URL§§?k=http%3A%2F%2Fexample.com", "2"})
375     public void maxLengthValidationValid() throws Exception {
376         validation("<input type='url' maxlength='20' id='e1' name='k'>\n", "", "http://example.com");
377     }
378 
379     /**
380      * @throws Exception if an error occurs
381      */
382     @Test
383     @Alerts({"null",
384              "http://example.com/t",
385              "true",
386              "false-false-false-false-false-false-false-false-false-true-false",
387              "true",
388              "§§URL§§?k=http%3A%2F%2Fexample.com%2Ft", "2"})
389     public void maxLengthValidationInvalid() throws Exception {
390         validation("<input type='url' maxlength='20' id='e1' name='k'>\n", "", "http://example.com/test");
391     }
392 
393     /**
394      * @throws Exception if an error occurs
395      */
396     @Test
397     @Alerts({"http://example.com/test",
398              "http://example.com/test",
399              "true",
400              "false-false-false-false-false-false-false-false-false-true-false",
401              "true",
402              "§§URL§§?k=http%3A%2F%2Fexample.com%2Ftest", "2"})
403     public void maxLengthValidationInvalidInitial() throws Exception {
404         validation("<input type='url' maxlength='20' "
405                     + "id='e1' name='k' value='http://example.com/test'>\n", "", null);
406     }
407 
408     /**
409      * @throws Exception if an error occurs
410      */
411     @Test
412     @Alerts({"true", "false", "true", "false", "true"})
413     public void willValidate() throws Exception {
414         final String html = DOCTYPE_HTML
415                 + "<html><head>\n"
416                 + "  <script>\n"
417                 + LOG_TITLE_FUNCTION
418                 + "    function test() {\n"
419                 + "      log(document.getElementById('o1').willValidate);\n"
420                 + "      log(document.getElementById('o2').willValidate);\n"
421                 + "      log(document.getElementById('o3').willValidate);\n"
422                 + "      log(document.getElementById('o4').willValidate);\n"
423                 + "      log(document.getElementById('o5').willValidate);\n"
424                 + "    }\n"
425                 + "  </script>\n"
426                 + "</head>\n"
427                 + "<body onload='test()'>\n"
428                 + "  <form>\n"
429                 + "    <input type='url' id='o1'>\n"
430                 + "    <input type='url' id='o2' disabled>\n"
431                 + "    <input type='url' id='o3' hidden>\n"
432                 + "    <input type='url' id='o4' readonly>\n"
433                 + "    <input type='url' id='o5' style='display: none'>\n"
434                 + "  </form>\n"
435                 + "</body></html>";
436 
437         loadPageVerifyTitle2(html);
438     }
439 
440     /**
441      * @throws Exception if an error occurs
442      */
443     @Test
444     @Alerts({"null",
445              "",
446              "true",
447              "false-false-false-false-false-false-false-false-false-true-false",
448              "true",
449              "§§URL§§?k=", "2"})
450     public void validationEmpty() throws Exception {
451         validation("<input type='url' id='e1' name='k'>\n", "", null);
452     }
453 
454     /**
455      * @throws Exception if an error occurs
456      */
457     @Test
458     @Alerts({"null",
459              "",
460              "false",
461              "false-true-false-false-false-false-false-false-false-false-false",
462              "true",
463              "§§URL§§", "1"})
464     public void validationCustomValidity() throws Exception {
465         validation("<input type='url' id='e1' name='k'>\n", "elem.setCustomValidity('Invalid');", null);
466     }
467 
468     /**
469      * @throws Exception if an error occurs
470      */
471     @Test
472     @Alerts({"null",
473              "",
474              "false",
475              "false-true-false-false-false-false-false-false-false-false-false",
476              "true",
477              "§§URL§§", "1"})
478     public void validationBlankCustomValidity() throws Exception {
479         validation("<input type='url' id='e1' name='k'>\n", "elem.setCustomValidity(' ');\n", null);
480     }
481 
482     /**
483      * @throws Exception if an error occurs
484      */
485     @Test
486     @Alerts({"null",
487              "",
488              "true",
489              "false-false-false-false-false-false-false-false-false-true-false",
490              "true",
491              "§§URL§§?k=", "2"})
492     public void validationResetCustomValidity() throws Exception {
493         validation("<input type='url' id='e1' name='k'>\n",
494                 "elem.setCustomValidity('Invalid');elem.setCustomValidity('');", null);
495     }
496 
497     /**
498      * @throws Exception if an error occurs
499      */
500     @Test
501     @Alerts({"null",
502              "",
503              "false",
504              "false-false-false-false-false-false-false-false-false-false-true",
505              "true",
506              "§§URL§§", "1"})
507     public void validationRequired() throws Exception {
508         validation("<input type='url' id='e1' name='k' required>\n", "", null);
509     }
510 
511     /**
512      * @throws Exception if an error occurs
513      */
514     @Test
515     @Alerts({"null",
516              "",
517              "true",
518              "false-false-false-false-false-false-false-false-false-true-false",
519              "true",
520              "§§URL§§?k=http%3A%2F%2Fexample.com", "2"})
521     public void validationRequiredValueSet() throws Exception {
522         validation("<input type='url' id='e1' name='k' required>\n", "elem.value='http://example.com';", null);
523     }
524 
525     /**
526      * @throws Exception if an error occurs
527      */
528     @Test
529     @Alerts({"null",
530              "",
531              "false",
532              "false-false-true-false-false-false-false-false-false-false-false",
533              "true",
534              "§§URL§§", "1"})
535     public void validationPattern() throws Exception {
536         validation("<input type='url' id='e1' name='k' pattern='.*test.*'>\n",
537                     "elem.value='http://example.com';", null);
538     }
539 
540     private void validation(final String htmlPart, final String jsPart, final String sendKeys) throws Exception {
541         final String html = DOCTYPE_HTML
542                 + "<html><head>\n"
543                 + "  <script>\n"
544                 + LOG_TITLE_FUNCTION
545                 + "    function logValidityState(s) {\n"
546                 + "      log(s.badInput"
547                         + "+ '-' + s.customError"
548                         + "+ '-' + s.patternMismatch"
549                         + "+ '-' + s.rangeOverflow"
550                         + "+ '-' + s.rangeUnderflow"
551                         + "+ '-' + s.stepMismatch"
552                         + "+ '-' + s.tooLong"
553                         + "+ '-' + s.tooShort"
554                         + " + '-' + s.typeMismatch"
555                         + " + '-' + s.valid"
556                         + " + '-' + s.valueMissing);\n"
557                 + "    }\n"
558                 + "    function test() {\n"
559                 + "      var elem = document.getElementById('e1');\n"
560                 + jsPart
561                 + "      log(elem.checkValidity());\n"
562                 + "      logValidityState(elem.validity);\n"
563                 + "      log(elem.willValidate);\n"
564                 + "    }\n"
565                 + "  </script>\n"
566                 + "</head>\n"
567                 + "<body>\n"
568                 + "  <form>\n"
569                 + htmlPart
570                 + "    <button id='myTest' type='button' onclick='test()'>Test</button>\n"
571                 + "    <button id='myButton' type='submit'>Submit</button>\n"
572                 + "  </form>\n"
573                 + "</body></html>";
574 
575         final String secondContent = DOCTYPE_HTML
576                 + "<html><head><title>second</title></head><body>\n"
577                 + "  <p>hello world</p>\n"
578                 + "</body></html>";
579 
580         getMockWebConnection().setResponse(URL_SECOND, secondContent);
581         expandExpectedAlertsVariables(URL_FIRST);
582 
583         final WebDriver driver = loadPage2(html, URL_FIRST);
584 
585         final WebElement foo = driver.findElement(By.id("e1"));
586         if (sendKeys != null) {
587             foo.sendKeys(sendKeys);
588         }
589         assertEquals(getExpectedAlerts()[0], "" + foo.getDomAttribute("value"));
590         assertEquals(getExpectedAlerts()[1], foo.getDomProperty("value"));
591 
592         driver.findElement(By.id("myTest")).click();
593         verifyTitle2(driver, getExpectedAlerts()[2], getExpectedAlerts()[3], getExpectedAlerts()[4]);
594 
595         driver.findElement(By.id("myButton")).click();
596         if (useRealBrowser()) {
597             Thread.sleep(400);
598         }
599         assertEquals(getExpectedAlerts()[5], getMockWebConnection().getLastWebRequest().getUrl());
600         assertEquals(Integer.parseInt(getExpectedAlerts()[6]), getMockWebConnection().getRequestCount());
601     }
602 }