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