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