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 static org.junit.jupiter.api.Assertions.assertNotEquals;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Collections;
22  import java.util.List;
23  
24  import org.htmlunit.HttpMethod;
25  import org.htmlunit.MockWebConnection;
26  import org.htmlunit.SimpleWebTestCase;
27  import org.htmlunit.WebClient;
28  import org.htmlunit.corejs.javascript.ScriptableObject;
29  import org.junit.jupiter.api.Test;
30  
31  /**
32   * Tests for {@link HtmlInput}.
33   *
34   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
35   * @author Marc Guillemot
36   * @author Ahmed Ashour
37   * @author Anton Demydenko
38   * @author Ronny Shapiro
39   */
40  public final class HtmlInputTest extends SimpleWebTestCase {
41  
42      /**
43       * Tests that selecting one radio button will deselect all the others.
44       * @exception Exception If the test fails
45       */
46      @Test
47      public void radioButtonsAreMutuallyExclusive() throws Exception {
48          final String htmlContent = DOCTYPE_HTML
49              + "<html><head><title>foo</title></head><body>\n"
50              + "<form id='form1'>\n"
51              + "<input type='radio' name='foo' value='1' selected='selected'/>\n"
52              + "<input type='radio' name='foo' value='2'/>\n"
53              + "<input type='radio' name='foo' value='3'/>\n"
54              + "<input type='submit' name='button' value='foo'/>\n"
55              + "</form></body></html>";
56          final HtmlPage page = loadPage(htmlContent);
57          final MockWebConnection webConnection = getMockConnection(page);
58  
59          final HtmlForm form = page.getHtmlElementById("form1");
60  
61          final HtmlRadioButtonInput radioButton = form.getFirstByXPath(
62              "//input[@type='radio' and @name='foo' and @value='2']");
63  
64          final HtmlSubmitInput pushButton = form.getInputByName("button");
65  
66          radioButton.setChecked(true);
67  
68          // Test that only one value for the radio button is being passed back to the server
69          final HtmlPage secondPage = pushButton.click();
70  
71          assertEquals("url", URL_FIRST + "?foo=2&button=foo", secondPage.getUrl());
72          assertSame("method", HttpMethod.GET, webConnection.getLastMethod());
73          assertNotNull(secondPage);
74      }
75  
76      /**
77       * @throws Exception if the test fails
78       */
79      @Test
80      public void setChecked_CheckBox() throws Exception {
81          final String htmlContent = DOCTYPE_HTML
82              + "<html><head><title>foo</title></head><body>\n"
83              + "<form id='form1'>\n"
84              + "<input type='checkbox' name='foo'/>\n"
85              + "<input type='checkbox' name='bar'/>\n"
86              + "<input type='submit' name='button' value='foo'/>\n"
87              + "</form></body></html>";
88          final HtmlPage page = loadPage(htmlContent);
89  
90          final HtmlForm form = page.getHtmlElementById("form1");
91  
92          final HtmlCheckBoxInput checkbox = form.getInputByName("foo");
93          assertFalse("Initial state", checkbox.isChecked());
94          checkbox.setChecked(true);
95          assertTrue("After setSelected(true)", checkbox.isChecked());
96          checkbox.setChecked(false);
97          assertFalse("After setSelected(false)", checkbox.isChecked());
98      }
99  
100     /**
101      * @throws Exception if the test fails
102      */
103     @Test
104     public void getChecked_RadioButton() throws Exception {
105         final String htmlContent = DOCTYPE_HTML
106             + "<html><head><title>foo</title></head><body>\n"
107             + "<form id='form1'>\n"
108             + "<input type='radio' name='radio1'>\n"
109             + "<input type='RADIO' name='radio1' value='bar' checked>\n"
110             + "<input type='submit' name='button' value='foo'>\n"
111             + "</form></body></html>";
112         final HtmlPage page = loadPage(htmlContent);
113 
114         final HtmlForm form = page.getHtmlElementById("form1");
115 
116         final List<HtmlRadioButtonInput> radioButtons = form.getRadioButtonsByName("radio1");
117         assertEquals(2, radioButtons.size());
118 
119         assertFalse(radioButtons.get(0).isChecked());
120         assertTrue(radioButtons.get(1).isChecked());
121     }
122 
123     /**
124      * @throws Exception if the test fails
125      */
126     @Test
127     public void setValueAttribute() throws Exception {
128         final String htmlContent = DOCTYPE_HTML
129             + "<html><head><title>foo</title></head><body>\n"
130             + "<form id='form1'>\n"
131             + "<input type='text' name='text1' onchange='alert(\"changed\")')>\n"
132             + "</form></body></html>";
133         final List<String> collectedAlerts = new ArrayList<>();
134         final HtmlPage page = loadPage(htmlContent, collectedAlerts);
135 
136         final HtmlForm form = page.getHtmlElementById("form1");
137         final HtmlTextInput input = form.getInputByName("text1");
138 
139         assertEquals(Collections.EMPTY_LIST, collectedAlerts);
140         input.setValueAttribute("foo");
141         input.setValue("foo");
142         assertNotEquals(Arrays.asList("changed").toString(), collectedAlerts.toString());
143     }
144 
145     /**
146      * @throws Exception if the test fails
147      */
148     @Test
149     public void checkboxDefaultValue() throws Exception {
150         final String htmlContent = DOCTYPE_HTML
151             + "<html><head><title>foo</title></head><body>\n"
152             + "<form id='form1'>\n"
153             + "<input type='checkbox' name='checkbox1')>\n"
154             + "</form></body></html>";
155         final HtmlPage page = loadPage(htmlContent);
156 
157         final HtmlForm form = page.getHtmlElementById("form1");
158         final HtmlCheckBoxInput input = form.getInputByName("checkbox1");
159         assertEquals("", input.getValueAttribute());
160         assertEquals("on", input.getValue());
161     }
162 
163     /**
164      * Tests that clicking a radio button will select it.
165      * @exception Exception If the test fails
166      */
167     @Test
168     public void clickRadioButton() throws Exception {
169         final String htmlContent = DOCTYPE_HTML
170             + "<html><head><title>foo</title></head><body>\n"
171             + "<form id='form1'>\n"
172             + "<input type='radio' name='foo' value='1' selected='selected'/>\n"
173             + "<input type='radio' name='foo' value='2'/>\n"
174             + "<input type='radio' name='foo' value='3'/>\n"
175             + "<input type='submit' name='button' value='foo'/>\n"
176             + "</form></body></html>";
177         final HtmlPage page = loadPage(htmlContent);
178 
179         final HtmlForm form = page.getHtmlElementById("form1");
180 
181         final HtmlRadioButtonInput radioButton = form.getFirstByXPath(
182                 "//input[@type='radio' and @name='foo' and @value='2']");
183 
184         assertFalse("Should not be checked before click", radioButton.isChecked());
185         radioButton.click();
186         assertTrue("Should be checked after click", radioButton.isChecked());
187     }
188 
189     /**
190      * Tests that default type of input is text.
191      * @exception Exception If the test fails
192      */
193     @Test
194     public void inputNoType() throws Exception {
195         final String htmlContent = DOCTYPE_HTML
196             + "<html><head><title>foo</title></head><body>\n"
197             + "<form id='form1'>\n"
198             + "<input name='foo'/>\n"
199             + "</form></body></html>";
200 
201         final HtmlPage page = loadPage(htmlContent);
202         final HtmlForm form = page.getHtmlElementById("form1");
203 
204         assertEquals("text", form.getInputByName("foo").getTypeAttribute());
205     }
206 
207     /**
208      * @throws Exception if the test fails
209      */
210     @Test
211     public void onChangeHandlerNotFiredOnLoad() throws Exception {
212         final String htmlContent = DOCTYPE_HTML
213             + "<html><head><title>foo</title></head><body>\n"
214             + "<form id='form1'>\n"
215             + "<input type='file' name='text1' onchange='alert(\"changed\")')>\n"
216             + "</form></body></html>";
217         final List<String> collectedAlerts = new ArrayList<>();
218         loadPage(htmlContent, collectedAlerts);
219         assertEquals(Collections.EMPTY_LIST, collectedAlerts);
220     }
221 
222     /**
223      * @throws Exception
224      *         if the test fails
225      */
226     @Test
227     public void testRequiredValidation() throws Exception {
228         final String htmlContent = DOCTYPE_HTML
229             + "<html>\n"
230             + "<head></head>\n"
231             + "<body>\n"
232             + "<form id='form1'>\n"
233             + "  <input id='foo' required='required'>\n"
234             + "</form>\n"
235             + "</body></html>";
236 
237         final HtmlPage page = loadPage(htmlContent);
238 
239         final HtmlInput input = (HtmlInput) page.getElementById("foo");
240         assertFalse(input.isValid());
241     }
242 
243     /**
244      * @throws Exception if an error occurs
245      */
246     @Test
247     public void changeType_javascriptEngineDisabled() throws Exception {
248         final String htmlContent = DOCTYPE_HTML
249                 + "<html><head><title>foo</title></head><body>\n"
250                 + "<form id='form1'>\n"
251                 + "<input type='text' name='text1' onchange='alert(\"changed\")')>\n"
252                 + "</form></body></html>";
253 
254         try (WebClient webClient = new WebClient(getBrowserVersion(), false, null, -1)) {
255             final HtmlPage page = loadPage(webClient, htmlContent, null, URL_FIRST);
256             assertFalse(page.getWebClient().isJavaScriptEngineEnabled());
257 
258             final HtmlForm form = page.getHtmlElementById("form1");
259             final HtmlTextInput input = form.getInputByName("text1");
260 
261             input.setAttribute("type", "hidden");
262         }
263     }
264 
265     /**
266      * @throws Exception if an error occurs
267      */
268     @Test
269     public void changeType_javascriptDisabled() throws Exception {
270         final String htmlContent = DOCTYPE_HTML
271                 + "<html><head><title>foo</title></head><body>\n"
272                 + "<form id='form1'>\n"
273                 + "<input type='text' name='text1' onchange='alert(\"changed\")')>\n"
274                 + "</form></body></html>";
275 
276         try (WebClient webClient = new WebClient(getBrowserVersion())) {
277             webClient.getOptions().setJavaScriptEnabled(false);
278             final HtmlPage page = loadPage(webClient, htmlContent, null, URL_FIRST);
279             final HtmlForm form = page.getHtmlElementById("form1");
280             final HtmlTextInput input = form.getInputByName("text1");
281 
282             final ScriptableObject jsPeer = input.getScriptableObject();
283             assertNotNull(jsPeer);
284 
285             input.setAttribute("type", "hidden");
286             assertNotNull(input.getScriptableObject());
287             assertNotEquals(jsPeer, input.getScriptableObject());
288         }
289     }
290 }