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 java.nio.charset.StandardCharsets.ISO_8859_1;
18  import static java.nio.charset.StandardCharsets.UTF_8;
19  
20  import java.io.IOException;
21  import java.io.Writer;
22  import java.net.URL;
23  import java.nio.charset.Charset;
24  import java.util.Collections;
25  import java.util.Comparator;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import javax.servlet.Servlet;
31  import javax.servlet.ServletException;
32  import javax.servlet.http.HttpServlet;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  
36  import org.htmlunit.FormEncodingType;
37  import org.htmlunit.HttpHeader;
38  import org.htmlunit.HttpMethod;
39  import org.htmlunit.MockWebConnection;
40  import org.htmlunit.WebClient;
41  import org.htmlunit.WebDriverTestCase;
42  import org.htmlunit.junit.annotation.Alerts;
43  import org.htmlunit.junit.annotation.HtmlUnitNYI;
44  import org.htmlunit.util.MimeType;
45  import org.htmlunit.util.NameValuePair;
46  import org.htmlunit.util.UrlUtils;
47  import org.junit.jupiter.api.Test;
48  import org.openqa.selenium.By;
49  import org.openqa.selenium.By.ById;
50  import org.openqa.selenium.By.ByTagName;
51  import org.openqa.selenium.WebDriver;
52  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
53  
54  /**
55   * Tests for {@link HtmlForm}, with BrowserRunner.
56   *
57   * @author Ahmed Ashour
58   * @author Ronald Brill
59   * @author Anton Demydenko
60   */
61  public class HtmlForm2Test extends WebDriverTestCase {
62  
63      /**
64       * @throws Exception if the test fails
65       */
66      @Test
67      @Alerts({"myForm", "TypeError"})
68      public void formsAccessor_FormsAsFunction() throws Exception {
69          final String html = DOCTYPE_HTML
70              + "<html><head>\n"
71              + "<script>\n"
72              + LOG_TITLE_FUNCTION
73              + "function doTest() {\n"
74              + "  try {\n"
75              + "    log(document.forms[0].id);\n"
76              + "    log(document.forms(0).id);\n"
77              + "  } catch (err) {\n"
78              + "    log('TypeError');\n"
79              + "  }\n"
80              + "}\n"
81              + "</script></head><body onload='doTest()'>\n"
82              + "<p>hello world</p>\n"
83              + "<form id='myForm'>\n"
84              + "  <input type='text' name='textfield1' value='foo' />\n"
85              + "</form>\n"
86              + "</body></html>";
87  
88          loadPageVerifyTitle2(html);
89      }
90  
91      /**
92       * @throws Exception if the test fails
93       */
94      @Test
95      @Alerts({"myForm", "TypeError"})
96      public void formsAccessor_FormsAsFunction2() throws Exception {
97          final String html = DOCTYPE_HTML
98              + "<html><head>\n"
99              + "<script>\n"
100             + LOG_TITLE_FUNCTION
101             + "function doTest() {\n"
102             + "  try {\n"
103             + "    log(document.forms['myName'].id);\n"
104             + "    log(document.forms('myName').id);\n"
105             + "  } catch (err) {\n"
106             + "    log('TypeError');\n"
107             + "  }\n"
108             + "}\n"
109             + "</script></head><body onload='doTest()'>\n"
110             + "<p>hello world</p>\n"
111             + "<form id='myForm' name='myName'>\n"
112             + "  <input type='text' name='textfield1' value='foo' />\n"
113             + "</form>\n"
114             + "</body></html>";
115 
116         loadPageVerifyTitle2(html);
117     }
118 
119     /**
120      * @throws Exception if an error occurs
121      */
122     @Test
123     @Alerts({"TypeError", "TypeError", "TypeError"})
124     public void asFunction() throws Exception {
125         final String html = DOCTYPE_HTML
126             + "<html><head>\n"
127             + "<script>\n"
128             + LOG_TITLE_FUNCTION
129             + "function test() {\n"
130             + "  var f1 = document.forms[0];\n"
131             + "  try { log(f1('textfieldid').id) } catch(e) { logEx(e) }\n"
132             + "  try { log(f1('textfieldname').name) } catch(e) { logEx(e) }\n"
133             + "  try { log(f1(0).id) } catch(e) { logEx(e) }\n"
134             + "}\n"
135             + "</script></head><body onload='test()'>\n"
136             + "<p>hello world</p>\n"
137             + "<form id='firstid' name='firstname'>\n"
138             + "  <input type='text' id='textfieldid' value='foo' />\n"
139             + "  <input type='text' name='textfieldname' value='foo' />\n"
140             + "</form>\n"
141             + "</body></html>";
142 
143         loadPageVerifyTitle2(html);
144     }
145 
146     /**
147      * @throws Exception if an error occurs
148      */
149     @Test
150     @Alerts("TypeError")
151     public void asFunctionFormsFunction() throws Exception {
152         final String html = DOCTYPE_HTML
153             + "<html><head>\n"
154             + "<script>\n"
155             + LOG_TITLE_FUNCTION
156             + "function test() {\n"
157             + "  try {\n"
158             + "    var f1 = document.forms(0);\n"
159             + "    try { log(f1('textfieldid').id) } catch(e) { logEx(e) }\n"
160             + "    try { log(f1('textfieldname').name) } catch(e) { logEx(e) }\n"
161             + "    try { log(f1(0).id) } catch(e) { logEx(e) }\n"
162             + "  } catch(e) { logEx(e) }\n"
163             + "}\n"
164             + "</script></head><body onload='test()'>\n"
165             + "<p>hello world</p>\n"
166             + "<form id='firstid' name='firstname'>\n"
167             + "  <input type='text' id='textfieldid' value='foo' />\n"
168             + "  <input type='text' name='textfieldname' value='foo' />\n"
169             + "</form>\n"
170             + "</body></html>";
171 
172         loadPageVerifyTitle2(html);
173     }
174 
175     /**
176      * @throws Exception if the test fails
177      */
178     @Test
179     public void base() throws Exception {
180         final String html = DOCTYPE_HTML
181             + "<html><head>\n"
182             + "  <base href='" + URL_SECOND + "'>\n"
183             + "</head><body>\n"
184             + "<form action='two.html'>\n"
185             + "  <input type='submit'>\n"
186             + "</form></body></html>";
187 
188         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><head></head><body>foo</body></html>");
189 
190         final WebDriver driver = loadPage2(html);
191         driver.findElement(new ByTagName("input")).click();
192         if (useRealBrowser()) {
193             Thread.sleep(400);
194         }
195 
196         assertEquals(2, getMockWebConnection().getRequestCount());
197         final URL requestedUrl = getMockWebConnection().getLastWebRequest().getUrl();
198         final URL expectedUrl = new URL(URL_SECOND, "two.html");
199         assertEquals(expectedUrl, requestedUrl);
200     }
201 
202     /**
203      * @throws Exception if the test fails
204      */
205     @Test
206     public void emptyActionWithBase() throws Exception {
207         final String html = DOCTYPE_HTML
208             + "<html><head>\n"
209             + "  <base href='" + URL_SECOND + "'>\n"
210             + "</head><body>\n"
211             + "<form>\n"
212             + "  <input type='submit'>\n"
213             + "</form></body></html>";
214 
215         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><head></head><body>foo</body></html>");
216 
217         final WebDriver driver = loadPage2(html);
218         driver.findElement(new ByTagName("input")).click();
219         if (useRealBrowser()) {
220             Thread.sleep(400);
221         }
222 
223         assertEquals(2, getMockWebConnection().getRequestCount());
224         final URL requestedUrl = getMockWebConnection().getLastWebRequest().getUrl();
225         assertEquals(URL_FIRST.toExternalForm(), requestedUrl);
226     }
227 
228     /**
229      * @throws Exception if the test fails
230      */
231     @Test
232     public void emptyActionWithBase2() throws Exception {
233         final String html = DOCTYPE_HTML
234             + "<html><head>\n"
235             + "  <base href='" + URL_SECOND + "'>\n"
236             + "</head><body>\n"
237             + "<form>\n"
238             + "  <input name='myName' value='myValue'>\n"
239             + "  <input type='submit'>\n"
240             + "</form></body></html>";
241 
242         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><head></head><body>foo</body></html>");
243 
244         final WebDriver driver = loadPage2(html);
245         driver.findElement(new ByTagName("input")).click();
246 
247         assertEquals(1, getMockWebConnection().getRequestCount());
248         final URL requestedUrl = getMockWebConnection().getLastWebRequest().getUrl();
249         assertEquals(URL_FIRST.toExternalForm(), requestedUrl);
250     }
251 
252     /**
253      * Simulates a bug report where using JavaScript to submit a form that contains a
254      * JavaScript action causes a an "IllegalArgumentException: JavaScript URLs can only
255      * be used to load content into frames and iframes".
256      *
257      * @throws Exception if the test fails
258      */
259     @Test
260     @Alerts("clicked")
261     public void jSSubmit_JavaScriptAction() throws Exception {
262         final String html = DOCTYPE_HTML
263             + "<html><head><title>First</title></head>\n"
264             + "<body onload='document.getElementById(\"aForm\").submit()'>\n"
265             + "<form id='aForm' action='javascript:alert(\"clicked\")'"
266             + "</form>\n"
267             + "</body></html>";
268 
269         loadPageWithAlerts2(html);
270     }
271 
272     /**
273      * @throws Exception if the test page can't be loaded
274      */
275     @Test
276     @Alerts({"1", "val2", "3", "3"})
277     public void malformedHtml_nestedForms() throws Exception {
278         final String html = DOCTYPE_HTML
279             + "<html><head>\n"
280             + "<script>\n"
281             + LOG_TITLE_FUNCTION
282             + "  function test() {\n"
283             + "    log(document.forms.length);\n"
284             + "    log(document.forms[0].field2.value);\n"
285 
286             + "    log(document.forms[0].length);\n"
287             + "    log(document.forms[0].elements.length);\n"
288             + "  }\n"
289             + "</script></head><body onload='test()'>\n"
290             + "<form id='form1' method='get' action='foo'>\n"
291             + "  <input name='field1' value='val1'/>\n"
292             + "  <form>\n"
293             + "  <input name='field2' value='val2'/>\n"
294             + "  <input type='submit' id='submitButton'/>\n"
295             + "  </form>\n"
296             + "</form></body></html>";
297 
298         loadPageVerifyTitle2(html);
299     }
300 
301     /**
302      * @throws Exception if the test fails
303      */
304     @Test
305     @Alerts({"§§URL§§?par%F6m=Hello+G%FCnter", "par\u00F6m", "Hello G\u00FCnter"})
306     public void encodingSubmit() throws Exception {
307         stopWebServers();
308         final String html = DOCTYPE_HTML
309             + "<html>\n"
310             + "<head>\n"
311             + "  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
312             + "</head>\n"
313             + "<body>\n"
314             + "  <form>\n"
315             + "    <input name='par\u00F6m' value='Hello G\u00FCnter'>\n"
316             + "    <input id='mySubmit' type='submit' value='Submit'>\n"
317             + "  </form>\n"
318             + "</body></html>";
319 
320         expandExpectedAlertsVariables(URL_FIRST);
321         final WebDriver driver = loadPage2(html, URL_FIRST, "text/html;charset=ISO-8859-1", ISO_8859_1, ISO_8859_1);
322         driver.findElement(new ById("mySubmit")).click();
323         if (useRealBrowser()) {
324             Thread.sleep(400);
325         }
326 
327         assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
328         assertEquals(2, getMockWebConnection().getRequestCount());
329 
330         final List<NameValuePair> requestedParams =
331                 getMockWebConnection().getLastWebRequest().getRequestParameters();
332         assertEquals(1, requestedParams.size());
333         assertEquals(getExpectedAlerts()[1], requestedParams.get(0).getName());
334         assertEquals(getExpectedAlerts()[2], requestedParams.get(0).getValue());
335     }
336 
337     /**
338      * Tests the 'Origin' and 'Referer' HTTP header.
339      * @throws Exception on test failure
340      */
341     @Test
342     @Alerts({"null", "§§URL§§path?query"})
343     public void originRefererHeaderGet() throws Exception {
344         final String firstHtml = DOCTYPE_HTML
345             + "<html>\n"
346             + "<head></head>\n"
347             + "<body>\n"
348             + "  <form method='get' action='" + URL_SECOND + "'>\n"
349             + "    <input id='mySubmit' type='submit' value='Submit'>\n"
350             + "  </form>\n"
351             + "</body>\n"
352             + "</html>";
353         final String secondHtml = DOCTYPE_HTML + "<html><body></body></html>";
354 
355         final MockWebConnection webConnection = getMockWebConnection();
356         final URL requestUrl = new URL(URL_FIRST, "/path?query");
357         webConnection.setResponse(URL_SECOND, secondHtml);
358 
359         expandExpectedAlertsVariables(URL_FIRST);
360         final WebDriver driver = loadPage2(firstHtml, requestUrl);
361 
362         driver.findElement(new ById("mySubmit")).click();
363         if (useRealBrowser()) {
364             Thread.sleep(400);
365         }
366 
367         assertEquals(2, getMockWebConnection().getRequestCount());
368         final Map<String, String> lastAdditionalHeaders = webConnection.getLastAdditionalHeaders();
369         assertEquals(getExpectedAlerts()[0], "" + lastAdditionalHeaders.get(HttpHeader.ORIGIN));
370         assertEquals(getExpectedAlerts()[1], "" + lastAdditionalHeaders.get(HttpHeader.REFERER));
371     }
372 
373     /**
374      * Tests the 'Origin' HTTP header.
375      * @throws Exception on test failure
376      */
377     @Test
378     @Alerts({"§§URL§§", "§§URL§§/path?query"})
379     public void originRefererHeaderPost() throws Exception {
380         final String firstHtml = DOCTYPE_HTML
381             + "<html>\n"
382             + "<head></head>\n"
383             + "<body>\n"
384             + "  <form method='post' action='" + URL_SECOND + "'>\n"
385             + "    <input id='mySubmit' type='submit' value='Submit'>\n"
386             + "  </form>\n"
387             + "</body>\n"
388             + "</html>";
389         final String secondHtml = DOCTYPE_HTML + "<html><body></body></html>";
390 
391         final MockWebConnection webConnection = getMockWebConnection();
392         final URL requestUrl = new URL(URL_FIRST, "/path?query");
393         webConnection.setResponse(URL_SECOND, secondHtml);
394 
395         String url = URL_FIRST.toExternalForm();
396         url = url.substring(0, url.length() - 1);
397         expandExpectedAlertsVariables(url);
398         final WebDriver driver = loadPage2(firstHtml, requestUrl);
399 
400         driver.findElement(new ById("mySubmit")).click();
401         if (useRealBrowser()) {
402             Thread.sleep(400);
403         }
404 
405         assertEquals(2, getMockWebConnection().getRequestCount());
406         final Map<String, String> lastAdditionalHeaders = webConnection.getLastAdditionalHeaders();
407         assertEquals(getExpectedAlerts()[0], "" + lastAdditionalHeaders.get(HttpHeader.ORIGIN));
408         assertEquals(getExpectedAlerts()[1], "" + lastAdditionalHeaders.get(HttpHeader.REFERER));
409     }
410 
411     /**
412      * @throws Exception if an error occurs
413      */
414     @Test
415     @Alerts(DEFAULT = "text/html,application/xhtml+xml,application/xml;q=0.9,"
416                     + "image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
417             FF = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
418             FF_ESR = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
419     public void acceptHeader() throws Exception {
420         final String html = DOCTYPE_HTML
421             + "<html><head></head><body>\n"
422             + "  <form action='test2'>\n"
423             + "    <input type=submit id='mySubmit'>\n"
424             + "  </form>\n"
425             + "</body></html>";
426 
427         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
428         servlets.put("/test2", AcceptHeaderServlet.class);
429 
430         final WebDriver driver = loadPage2(html, servlets);
431         driver.findElement(By.id("mySubmit")).click();
432         verifyAlerts(driver, getExpectedAlerts());
433     }
434 
435     /**
436      * Servlet for {@link #acceptHeader()}.
437      */
438     public static class AcceptHeaderServlet extends HttpServlet {
439 
440         /**
441          * {@inheritDoc}
442          */
443         @Override
444         protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
445             throws ServletException, IOException {
446             request.setCharacterEncoding(UTF_8.name());
447             response.setContentType(MimeType.TEXT_HTML);
448             final Writer writer = response.getWriter();
449             final String html = DOCTYPE_HTML
450                     + "<html><head><script>\n"
451                     + "function test() {\n"
452                     + "  alert('" + request.getHeader(HttpHeader.ACCEPT) + "');\n"
453                     + "}\n"
454                     + "</script></head><body onload='test()'></body></html>";
455 
456             writer.write(html);
457         }
458     }
459 
460     /**
461      * @throws Exception if an error occurs
462      */
463     @Test
464     @Alerts("gzip, deflate, br, zstd")
465     @HtmlUnitNYI(CHROME = "gzip, deflate, br",
466             EDGE = "gzip, deflate, br",
467             FF = "gzip, deflate, br",
468             FF_ESR = "gzip, deflate, br")
469     public void acceptEncodingHeader() throws Exception {
470         final String html = DOCTYPE_HTML
471             + "<html><head></head><body>\n"
472             + "  <form action='test2'>\n"
473             + "    <input type=submit id='mySubmit'>\n"
474             + "  </form>\n"
475             + "</body></html>";
476 
477         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
478         servlets.put("/test2", AcceptEncodingHeaderServlet.class);
479 
480         final WebDriver driver = loadPage2(html, servlets);
481         driver.findElement(By.id("mySubmit")).click();
482         verifyAlerts(driver, getExpectedAlerts());
483     }
484 
485     /**
486      * @throws Exception if an error occurs
487      */
488     @Test
489     public void formMultipartEncodingTypeTest() throws Exception {
490         final String html = DOCTYPE_HTML
491             + "<html><head></head>\n"
492             + "<body>\n"
493             + "  <p>hello world</p>\n"
494             + "  <form id='myForm' action='" + URL_SECOND
495                     + "' method='" + HttpMethod.POST
496                     + "' enctype='" + FormEncodingType.MULTIPART.getName()
497                     + "'>\n"
498             + "    <input type='file' value='file1'>\n"
499             + "    <button id='myButton' type='submit'>Submit</button>\n"
500             + "  </form>\n"
501             + "</body></html>";
502         final String secondContent = DOCTYPE_HTML
503             + "<html><head><title>second</title></head><body>\n"
504             + "  <p>hello world</p>\n"
505             + "</body></html>";
506 
507         getMockWebConnection().setResponse(URL_SECOND, secondContent);
508 
509         final WebDriver driver = loadPage2(html, URL_FIRST);
510         driver.findElement(By.id("myButton")).click();
511         if (useRealBrowser()) {
512             Thread.sleep(400);
513         }
514 
515         assertEquals(2, getMockWebConnection().getRequestCount());
516         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
517         assertEquals(FormEncodingType.MULTIPART, getMockWebConnection().getLastWebRequest().getEncodingType());
518     }
519 
520     /**
521      * @throws Exception if an error occurs
522      */
523     @Test
524     public void formUrlEncodedEncodingTypeTest() throws Exception {
525         final String html = DOCTYPE_HTML
526             + "<html><head></head>\n"
527             + "<body>\n"
528             + "  <p>hello world</p>\n"
529             + "  <form id='myForm' action='" + URL_SECOND
530                         + "' method='" + HttpMethod.POST
531                         + "' enctype='" + FormEncodingType.URL_ENCODED.getName()
532                         + "'>\n"
533             + "    <button id='myButton' type='submit'>Submit</button>\n"
534             + "  </form>\n"
535             + "</body></html>";
536 
537         final String secondContent = DOCTYPE_HTML
538             + "<html><head><title>second</title></head><body>\n"
539             + "  <p>hello world</p>\n"
540             + "</body></html>";
541 
542         getMockWebConnection().setResponse(URL_SECOND, secondContent);
543 
544         final WebDriver driver = loadPage2(html, URL_FIRST);
545         driver.findElement(By.id("myButton")).click();
546         if (useRealBrowser()) {
547             Thread.sleep(400);
548         }
549 
550         assertEquals(2, getMockWebConnection().getRequestCount());
551         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
552         assertEquals(FormEncodingType.URL_ENCODED, getMockWebConnection().getLastWebRequest().getEncodingType());
553     }
554 
555     /**
556      * @throws Exception if the test fails
557      */
558     @Test
559     @Alerts({"2", "third"})
560     public void buttonWithFormAction() throws Exception {
561         final String html = DOCTYPE_HTML
562             + "<html><head><title>first</title></head>\n"
563             + "<body>\n"
564             + "  <p>hello world</p>\n"
565             + "  <form id='myForm' action='" + URL_SECOND + "'>\n"
566             + "    <button id='myButton' type='submit' formaction='" + URL_THIRD
567                         + "'>Submit with different form action</button>\n"
568             + "  </form>\n"
569             + "</body></html>";
570 
571         final String secondContent = DOCTYPE_HTML
572                 + "<html><head><title>second</title></head>\n"
573                 + "<body>\n"
574                 + "  <p>hello world</p>\n"
575                 + "</body></html>";
576 
577         final String thirdContent = DOCTYPE_HTML
578                 + "<html><head><title>third</title></head>\n"
579                 + "<body>\n"
580                 + "  <p>hello world</p>\n"
581                 + "</body></html>";
582 
583         getMockWebConnection().setResponse(URL_SECOND, secondContent);
584         getMockWebConnection().setResponse(URL_THIRD, thirdContent);
585 
586         final WebDriver driver = loadPage2(html);
587         driver.findElement(By.id("myButton")).click();
588         if (useRealBrowser()) {
589             Thread.sleep(400);
590         }
591 
592         assertEquals(Integer.parseInt(getExpectedAlerts()[0]), getMockWebConnection().getRequestCount());
593         assertTrue(driver.getPageSource().contains(getExpectedAlerts()[1]));
594     }
595 
596     /**
597      * @throws Exception if the test fails
598      */
599     @Test
600     @Alerts({"2", "third"})
601     public void buttonWithFormActionWithoutType() throws Exception {
602         final String html = DOCTYPE_HTML
603             + "<html><head><title>first</title></head>\n"
604             + "<body>\n"
605             + "  <p>hello world</p>\n"
606             + "  <form id='myForm' action='" + URL_SECOND + "'>\n"
607             + "    <button id='myButton' formaction='" + URL_THIRD
608                         + "'>Submit with different form action</button>\n"
609             + "  </form>\n"
610             + "</body></html>";
611 
612         final String secondContent = DOCTYPE_HTML
613                 + "<html><head><title>second</title></head>\n"
614                 + "<body>\n"
615                 + "  <p>hello world</p>\n"
616                 + "</body></html>";
617 
618         final String thirdContent = DOCTYPE_HTML
619                 + "<html><head><title>third</title></head>\n"
620                 + "<body>\n"
621                 + "  <p>hello world</p>\n"
622                 + "</body></html>";
623 
624         getMockWebConnection().setResponse(URL_SECOND, secondContent);
625         getMockWebConnection().setResponse(URL_THIRD, thirdContent);
626 
627         final WebDriver driver = loadPage2(html);
628         driver.findElement(By.id("myButton")).click();
629         if (useRealBrowser()) {
630             Thread.sleep(400);
631         }
632 
633         assertEquals(Integer.parseInt(getExpectedAlerts()[0]), getMockWebConnection().getRequestCount());
634         assertTrue(driver.getPageSource().contains(getExpectedAlerts()[1]));
635     }
636 
637     /**
638      * @throws Exception if the test fails
639      */
640     @Test
641     public void buttonWithFormActionNegative() throws Exception {
642         final String html = DOCTYPE_HTML
643             + "<html><head></head>\n"
644             + "<body>\n"
645             + "  <p>hello world</p>\n"
646             + "  <form id='myForm' action='" + URL_SECOND + "'>\n"
647             + "    <button id='myButton' type='reset' formaction='" + URL_THIRD
648             + "'>Submit with different form action</button>\n"
649             + "  </form>\n"
650             + "</body></html>";
651 
652         final WebDriver driver = loadPage2(html);
653         driver.findElement(By.id("myButton")).click();
654 
655         //no additional actions
656         assertEquals(1, getMockWebConnection().getRequestCount());
657         assertEquals(URL_FIRST.toString(), getMockWebConnection().getLastWebRequest().getUrl());
658     }
659 
660     /**
661      * @throws Exception if the test fails
662      */
663     @Test
664     @Alerts({"2", "third/"})
665     public void inputTypeSubmitWithFormAction() throws Exception {
666         final String html = DOCTYPE_HTML
667             + "<html><head></head>\n"
668             + "<body>\n"
669             + "  <p>hello world</p>\n"
670             + "  <form id='myForm' action='" + URL_SECOND + "'>\n"
671             + "    <input id='myButton' type='submit' formaction='" + URL_THIRD + "' />\n"
672             + "  </form>\n"
673             + "</body></html>";
674         final String secondContent = "second content";
675         final String thirdContent = "third content";
676 
677         getMockWebConnection().setResponse(URL_SECOND, secondContent);
678         getMockWebConnection().setResponse(URL_THIRD, thirdContent);
679 
680         final WebDriver driver = loadPage2(html);
681         driver.findElement(By.id("myButton")).click();
682         if (useRealBrowser()) {
683             Thread.sleep(400);
684         }
685 
686         assertEquals(Integer.parseInt(getExpectedAlerts()[0]), getMockWebConnection().getRequestCount());
687         assertTrue(getMockWebConnection().getLastWebRequest()
688                     .getUrl().toExternalForm().endsWith(getExpectedAlerts()[1]));
689     }
690 
691     /**
692      * @throws Exception if the test fails
693      */
694     @Test
695     @Alerts("third content")
696     public void inputTypeImageWithFormAction() throws Exception {
697         final String html = DOCTYPE_HTML
698             + "<html><head></head>\n"
699             + "<body>\n"
700             + "  <p>hello world</p>\n"
701             + "  <form id='myForm' action='" + URL_SECOND + "'>\n"
702             + "    <input id='myButton' type='image' alt='Submit' formaction='" + URL_THIRD + "' />\n"
703             + "  </form>\n"
704             + "</body></html>";
705         final String secondContent = "second content";
706         final String thirdContent = "third content";
707 
708         getMockWebConnection().setResponse(URL_SECOND, secondContent);
709         getMockWebConnection().setResponse(URL_THIRD, thirdContent);
710 
711         final WebDriver driver = loadPage2(html);
712         driver.findElement(By.id("myButton")).click();
713         if (useRealBrowser()) {
714             Thread.sleep(400);
715         }
716 
717         assertEquals(2, getMockWebConnection().getRequestCount());
718         assertTrue("Incorrect conent of new window", driver.getPageSource().contains(getExpectedAlerts()[0]));
719     }
720 
721     /**
722      * @throws Exception if the test fails
723      */
724     @Test
725     public void buttonSubmitWithFormMethod() throws Exception {
726         final String html = DOCTYPE_HTML
727             + "<html><head></head>\n"
728             + "<body>\n"
729             + "  <p>hello world</p>\n"
730             + "  <form id='myForm' action='" + URL_SECOND
731                                 + "' method='" + HttpMethod.POST + "'>\n"
732             + "    <button id='myButton' type='submit' formmethod='" + HttpMethod.GET
733                         + "'>Submit with different form method</button>\n"
734             + "  </form>\n"
735             + "</body></html>";
736         final String secondContent = "second content";
737 
738         getMockWebConnection().setResponse(URL_SECOND, secondContent);
739 
740         final WebDriver driver = loadPage2(html);
741         driver.findElement(By.id("myButton")).click();
742         if (useRealBrowser()) {
743             Thread.sleep(400);
744         }
745 
746         assertEquals(2, getMockWebConnection().getRequestCount());
747         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
748         assertEquals(HttpMethod.GET, getMockWebConnection().getLastWebRequest().getHttpMethod());
749     }
750 
751     /**
752      * @throws Exception if the test fails
753      */
754     @Test
755     public void inputTypeSubmitWithFormMethod() throws Exception {
756         final String html = DOCTYPE_HTML
757             + "<html><head></head>\n"
758             + "<body>\n"
759             + "  <p>hello world</p>\n"
760             + "  <form id='myForm' action='" + URL_SECOND
761                                 + "' method='" + HttpMethod.POST + "'>\n"
762             + "    <input id='myButton' type='submit' formmethod='" + HttpMethod.GET + "' />\n"
763             + "  </form>\n"
764             + "</body></html>";
765         final String secondContent = "second content";
766 
767         getMockWebConnection().setResponse(URL_SECOND, secondContent);
768 
769         final WebDriver driver = loadPage2(html);
770         driver.findElement(By.id("myButton")).click();
771         if (useRealBrowser()) {
772             Thread.sleep(400);
773         }
774 
775         assertEquals(2, getMockWebConnection().getRequestCount());
776         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
777         assertEquals(HttpMethod.GET, getMockWebConnection().getLastWebRequest().getHttpMethod());
778     }
779 
780     /**
781      * @throws Exception if the test fails
782      */
783     @Test
784     @Alerts("GET")
785     public void inputTypeImageWithFormMethod() throws Exception {
786         final String html = DOCTYPE_HTML
787             + "<html><head></head>\n"
788             + "<body>\n"
789             + "  <p>hello world</p>\n"
790             + "  <form id='myForm' action='" + URL_SECOND
791                                 + "' method='" + HttpMethod.POST + "'>\n"
792             + "    <input id='myButton' type='image' alt='Submit' formmethod='" + HttpMethod.GET + "' />\n"
793             + "  </form>\n"
794             + "</body></html>";
795         final String secondContent = "second content";
796 
797         getMockWebConnection().setResponse(URL_SECOND, secondContent);
798 
799         final WebDriver driver = loadPage2(html);
800         driver.findElement(By.id("myButton")).click();
801         if (useRealBrowser()) {
802             Thread.sleep(400);
803         }
804 
805         assertEquals(2, getMockWebConnection().getRequestCount());
806         assertEquals(URL_SECOND.toString(),
807                 UrlUtils.getUrlWithNewQuery(getMockWebConnection().getLastWebRequest().getUrl(), null));
808         assertEquals(getExpectedAlerts()[0], getMockWebConnection().getLastWebRequest().getHttpMethod().name());
809     }
810 
811     /**
812      * @throws Exception if the test fails
813      */
814     @Test
815     public void buttonWithFormEnctype() throws Exception {
816         final String html = DOCTYPE_HTML
817             + "<html><head></head>\n"
818             + "<body>\n"
819             + "  <p>hello world</p>\n"
820             + "  <form id='myForm' action='" + URL_SECOND
821                                 + "' method='" + HttpMethod.POST
822                                 + "' enctype='" + FormEncodingType.URL_ENCODED.getName() + "'>\n"
823             + "    <input type='file' value='file1'>\n"
824             + "    <button id='myButton' type='submit' formenctype='" + FormEncodingType.MULTIPART.getName()
825             + "'>Submit with different form encoding type</button>\n"
826             + "  </form>\n"
827             + "</body></html>";
828         final String secondContent = "second content";
829 
830         getMockWebConnection().setResponse(URL_SECOND, secondContent);
831 
832         final WebDriver driver = loadPage2(html);
833         driver.findElement(By.id("myButton")).click();
834         if (useRealBrowser()) {
835             Thread.sleep(400);
836         }
837 
838         assertEquals(2, getMockWebConnection().getRequestCount());
839         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
840         assertEquals(FormEncodingType.MULTIPART, getMockWebConnection().getLastWebRequest().getEncodingType());
841     }
842 
843     /**
844      * @throws Exception if the test fails
845      */
846     @Test
847     public void inputTypeSubmitWithFormEnctype() throws Exception {
848         final String html = DOCTYPE_HTML
849             + "<html><head></head>\n"
850             + "<body>\n"
851             + "  <p>hello world</p>\n"
852             + "  <form id='myForm' action='" + URL_SECOND
853                                 + "' method='" + HttpMethod.POST
854                                 + "' enctype='" + FormEncodingType.URL_ENCODED.getName()
855                                 + "'>\n"
856             + "    <input type='file' value='file1'>\n"
857             + "    <input id='myButton' type='submit' formenctype='" + FormEncodingType.MULTIPART.getName() + "' />\n"
858             + "  </form>\n"
859             + "</body></html>";
860         final String secondContent = "second content";
861 
862         getMockWebConnection().setResponse(URL_SECOND, secondContent);
863 
864         final WebDriver driver = loadPage2(html);
865         driver.findElement(By.id("myButton")).click();
866         if (useRealBrowser()) {
867             Thread.sleep(400);
868         }
869 
870         assertEquals(2, getMockWebConnection().getRequestCount());
871         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
872         assertEquals(FormEncodingType.MULTIPART, getMockWebConnection().getLastWebRequest().getEncodingType());
873     }
874 
875     /**
876      * @throws Exception if the test fails
877      */
878     @Test
879     @Alerts("application/x-www-form-urlencoded")
880     public void inputTypeImageWithFormEnctype() throws Exception {
881         final String html = DOCTYPE_HTML
882             + "<html><head></head>\n"
883             + "<body>\n"
884             + "  <p>hello world</p>\n"
885             + "  <form id='myForm' action='" + URL_SECOND
886                                 + "' method='" + HttpMethod.POST
887                                 + "' enctype='" + FormEncodingType.MULTIPART.getName() + "'>\n"
888             + "    <input id='myButton' type='image' formenctype='" + FormEncodingType.URL_ENCODED.getName() + "' />\n"
889             + "  </form>\n"
890             + "</body></html>";
891         final String secondContent = "second content";
892 
893         getMockWebConnection().setResponse(URL_SECOND, secondContent);
894 
895         final WebDriver driver = loadPage2(html, URL_FIRST);
896         driver.findElement(By.id("myButton")).click();
897         if (useRealBrowser()) {
898             Thread.sleep(400);
899         }
900 
901         assertEquals(2, getMockWebConnection().getRequestCount());
902         assertEquals(URL_SECOND.toString(), getMockWebConnection().getLastWebRequest().getUrl());
903         assertEquals(getExpectedAlerts()[0],
904                     getMockWebConnection().getLastWebRequest().getEncodingType().getName());
905     }
906 
907     /**
908      * @throws Exception if the test fails
909      */
910     @Test
911     public void buttonWithFormTarget() throws Exception {
912         final String html = DOCTYPE_HTML
913             + "<html><head></head>\n"
914             + "<body>\n"
915             + "  <p>hello world</p>\n"
916             + "  <form id='myForm' action='" + URL_SECOND + "' target='_self'>\n"
917             + "    <button id='myButton' type='submit' "
918                                 + "formtarget='_blank'>Submit with different form target</button>\n"
919             + "  </form>\n"
920             + "</body></html>";
921         final String secondContent = "second content";
922 
923         getMockWebConnection().setResponse(URL_SECOND, secondContent);
924 
925         final WebDriver driver = loadPage2(html);
926         // check that initially we have one window
927         assertEquals("Incorrect number of openned window", 1, driver.getWindowHandles().size());
928         final String firstWindowId = driver.getWindowHandle();
929 
930         driver.findElement(By.id("myButton")).click();
931 
932         // check that after submit we have a new window
933         assertEquals("Incorrect number of openned window", 2, driver.getWindowHandles().size());
934 
935         String newWindowId = "";
936         for (final String id : driver.getWindowHandles()) {
937             if (!firstWindowId.equals(id)) {
938                 newWindowId = id;
939                 break;
940             }
941         }
942         // switch to the new window and check its content
943         driver.switchTo().window(newWindowId);
944         assertTrue("Incorrect conent of new window", driver.getPageSource().contains(secondContent));
945         driver.close();
946     }
947 
948     /**
949      * @throws Exception if the test fails
950      */
951     @Test
952     @Alerts("second content")
953     public void inputTypeSubmitWithFormTarget() throws Exception {
954         final String html = DOCTYPE_HTML
955             + "<html><head></head>\n"
956             + "<body>\n"
957             + "  <p>hello world</p>\n"
958             + "  <form id='myForm' action='" + URL_SECOND + "' target='_self'>\n"
959             + "    <input id='myButton' type='submit' formtarget='_blank' />\n"
960             + "  </form>\n"
961             + "</body></html>";
962         final String secondContent = "second content";
963 
964         getMockWebConnection().setResponse(URL_SECOND, secondContent);
965 
966         final WebDriver driver = loadPage2(html);
967         // check that initially we have one window
968         assertEquals("Incorrect number of openned window", 1, driver.getWindowHandles().size());
969         final String firstWindowId = driver.getWindowHandle();
970 
971         driver.findElement(By.id("myButton")).click();
972 
973         // check that after submit we have a new window
974         assertEquals("Incorrect number of openned window", 2, driver.getWindowHandles().size());
975 
976         String newWindowId = "";
977         for (final String id : driver.getWindowHandles()) {
978             if (!firstWindowId.equals(id)) {
979                 newWindowId = id;
980                 break;
981             }
982         }
983         // switch to the new window and check its content
984         driver.switchTo().window(newWindowId);
985         assertTrue("Incorrect conent of new window", driver.getPageSource().contains(getExpectedAlerts()[0]));
986         driver.close();
987     }
988 
989     /**
990      * @throws Exception if the test fails
991      */
992     @Test
993     @Alerts("2")
994     public void inputTypeImageWithFormTarget() throws Exception {
995         final String html = DOCTYPE_HTML
996             + "<html><head></head>\n"
997             + "<body>\n"
998             + "  <p>hello world</p>\n"
999             + "  <form id='myForm' action='" + URL_SECOND + "' target='_self'>\n"
1000             + "    <input id='myButton' type='image' alt='Submit' formtarget='_blank' />\n"
1001             + "  </form>\n"
1002             + "</body></html>";
1003         final String secondContent = "second content";
1004 
1005         getMockWebConnection().setResponse(URL_SECOND, secondContent);
1006 
1007         final WebDriver driver = loadPage2(html);
1008         // check that initially we have one window
1009         assertEquals("Incorrect number of openned window", 1, driver.getWindowHandles().size());
1010         final String firstWindowId = driver.getWindowHandle();
1011 
1012         driver.findElement(By.id("myButton")).click();
1013 
1014         // check that after submit we have a new window
1015         assertEquals("Incorrect number of openned window",
1016                 Integer.parseInt(getExpectedAlerts()[0]), driver.getWindowHandles().size());
1017 
1018         String newWindowId = "";
1019         for (final String id : driver.getWindowHandles()) {
1020             if (!firstWindowId.equals(id)) {
1021                 newWindowId = id;
1022                 break;
1023             }
1024         }
1025         // switch to the new window and check its content
1026         driver.switchTo().window(newWindowId);
1027         assertTrue("Incorrect conent of new window", driver.getPageSource().contains(secondContent));
1028         driver.close();
1029     }
1030 
1031     /**
1032      * Servlet for {@link #acceptEncodingHeader()}.
1033      */
1034     public static class AcceptEncodingHeaderServlet extends HttpServlet {
1035 
1036         /**
1037          * {@inheritDoc}
1038          */
1039         @Override
1040         protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
1041             throws ServletException, IOException {
1042             request.setCharacterEncoding(UTF_8.name());
1043             response.setContentType(MimeType.TEXT_HTML);
1044             final Writer writer = response.getWriter();
1045             final String html = DOCTYPE_HTML
1046                     + "<html><head><script>\n"
1047                     + "function test() {\n"
1048                     + "  alert('" + request.getHeader(HttpHeader.ACCEPT_ENCODING) + "');\n"
1049                     + "}\n"
1050                     + "</script></head><body onload='test()'></body></html>";
1051 
1052             writer.write(html);
1053         }
1054     }
1055 
1056     /**
1057      * @throws Exception if the test fails
1058      */
1059     @Test
1060     @Alerts("second")
1061     public void novalidate() throws Exception {
1062         final String html = DOCTYPE_HTML
1063             + "<html>\n"
1064             + "<head><title>first</title></head>\n"
1065             + "<body>\n"
1066             + "  <form name='testForm' action='\" + URL_SECOND + \"' novalidate>\n"
1067             + "    <input type='submit' id='submit'>\n"
1068             + "    <input name='test' value='' required='required' >"
1069             + "  </form>\n"
1070             + "</body></html>";
1071 
1072         final String html2 = "<?xml version='1.0'?>\n"
1073             + "<html>\n"
1074             + "<head><title>second</title></head>\n"
1075             + "<body>OK</body></html>";
1076         getMockWebConnection().setDefaultResponse(html2);
1077 
1078         final WebDriver driver = loadPage2(html);
1079         driver.findElement(By.id("submit")).click();
1080         if (useRealBrowser()) {
1081             Thread.sleep(400);
1082         }
1083 
1084         assertEquals(2, getMockWebConnection().getRequestCount());
1085         assertEquals(getExpectedAlerts()[0], driver.getTitle());
1086     }
1087 
1088     /**
1089      * @throws Exception if the test fails
1090      */
1091     @Test
1092     @Alerts("second")
1093     public void submitFormnovalidate() throws Exception {
1094         final String html = DOCTYPE_HTML
1095             + "<html>\n"
1096             + "<head><title>first</title></head>\n"
1097             + "<body>\n"
1098             + "  <form name='testForm' action='\" + URL_SECOND + \"'>\n"
1099             + "    <input type='submit' id='submit' formnovalidate>\n"
1100             + "    <input name='test' value='' required='required' >"
1101             + "  </form>\n"
1102             + "</body></html>";
1103 
1104         final String html2 = "<?xml version='1.0'?>\n"
1105             + "<html>\n"
1106             + "<head><title>second</title></head>\n"
1107             + "<body>OK</body></html>";
1108         getMockWebConnection().setDefaultResponse(html2);
1109 
1110         final WebDriver driver = loadPage2(html);
1111         driver.findElement(By.id("submit")).click();
1112         if (useRealBrowser()) {
1113             Thread.sleep(400);
1114         }
1115 
1116         assertEquals(2, getMockWebConnection().getRequestCount());
1117         assertEquals(getExpectedAlerts()[0], driver.getTitle());
1118     }
1119 
1120     /**
1121      * @throws Exception if the test fails
1122      */
1123     @Test
1124     @Alerts("second")
1125     public void submitButtonFormnovalidate() throws Exception {
1126         final String html = DOCTYPE_HTML
1127             + "<html>\n"
1128             + "<head><title>first</title></head>\n"
1129             + "<body>\n"
1130             + "  <form name='testForm' action='\" + URL_SECOND + \"'>\n"
1131             + "    <button type='submit' id='submit' formnovalidate>submit</button>\n"
1132             + "    <input name='test' value='' required='required' >"
1133             + "  </form>\n"
1134             + "</body></html>";
1135 
1136         final String html2 = "<?xml version='1.0'?>\n"
1137             + "<html>\n"
1138             + "<head><title>second</title></head>\n"
1139             + "<body>OK</body></html>";
1140         getMockWebConnection().setDefaultResponse(html2);
1141 
1142         final WebDriver driver = loadPage2(html);
1143         driver.findElement(By.id("submit")).click();
1144         if (useRealBrowser()) {
1145             Thread.sleep(400);
1146         }
1147 
1148         assertEquals(2, getMockWebConnection().getRequestCount());
1149         assertEquals(getExpectedAlerts()[0], driver.getTitle());
1150     }
1151 
1152     /**
1153      * @throws Exception if the test fails
1154      */
1155     @Test
1156     @Alerts("second")
1157     public void defaultButtonFormnovalidate() throws Exception {
1158         final String html = DOCTYPE_HTML
1159             + "<html>\n"
1160             + "<head><title>first</title></head>\n"
1161             + "<body>\n"
1162             + "  <form name='testForm' action='\" + URL_SECOND + \"'>\n"
1163             + "    <button id='submit' formnovalidate>submit</button>\n"
1164             + "    <input name='test' value='' required='required' >"
1165             + "  </form>\n"
1166             + "</body></html>";
1167 
1168         final String html2 = "<?xml version='1.0'?>\n"
1169             + "<html>\n"
1170             + "<head><title>second</title></head>\n"
1171             + "<body>OK</body></html>";
1172         getMockWebConnection().setDefaultResponse(html2);
1173 
1174         final WebDriver driver = loadPage2(html);
1175         driver.findElement(By.id("submit")).click();
1176         if (useRealBrowser()) {
1177             Thread.sleep(400);
1178         }
1179 
1180         assertEquals(2, getMockWebConnection().getRequestCount());
1181         assertEquals(getExpectedAlerts()[0], driver.getTitle());
1182     }
1183 
1184     /**
1185      * @throws Exception if the test fails
1186      */
1187     @Test
1188     @Alerts({"radioParam2#radioValue2", "selectParam#selectValue", "textParam#textValue",
1189              "textareaParam#textarea value"})
1190     public void submitUsingFormAttribute() throws Exception {
1191         final String html = DOCTYPE_HTML
1192             + "<html>\n"
1193             + "<head>\n"
1194             + "</head>\n"
1195             + "<body>\n"
1196             + "  <form id='formId'>\n"
1197             + "  </form>\n"
1198 
1199             + "  <input form='formId' type='text' name='textParam' value='textValue'>\n"
1200 
1201             + "  <fieldset form='formId'>\n"
1202             + "    <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1203             + "    <input type='text' name='fieldsetTextParam' value='fieldsetTextValue'>\n"
1204             + "  </fieldset>\n"
1205 
1206             + "  <label for='radioId' form='formId'>Male</label>\n"
1207             + "  <input id='radioId' type='radio' name='radioParam' value='radioValue'>\n"
1208 
1209             + "  <input form='formId' type='radio' name='radioParam2' value='radioValue2' checked='checked'>\n"
1210 
1211             + "  <select form='formId' name='selectParam'>\n"
1212             + "    <option value='selectValue' selected='selected'>selected</option>\n"
1213             + "  </select>\n"
1214 
1215             + "  <textarea form='formId' name='textareaParam'>textarea value</textarea>\n"
1216 
1217             + "  <input form='formId' id='mySubmit' type='submit' value='Submit'>\n"
1218             + "</body></html>";
1219 
1220         final WebDriver driver = loadPage2(html);
1221         driver.findElement(new ById("mySubmit")).click();
1222         if (useRealBrowser()) {
1223             Thread.sleep(400);
1224         }
1225 
1226         assertEquals(2, getMockWebConnection().getRequestCount());
1227 
1228         final List<NameValuePair> requestedParams =
1229                 getMockWebConnection().getLastWebRequest().getRequestParameters();
1230         Collections.sort(requestedParams, Comparator.comparing(NameValuePair::getName));
1231 
1232         assertEquals(getExpectedAlerts().length, requestedParams.size());
1233 
1234         for (int i = 0; i < requestedParams.size(); i++) {
1235             assertEquals(getExpectedAlerts()[i],
1236                     requestedParams.get(i).getName() + '#' + requestedParams.get(i).getValue());
1237         }
1238     }
1239 
1240     /**
1241      * @throws Exception if the test fails
1242      */
1243     @Test
1244     @Alerts({"radioParam2#radioValue2", "selectParam#selectValue", "textParam#textValue",
1245              "textareaParam#textarea value"})
1246     public void submitUsingFormAttributeElementsDeclaredBeforeForm() throws Exception {
1247         final String html = DOCTYPE_HTML
1248             + "<html>\n"
1249             + "<head>\n"
1250             + "</head>\n"
1251             + "<body>\n"
1252 
1253             + "  <input form='formId' type='text' name='textParam' value='textValue'>\n"
1254 
1255             + "  <fieldset form='formId'>\n"
1256             + "    <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1257             + "    <input type='text' name='fieldsetTextParam' value='fieldsetTextValue'>\n"
1258             + "  </fieldset>\n"
1259 
1260             + "  <label for='radioId' form='formId'>Male</label>\n"
1261             + "  <input id='radioId' type='radio' name='radioParam' value='radioValue'>\n"
1262 
1263             + "  <input form='formId' type='radio' name='radioParam2' value='radioValue2' checked='checked'>\n"
1264 
1265             + "  <select form='formId' name='selectParam'>\n"
1266             + "    <option value='selectValue' selected='selected'>selected</option>\n"
1267             + "  </select>\n"
1268 
1269             + "  <textarea form='formId' name='textareaParam'>textarea value</textarea>\n"
1270 
1271             + "  <input form='formId' id='mySubmit' type='submit' value='Submit'>\n"
1272 
1273             + "  <form id='formId'>\n"
1274             + "  </form>\n"
1275 
1276             + "</body></html>";
1277 
1278         final WebDriver driver = loadPage2(html);
1279         driver.findElement(new ById("mySubmit")).click();
1280         if (useRealBrowser()) {
1281             Thread.sleep(400);
1282         }
1283 
1284         assertEquals(2, getMockWebConnection().getRequestCount());
1285 
1286         final List<NameValuePair> requestedParams =
1287                 getMockWebConnection().getLastWebRequest().getRequestParameters();
1288         Collections.sort(requestedParams, Comparator.comparing(NameValuePair::getName));
1289 
1290         assertEquals(getExpectedAlerts().length, requestedParams.size());
1291 
1292         for (int i = 0; i < requestedParams.size(); i++) {
1293             assertEquals(getExpectedAlerts()[i],
1294                     requestedParams.get(i).getName() + '#' + requestedParams.get(i).getValue());
1295         }
1296     }
1297 
1298     /**
1299      * @throws Exception if the test fails
1300      */
1301     @Test
1302     @Alerts("textParam#textValue")
1303     public void submitUsingFormAttributeElementsDeeplyNested() throws Exception {
1304         final String html = DOCTYPE_HTML
1305             + "<html>\n"
1306             + "<head>\n"
1307             + "</head>\n"
1308             + "<body>\n"
1309 
1310             + "  <form id='formId'>\n"
1311             + "  </form>\n"
1312 
1313             + "  <div><div><div><div>\n"
1314             + "    <input form='formId' type='text' name='textParam' value='textValue'>\n"
1315             + "  </div></div></div></div>\n"
1316 
1317             + "  <input form='formId' id='mySubmit' type='submit' value='Submit'>\n"
1318 
1319             + "</body></html>";
1320 
1321         final WebDriver driver = loadPage2(html);
1322         driver.findElement(new ById("mySubmit")).click();
1323         if (useRealBrowser()) {
1324             Thread.sleep(400);
1325         }
1326 
1327         assertEquals(2, getMockWebConnection().getRequestCount());
1328 
1329         final List<NameValuePair> requestedParams =
1330                 getMockWebConnection().getLastWebRequest().getRequestParameters();
1331         Collections.sort(requestedParams, Comparator.comparing(NameValuePair::getName));
1332 
1333         assertEquals(getExpectedAlerts().length, requestedParams.size());
1334 
1335         for (int i = 0; i < requestedParams.size(); i++) {
1336             assertEquals(getExpectedAlerts()[i],
1337                     requestedParams.get(i).getName() + '#' + requestedParams.get(i).getValue());
1338         }
1339     }
1340 
1341     /**
1342      * @throws Exception if the test fails
1343      */
1344     @Test
1345     @Alerts("hiddenParam#form1")
1346     public void submitFromInsideAnother() throws Exception {
1347         final String html = DOCTYPE_HTML
1348             + "<html>\n"
1349             + "<head>\n"
1350             + "</head>\n"
1351             + "<body>\n"
1352             + "  <form id='formId'>\n"
1353             + "    <input type='hidden' name='hiddenParam' value='form1'>\n"
1354             + "  </form>\n"
1355 
1356             + "  <form id='formId2'>\n"
1357             + "    <input type='hidden' name='hiddenParam' value='form2'>\n"
1358             + "    <input form='formId' id='mySubmit' type='submit' value='Submit'>\n"
1359             + "  </form>\n"
1360 
1361             + "</body></html>";
1362 
1363         final WebDriver driver = loadPage2(html);
1364         driver.findElement(new ById("mySubmit")).click();
1365         if (useRealBrowser()) {
1366             Thread.sleep(400);
1367         }
1368 
1369         assertEquals(2, getMockWebConnection().getRequestCount());
1370 
1371         final List<NameValuePair> requestedParams =
1372                 getMockWebConnection().getLastWebRequest().getRequestParameters();
1373         Collections.sort(requestedParams, Comparator.comparing(NameValuePair::getName));
1374 
1375         assertEquals(getExpectedAlerts().length, requestedParams.size());
1376 
1377         for (int i = 0; i < requestedParams.size(); i++) {
1378             assertEquals(getExpectedAlerts()[i],
1379                     requestedParams.get(i).getName() + '#' + requestedParams.get(i).getValue());
1380         }
1381     }
1382 
1383     /**
1384      * @throws Exception if the test fails
1385      */
1386     @Test
1387     @Alerts({})
1388     public void submitFromInsideAnotherInvalidFormRef() throws Exception {
1389         final String html = DOCTYPE_HTML
1390             + "<html>\n"
1391             + "<head>\n"
1392             + "</head>\n"
1393             + "<body>\n"
1394             + "  <form id='formId'>\n"
1395             + "    <input type='hidden' name='hiddenParam' value='form1'>\n"
1396             + "  </form>\n"
1397 
1398             + "  <form id='formId2'>\n"
1399             + "    <input type='hidden' name='hiddenParam' value='form2'>\n"
1400             + "    <input form='formIdInvalid' id='mySubmit' type='submit' value='Submit'>\n"
1401             + "  </form>\n"
1402 
1403             + "</body></html>";
1404 
1405         final WebDriver driver = loadPage2(html);
1406         driver.findElement(new ById("mySubmit")).click();
1407 
1408         assertEquals(1, getMockWebConnection().getRequestCount());
1409 
1410         final List<NameValuePair> requestedParams =
1411                 getMockWebConnection().getLastWebRequest().getRequestParameters();
1412         Collections.sort(requestedParams, Comparator.comparing(NameValuePair::getName));
1413 
1414         assertEquals(getExpectedAlerts().length, requestedParams.size());
1415 
1416         for (int i = 0; i < requestedParams.size(); i++) {
1417             assertEquals(getExpectedAlerts()[i],
1418                     requestedParams.get(i).getName() + '#' + requestedParams.get(i).getValue());
1419         }
1420     }
1421 
1422     /**
1423      * @throws Exception if the test fails
1424      */
1425     @Test
1426     @Alerts({"button#foo", "textfield#"})
1427     public void submit_NoDefaultValue() throws Exception {
1428         final String controls =
1429                 "  <input type='text' name='textfield'/>\n"
1430                 + "  <input type='submit' id='mySubmit' name='button' value='foo'/>\n";
1431 
1432         submitParams(controls);
1433     }
1434 
1435     /**
1436      * @throws Exception if the test fails
1437      */
1438     @Test
1439     @Alerts("button#foo")
1440     public void submit_NoNameOnControl() throws Exception {
1441         final String controls =
1442                 "  <input type='text' id='textfield' value='blah' />\n"
1443                 + "  <input type='submit' id='mySubmit' name='button' value='foo'/>\n";
1444 
1445         submitParams(controls);
1446     }
1447 
1448     /**
1449      * @throws Exception if the test fails
1450      */
1451     @Test
1452     @Alerts("textfield#blah")
1453     public void submit_NoNameOnButton() throws Exception {
1454         final String controls =
1455                 "  <input type='text' id='textfield' value='blah' name='textfield' />\n"
1456                 + "  <button type='submit' id='mySubmit' value='Go'>Go</button>\n";
1457 
1458         submitParams(controls);
1459     }
1460 
1461     /**
1462      * @throws Exception if the test fails
1463      */
1464     @Test
1465     @Alerts({"submit#submit", "textfield#blah", "textfield2#blaha"})
1466     public void submit_NestedInput() throws Exception {
1467         final String controls =
1468                 "  <table><tr><td>\n"
1469                 + "    <input type='text' name='textfield' value='blah'/>\n"
1470                 + "    </td><td>\n"
1471                 + "    <input type='text' name='textfield2' value='blaha'/>\n"
1472                 + "    </td></tr>\n"
1473 
1474                 + "    <tr><td>\n"
1475                 + "    <input type='submit' name='submit' id='mySubmit' value='submit'/>\n"
1476                 + "    </td><td></td></tr>\n"
1477                 + "  </table>\n";
1478 
1479         submitParams(controls);
1480     }
1481 
1482     /**
1483      * @throws Exception if the test fails
1484      */
1485     @Test
1486     @Alerts("submit#submit")
1487     public void submit_IgnoresDisabledControls() throws Exception {
1488         final String controls =
1489                 "  <input type='text' name='textfield' value='blah' disabled />\n"
1490                 + "  <input type='submit' name='submit' id='mySubmit' value='submit'/>\n";
1491 
1492         submitParams(controls);
1493     }
1494 
1495     /**
1496      * @throws Exception if the test fails
1497      */
1498     @Test
1499     @Alerts({"hidden#blah", "submit#submit"})
1500     public void submit_IgnoresDisabledHiddenControls() throws Exception {
1501         final String controls =
1502                 "  <input type='text' name='textfield' value='blah' disabled />\n"
1503                 + "  <input type='hidden' name='disabledHidden' value='blah' disabled />\n"
1504                 + "  <input type='hidden' name='hidden' value='blah' />\n"
1505                 + "  <input type='submit' name='submit' id='mySubmit' value='submit'/>\n";
1506 
1507         submitParams(controls);
1508     }
1509 
1510     /**
1511      * Reset buttons should not be submitted.
1512      * @see <a href="http://www.w3.org/TR/html4/interact/forms.html#h-17.13.2">Spec</a>
1513      * @throws Exception if the test fails
1514      */
1515     @Test
1516     @Alerts("submit#submit")
1517     public void submit_IgnoresResetControl() throws Exception {
1518         final String controls =
1519                 "  <input type='reset' name='reset' value='reset'/>\n"
1520                 + "  <input type='submit' name='submit' id='mySubmit' value='submit'/>\n";
1521 
1522         submitParams(controls);
1523     }
1524 
1525     /**
1526      * Reset buttons should not be submitted.
1527      * @see <a href="http://www.w3.org/TR/html4/interact/forms.html#h-17.13.2">Spec</a>
1528      * @throws Exception if the test fails
1529      */
1530     @Test
1531     @Alerts("submit#submit")
1532     public void submit_IgnoresResetButtonControl() throws Exception {
1533         final String controls =
1534                 "  <button type='reset' name='buttonreset' value='buttonreset'>Reset</button>\n"
1535                 + "  <input type='submit' name='submit' id='mySubmit' value='submit'/>\n";
1536 
1537         submitParams(controls);
1538     }
1539 
1540     private void submitParams(final String controls) throws Exception {
1541         final String html = DOCTYPE_HTML
1542             + "<html><head><title>foo</title></head><body>\n"
1543             + "<form id='form1' method='post'>\n"
1544             + controls
1545             + "</form></body></html>";
1546 
1547         final WebDriver driver = loadPage2(html);
1548         driver.findElement(new ById("mySubmit")).click();
1549         if (useRealBrowser()) {
1550             Thread.sleep(400);
1551         }
1552 
1553         assertEquals(2, getMockWebConnection().getRequestCount());
1554 
1555         final List<NameValuePair> requestedParams =
1556                 getMockWebConnection().getLastWebRequest().getRequestParameters();
1557         Collections.sort(requestedParams, Comparator.comparing(NameValuePair::getName));
1558 
1559         assertEquals(getExpectedAlerts().length, requestedParams.size());
1560 
1561         for (int i = 0; i < requestedParams.size(); i++) {
1562             assertEquals(getExpectedAlerts()[i],
1563                     requestedParams.get(i).getName() + '#' + requestedParams.get(i).getValue());
1564         }
1565     }
1566 
1567     /**
1568      * Tests the 'Referer' HTTP header.
1569      * @throws Exception on test failure
1570      */
1571     @Test
1572     @Alerts("§§URL§§index.html?test")
1573     public void submit_refererHeader() throws Exception {
1574         final String firstHtml = DOCTYPE_HTML
1575             + "<html><head><title>First</title></head><body>\n"
1576             + "<form method='post' action='" + URL_SECOND + "'>\n"
1577             + "<input name='button' type='submit' value='PushMe' id='button'/></form>\n"
1578             + "</body></html>";
1579         final String secondHtml = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
1580 
1581         expandExpectedAlertsVariables(URL_FIRST);
1582 
1583         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
1584 
1585         getMockWebConnection().setResponse(indexUrl, firstHtml);
1586         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
1587 
1588         final WebDriver driver = loadPage2(firstHtml, new URL(URL_FIRST.toString() + "index.html?test#ref"));
1589         driver.findElement(By.id("button")).click();
1590         if (useRealBrowser()) {
1591             Thread.sleep(400);
1592         }
1593 
1594         assertEquals(2, getMockWebConnection().getRequestCount());
1595 
1596         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
1597         assertEquals(getExpectedAlerts()[0], lastAdditionalHeaders.get(HttpHeader.REFERER));
1598     }
1599 
1600     /**
1601      * Tests the 'Referer' HTTP header for rel='noreferrer'.
1602      * @throws Exception on test failure
1603      */
1604     @Test
1605     @Alerts(DEFAULT = "§§URL§§index.html?test",
1606             FF = "null",
1607             FF_ESR = "null")
1608     public void submit_refererHeaderNoreferrer() throws Exception {
1609         final String firstHtml = DOCTYPE_HTML
1610             + "<html><head><title>First</title></head><body>\n"
1611             + "<form method='post' action='" + URL_SECOND + "' rel='noreferrer'>\n"
1612             + "<input name='button' type='submit' value='PushMe' id='button'/></form>\n"
1613             + "</body></html>";
1614         final String secondHtml = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
1615 
1616         expandExpectedAlertsVariables(URL_FIRST);
1617 
1618         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
1619 
1620         getMockWebConnection().setResponse(indexUrl, firstHtml);
1621         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
1622 
1623         final WebDriver driver = loadPage2(firstHtml, new URL(URL_FIRST.toString() + "index.html?test#ref"));
1624         driver.findElement(By.id("button")).click();
1625         if (useRealBrowser()) {
1626             Thread.sleep(400);
1627         }
1628 
1629         assertEquals(2, getMockWebConnection().getRequestCount());
1630 
1631         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
1632         assertEquals(getExpectedAlerts()[0], "" + lastAdditionalHeaders.get(HttpHeader.REFERER));
1633     }
1634 
1635     /**
1636      * Tests the 'Referer' HTTP header for rel='noreferrer'.
1637      * @throws Exception on test failure
1638      */
1639     @Test
1640     @Alerts(DEFAULT = "§§URL§§index.html?test",
1641             FF = "null",
1642             FF_ESR = "null")
1643     public void submit_refererHeaderNoreferrerCaseSensitive() throws Exception {
1644         final String firstHtml = DOCTYPE_HTML
1645             + "<html><head><title>First</title></head><body>\n"
1646             + "<form method='post' action='" + URL_SECOND + "' rel='NoReferrer'>\n"
1647             + "<input name='button' type='submit' value='PushMe' id='button'/></form>\n"
1648             + "</body></html>";
1649         final String secondHtml = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
1650 
1651         expandExpectedAlertsVariables(URL_FIRST);
1652 
1653         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
1654 
1655         getMockWebConnection().setResponse(indexUrl, firstHtml);
1656         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
1657 
1658         final WebDriver driver = loadPage2(firstHtml, new URL(URL_FIRST.toString() + "index.html?test#ref"));
1659         driver.findElement(By.id("button")).click();
1660         if (useRealBrowser()) {
1661             Thread.sleep(400);
1662         }
1663 
1664         assertEquals(2, getMockWebConnection().getRequestCount());
1665 
1666         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
1667         assertEquals(getExpectedAlerts()[0], "" + lastAdditionalHeaders.get(HttpHeader.REFERER));
1668     }
1669 
1670     /**
1671      * Tests the 'Referer' HTTP header for rel='noreferrer'.
1672      * @throws Exception on test failure
1673      */
1674     @Test
1675     @Alerts(DEFAULT = "§§URL§§index.html?test",
1676             FF = "null",
1677             FF_ESR = "null")
1678     public void submit_refererHeaderNoreferrerGet() throws Exception {
1679         final String firstHtml = DOCTYPE_HTML
1680             + "<html><head><title>First</title></head><body>\n"
1681             + "<form method='get' action='" + URL_SECOND + "' rel='NoReferrer'>\n"
1682             + "<input name='button' type='submit' value='PushMe' id='button'/></form>\n"
1683             + "</body></html>";
1684         final String secondHtml = DOCTYPE_HTML + "<html><head><title>Second</title></head><body></body></html>";
1685 
1686         expandExpectedAlertsVariables(URL_FIRST);
1687 
1688         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
1689 
1690         getMockWebConnection().setResponse(indexUrl, firstHtml);
1691         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
1692 
1693         final WebDriver driver = loadPage2(firstHtml, new URL(URL_FIRST.toString() + "index.html?test#ref"));
1694         driver.findElement(By.id("button")).click();
1695         if (useRealBrowser()) {
1696             Thread.sleep(400);
1697         }
1698 
1699         assertEquals(2, getMockWebConnection().getRequestCount());
1700 
1701         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
1702         assertEquals(getExpectedAlerts()[0], "" + lastAdditionalHeaders.get(HttpHeader.REFERER));
1703     }
1704 
1705     /**
1706      * @throws Exception on test failure
1707      */
1708     @Test
1709     @Alerts("NoReferrer")
1710     public void relAttribute() throws Exception {
1711         final String html = DOCTYPE_HTML
1712             + "<html><head></head>\n"
1713             + "<body>\n"
1714             + "<form method='get' action='" + URL_SECOND + "' rel='NoReferrer'>\n"
1715             + "  <input name='button' type='submit' value='PushMe' id='button'/>\n"
1716             + "</form>\n"
1717             + "<script>\n"
1718             + LOG_TITLE_FUNCTION
1719             + "  log(document.forms[0].rel);\n"
1720             + "</script>\n"
1721             + "</body></html>";
1722 
1723         loadPageVerifyTitle2(html);
1724     }
1725 
1726     /**
1727      * @throws Exception on test failure
1728      */
1729     @Test
1730     @Alerts({"[object HTMLFormElement]", "[object HTMLInputElement]", "true",
1731              "[object HTMLInputElement]", "true"})
1732     public void inputNameProperty() throws Exception {
1733         final String html = DOCTYPE_HTML
1734             + "<html>\n"
1735             + "<head></head>\n"
1736             + "<body>\n"
1737             + "  <form id='testForm' name='testForm' action='/dosomething\' method='POST'>\n"
1738             + "    <input type='submit' name='button' value='PushMe' id='button'/>\n"
1739             + "    <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1740             + "  </form>\n"
1741             + "<script>\n"
1742             + LOG_TITLE_FUNCTION
1743             + "  log(testForm);\n"
1744             + "  log(testForm.button);\n"
1745             + "  log(testForm.button !== undefined);\n"
1746             + "  log(testForm.hiddenParam);\n"
1747             + "  log(testForm.hiddenParam !== undefined);\n"
1748             + "</script>\n"
1749             + "</body></html>";
1750 
1751         loadPageVerifyTitle2(html);
1752     }
1753 
1754     /**
1755      * @throws Exception on test failure
1756      */
1757     @Test
1758     @Alerts({"[object HTMLFormElement]", "[object HTMLInputElement]", "true",
1759              "[object HTMLInputElement]", "true"})
1760     public void inputHasOwnProperty() throws Exception {
1761         final String html = DOCTYPE_HTML
1762             + "<html>\n"
1763             + "<head></head>\n"
1764             + "<body>\n"
1765             + "  <form id='testForm' name='testForm' action='/dosomething\' method='POST'>\n"
1766             + "    <input type='submit' name='button' value='PushMe' id='button'/>\n"
1767             + "    <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1768             + "  </form>\n"
1769             + "<script>\n"
1770             + LOG_TITLE_FUNCTION
1771             + "  log(testForm);\n"
1772             + "  log(testForm.button);\n"
1773             + "  log(testForm.hasOwnProperty('button'));\n"
1774             + "  log(testForm.hiddenParam);\n"
1775             + "  log(testForm.hasOwnProperty('hiddenParam'));\n"
1776             + "</script>\n"
1777             + "</body></html>";
1778 
1779         loadPageVerifyTitle2(html);
1780     }
1781 
1782 
1783     /**
1784      * @throws Exception on test failure
1785      */
1786     @Test
1787     @Alerts({"[object HTMLFormElement]", "[object HTMLInputElement]",
1788              "undefined", "undefined", "[object HTMLInputElement]", "true", "false", "false",
1789              "undefined", "undefined", "[object HTMLInputElement]", "true", "false", "false"})
1790     public void inputGetOwnPropertyDescriptor() throws Exception {
1791         final String html = DOCTYPE_HTML
1792             + "<html>\n"
1793             + "<head></head>\n"
1794             + "<body>\n"
1795             + "  <form id='testForm' name='testForm' action='/dosomething\' method='POST'>\n"
1796             + "    <input type='submit' name='button' value='PushMe' id='button'/>\n"
1797             + "    <input type='hidden' name='hiddenParam' value='hiddenValue'>\n"
1798             + "  </form>\n"
1799             + "<script>\n"
1800             + LOG_TITLE_FUNCTION
1801             + "  log(testForm);\n"
1802             + "  log(testForm.button);\n"
1803 
1804             + "  var prop = Object.getOwnPropertyDescriptor(testForm, 'button');\n"
1805             + "  log(prop.get);\n"
1806             + "  log(prop.set);\n"
1807             + "  log(prop.value);\n"
1808             + "  log(prop.configurable);\n"
1809             + "  log(prop.enumerable);\n"
1810             + "  log(prop.writable);\n"
1811 
1812             + "  prop = Object.getOwnPropertyDescriptor(testForm, 'hiddenParam');\n"
1813             + "  log(prop.get);\n"
1814             + "  log(prop.set);\n"
1815             + "  log(prop.value);\n"
1816             + "  log(prop.configurable);\n"
1817             + "  log(prop.enumerable);\n"
1818             + "  log(prop.writable);\n"
1819 
1820             + "</script>\n"
1821             + "</body></html>";
1822 
1823         loadPageVerifyTitle2(html);
1824     }
1825 
1826     /**
1827      * @throws Exception if the test fails
1828      */
1829     @Test
1830     @Alerts("second/?hiddenName=hiddenValue")
1831     public void inputHiddenAdded() throws Exception {
1832         final String html = DOCTYPE_HTML
1833             + "<html><head></head>\n"
1834             + "<body>\n"
1835             + "  <p>hello world</p>\n"
1836             + "  <form id='myForm' method='GET' action='" + URL_SECOND + "'>\n"
1837             + "    <input id='myButton' type='submit' />\n"
1838             + "  </form>\n"
1839             + "  <script>\n"
1840             + "    var i = document.createElement('input');\n"
1841             + "    i.setAttribute('type', 'hidden');\n"
1842             + "    i.setAttribute('id', 'hiddenId');\n"
1843             + "    i.setAttribute('name', 'hiddenName');\n"
1844             + "    i.setAttribute('value', 'hiddenValue');\n"
1845 
1846             + "    var f = document.getElementById('myForm');\n"
1847             + "    f.appendChild(i);\n"
1848             + "  </script>\n"
1849             + "</body></html>";
1850 
1851         final String secondContent = "second content";
1852         getMockWebConnection().setResponse(URL_SECOND, secondContent);
1853 
1854         final WebDriver driver = loadPage2(html);
1855         driver.findElement(By.id("myButton")).click();
1856         if (useRealBrowser()) {
1857             Thread.sleep(400);
1858         }
1859 
1860         assertEquals(2, getMockWebConnection().getRequestCount());
1861 
1862         final String url = getMockWebConnection().getLastWebRequest().getUrl().toExternalForm();
1863         assertTrue(url.endsWith(getExpectedAlerts()[0]));
1864     }
1865 
1866     /**
1867      * @throws Exception if the test page can't be loaded
1868      */
1869     @Test
1870     @Alerts({"2", "inp", "submitButton"})
1871     public void elements() throws Exception {
1872         final String html = DOCTYPE_HTML
1873             + "<html><head>\n"
1874             + "<script>\n"
1875             + LOG_TITLE_FUNCTION
1876             + "  function test() {\n"
1877             + "    log(document.forms[0].elements.length);\n"
1878             + "    log(document.forms[0].elements[0].id);\n"
1879             + "    log(document.forms[0].elements[1].id);\n"
1880             + "  }\n"
1881             + "</script>\n"
1882             + "</head>\n"
1883             + "<body onload='test()'>\n"
1884             + "<form id='form1' method='get' action='foo'>\n"
1885             + "  <input name='field1' value='val1' id='inp'/>\n"
1886             + "  <input type='submit' id='submitButton'/>\n"
1887             + "</form>\n"
1888             + "</body></html>";
1889 
1890         loadPageVerifyTitle2(html);
1891     }
1892 
1893     /**
1894      * @throws Exception if the test page can't be loaded
1895      */
1896     @Test
1897     @Alerts({"1", "[object HTMLInputElement]"})
1898     public void elementsDetached() throws Exception {
1899         final String html = DOCTYPE_HTML
1900             + "<html><head>\n"
1901             + "<script>\n"
1902             + LOG_TITLE_FUNCTION
1903             + "  function test() {\n"
1904             + "    let frm = document.createElement('form');\n"
1905             + "    frm.appendChild(document.createElement('input'));\n"
1906             + "    frm.remove();\n"
1907             + "    log(frm.elements.length);\n"
1908             + "    log(frm.elements[0]);\n"
1909             + "  }\n"
1910             + "</script>\n"
1911             + "</head>\n"
1912             + "<body onload='test()'>\n"
1913             + "</body></html>";
1914 
1915         loadPageVerifyTitle2(html);
1916     }
1917 
1918     /**
1919      * @throws Exception if the test page can't be loaded
1920      */
1921     @Test
1922     @Alerts({"2", "inpt1", "inpt2", "1", "inpt1"})
1923     public void elementsDetachedFormAttribute() throws Exception {
1924         final String html = DOCTYPE_HTML
1925             + "<html><head>\n"
1926             + "<script>\n"
1927             + LOG_TITLE_FUNCTION
1928             + "  function test() {\n"
1929             + "    let frm = document.getElementById('formId');\n"
1930 
1931             + "    log(frm.elements.length);\n"
1932             + "    log(frm.elements[0].id);\n"
1933             + "    log(frm.elements[1].id);\n"
1934 
1935             + "    frm.remove();\n"
1936             + "    log(frm.elements.length);\n"
1937             + "    log(frm.elements[0].id);\n"
1938             + "  }\n"
1939             + "</script>\n"
1940             + "</head>\n"
1941             + "<body onload='test()'>\n"
1942             + "  <form id='formId'>\n"
1943             + "    <input id='inpt1' type='text' name='textParam' value='textValue'>\n"
1944             + "  </form>\n"
1945 
1946             + "  <input form='formId' id='inpt2' type='text' name='textParam' value='textValue'>\n"
1947             + "</body></html>";
1948 
1949         loadPageVerifyTitle2(html);
1950     }
1951 
1952     /**
1953      * @throws Exception if the test fails
1954      */
1955     @Test
1956     public void submitRequestCharset() throws Exception {
1957         submitRequestCharset("utf-8", null, null, null, ISO_8859_1);
1958         submitRequestCharset(null, "utf-8", null, null, ISO_8859_1);
1959         submitRequestCharset("iso-8859-1", null, "utf-8", null, ISO_8859_1);
1960         submitRequestCharset("iso-8859-1", null, "utf-8, iso-8859-1", null, ISO_8859_1);
1961         submitRequestCharset("utf-8", null, "iso-8859-1 utf-8", null, ISO_8859_1);
1962         submitRequestCharset("iso-8859-1", null, "utf-8, iso-8859-1", null, ISO_8859_1);
1963     }
1964 
1965     /**
1966      * @throws Exception if the test fails
1967      */
1968     @Test
1969     public void submitRequestCharsetTextPlain() throws Exception {
1970         submitRequestCharset("utf-8", null, null, "text/plain", null);
1971         submitRequestCharset(null, "utf-8", null, "text/plain", null);
1972         submitRequestCharset("iso-8859-1", null, "utf-8", "text/plain", null);
1973         submitRequestCharset("iso-8859-1", null, "utf-8, iso-8859-1", "text/plain", null);
1974         submitRequestCharset("utf-8", null, "iso-8859-1 utf-8", "text/plain", null);
1975         submitRequestCharset("iso-8859-1", null, "utf-8, iso-8859-1", "text/plain", null);
1976     }
1977 
1978     /**
1979      * @throws Exception if the test fails
1980      */
1981     @Test
1982     public void submitRequestCharsetMultipartFormData() throws Exception {
1983         submitRequestCharset("utf-8", null, null, "multipart/form-data", null);
1984         submitRequestCharset(null, "utf-8", null, "multipart/form-data", null);
1985         submitRequestCharset("iso-8859-1", null, "utf-8", "multipart/form-data", null);
1986         submitRequestCharset("iso-8859-1", null, "utf-8, iso-8859-1", "multipart/form-data", null);
1987         submitRequestCharset("utf-8", null, "iso-8859-1 utf-8", "multipart/form-data", null);
1988         submitRequestCharset("iso-8859-1", null, "utf-8, iso-8859-1", "multipart/form-data", null);
1989     }
1990 
1991     /**
1992      * Utility for {@link #submitRequestCharset()}
1993      * @param headerCharset the charset for the content type header if not null
1994      * @param metaCharset the charset for the meta http-equiv content type tag if not null
1995      * @param formCharset the charset for the form's accept-charset attribute if not null
1996      * @param expectedRequestCharset the charset expected for the form submission
1997      * @throws Exception if the test fails
1998      */
1999     private void submitRequestCharset(final String headerCharset,
2000             final String metaCharset, final String formCharset,
2001             final String formEnctype,
2002             final Charset expectedRequestCharset) throws Exception {
2003 
2004         final String formAcceptCharset;
2005         if (formCharset == null) {
2006             formAcceptCharset = "";
2007         }
2008         else {
2009             formAcceptCharset = " accept-charset='" + formCharset + "'";
2010         }
2011 
2012         final String formEnc;
2013         if (formEnctype == null) {
2014             formEnc = "";
2015         }
2016         else {
2017             formEnc = " enctype='" + formEnctype + "'";
2018         }
2019 
2020         final String metaContentType;
2021         if (metaCharset == null) {
2022             metaContentType = "";
2023         }
2024         else {
2025             metaContentType = "<meta http-equiv='Content-Type' content='text/html; charset="
2026                 + metaCharset + "'>\n";
2027         }
2028 
2029         final String html = DOCTYPE_HTML
2030             + "<html><head><title>foo</title>\n"
2031             + metaContentType
2032             + "</head><body>\n"
2033             + "<form name='form1' method='post' action='foo'" + formAcceptCharset + formEnc + ">\n"
2034             + "<input type='text' name='textField' value='foo'/>\n"
2035             + "<input type='text' name='nonAscii' value='Flo\u00DFfahrt'/>\n"
2036             + "<input type='submit' name='button' id='myButton' value='foo'/>\n"
2037             + "</form></body></html>";
2038 
2039         String contentType = MimeType.TEXT_HTML;
2040         if (headerCharset != null) {
2041             contentType += ";charset=" + headerCharset;
2042         }
2043         getMockWebConnection().setDefaultResponse(html, 200, "ok", contentType);
2044 
2045         final WebDriver driver = loadPage2(URL_FIRST, null);
2046         driver.findElement(By.id("myButton")).click();
2047         if (useRealBrowser()) {
2048             Thread.sleep(400);
2049         }
2050 
2051         assertSame(expectedRequestCharset, getMockWebConnection().getLastWebRequest().getCharset());
2052 
2053         if (driver instanceof HtmlUnitDriver) {
2054             final WebClient webClient = ((HtmlUnitDriver) driver).getWebClient();
2055 
2056             final HtmlPage page = webClient.getPage(URL_FIRST);
2057 
2058             final HtmlForm form = page.getFormByName("form1");
2059             form.getInputByName("button").click();
2060 
2061             assertSame(expectedRequestCharset, getMockWebConnection().getLastWebRequest().getCharset());
2062         }
2063     }
2064 }