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 java.util.LinkedList;
18  import java.util.List;
19  
20  import org.apache.commons.lang3.StringUtils;
21  import org.htmlunit.WebDriverTestCase;
22  import org.htmlunit.junit.BrowserRunner;
23  import org.htmlunit.junit.annotation.Alerts;
24  import org.htmlunit.junit.annotation.BuggyWebDriver;
25  import org.junit.Test;
26  import org.junit.runner.RunWith;
27  import org.openqa.selenium.By;
28  import org.openqa.selenium.WebDriver;
29  import org.openqa.selenium.WebElement;
30  
31  /**
32   * Tests for {@link HtmlInput}.
33   *
34   * @author Ronald Brill
35   * @author Frank Danek
36   */
37  @RunWith(BrowserRunner.class)
38  public final class HtmlInput2Test extends WebDriverTestCase {
39      private static final String TEST_ID = "clickId";
40  
41      /**
42       * @throws Exception if the test fails
43       */
44      @Test
45      @Alerts({"null", "TypeError", "handler", "null", "TypeError"})
46      public void onchangeDirectCall() throws Exception {
47          final String html = DOCTYPE_HTML
48              + "<html><head>\n"
49              + "<script>\n"
50              + LOG_TITLE_FUNCTION
51              + "  function handler() { log('handler');}\n"
52              + "  function test() {\n"
53              + "    var elem = document.getElementById('myInput');\n"
54              + "    try {\n"
55              + "      log(elem.onchange);\n"
56              + "      elem.onchange();\n"
57              + "      log('onchange called');\n"
58              + "    } catch(e) { logEx(e) }\n"
59  
60              + "    elem.onchange = handler;\n"
61              + "    elem.onchange();\n"
62  
63              + "    elem.onchange = null;\n"
64              + "    try {\n"
65              + "      log(elem.onchange);\n"
66              + "      elem.onchange();\n"
67              + "      log('onchange called');\n"
68              + "    } catch(e) { logEx(e) }\n"
69  
70              + "  }\n"
71              + "</script>\n"
72              + "<body onload=test()>\n"
73              + "  <input id='myInput'>\n"
74              + "</body></html>";
75  
76          loadPageVerifyTitle2(html);
77      }
78  
79      /**
80       * @throws Exception if the test fails
81       */
82      @Test
83      @Alerts({"function handler() {}", "null"})
84      public void onchangeNull() throws Exception {
85          final String html = DOCTYPE_HTML
86              + "<html><head>\n"
87              + "<script>\n"
88              + LOG_TITLE_FUNCTION
89              + "  function handler() {}\n"
90              + "  function test() {\n"
91              + "    var elem = document.getElementById('myInput');\n"
92              + "    elem.onchange = handler;\n"
93              + "    log(elem.onchange);\n"
94              + "    elem.onchange = null;\n"
95              + "    log(elem.onchange);\n"
96              + "  }\n"
97              + "</script>\n"
98              + "<body onload=test()>\n"
99              + "  <input id='myInput'>\n"
100             + "</body></html>";
101 
102         loadPageVerifyTitle2(html);
103     }
104 
105     /**
106      * Test for the right event sequence when clicking.
107      *
108      * @throws Exception if the test fails
109      */
110     @Test
111     @Alerts({"mousedown; onfocus; mouseup; onclick;", ""})
112     public void clickButtonEventSequence() throws Exception {
113         testClickEventSequence("<input type='button' id='" + TEST_ID + "'>Check", false);
114     }
115 
116     /**
117      * Test for the right event sequence when clicking.
118      *
119      * @throws Exception if the test fails
120      */
121     @Test
122     @Alerts({"mousedown; onfocus; mouseup; onclick;", ""})
123     public void clickImageEventSequence() throws Exception {
124         testClickEventSequence("<input type='image' id='" + TEST_ID + "'>Check", true);
125     }
126 
127     /**
128      * Test for the right event sequence when clicking.
129      *
130      * @throws Exception if the test fails
131      */
132     @Test
133     @Alerts({"mousedown; onfocus; mouseup; onclick; onchange;", ""})
134     public void clickCheckboxEventSequence() throws Exception {
135         testClickEventSequence("<input type='checkbox' id='" + TEST_ID + "'>Check", false);
136     }
137 
138     /**
139      * Test for the right event sequence when clicking.
140      *
141      * @throws Exception if the test fails
142      */
143     @Test
144     @Alerts({"mousedown; onfocus; mouseup; onclick;", ""})
145     public void clickPasswordEventSequence() throws Exception {
146         testClickEventSequence("<input type='password' id='" + TEST_ID + "'>Check", false);
147     }
148 
149     /**
150      * Test for the right event sequence when clicking.
151      *
152      * @throws Exception if the test fails
153      */
154     @Test
155     @Alerts({"mousedown; onfocus; mouseup; onclick; onchange;", ""})
156     public void clickRadioEventSequence() throws Exception {
157         testClickEventSequence("<input type='radio' name='test' id='" + TEST_ID + "'>Check", false);
158     }
159 
160     /**
161      * Test for the right event sequence when clicking.
162      *
163      * @throws Exception if the test fails
164      */
165     @Test
166     @Alerts({"mousedown; onfocus; mouseup; onclick;", ""})
167     public void clickResetEventSequence() throws Exception {
168         testClickEventSequence("<input type='reset' id='" + TEST_ID + "'>Check", true);
169     }
170 
171     /**
172      * Test for the right event sequence when clicking.
173      *
174      * @throws Exception if the test fails
175      */
176     @Test
177     @Alerts({"mousedown; onfocus; mouseup; onclick;", ""})
178     public void clickTextEventSequence() throws Exception {
179         testClickEventSequence("<input type='text' id='" + TEST_ID + "'>Check", false);
180     }
181 
182     /**
183      * Test for the right event sequence when clicking.
184      *
185      * @throws Exception if the test fails
186      */
187     @Test
188     @Alerts({"mousedown; onfocus; mouseup; onchange; onclick;", ""})
189     @BuggyWebDriver(CHROME = {"onfocus; onchange; mouseup; onclick;", ""},
190                     EDGE = {"onfocus; onchange; mouseup; onclick;", ""},
191                     FF = {"mousedown; onfocus; onchange; mouseup; onclick;", ""},
192                     FF_ESR = {"mousedown; onfocus; onchange; mouseup; onclick;", ""})
193     public void clickOptionEventSequence() throws Exception {
194         testClickEventSequence("<select size='2'><option id='" + TEST_ID + "'>1</option></select>", false);
195     }
196 
197     private void testClickEventSequence(final String input, final boolean onClickRetFalse) throws Exception {
198         final String events = " onmousedown=\"log('mousedown')\" onmouseup=\"log('mouseup')\" "
199                 + "onfocus=\"log('onfocus')\" onchange=\"log('onchange')\" "
200                 + "onclick=\"log('onclick')\"";
201         String tag = StringUtils.replaceOnce(input, ">", events + ">");
202         if (onClickRetFalse) {
203             tag = StringUtils.replaceOnce(tag, "onclick')", "onclick');return false;");
204         }
205 
206         final String html = DOCTYPE_HTML
207                 + "<html><head>\n"
208                 + "<script>\n"
209                 + "  function log(x) {\n"
210                 + "    document.getElementById('log_').value += x + '; ';\n"
211                 + "  }\n"
212                 + "</script>\n"
213 
214                 + "</head>\n<body>\n"
215                 + "<form>\n"
216                 + "  <textarea id='log_' rows='4' cols='50'></textarea>\n"
217                 + tag + "\n"
218                 + "  <input type='text' id='next'>\n"
219                 + "</form>\n"
220 
221                 + "</body></html>";
222 
223         final List<String> alerts = new LinkedList<>();
224 
225         final WebDriver driver = loadPage2(html);
226         final WebElement log = driver.findElement(By.id("log_"));
227 
228         driver.findElement(By.id(TEST_ID)).click();
229         alerts.add(log.getDomProperty("value").trim());
230 
231         log.clear();
232         driver.findElement(By.id("next")).click();
233 
234         alerts.add(log.getDomProperty("value").trim());
235         assertEquals(getExpectedAlerts(), alerts);
236     }
237 
238     /**
239      * @throws Exception if the test fails
240      */
241     @Test
242     @Alerts("something")
243     public void placeholder() throws Exception {
244         final String html = DOCTYPE_HTML
245             + "<html><head>\n"
246             + "<script>\n"
247             + LOG_TITLE_FUNCTION
248             + "  function test() {\n"
249             + "    var elem = document.getElementById('myInput');\n"
250             + "    log(elem.placeholder);\n"
251             + "  }\n"
252             + "</script>\n"
253             + "<body onload=test()>\n"
254             + "  <input id='myInput' placeholder='something'>\n"
255             + "</body></html>";
256 
257         loadPageVerifyTitle2(html);
258     }
259 
260     /**
261      * @throws Exception if the test fails
262      */
263     @Test
264     @Alerts("text")
265     public void badInputType() throws Exception {
266         final String html = DOCTYPE_HTML
267             + "<html>\n"
268             + "<head>"
269             + "<script>\n"
270             + LOG_TITLE_FUNCTION
271             + "</script>\n"
272             + "</head>\n"
273             + "<body onload='log(document.form1.text1.type)'>\n"
274             + "<form name='form1'>\n"
275             + "<input type='foo' name='text1'>\n"
276             + "</form></body></html>";
277 
278         loadPageVerifyTitle2(html);
279     }
280 
281     /**
282      * Tests that clicking a radio button will select it.
283      * @exception Exception If the test fails
284      */
285     @Test
286     @Alerts({"undefined", "undefined", "undefined", "undefined", "undefined"})
287     public void select() throws Exception {
288         final String html = DOCTYPE_HTML
289             + "<html><head>\n"
290             + "<script>\n"
291             + LOG_TITLE_FUNCTION
292             + "  function test() {\n"
293             + "    var form = document.getElementById('form1');\n"
294             + "    for (var i = 0; i < form.elements.length; i++) {\n"
295             + "      log(form.elements[i].select());\n"
296             + "    }\n"
297             + "  }\n"
298             + "</script>\n"
299             + "</head>\n"
300             + "<body onload='test()'>\n"
301             + "<form id='form1'>\n"
302             + "<input type='radio' name='foo' value='1'/>\n"
303             + "<input type='password' name='pwd'/>\n"
304             + "<input type='checkbox' name='cb'/>\n"
305             + "<input type='submit' name='button' value='foo'/>\n"
306             + "<textarea name='t'></textarea>\n"
307             + "</form></body></html>";
308 
309         loadPageVerifyTitle2(html);
310     }
311 }