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