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