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 static org.junit.jupiter.api.Assertions.fail;
18  
19  import java.util.Collections;
20  
21  import org.htmlunit.WebDriverTestCase;
22  import org.htmlunit.junit.annotation.Alerts;
23  import org.junit.jupiter.api.Test;
24  import org.openqa.selenium.By;
25  import org.openqa.selenium.InvalidElementStateException;
26  import org.openqa.selenium.Keys;
27  import org.openqa.selenium.WebDriver;
28  import org.openqa.selenium.WebElement;
29  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
30  
31  /**
32   * Tests for {@link HtmlPasswordInput}.
33   *
34   * @author Ahmed Ashour
35   * @author Ronald Brill
36   * @author Anton Demydenko
37   */
38  public class HtmlPasswordInputTest extends WebDriverTestCase {
39  
40      /**
41       * Verifies getVisibleText().
42       * @throws Exception if the test fails
43       */
44      @Test
45      @Alerts("")
46      public void getVisibleText() throws Exception {
47          final String htmlContent = DOCTYPE_HTML
48              + "<html>\n"
49              + "<head></head>\n"
50              + "<body>\n"
51              + "<form id='form1'>\n"
52              + "  <input type='password' name='tester' id='tester' value='bla'>\n"
53              + "</form>\n"
54              + "</body></html>";
55  
56          final WebDriver driver = loadPage2(htmlContent);
57          final String text = driver.findElement(By.id("tester")).getText();
58          assertEquals(getExpectedAlerts()[0], text);
59  
60          if (driver instanceof HtmlUnitDriver) {
61              final HtmlPage page = (HtmlPage) getEnclosedPage();
62              assertEquals(getExpectedAlerts()[0], page.getBody().getVisibleText());
63          }
64      }
65  
66      /**
67       * @throws Exception if the test fails
68       */
69      @Test
70      public void type() throws Exception {
71          final String html = DOCTYPE_HTML
72                  + "<html><head></head><body><input type='password' id='p'/></body></html>";
73          final WebDriver driver = loadPage2(html);
74          final WebElement p = driver.findElement(By.id("p"));
75  
76          p.sendKeys("abc");
77          assertNull(p.getDomAttribute("value"));
78          assertEquals("abc", p.getDomProperty("value"));
79  
80          p.sendKeys(Keys.BACK_SPACE);
81          assertNull(p.getDomAttribute("value"));
82          assertEquals("ab", p.getDomProperty("value"));
83  
84          p.sendKeys(Keys.BACK_SPACE);
85          assertNull(p.getDomAttribute("value"));
86          assertEquals("a", p.getDomProperty("value"));
87  
88          p.sendKeys(Keys.BACK_SPACE);
89          assertNull(p.getDomAttribute("value"));
90          assertEquals("", p.getDomProperty("value"));
91  
92          p.sendKeys(Keys.BACK_SPACE);
93          assertNull(p.getDomAttribute("value"));
94          assertEquals("", p.getDomProperty("value"));
95      }
96  
97      /**
98       * @throws Exception if the test fails
99       */
100     @Test
101     public void typeWhileDisabled() throws Exception {
102         final String html = DOCTYPE_HTML
103                 + "<html><body><input type='password' id='p' disabled='disabled'/></body></html>";
104         final WebDriver driver = loadPage2(html);
105         final WebElement p = driver.findElement(By.id("p"));
106         try {
107             p.sendKeys("abc");
108             fail();
109         }
110         catch (final InvalidElementStateException e) {
111             // as expected
112         }
113         assertNull(p.getDomAttribute("value"));
114         assertEquals("", p.getDomProperty("value"));
115     }
116 
117     /**
118      * @throws Exception if the test fails
119      */
120     @Test
121     @Alerts({"null", "null"})
122     public void typeDoesNotChangeValueAttribute() throws Exception {
123         final String html = DOCTYPE_HTML
124                 + "<html>\n"
125                 + "<head>\n"
126                 + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
127                 + "</head>\n"
128                 + "<body>\n"
129                 + "  <input type='password' id='p'/>\n"
130                 + "  <button id='check' onclick='log(document.getElementById(\"p\").getAttribute(\"value\"));'>"
131                         + "DoIt</button>\n"
132                 + "</body></html>";
133 
134         final WebDriver driver = loadPage2(html);
135         final WebElement p = driver.findElement(By.id("p"));
136 
137         final WebElement check = driver.findElement(By.id("check"));
138         check.click();
139         verifyTitle2(driver, getExpectedAlerts()[0]);
140 
141         p.sendKeys("abc");
142         check.click();
143         verifyTitle2(driver, getExpectedAlerts());
144     }
145 
146     /**
147      * @throws Exception if the test fails
148      */
149     @Test
150     @Alerts({"HtmlUnit", "HtmlUnit"})
151     public void typeDoesNotChangeValueAttributeWithInitialValue() throws Exception {
152         final String html = DOCTYPE_HTML
153                 + "<html>\n"
154                 + "<head>\n"
155                 + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
156                 + "</head>\n"
157                 + "<body>\n"
158                 + "  <input type='password' id='p' value='HtmlUnit'/>\n"
159                 + "  <button id='check' onclick='log(document.getElementById(\"p\").getAttribute(\"value\"));'>"
160                         + "DoIt</button>\n"
161                 + "</body></html>";
162 
163         final WebDriver driver = loadPage2(html);
164         final WebElement p = driver.findElement(By.id("p"));
165 
166         final WebElement check = driver.findElement(By.id("check"));
167         check.click();
168         verifyTitle2(driver, getExpectedAlerts()[0]);
169 
170         p.sendKeys("abc");
171         check.click();
172         verifyTitle2(driver, getExpectedAlerts());
173     }
174 
175     /**
176      * @throws Exception if an error occurs
177      */
178     @Test
179     public void preventDefault_OnKeyDown() throws Exception {
180         final String html = DOCTYPE_HTML
181             + "<html><head><script>\n"
182             + "  function handler(e) {\n"
183             + "    if (e && e.target.value.length > 2)\n"
184             + "      e.preventDefault();\n"
185             + "    else if (!e && window.event.srcElement.value.length > 2)\n"
186             + "      return false;\n"
187             + "  }\n"
188             + "  function init() {\n"
189             + "    document.getElementById('p').onkeydown = handler;\n"
190             + "  }\n"
191             + "</script></head>\n"
192             + "<body onload='init()'>\n"
193             + "<input type='password' id='p'></input>\n"
194             + "</body></html>";
195 
196         final WebDriver driver = loadPage2(html);
197         final WebElement p = driver.findElement(By.id("p"));
198 
199         p.sendKeys("abcd");
200         assertNull(p.getDomAttribute("value"));
201         assertEquals("abc", p.getDomProperty("value"));
202     }
203 
204     /**
205      * @throws Exception if an error occurs
206      */
207     @Test
208     public void preventDefault_OnKeyPress() throws Exception {
209         final String html = DOCTYPE_HTML
210             + "<html><head><script>\n"
211             + "  function handler(e) {\n"
212             + "    if (e && e.target.value.length > 2)\n"
213             + "      e.preventDefault();\n"
214             + "    else if (!e && window.event.srcElement.value.length > 2)\n"
215             + "      return false;\n"
216             + "  }\n"
217             + "  function init() {\n"
218             + "    document.getElementById('p').onkeypress = handler;\n"
219             + "  }\n"
220             + "</script></head>\n"
221             + "<body onload='init()'>\n"
222             + "<input type='password' id='p'></input>\n"
223             + "</body></html>";
224 
225         final WebDriver driver = loadPage2(html);
226         final WebElement p = driver.findElement(By.id("p"));
227 
228         p.sendKeys("abcd");
229         assertNull(p.getDomAttribute("value"));
230         assertEquals("abc", p.getDomProperty("value"));
231     }
232 
233     /**
234      * @throws Exception if an error occurs
235      */
236     @Test
237     @Alerts({"foo", "change", "boo", "blur", "boo", "blur"})
238     public void typeOnChange() throws Exception {
239         final String html = DOCTYPE_HTML
240             + "<html><head>\n"
241             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
242             + "</head>\n"
243             + "<body>\n"
244             + "<input type='password' id='p' value='Hello world'"
245                 + " onChange='log(\"foo\");log(event.type);'"
246                 + " onBlur='log(\"boo\");log(event.type);'>\n"
247             + "<button id='b'>some button</button>\n"
248             + "</body></html>";
249 
250         final WebDriver driver = loadPage2(html);
251         final WebElement p = driver.findElement(By.id("p"));
252         p.sendKeys("HtmlUnit");
253 
254         assertTrue(getCollectedAlerts(driver, 1).isEmpty());
255 
256         // trigger lost focus
257         driver.findElement(By.id("b")).click();
258         verifyTitle2(driver, getExpectedAlerts()[0], getExpectedAlerts()[1],
259                 getExpectedAlerts()[2], getExpectedAlerts()[3]);
260 
261         // set only the focus but change nothing
262         p.click();
263         assertTrue(getCollectedAlerts(driver, 1).isEmpty());
264 
265         // trigger lost focus
266         driver.findElement(By.id("b")).click();
267         verifyTitle2(driver, getExpectedAlerts());
268     }
269 
270     /**
271      * @throws Exception if an error occurs
272      */
273     @Test
274     public void setValueOnChange() throws Exception {
275         final String html = DOCTYPE_HTML
276               + "<html>\n"
277               + "<head>\n"
278               + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
279               + "</head>\n"
280               + "<body>\n"
281               + "  <input type='password' id='p' value='Hello world'"
282                     + " onChange='log(\"foo\");log(event.type);'>\n"
283               + "  <button id='b'>some button</button>\n"
284               + "  <button id='set' onclick='document.getElementById(\"p\").value=\"HtmlUnit\"'>setValue</button>\n"
285               + "</body></html>";
286 
287         final WebDriver driver = loadPage2(html);
288         driver.findElement(By.id("set")).click();
289 
290         assertEquals(Collections.emptyList(), getCollectedAlerts(driver));
291 
292         // trigger lost focus
293         driver.findElement(By.id("b")).click();
294         assertEquals(Collections.emptyList(), getCollectedAlerts(driver));
295     }
296 
297     /**
298      * @throws Exception if an error occurs
299      */
300     @Test
301     public void setDefaultValueOnChange() throws Exception {
302         final String html = DOCTYPE_HTML
303               + "<html>\n"
304               + "<head></head>\n"
305               + "<body>\n"
306               + "  <input type='password' id='p' value='Hello world'"
307                     + " onChange='log(\"foo\");log(event.type);'>\n"
308               + "  <button id='b'>some button</button>\n"
309               + "  <button id='set' onclick='document.getElementById(\"p\").defaultValue=\"HtmlUnit\"'>"
310                       + "setValue</button>\n"
311               + "</body></html>";
312 
313         final WebDriver driver = loadPage2(html);
314         driver.findElement(By.id("set")).click();
315 
316         verifyTitle2(driver);
317 
318         // trigger lost focus
319         driver.findElement(By.id("b")).click();
320         verifyTitle2(driver);
321     }
322 
323     /**
324      * @throws Exception if the test fails
325      */
326     @Test
327     @Alerts({"--null", "--null", "--null"})
328     public void defaultValues() throws Exception {
329         final String html = DOCTYPE_HTML
330             + "<html><head>\n"
331             + "<script>\n"
332             + LOG_TITLE_FUNCTION
333             + "  function test() {\n"
334             + "    var input = document.getElementById('password1');\n"
335             + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
336 
337             + "    input = document.createElement('input');\n"
338             + "    input.type = 'password';\n"
339             + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
340 
341             + "    var builder = document.createElement('div');\n"
342             + "    builder.innerHTML = '<input type=\"password\">';\n"
343             + "    input = builder.firstChild;\n"
344             + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
345             + "  }\n"
346             + "</script>\n"
347             + "</head><body onload='test()'>\n"
348             + "<form>\n"
349             + "  <input type='password' id='password1'>\n"
350             + "</form>\n"
351             + "</body></html>";
352 
353         loadPageVerifyTitle2(html);
354     }
355 
356     /**
357      * @throws Exception if the test fails
358      */
359     @Test
360     @Alerts({"--null", "--null", "--null"})
361     public void defaultValuesAfterClone() throws Exception {
362         final String html = DOCTYPE_HTML
363             + "<html><head>\n"
364             + "<script>\n"
365             + LOG_TITLE_FUNCTION
366             + "  function test() {\n"
367             + "    var input = document.getElementById('password1');\n"
368             + "    input = input.cloneNode(false);\n"
369             + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
370 
371             + "    input = document.createElement('input');\n"
372             + "    input.type = 'password';\n"
373             + "    input = input.cloneNode(false);\n"
374             + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
375 
376             + "    var builder = document.createElement('div');\n"
377             + "    builder.innerHTML = '<input type=\"password\">';\n"
378             + "    input = builder.firstChild;\n"
379             + "    input = input.cloneNode(false);\n"
380             + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
381             + "  }\n"
382             + "</script>\n"
383             + "</head><body onload='test()'>\n"
384             + "<form>\n"
385             + "  <input type='password' id='password1'>\n"
386             + "</form>\n"
387             + "</body></html>";
388 
389         loadPageVerifyTitle2(html);
390     }
391 
392     /**
393      * @throws Exception if the test fails
394      */
395     @Test
396     @Alerts({"initial-initial-initial", "initial-initial-initial",
397                 "newValue-initial-initial", "newValue-initial-initial",
398                 "newValue-newDefault-newDefault", "newValue-newDefault-newDefault"})
399     public void resetByClick() throws Exception {
400         final String html = DOCTYPE_HTML
401             + "<html><head>\n"
402             + "<script>\n"
403             + LOG_TITLE_FUNCTION
404             + "  function test() {\n"
405             + "    var password = document.getElementById('testId');\n"
406             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
407 
408             + "    document.getElementById('testReset').click;\n"
409             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
410 
411             + "    password.value = 'newValue';\n"
412             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
413 
414             + "    document.getElementById('testReset').click;\n"
415             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
416 
417             + "    password.defaultValue = 'newDefault';\n"
418             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
419 
420             + "    document.forms[0].reset;\n"
421             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
422             + "  }\n"
423             + "</script>\n"
424             + "</head><body onload='test()'>\n"
425             + "<form>\n"
426             + "  <input type='password' id='testId' value='initial'>\n"
427             + "  <input type='reset' id='testReset'>\n"
428             + "</form>\n"
429             + "</body></html>";
430 
431         loadPageVerifyTitle2(html);
432     }
433 
434     /**
435      * @throws Exception if the test fails
436      */
437     @Test
438     @Alerts({"initial-initial-initial", "initial-initial-initial",
439                 "newValue-initial-initial", "newValue-initial-initial",
440                 "newValue-newDefault-newDefault", "newValue-newDefault-newDefault"})
441     public void resetByJS() throws Exception {
442         final String html = DOCTYPE_HTML
443             + "<html><head>\n"
444             + "<script>\n"
445             + LOG_TITLE_FUNCTION
446             + "  function test() {\n"
447             + "    var password = document.getElementById('testId');\n"
448             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
449 
450             + "    document.forms[0].reset;\n"
451             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
452 
453             + "    password.value = 'newValue';\n"
454             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
455 
456             + "    document.forms[0].reset;\n"
457             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
458 
459             + "    password.defaultValue = 'newDefault';\n"
460             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
461 
462             + "    document.forms[0].reset;\n"
463             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
464             + "  }\n"
465             + "</script>\n"
466             + "</head><body onload='test()'>\n"
467             + "<form>\n"
468             + "  <input type='password' id='testId' value='initial'>\n"
469             + "</form>\n"
470             + "</body></html>";
471 
472         loadPageVerifyTitle2(html);
473     }
474 
475     /**
476      * @throws Exception if the test fails
477      */
478     @Test
479     @Alerts({"initial-initial-initial", "default-default-default",
480                 "newValue-default-default", "newValue-attribValue-attribValue",
481                 "newValue-newDefault-newDefault"})
482     public void value() throws Exception {
483         final String html = DOCTYPE_HTML
484             + "<html><head>\n"
485             + "<script>\n"
486             + LOG_TITLE_FUNCTION
487             + "  function test() {\n"
488             + "    var password = document.getElementById('testId');\n"
489             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
490 
491             + "    password.defaultValue = 'default';\n"
492             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
493 
494             + "    password.value = 'newValue';\n"
495             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
496 
497             + "    password.setAttribute('value', 'attribValue');\n"
498             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
499 
500             + "    password.defaultValue = 'newDefault';\n"
501             + "    log(password.value + '-' + password.defaultValue + '-' + password.getAttribute('value'));\n"
502             + "  }\n"
503             + "</script>\n"
504             + "</head><body onload='test()'>\n"
505             + "<form>\n"
506             + "  <input type='password' id='testId' value='initial'>\n"
507             + "</form>\n"
508             + "</body></html>";
509 
510         loadPageVerifyTitle2(html);
511     }
512 
513     /**
514      * @throws Exception if the test fails
515      */
516     @Test
517     @Alerts(DEFAULT = "textLength not available",
518             FF = "7",
519             FF_ESR = "7")
520     public void textLength() throws Exception {
521         final String html = DOCTYPE_HTML
522             + "<html><head>\n"
523             + "<script>\n"
524             + LOG_TITLE_FUNCTION
525             + "  function test() {\n"
526             + "    var text = document.getElementById('testId');\n"
527             + "    if(text.textLength) {\n"
528             + "      log(text.textLength);\n"
529             + "    } else {\n"
530             + "      log('textLength not available');\n"
531             + "    }\n"
532             + "  }\n"
533             + "</script>\n"
534             + "</head><body onload='test()'>\n"
535             + "<form>\n"
536             + "  <input type='password' id='testId' value='initial'>\n"
537             + "</form>\n"
538             + "</body></html>";
539 
540         loadPageVerifyTitle2(html);
541     }
542 
543     /**
544      * @throws Exception if an error occurs
545      */
546     @Test
547     @Alerts("0")
548     public void selection() throws Exception {
549         final String html = DOCTYPE_HTML
550             + "<html><head><script>\n"
551             + LOG_TITLE_FUNCTION
552             + "  function test() {\n"
553             + "    log(getSelection(document.getElementById('text1')).length);\n"
554             + "  }\n"
555             + "  function getSelection(element) {\n"
556             + "    return element.value.substring(element.selectionStart, element.selectionEnd);\n"
557             + "  }\n"
558             + "</script></head>\n"
559             + "<body onload='test()'>\n"
560             + "  <input type='password' id='text1'/>\n"
561             + "</body></html>";
562         loadPageVerifyTitle2(html);
563     }
564 
565     /**
566      * @throws Exception if test fails
567      */
568     @Test
569     @Alerts({"0,0", "11,11", "3,11", "3,10"})
570     public void selection2_1() throws Exception {
571         selection2(3, 10);
572     }
573 
574     /**
575      * @throws Exception if test fails
576      */
577     @Test
578     @Alerts({"0,0", "11,11", "11,11", "11,11"})
579     public void selection2_2() throws Exception {
580         selection2(-3, 15);
581     }
582 
583     /**
584      * @throws Exception if test fails
585      */
586     @Test
587     @Alerts({"0,0", "11,11", "10,11", "5,5"})
588     public void selection2_3() throws Exception {
589         selection2(10, 5);
590     }
591 
592     private void selection2(final int selectionStart, final int selectionEnd) throws Exception {
593         final String html = DOCTYPE_HTML
594             + "<html>\n"
595             + "<body>\n"
596             + "<input id='myTextInput' value='Bonjour' type='password'>\n"
597             + "<script>\n"
598             + LOG_TITLE_FUNCTION
599             + "  var input = document.getElementById('myTextInput');\n"
600             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
601             + "  input.value = 'Hello there';\n"
602             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
603             + "  input.selectionStart = " + selectionStart + ";\n"
604             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
605             + "  input.selectionEnd = " + selectionEnd + ";\n"
606             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
607             + "</script>\n"
608             + "</body>\n"
609             + "</html>";
610 
611         loadPageVerifyTitle2(html);
612     }
613 
614     /**
615      * @throws Exception if test fails
616      */
617     @Test
618     @Alerts({"0,0", "4,5", "10,10", "4,4", "1,1"})
619     public void selectionOnUpdate() throws Exception {
620         final String html = DOCTYPE_HTML
621             + "<html>\n"
622             + "<body>\n"
623             + "<input id='myTextInput' value='Hello' type='password'>\n"
624             + "<script>\n"
625             + LOG_TITLE_FUNCTION
626             + "  var input = document.getElementById('myTextInput');\n"
627             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
628 
629             + "  input.selectionStart = 4;\n"
630             + "  input.selectionEnd = 5;\n"
631             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
632             + "  input.value = 'abcdefghif';\n"
633             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
634 
635             + "  input.value = 'abcd';\n"
636             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
637 
638             + "  input.selectionStart = 0;\n"
639             + "  input.selectionEnd = 4;\n"
640 
641             + "  input.value = 'a';\n"
642             + "  log(input.selectionStart + ',' + input.selectionEnd);\n"
643             + "</script>\n"
644             + "</body>\n"
645             + "</html>";
646 
647         loadPageVerifyTitle2(html);
648     }
649 
650     /**
651      * @throws Exception if an error occurs
652      */
653     @Test
654     @Alerts("password")
655     public void upperCase() throws Exception {
656         final String html = DOCTYPE_HTML
657             + "<html><head><script>\n"
658             + LOG_TITLE_FUNCTION
659             + "  function test() {\n"
660             + "    log(document.getElementById('myId').type);\n"
661             + "  }\n"
662             + "</script></head>\n"
663             + "<body onload='test()'>\n"
664             + "  <input TYPE='password' id='myId'>\n"
665             + "</body></html>";
666         final WebDriver driver = loadPageVerifyTitle2(html);
667         if (driver instanceof HtmlUnitDriver) {
668             final HtmlPage page = (HtmlPage) getEnclosedPage();
669             assertTrue(HtmlPasswordInput.class.isInstance(page.getHtmlElementById("myId")));
670         }
671     }
672 
673     /**
674      * @throws Exception if the test fails
675      */
676     @Test
677     @Alerts("--")
678     public void minMaxStep() throws Exception {
679         final String html = DOCTYPE_HTML
680             + "<html>\n"
681             + "<head>\n"
682             + "<script>\n"
683             + LOG_TITLE_FUNCTION
684             + "  function test() {\n"
685             + "    var input = document.getElementById('tester');\n"
686             + "    log(input.min + '-' + input.max + '-' + input.step);\n"
687             + "  }\n"
688             + "</script>\n"
689             + "</head>\n"
690             + "<body onload='test()'>\n"
691             + "<form>\n"
692             + "  <input type='password' id='tester'>\n"
693             + "</form>\n"
694             + "</body>\n"
695             + "</html>";
696 
697         loadPageVerifyTitle2(html);
698     }
699 
700     /**
701      * @throws Exception if an error occurs
702      */
703     @Test
704     @Alerts({"0987654321!",
705              "0987654321!",
706              "false",
707              "false-false-true-false-false-false-false-false-false-false-false",
708              "true",
709              "§§URL§§", "1"})
710     public void patternValidationInvalid() throws Exception {
711         validation("<input type='password' pattern='[0-9a-zA-Z]{10,40}' id='e1' name='k' value='0987654321!'>\n",
712                     "", null);
713     }
714 
715     /**
716      * @throws Exception if an error occurs
717      */
718     @Test
719     @Alerts({"68746d6c756e69742072756c657a21",
720              "68746d6c756e69742072756c657a21",
721              "true",
722              "false-false-false-false-false-false-false-false-false-true-false",
723              "true",
724              "§§URL§§?k=68746d6c756e69742072756c657a21", "2"})
725     public void patternValidationValid() throws Exception {
726         validation("<input type='password' pattern='[0-9a-zA-Z]{10,40}' "
727                 + "id='e1' name='k' value='68746d6c756e69742072756c657a21'>\n", "", null);
728     }
729 
730     /**
731      * @throws Exception if an error occurs
732      */
733     @Test
734     @Alerts({"",
735              "",
736              "true",
737              "false-false-false-false-false-false-false-false-false-true-false",
738              "true",
739              "§§URL§§?k=", "2"})
740     public void patternValidationEmpty() throws Exception {
741         validation("<input type='password' pattern='[0-9a-zA-Z]{10,40}' id='e1' name='k' value=''>\n", "", null);
742     }
743 
744     /**
745      * @throws Exception if an error occurs
746      */
747     @Test
748     @Alerts({" ",
749              " ",
750              "false",
751              "false-false-true-false-false-false-false-false-false-false-false",
752              "true",
753              "§§URL§§", "1"})
754     public void patternValidationBlank() throws Exception {
755         validation("<input type='password' pattern='[0-9a-zA-Z]{10,40}' id='e1' name='k' value=' '>\n", "", null);
756     }
757 
758     /**
759      * @throws Exception if an error occurs
760      */
761     @Test
762     @Alerts({"  \t",
763              "  \t",
764              "false",
765              "false-false-true-false-false-false-false-false-false-false-false",
766              "true",
767              "§§URL§§", "1"})
768     public void patternValidationWhitespace() throws Exception {
769         validation("<input type='password' pattern='[0-9a-zA-Z]{10,40}' id='e1' name='k' value='  \t'>\n", "", null);
770     }
771 
772     /**
773      * @throws Exception if an error occurs
774      */
775     @Test
776     @Alerts({" 210 ",
777              " 210 ",
778              "true",
779              "false-false-false-false-false-false-false-false-false-true-false",
780              "true",
781              "§§URL§§?k=+210+", "2"})
782     public void patternValidationTrimInitial() throws Exception {
783         validation("<input type='password' pattern='[ 012]{3,10}' id='e1' name='k' value=' 210 '>\n", "", null);
784     }
785 
786     /**
787      * @throws Exception if an error occurs
788      */
789     @Test
790     @Alerts({"null",
791              " 210 ",
792              "true",
793              "false-false-false-false-false-false-false-false-false-true-false",
794              "true",
795              "§§URL§§?k=+210+", "2"})
796     public void patternValidationTrimType() throws Exception {
797         validation("<input type='password' pattern='[ 012]{3,10}' id='e1' name='k'>\n", "", " 210 ");
798     }
799 
800     /**
801      * @throws Exception if an error occurs
802      */
803     @Test
804     @Alerts({"null",
805              "abcd",
806              "false",
807              "false-false-false-false-false-false-false-true-false-false-false",
808              "true",
809              "§§URL§§", "1"})
810     public void minLengthValidationInvalid() throws Exception {
811         validation("<input type='password' minlength='5' id='e1' name='k'>\n", "", "abcd");
812     }
813 
814 
815     /**
816      * @throws Exception if an error occurs
817      */
818     @Test
819     @Alerts({"ab",
820              "ab",
821              "true",
822              "false-false-false-false-false-false-false-false-false-true-false",
823              "true",
824              "§§URL§§?k=ab", "2"})
825     public void minLengthValidationInvalidInitial() throws Exception {
826         validation("<input type='password' minlength='5' id='e1' name='k' value='ab'>\n", "", null);
827     }
828 
829     /**
830      * @throws Exception if an error occurs
831      */
832     @Test
833     @Alerts({"null",
834              "",
835              "true",
836              "false-false-false-false-false-false-false-false-false-true-false",
837              "true",
838              "§§URL§§?k=", "2"})
839     public void minLengthValidationInvalidNoInitial() throws Exception {
840         validation("<input type='password' minlength='5' id='e1' name='k'>\n", "", null);
841     }
842 
843     /**
844      * @throws Exception if an error occurs
845      */
846     @Test
847     @Alerts({"null",
848              "abcdefghi",
849              "true",
850              "false-false-false-false-false-false-false-false-false-true-false",
851              "true",
852              "§§URL§§?k=abcdefghi", "2"})
853     public void minLengthValidationValid() throws Exception {
854         validation("<input type='password' minlength='5' id='e1' name='k'>\n", "", "abcdefghi");
855     }
856 
857     /**
858      * @throws Exception if an error occurs
859      */
860     @Test
861     @Alerts({"null",
862              "abcd",
863              "true",
864              "false-false-false-false-false-false-false-false-false-true-false",
865              "true",
866              "§§URL§§?k=abcd", "2"})
867     public void maxLengthValidationValid() throws Exception {
868         validation("<input type='password' maxlength='5' id='e1' name='k'>\n", "", "abcd");
869     }
870 
871     /**
872      * @throws Exception if an error occurs
873      */
874     @Test
875     @Alerts({"null",
876              "abcde",
877              "true",
878              "false-false-false-false-false-false-false-false-false-true-false",
879              "true",
880              "§§URL§§?k=abcde", "2"})
881     public void maxLengthValidationInvalid() throws Exception {
882         validation("<input type='password' maxlength='5' id='e1' name='k'>\n", "", "abcdefghi");
883     }
884 
885     /**
886      * @throws Exception if an error occurs
887      */
888     @Test
889     @Alerts({"abcdefghi",
890              "abcdefghi",
891              "true",
892              "false-false-false-false-false-false-false-false-false-true-false",
893              "true",
894              "§§URL§§?k=abcdefghi", "2"})
895     public void maxLengthValidationInvalidInitial() throws Exception {
896         validation("<input type='password' maxlength='5' id='e1' name='k' value='abcdefghi'>\n", "", null);
897     }
898 
899     /**
900      * @throws Exception if an error occurs
901      */
902     @Test
903     @Alerts({"true", "false", "true", "false", "true"})
904     public void willValidate() throws Exception {
905         final String html = DOCTYPE_HTML
906                 + "<html><head>\n"
907                 + "  <script>\n"
908                 + LOG_TITLE_FUNCTION
909                 + "    function test() {\n"
910                 + "      log(document.getElementById('o1').willValidate);\n"
911                 + "      log(document.getElementById('o2').willValidate);\n"
912                 + "      log(document.getElementById('o3').willValidate);\n"
913                 + "      log(document.getElementById('o4').willValidate);\n"
914                 + "      log(document.getElementById('o5').willValidate);\n"
915                 + "    }\n"
916                 + "  </script>\n"
917                 + "</head>\n"
918                 + "<body onload='test()'>\n"
919                 + "  <form>\n"
920                 + "    <input type='password' id='o1'>\n"
921                 + "    <input type='password' id='o2' disabled>\n"
922                 + "    <input type='password' id='o3' hidden>\n"
923                 + "    <input type='password' id='o4' readonly>\n"
924                 + "    <input type='password' id='o5' style='display: none'>\n"
925                 + "  </form>\n"
926                 + "</body></html>";
927 
928         loadPageVerifyTitle2(html);
929     }
930 
931     /**
932      * @throws Exception if an error occurs
933      */
934     @Test
935     @Alerts({"null",
936              "",
937              "true",
938              "false-false-false-false-false-false-false-false-false-true-false",
939              "true",
940              "§§URL§§?k=", "2"})
941     public void validationEmpty() throws Exception {
942         validation("<input type='password' id='e1' name='k'>\n", "", null);
943     }
944 
945     /**
946      * @throws Exception if an error occurs
947      */
948     @Test
949     @Alerts({"null",
950              "",
951              "false",
952              "false-true-false-false-false-false-false-false-false-false-false",
953              "true",
954              "§§URL§§", "1"})
955     public void validationCustomValidity() throws Exception {
956         validation("<input type='password' id='e1' name='k'>\n", "elem.setCustomValidity('Invalid');", null);
957     }
958 
959     /**
960      * @throws Exception if an error occurs
961      */
962     @Test
963     @Alerts({"null",
964              "",
965              "false",
966              "false-true-false-false-false-false-false-false-false-false-false",
967              "true",
968              "§§URL§§", "1"})
969     public void validationBlankCustomValidity() throws Exception {
970         validation("<input type='password' id='e1' name='k'>\n", "elem.setCustomValidity(' ');\n", null);
971     }
972 
973     /**
974      * @throws Exception if an error occurs
975      */
976     @Test
977     @Alerts({"null",
978              "",
979              "true",
980              "false-false-false-false-false-false-false-false-false-true-false",
981              "true",
982              "§§URL§§?k=", "2"})
983     public void validationResetCustomValidity() throws Exception {
984         validation("<input type='password' id='e1' name='k'>\n",
985                 "elem.setCustomValidity('Invalid');elem.setCustomValidity('');", null);
986     }
987 
988     /**
989      * @throws Exception if an error occurs
990      */
991     @Test
992     @Alerts({"null",
993              "",
994              "false",
995              "false-false-false-false-false-false-false-false-false-false-true",
996              "true",
997              "§§URL§§", "1"})
998     public void validationRequired() throws Exception {
999         validation("<input type='password' id='e1' name='k' required>\n", "", null);
1000     }
1001 
1002     /**
1003      * @throws Exception if an error occurs
1004      */
1005     @Test
1006     @Alerts({"null",
1007              "",
1008              "true",
1009              "false-false-false-false-false-false-false-false-false-true-false",
1010              "true",
1011              "§§URL§§?k=victoria", "2"})
1012     public void validationRequiredValueSet() throws Exception {
1013         validation("<input type='password' id='e1' name='k' required>\n", "elem.value='victoria';", null);
1014     }
1015 
1016     /**
1017      * @throws Exception if an error occurs
1018      */
1019     @Test
1020     @Alerts({"null",
1021              "",
1022              "false",
1023              "false-false-true-false-false-false-false-false-false-false-false",
1024              "true",
1025              "§§URL§§", "1"})
1026     public void validationPattern() throws Exception {
1027         validation("<input type='password' id='e1' name='k' pattern='abc'>\n", "elem.value='one';", null);
1028     }
1029 
1030     private void validation(final String htmlPart, final String jsPart, final String sendKeys) throws Exception {
1031         final String html = DOCTYPE_HTML
1032                 + "<html><head>\n"
1033                 + "  <script>\n"
1034                 + LOG_TITLE_FUNCTION
1035                 + "    function logValidityState(s) {\n"
1036                 + "      log(s.badInput"
1037                         + "+ '-' + s.customError"
1038                         + "+ '-' + s.patternMismatch"
1039                         + "+ '-' + s.rangeOverflow"
1040                         + "+ '-' + s.rangeUnderflow"
1041                         + "+ '-' + s.stepMismatch"
1042                         + "+ '-' + s.tooLong"
1043                         + "+ '-' + s.tooShort"
1044                         + " + '-' + s.typeMismatch"
1045                         + " + '-' + s.valid"
1046                         + " + '-' + s.valueMissing);\n"
1047                 + "    }\n"
1048                 + "    function test() {\n"
1049                 + "      var elem = document.getElementById('e1');\n"
1050                 + jsPart
1051                 + "      log(elem.checkValidity());\n"
1052                 + "      logValidityState(elem.validity);\n"
1053                 + "      log(elem.willValidate);\n"
1054                 + "    }\n"
1055                 + "  </script>\n"
1056                 + "</head>\n"
1057                 + "<body>\n"
1058                 + "  <form>\n"
1059                 + htmlPart
1060                 + "    <button id='myTest' type='button' onclick='test()'>Test</button>\n"
1061                 + "    <button id='myButton' type='submit'>Submit</button>\n"
1062                 + "  </form>\n"
1063                 + "</body></html>";
1064 
1065         final String secondContent = DOCTYPE_HTML
1066                 + "<html><head><title>second</title></head><body>\n"
1067                 + "  <p>hello world</p>\n"
1068                 + "</body></html>";
1069 
1070         getMockWebConnection().setResponse(URL_SECOND, secondContent);
1071         expandExpectedAlertsVariables(URL_FIRST);
1072 
1073         final WebDriver driver = loadPage2(html, URL_FIRST);
1074 
1075         final WebElement foo = driver.findElement(By.id("e1"));
1076         if (sendKeys != null) {
1077             foo.sendKeys(sendKeys);
1078         }
1079 
1080         assertEquals(getExpectedAlerts()[0], "" + foo.getDomAttribute("value"));
1081         assertEquals(getExpectedAlerts()[1], foo.getDomProperty("value"));
1082 
1083         driver.findElement(By.id("myTest")).click();
1084         verifyTitle2(driver, getExpectedAlerts()[2], getExpectedAlerts()[3], getExpectedAlerts()[4]);
1085 
1086         driver.findElement(By.id("myButton")).click();
1087         if (useRealBrowser()) {
1088             Thread.sleep(400);
1089         }
1090         assertEquals(getExpectedAlerts()[5], getMockWebConnection().getLastWebRequest().getUrl());
1091         assertEquals(Integer.parseInt(getExpectedAlerts()[6]), getMockWebConnection().getRequestCount());
1092     }
1093 }