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