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.List;
18  
19  import org.htmlunit.WebDriverTestCase;
20  import org.htmlunit.junit.BrowserRunner;
21  import org.htmlunit.junit.annotation.Alerts;
22  import org.junit.Test;
23  import org.junit.runner.RunWith;
24  import org.openqa.selenium.By;
25  import org.openqa.selenium.Keys;
26  import org.openqa.selenium.WebDriver;
27  import org.openqa.selenium.WebElement;
28  import org.openqa.selenium.interactions.Action;
29  import org.openqa.selenium.interactions.Actions;
30  
31  /**
32   * Tests for {@link HtmlSelect}.
33   *
34   * @author Ahmed Ashour
35   * @author Ronald Brill
36   */
37  @RunWith(BrowserRunner.class)
38  public class HtmlSelect2Test extends WebDriverTestCase {
39  
40      /**
41       * @exception Exception If the test fails
42       */
43      @Test
44      @Alerts({"false", "false", "false", "true"})
45      public void select() throws Exception {
46          final String html = DOCTYPE_HTML
47              + "<html><head><title>foo</title></head><body>\n"
48              + "<form id='form1'><select name='select1' multiple>\n"
49              + "  <option value='option1'>Option1</option>\n"
50              + "  <option value='option2'>Option2</option>\n"
51              + "  <option value='option3' selected='selected'>Option3</option>\n"
52              + "  <option value='option4'>Option4</option>\n"
53              + "</select>\n"
54              + "<input type='submit' name='button' value='foo'/>\n"
55              + "</form></body></html>";
56  
57          final WebDriver driver = loadPage2(html);
58  
59          final List<WebElement> options = driver.findElements(By.tagName("option"));
60  
61          final Actions actions = new Actions(driver);
62          final Action selectThreeOptions = actions.click(options.get(1))
63              .click(options.get(2))
64              .click(options.get(3))
65              .build();
66  
67          selectThreeOptions.perform();
68  
69          assertEquals(Boolean.parseBoolean(getExpectedAlerts()[0]), options.get(0).isSelected());
70          assertEquals(Boolean.parseBoolean(getExpectedAlerts()[1]), options.get(1).isSelected());
71          assertEquals(Boolean.parseBoolean(getExpectedAlerts()[2]), options.get(2).isSelected());
72          assertEquals(Boolean.parseBoolean(getExpectedAlerts()[3]), options.get(3).isSelected());
73      }
74  
75      /**
76       * @exception Exception If the test fails
77       */
78      @Test
79      @Alerts({"false", "true", "true", "true"})
80      public void shiftClick() throws Exception {
81          final String html = DOCTYPE_HTML
82              + "<html><head><title>foo</title></head><body>\n"
83              + "<form id='form1'><select name='select1' multiple>\n"
84              + "  <option value='option1'>Option1</option>\n"
85              + "  <option value='option2'>Option2</option>\n"
86              + "  <option value='option3' selected='selected'>Option3</option>\n"
87              + "  <option value='option4'>Option4</option>\n"
88              + "</select>\n"
89              + "<input type='submit' name='button' value='foo'/>\n"
90              + "</form></body></html>";
91  
92          final WebDriver driver = loadPage2(html);
93  
94          final List<WebElement> options = driver.findElements(By.tagName("option"));
95  
96          final Actions actions = new Actions(driver);
97          final Action selectThreeOptions = actions.click(options.get(1))
98                  .keyDown(Keys.SHIFT)
99                  .click(options.get(3))
100                 .keyUp(Keys.SHIFT)
101                 .build();
102 
103         selectThreeOptions.perform();
104 
105         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[0]), options.get(0).isSelected());
106         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[1]), options.get(1).isSelected());
107         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[2]), options.get(2).isSelected());
108         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[3]), options.get(3).isSelected());
109     }
110 
111     /**
112      * @exception Exception If the test fails
113      */
114     @Test
115     @Alerts({"false", "true", "false", "true"})
116     public void controlClick() throws Exception {
117         final String html = DOCTYPE_HTML
118             + "<html><head><title>foo</title></head><body>\n"
119             + "<form id='form1'><select name='select1' multiple>\n"
120             + "  <option value='option1'>Option1</option>\n"
121             + "  <option value='option2'>Option2</option>\n"
122             + "  <option value='option3' selected='selected'>Option3</option>\n"
123             + "  <option value='option4'>Option4</option>\n"
124             + "</select>\n"
125             + "<input type='submit' name='button' value='foo'/>\n"
126             + "</form></body></html>";
127 
128         final WebDriver driver = loadPage2(html);
129 
130         final List<WebElement> options = driver.findElements(By.tagName("option"));
131 
132         final Actions actions = new Actions(driver);
133         final Action selectThreeOptions = actions.click(options.get(1))
134                 .keyDown(Keys.CONTROL)
135                 .click(options.get(3))
136                 .keyUp(Keys.CONTROL)
137                 .build();
138 
139         selectThreeOptions.perform();
140 
141         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[0]), options.get(0).isSelected());
142         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[1]), options.get(1).isSelected());
143         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[2]), options.get(2).isSelected());
144         assertEquals(Boolean.parseBoolean(getExpectedAlerts()[3]), options.get(3).isSelected());
145     }
146 
147     /**
148      * @throws Exception if an error occurs
149      */
150     @Test
151     @Alerts(DEFAULT = {"true", "false", "true", "false", "true"},
152             FF = {"true", "false", "true", "true", "true"},
153             FF_ESR = {"true", "false", "true", "true", "true"})
154     public void willValidate() throws Exception {
155         final String html = DOCTYPE_HTML
156                 + "<html><head>\n"
157                 + "  <script>\n"
158                 + LOG_TITLE_FUNCTION
159                 + "    function test() {\n"
160                 + "      log(document.getElementById('s1').willValidate);\n"
161                 + "      log(document.getElementById('s2').willValidate);\n"
162                 + "      log(document.getElementById('s3').willValidate);\n"
163                 + "      log(document.getElementById('s4').willValidate);\n"
164                 + "      log(document.getElementById('s5').willValidate);\n"
165                 + "    }\n"
166                 + "  </script>\n"
167                 + "</head>\n"
168                 + "<body onload='test()'>\n"
169                 + "  <form>\n"
170                 + "    <select id='s1'>s1</select>\n"
171                 + "    <select id='s2' disabled>s2</select>\n"
172                 + "    <select id='s3' hidden>s3</select>\n"
173                 + "    <select id='s4' readonly>s4</select>\n"
174                 + "    <select id='s5' style='display: none'>s5</select>\n"
175                 + "  </form>\n"
176                 + "</body></html>";
177 
178         loadPageVerifyTitle2(html);
179     }
180 
181     /**
182      * @throws Exception if an error occurs
183      */
184     @Test
185     @Alerts({"true",
186              "false-false-false-false-false-false-false-false-false-true-false",
187              "true"})
188     public void validationEmpty() throws Exception {
189         validation("<select id='e1'>s1</select>\n", "");
190     }
191 
192     /**
193      * @throws Exception if an error occurs
194      */
195     @Test
196     @Alerts({"false",
197              "false-true-false-false-false-false-false-false-false-false-false",
198              "true"})
199     public void validationCustomValidity() throws Exception {
200         validation("<select id='e1'>s1</select>\n", "elem.setCustomValidity('Invalid');");
201     }
202 
203     /**
204      * @throws Exception if an error occurs
205      */
206     @Test
207     @Alerts({"false",
208              "false-true-false-false-false-false-false-false-false-false-false",
209              "true"})
210     public void validationBlankCustomValidity() throws Exception {
211         validation("<select id='e1'>s1</select>\n", "elem.setCustomValidity(' ');\n");
212     }
213 
214     /**
215      * @throws Exception if an error occurs
216      */
217     @Test
218     @Alerts({"true",
219              "false-false-false-false-false-false-false-false-false-true-false",
220              "true"})
221     public void validationResetCustomValidity() throws Exception {
222         validation("<select id='e1'>s1</select>\n",
223                 "elem.setCustomValidity('Invalid');elem.setCustomValidity('');");
224     }
225 
226     /**
227      * @throws Exception if an error occurs
228      */
229     @Test
230     @Alerts({"false",
231              "false-false-false-false-false-false-false-false-false-false-true",
232              "true"})
233     public void validationRequired() throws Exception {
234         validation("<select id='e1' required>s1</select>\n", "");
235     }
236 
237     /**
238      * @throws Exception if an error occurs
239      */
240     @Test
241     @Alerts({"true",
242              "false-false-false-false-false-false-false-false-false-true-false",
243              "true"})
244     public void validationRequiredSelected() throws Exception {
245         validation("<select id='e1' size='4' required><option value='unit' selected>Html</option></select>\n", "");
246     }
247 
248     /**
249      * @throws Exception if an error occurs
250      */
251     @Test
252     @Alerts({"true",
253              "false-false-false-false-false-false-false-false-false-true-false",
254              "true"})
255     public void validationRequiredSelect() throws Exception {
256         validation("<select id='e1' size='4' required><option id='e2' value='unit'>Html</option></select>\n",
257                 "document.getElementById('e2').selected=true;");
258     }
259 
260     /**
261      * @throws Exception if an error occurs
262      */
263     @Test
264     @Alerts({"false",
265              "false-false-false-false-false-false-false-false-false-false-true",
266              "true"})
267     public void validationRequiredDeselect() throws Exception {
268         validation("<select id='e1' size='4' required><option id='e2' value='unit' selected>Html</option></select>\n",
269                 "document.getElementById('e2').selected=false;");
270     }
271 
272     private void validation(final String htmlPart, final String jsPart) throws Exception {
273         final String html = DOCTYPE_HTML
274                 + "<html><head>\n"
275                 + "  <script>\n"
276                 + LOG_TITLE_FUNCTION
277                 + "    function logValidityState(s) {\n"
278                 + "      log(s.badInput"
279                         + "+ '-' + s.customError"
280                         + "+ '-' + s.patternMismatch"
281                         + "+ '-' + s.rangeOverflow"
282                         + "+ '-' + s.rangeUnderflow"
283                         + "+ '-' + s.stepMismatch"
284                         + "+ '-' + s.tooLong"
285                         + "+ '-' + s.tooShort"
286                         + " + '-' + s.typeMismatch"
287                         + " + '-' + s.valid"
288                         + " + '-' + s.valueMissing);\n"
289                 + "    }\n"
290                 + "    function test() {\n"
291                 + "      var elem = document.getElementById('e1');\n"
292                 + jsPart
293                 + "      log(elem.checkValidity());\n"
294                 + "      logValidityState(elem.validity);\n"
295                 + "      log(elem.willValidate);\n"
296                 + "    }\n"
297                 + "  </script>\n"
298                 + "</head>\n"
299                 + "<body onload='test()'>\n"
300                 + "  <form>\n"
301                 + htmlPart
302                 + "  </form>\n"
303                 + "</body></html>";
304 
305         loadPageVerifyTitle2(html);
306     }
307 }