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