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  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
24  
25  /**
26   * Tests for {@link HtmlDateTimeLocalInput}.
27   *
28   * @author Ronald Brill
29   * @author Anton Demydenko
30   */
31  public class HtmlDateTimeLocalInputTest extends WebDriverTestCase {
32  
33      /**
34       * @throws Exception if the test fails
35       */
36      @Test
37      @Alerts({"--null", "--null", "--null"})
38      public void defaultValues() throws Exception {
39          final String html = DOCTYPE_HTML
40              + "<html><head>\n"
41              + "<script>\n"
42              + LOG_TITLE_FUNCTION
43              + "  function test() {\n"
44              + "    var input = document.getElementById('text1');\n"
45              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
46  
47              + "    try {\n"
48              + "      input = document.createElement('input');\n"
49              + "      input.type = 'datetime-local';\n"
50              + "      log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
51              + "    } catch(e)  { logEx(e); }\n"
52  
53              + "    var builder = document.createElement('div');\n"
54              + "    builder.innerHTML = '<input type=\"datetime-local\">';\n"
55              + "    input = builder.firstChild;\n"
56              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
57              + "  }\n"
58              + "</script>\n"
59              + "</head><body onload='test()'>\n"
60              + "<form>\n"
61              + "  <input type='datetime-local' id='text1'>\n"
62              + "</form>\n"
63              + "</body></html>";
64  
65          loadPageVerifyTitle2(html);
66      }
67  
68      /**
69       * @throws Exception if the test fails
70       */
71      @Test
72      @Alerts({"--null", "--null", "--null"})
73      public void defaultValuesAfterClone() throws Exception {
74          final String html = DOCTYPE_HTML
75              + "<html><head>\n"
76              + "<script>\n"
77              + LOG_TITLE_FUNCTION
78              + "  function test() {\n"
79              + "    var input = document.getElementById('text1');\n"
80              + "    input = input.cloneNode(false);\n"
81              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
82  
83              + "    try{\n"
84              + "      input = document.createElement('input');\n"
85              + "      input.type = 'datetime-local';\n"
86              + "      input = input.cloneNode(false);\n"
87              + "      log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
88              + "    } catch(e)  { logEx(e); }\n"
89  
90              + "    var builder = document.createElement('div');\n"
91              + "    builder.innerHTML = '<input type=\"datetime-local\">';\n"
92              + "    input = builder.firstChild;\n"
93              + "    input = input.cloneNode(false);\n"
94              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
95              + "  }\n"
96              + "</script>\n"
97              + "</head><body onload='test()'>\n"
98              + "<form>\n"
99              + "  <input type='datetime-local' id='text1'>\n"
100             + "</form>\n"
101             + "</body></html>";
102 
103         loadPageVerifyTitle2(html);
104     }
105 
106     /**
107      * Verifies getVisibleText().
108      * @throws Exception if the test fails
109      */
110     @Test
111     @Alerts("")
112     public void getVisibleText() throws Exception {
113         final String htmlContent = DOCTYPE_HTML
114             + "<html>\n"
115             + "<head></head>\n"
116             + "<body>\n"
117             + "<form id='form1'>\n"
118             + "  <input type='datetime-local' name='tester' id='tester' value='2018-06-12T19:30' "
119                                     + "min='2018-06-07T00:00' max='2018-06-14T00:00'>\n"
120             + "</form>\n"
121             + "</body></html>";
122 
123         final WebDriver driver = loadPage2(htmlContent);
124         final String text = driver.findElement(By.id("tester")).getText();
125         assertEquals(getExpectedAlerts()[0], text);
126 
127         if (driver instanceof HtmlUnitDriver) {
128             final HtmlPage page = (HtmlPage) getEnclosedPage();
129             assertEquals(getExpectedAlerts()[0], page.getBody().getVisibleText());
130         }
131     }
132 
133     /**
134      * Verifies clear().
135      * @throws Exception if the test fails
136      */
137     @Test
138     @Alerts({"2018-06-12T19:30", ""})
139     public void clearInput() throws Exception {
140         final String htmlContent = DOCTYPE_HTML
141                 + "<html>\n"
142                 + "<head></head>\n"
143                 + "<body>\n"
144                 + "<form id='form1'>\n"
145                 + "  <input type='datetime-local' name='tester' id='tester' value='2018-06-12T19:30'>\n"
146                 + "</form>\n"
147                 + "</body></html>";
148 
149         final WebDriver driver = loadPage2(htmlContent);
150         final WebElement element = driver.findElement(By.id("tester"));
151 
152         assertEquals(getExpectedAlerts()[0], element.getDomAttribute("value"));
153         assertEquals(getExpectedAlerts()[0], element.getDomProperty("value"));
154 
155         element.clear();
156         assertEquals(getExpectedAlerts()[0], element.getDomAttribute("value"));
157         assertEquals(getExpectedAlerts()[1], element.getDomProperty("value"));
158     }
159 
160     /**
161      * @throws Exception if the test fails
162      */
163     @Test
164     @Alerts("--")
165     public void minMaxStep() throws Exception {
166         final String html = DOCTYPE_HTML
167             + "<html>\n"
168             + "<head>\n"
169             + "<script>\n"
170             + LOG_TITLE_FUNCTION
171             + "  function test() {\n"
172             + "    var input = document.getElementById('tester');\n"
173             + "    log(input.min + '-' + input.max + '-' + input.step);\n"
174             + "  }\n"
175             + "</script>\n"
176             + "</head>\n"
177             + "<body onload='test()'>\n"
178             + "<form>\n"
179             + "  <input type='datetime-local' id='tester'>\n"
180             + "</form>\n"
181             + "</body>\n"
182             + "</html>";
183 
184         loadPageVerifyTitle2(html);
185     }
186 
187     /**
188      * @throws Exception if an error occurs
189      */
190     @Test
191     @Alerts("false-true")
192     public void maxValidation() throws Exception {
193         final String html = DOCTYPE_HTML
194             + "<html>\n"
195             + "<head>\n"
196             + "<script>\n"
197             + LOG_TITLE_FUNCTION
198             + "  function test() {\n"
199             + "    var foo = document.getElementById('foo');\n"
200             + "    var bar = document.getElementById('bar');\n"
201             + "    log(foo.checkValidity() + '-' + bar.checkValidity() );\n"
202             + "  }\n"
203             + "</script>\n"
204             + "</head>\n"
205             + "<body onload='test()'>\n"
206             + "  <input type='datetime-local' max='2018-12-01T00:00' id='foo' value='2018-12-11T00:00'>\n"
207             + "  <input type='datetime-local' max='2018-12-01T00:00' id='bar' value='2018-11-01T00:00'>\n"
208             + "</body>\n"
209             + "</html>";
210 
211         loadPageVerifyTitle2(html);
212     }
213 
214     /**
215      * @throws Exception if an error occurs
216      */
217     @Test
218     @Alerts("false-true")
219     public void minValidation() throws Exception {
220         final String html = DOCTYPE_HTML
221             + "<html>\n"
222             + "<head>\n"
223             + "<script>\n"
224             + LOG_TITLE_FUNCTION
225             + "  function test() {\n"
226             + "    var foo = document.getElementById('foo');\n"
227             + "    var bar = document.getElementById('bar');\n"
228             + "    log(foo.checkValidity() + '-' + bar.checkValidity() );\n"
229             + "  }\n"
230             + "</script>\n"
231             + "</head>\n"
232             + "<body onload='test()'>\n"
233             + "  <input type='datetime-local' min='2018-12-01T00:00' id='foo' value='2018-11-01T00:00'>\n"
234             + "  <input type='datetime-local' min='2018-12-01T00:00' id='bar' value='2018-12-01T01:00'>\n"
235             + "</body>\n"
236             + "</html>";
237 
238         loadPageVerifyTitle2(html);
239     }
240 
241     /**
242      * @throws Exception if an error occurs
243      */
244     @Test
245     @Alerts({"true", "false", "true", "false", "true"})
246     public void willValidate() throws Exception {
247         final String html = DOCTYPE_HTML
248                 + "<html><head>\n"
249                 + "  <script>\n"
250                 + LOG_TITLE_FUNCTION
251                 + "    function test() {\n"
252                 + "      log(document.getElementById('o1').willValidate);\n"
253                 + "      log(document.getElementById('o2').willValidate);\n"
254                 + "      log(document.getElementById('o3').willValidate);\n"
255                 + "      log(document.getElementById('o4').willValidate);\n"
256                 + "      log(document.getElementById('o5').willValidate);\n"
257                 + "    }\n"
258                 + "  </script>\n"
259                 + "</head>\n"
260                 + "<body onload='test()'>\n"
261                 + "  <form>\n"
262                 + "    <input type='datetime-local' id='o1'>\n"
263                 + "    <input type='datetime-local' id='o2' disabled>\n"
264                 + "    <input type='datetime-local' id='o3' hidden>\n"
265                 + "    <input type='datetime-local' id='o4' readonly>\n"
266                 + "    <input type='datetime-local' id='o5' style='display: none'>\n"
267                 + "  </form>\n"
268                 + "</body></html>";
269 
270         loadPageVerifyTitle2(html);
271     }
272 
273     /**
274      * @throws Exception if an error occurs
275      */
276     @Test
277     @Alerts({"true",
278              "false-false-false-false-false-false-false-false-false-true-false",
279              "true"})
280     public void validationEmpty() throws Exception {
281         validation("<input type='datetime-local' id='e1'>\n", "");
282     }
283 
284     /**
285      * @throws Exception if an error occurs
286      */
287     @Test
288     @Alerts({"false",
289              "false-true-false-false-false-false-false-false-false-false-false",
290              "true"})
291     public void validationCustomValidity() throws Exception {
292         validation("<input type='datetime-local' id='e1'>\n", "elem.setCustomValidity('Invalid');");
293     }
294 
295     /**
296      * @throws Exception if an error occurs
297      */
298     @Test
299     @Alerts({"false",
300              "false-true-false-false-false-false-false-false-false-false-false",
301              "true"})
302     public void validationBlankCustomValidity() throws Exception {
303         validation("<input type='datetime-local' id='e1'>\n", "elem.setCustomValidity(' ');\n");
304     }
305 
306     /**
307      * @throws Exception if an error occurs
308      */
309     @Test
310     @Alerts({"true",
311              "false-false-false-false-false-false-false-false-false-true-false",
312              "true"})
313     public void validationResetCustomValidity() throws Exception {
314         validation("<input type='datetime-local' id='e1'>\n",
315                 "elem.setCustomValidity('Invalid');elem.setCustomValidity('');");
316     }
317 
318     /**
319      * @throws Exception if an error occurs
320      */
321     @Test
322     @Alerts({"false",
323              "false-false-false-false-false-false-false-false-false-false-true",
324              "true"})
325     public void validationRequired() throws Exception {
326         validation("<input type='datetime-local' id='e1' required>\n", "");
327     }
328 
329     /**
330      * @throws Exception if an error occurs
331      */
332     @Test
333     @Alerts({"true",
334              "false-false-false-false-false-false-false-false-false-true-false",
335              "true"})
336     public void validationRequiredValueSet() throws Exception {
337         validation("<input type='datetime-local' id='e1' required>\n", "elem.value='2018-12-01T00:00';");
338     }
339 
340     private void validation(final String htmlPart, final String jsPart) throws Exception {
341         final String html = DOCTYPE_HTML
342                 + "<html><head>\n"
343                 + "  <script>\n"
344                 + LOG_TITLE_FUNCTION
345                 + "    function logValidityState(s) {\n"
346                 + "      log(s.badInput"
347                         + "+ '-' + s.customError"
348                         + "+ '-' + s.patternMismatch"
349                         + "+ '-' + s.rangeOverflow"
350                         + "+ '-' + s.rangeUnderflow"
351                         + "+ '-' + s.stepMismatch"
352                         + "+ '-' + s.tooLong"
353                         + "+ '-' + s.tooShort"
354                         + " + '-' + s.typeMismatch"
355                         + " + '-' + s.valid"
356                         + " + '-' + s.valueMissing);\n"
357                 + "    }\n"
358                 + "    function test() {\n"
359                 + "      var elem = document.getElementById('e1');\n"
360                 + jsPart
361                 + "      log(elem.checkValidity());\n"
362                 + "      logValidityState(elem.validity);\n"
363                 + "      log(elem.willValidate);\n"
364                 + "    }\n"
365                 + "  </script>\n"
366                 + "</head>\n"
367                 + "<body onload='test()'>\n"
368                 + "  <form>\n"
369                 + htmlPart
370                 + "  </form>\n"
371                 + "</body></html>";
372 
373         loadPageVerifyTitle2(html);
374     }
375 }