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.htmlunit.junit.annotation.HtmlUnitNYI;
21  import org.junit.Test;
22  import org.junit.runner.RunWith;
23  import org.openqa.selenium.By;
24  import org.openqa.selenium.WebDriver;
25  import org.openqa.selenium.WebElement;
26  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
27  
28  /**
29   * Tests for {@link HtmlMonthInput}.
30   *
31   * @author Ronald Brill
32   * @author Anton Demydenko
33   */
34  @RunWith(BrowserRunner.class)
35  public class HtmlMonthInputTest extends WebDriverTestCase {
36  
37      /**
38       * @throws Exception if the test fails
39       */
40      @Test
41      @Alerts({"--null", "--null", "--null"})
42      public void defaultValues() throws Exception {
43          final String html = DOCTYPE_HTML
44              + "<html><head>\n"
45              + "<script>\n"
46              + LOG_TITLE_FUNCTION
47              + "  function test() {\n"
48              + "    var input = document.getElementById('text1');\n"
49              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
50  
51              + "    try {\n"
52              + "      input = document.createElement('input');\n"
53              + "      input.type = 'month';\n"
54              + "      log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
55              + "    } catch(e)  { logEx(e); }\n"
56  
57              + "    var builder = document.createElement('div');\n"
58              + "    builder.innerHTML = '<input type=\"month\">';\n"
59              + "    input = builder.firstChild;\n"
60              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
61              + "  }\n"
62              + "</script>\n"
63              + "</head><body onload='test()'>\n"
64              + "<form>\n"
65              + "  <input type='month' id='text1'>\n"
66              + "</form>\n"
67              + "</body></html>";
68  
69          loadPageVerifyTitle2(html);
70      }
71  
72      /**
73       * @throws Exception if the test fails
74       */
75      @Test
76      @Alerts({"--null", "--null", "--null"})
77      public void defaultValuesAfterClone() throws Exception {
78          final String html = DOCTYPE_HTML
79              + "<html><head>\n"
80              + "<script>\n"
81              + LOG_TITLE_FUNCTION
82              + "  function test() {\n"
83              + "    var input = document.getElementById('text1');\n"
84              + "    input = input.cloneNode(false);\n"
85              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
86  
87              + "    try {\n"
88              + "      input = document.createElement('input');\n"
89              + "      input.type = 'month';\n"
90              + "      input = input.cloneNode(false);\n"
91              + "      log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
92              + "    } catch(e)  { logEx(e); }\n"
93  
94              + "    var builder = document.createElement('div');\n"
95              + "    builder.innerHTML = '<input type=\"month\">';\n"
96              + "    input = builder.firstChild;\n"
97              + "    input = input.cloneNode(false);\n"
98              + "    log(input.value + '-' + input.defaultValue + '-' + input.getAttribute('value'));\n"
99              + "  }\n"
100             + "</script>\n"
101             + "</head><body onload='test()'>\n"
102             + "<form>\n"
103             + "  <input type='month' id='text1'>\n"
104             + "</form>\n"
105             + "</body></html>";
106 
107         loadPageVerifyTitle2(html);
108     }
109 
110     /**
111      * Verifies getVisibleText().
112      * @throws Exception if the test fails
113      */
114     @Test
115     @Alerts("")
116     public void getVisibleText() throws Exception {
117         final String htmlContent = DOCTYPE_HTML
118             + "<html>\n"
119             + "<head></head>\n"
120             + "<body>\n"
121             + "<form id='form1'>\n"
122             + "  <input type='month' name='tester' id='tester' value='2018-2' min='2018-1' max='2018-26'>\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-20", ""})
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='month' name='tester' id='tester' value='2018-20'>\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(DEFAULT = "8",
168             CHROME = "",
169             EDGE = "")
170     @HtmlUnitNYI(FF = "",
171             FF_ESR = "")
172     public void typing() throws Exception {
173         final String htmlContent = DOCTYPE_HTML
174             + "<html><head><title>foo</title></head><body>\n"
175             + "<form id='form1'>\n"
176             + "  <input type='month' id='foo'>\n"
177             + "</form></body></html>";
178 
179         final WebDriver driver = loadPage2(htmlContent);
180 
181         final WebElement input = driver.findElement(By.id("foo"));
182 
183         input.sendKeys("8");
184         assertNull(input.getDomAttribute("value"));
185         assertEquals(getExpectedAlerts()[0], input.getDomProperty("value"));
186     }
187 
188     /**
189      * @throws Exception if the test fails
190      */
191     @Test
192     @Alerts("--")
193     public void minMaxStep() throws Exception {
194         final String html = DOCTYPE_HTML
195             + "<html>\n"
196             + "<head>\n"
197             + "<script>\n"
198             + LOG_TITLE_FUNCTION
199             + "  function test() {\n"
200             + "    var input = document.getElementById('tester');\n"
201             + "    log(input.min + '-' + input.max + '-' + input.step);\n"
202             + "  }\n"
203             + "</script>\n"
204             + "</head>\n"
205             + "<body onload='test()'>\n"
206             + "<form>\n"
207             + "  <input type='month' id='tester'>\n"
208             + "</form>\n"
209             + "</body>\n"
210             + "</html>";
211 
212         loadPageVerifyTitle2(html);
213     }
214 
215     /**
216      * @throws Exception if an error occurs
217      */
218     @Test
219     @Alerts(DEFAULT = "true-true",
220             CHROME = "false-true",
221             EDGE = "false-true")
222     public void maxValidation() 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='month' max='2018-12' id='foo' value='2019-01'>\n"
237             + "  <input type='month' max='2018-12' id='bar' value='2018-11'>\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(DEFAULT = "true-true",
249             CHROME = "false-true",
250             EDGE = "false-true")
251     public void minValidation() throws Exception {
252         final String html = DOCTYPE_HTML
253             + "<html>\n"
254             + "<head>\n"
255             + "<script>\n"
256             + LOG_TITLE_FUNCTION
257             + "  function test() {\n"
258             + "    var foo = document.getElementById('foo');\n"
259             + "    var bar = document.getElementById('bar');\n"
260             + "    log(foo.checkValidity() + '-' + bar.checkValidity() );\n"
261             + "  }\n"
262             + "</script>\n"
263             + "</head>\n"
264             + "<body onload='test()'>\n"
265             + "  <input type='month' min='2018-12' id='foo' value='2018-11'>\n"
266             + "  <input type='month' min='2018-12' id='bar' value='2019-01'>\n"
267             + "</body>\n"
268             + "</html>";
269 
270         loadPageVerifyTitle2(html);
271     }
272 
273     /**
274      * @throws Exception if an error occurs
275      */
276     @Test
277     @Alerts({"true", "false", "true", "false", "true"})
278     public void willValidate() throws Exception {
279         final String html = DOCTYPE_HTML
280                 + "<html><head>\n"
281                 + "  <script>\n"
282                 + LOG_TITLE_FUNCTION
283                 + "    function test() {\n"
284                 + "      log(document.getElementById('o1').willValidate);\n"
285                 + "      log(document.getElementById('o2').willValidate);\n"
286                 + "      log(document.getElementById('o3').willValidate);\n"
287                 + "      log(document.getElementById('o4').willValidate);\n"
288                 + "      log(document.getElementById('o5').willValidate);\n"
289                 + "    }\n"
290                 + "  </script>\n"
291                 + "</head>\n"
292                 + "<body onload='test()'>\n"
293                 + "  <form>\n"
294                 + "    <input type='month' id='o1'>\n"
295                 + "    <input type='month' id='o2' disabled>\n"
296                 + "    <input type='month' id='o3' hidden>\n"
297                 + "    <input type='month' id='o4' readonly>\n"
298                 + "    <input type='month' id='o5' style='display: none'>\n"
299                 + "  </form>\n"
300                 + "</body></html>";
301 
302         loadPageVerifyTitle2(html);
303     }
304 
305     /**
306      * @throws Exception if an error occurs
307      */
308     @Test
309     @Alerts({"true",
310              "false-false-false-false-false-false-false-false-false-true-false",
311              "true"})
312     public void validationEmpty() throws Exception {
313         validation("<input type='month' id='e1'>\n", "");
314     }
315 
316     /**
317      * @throws Exception if an error occurs
318      */
319     @Test
320     @Alerts({"false",
321              "false-true-false-false-false-false-false-false-false-false-false",
322              "true"})
323     public void validationCustomValidity() throws Exception {
324         validation("<input type='month' id='e1'>\n", "elem.setCustomValidity('Invalid');");
325     }
326 
327     /**
328      * @throws Exception if an error occurs
329      */
330     @Test
331     @Alerts({"false",
332              "false-true-false-false-false-false-false-false-false-false-false",
333              "true"})
334     public void validationBlankCustomValidity() throws Exception {
335         validation("<input type='month' id='e1'>\n", "elem.setCustomValidity(' ');\n");
336     }
337 
338     /**
339      * @throws Exception if an error occurs
340      */
341     @Test
342     @Alerts({"true",
343              "false-false-false-false-false-false-false-false-false-true-false",
344              "true"})
345     public void validationResetCustomValidity() throws Exception {
346         validation("<input type='month' id='e1'>\n",
347                 "elem.setCustomValidity('Invalid');elem.setCustomValidity('');");
348     }
349 
350     /**
351      * @throws Exception if an error occurs
352      */
353     @Test
354     @Alerts({"false",
355              "false-false-false-false-false-false-false-false-false-false-true",
356              "true"})
357     public void validationRequired() throws Exception {
358         validation("<input type='month' id='e1' required>\n", "");
359     }
360 
361     /**
362      * @throws Exception if an error occurs
363      */
364     @Test
365     @Alerts({"true",
366              "false-false-false-false-false-false-false-false-false-true-false",
367              "true"})
368     public void validationRequiredValueSet() throws Exception {
369         validation("<input type='month' id='e1' required>\n", "elem.value='2018-12';");
370     }
371 
372     private void validation(final String htmlPart, final String jsPart) throws Exception {
373         final String html = DOCTYPE_HTML
374                 + "<html><head>\n"
375                 + "  <script>\n"
376                 + LOG_TITLE_FUNCTION
377                 + "    function logValidityState(s) {\n"
378                 + "      log(s.badInput"
379                         + "+ '-' + s.customError"
380                         + "+ '-' + s.patternMismatch"
381                         + "+ '-' + s.rangeOverflow"
382                         + "+ '-' + s.rangeUnderflow"
383                         + "+ '-' + s.stepMismatch"
384                         + "+ '-' + s.tooLong"
385                         + "+ '-' + s.tooShort"
386                         + " + '-' + s.typeMismatch"
387                         + " + '-' + s.valid"
388                         + " + '-' + s.valueMissing);\n"
389                 + "    }\n"
390                 + "    function test() {\n"
391                 + "      var elem = document.getElementById('e1');\n"
392                 + jsPart
393                 + "      log(elem.checkValidity());\n"
394                 + "      logValidityState(elem.validity);\n"
395                 + "      log(elem.willValidate);\n"
396                 + "    }\n"
397                 + "  </script>\n"
398                 + "</head>\n"
399                 + "<body onload='test()'>\n"
400                 + "  <form>\n"
401                 + htmlPart
402                 + "  </form>\n"
403                 + "</body></html>";
404 
405         loadPageVerifyTitle2(html);
406     }
407 }