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