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.javascript.host.html;
16  
17  import static java.nio.charset.StandardCharsets.ISO_8859_1;
18  import static java.nio.charset.StandardCharsets.UTF_16;
19  import static java.nio.charset.StandardCharsets.UTF_8;
20  import static org.junit.jupiter.api.Assertions.fail;
21  
22  import java.io.File;
23  import java.net.URL;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.htmlunit.FormEncodingType;
27  import org.htmlunit.HttpHeader;
28  import org.htmlunit.MockWebConnection;
29  import org.htmlunit.WebDriverTestCase;
30  import org.htmlunit.junit.annotation.Alerts;
31  import org.htmlunit.junit.annotation.HtmlUnitNYI;
32  import org.htmlunit.util.MimeType;
33  import org.junit.jupiter.api.Test;
34  import org.openqa.selenium.By;
35  import org.openqa.selenium.NoSuchWindowException;
36  import org.openqa.selenium.WebDriver;
37  import org.openqa.selenium.WebElement;
38  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
39  
40  /**
41   * Tests for {@link HTMLFormElement}.
42   *
43   * @author Mike Bowler
44   * @author David K. Taylor
45   * @author Marc Guillemot
46   * @author Chris Erskine
47   * @author Ahmed Ashour
48   * @author Ronald Brill
49   * @author Frank Danek
50   */
51  public class HTMLFormElementTest extends WebDriverTestCase {
52  
53      /**
54       * @throws Exception if the test fails
55       */
56      @Test
57      @Alerts({"16", "button1", "button2", "checkbox1", "fileupload1", "hidden1",
58               "radio1", "radio1",
59               "select1", "select2", "password1", "reset1",
60               "reset2", "submit1", "submit2", "textInput1", "textarea1"})
61      public void elementsAccessor() throws Exception {
62          final String html = DOCTYPE_HTML
63              + "<html><head><script>\n"
64              + LOG_TITLE_FUNCTION
65              + "function doTest() {\n"
66              + "  log(document.form1.length);\n"
67              + "  for (var i = 0; i < document.form1.length; i++) {\n"
68              + "    var element = document.form1.elements[i];\n"
69              + "    if (element.type != 'radio' && element != document.form1[element.name]) {\n"
70              + "      log('name index not working for ' + element.name);\n"
71              + "    }\n"
72              + "    log(element.name);\n"
73              + "  }\n"
74              + "}\n"
75              + "</script></head><body onload='doTest()'>\n"
76              + "<p>hello world</p>\n"
77              + "<form name='form1'>\n"
78              + "  <input type='button' name='button1' />\n"
79              + "  <button type='button' name='button2'>button2</button>\n"
80              + "  <input type='checkbox' name='checkbox1' />\n"
81              + "  <input type='file' name='fileupload1' />\n"
82              + "  <input type='hidden' name='hidden1' />\n"
83              + "  <input type='radio' name='radio1' value='1' />\n"
84              + "  <input type='radio' name='radio1' value='2' />\n"
85              + "  <select name='select1'>\n"
86              + "    <option>foo</option>\n"
87              + "  </select>\n"
88              + "  <select multiple='multiple' name='select2'>\n"
89              + "    <option>foo</option>\n"
90              + "  </select>\n"
91              + "  <input type='password' name='password1' />\n"
92              + "  <input type='reset' name='reset1' />\n"
93              + "  <button type='reset' name='reset2'>reset2</button>\n"
94              + "  <input type='submit' name='submit1' />\n"
95              + "  <button type='submit' name='submit2'>submit2</button>\n"
96              + "  <input type='text' name='textInput1' />\n"
97              + "  <textarea name='textarea1'>foo</textarea>\n"
98              + "</form>\n"
99              + "</body></html>";
100 
101         loadPageVerifyTitle2(html);
102     }
103 
104     /**
105      * @throws Exception if the test fails
106      */
107     @Test
108     @Alerts({"undefined", "undefined"})
109     public void elementsAccessorOutOfBound() throws Exception {
110         final String html = DOCTYPE_HTML
111             + "<html><head><script>\n"
112             + LOG_TITLE_FUNCTION
113             + "function doTest() {\n"
114             + "  log(document.form1[-1]);\n"
115             + "  log(document.form1[2]);\n"
116             + "}\n"
117             + "</script></head><body onload='doTest()'>\n"
118             + "<form name='form1'>\n"
119             + "  <input type='button' name='button1'/>\n"
120             + "  <input type='submit' name='submit1'/>\n"
121             + "</form>\n"
122             + "</body></html>";
123 
124         loadPageVerifyTitle2(html);
125     }
126 
127     /**
128      * @throws Exception if the test fails
129      */
130     @Test
131     @Alerts({"3", "textInput1", "button1", "textInput3"})
132     public void elementsAccessorFormAttribute() throws Exception {
133         final String html = DOCTYPE_HTML
134             + "<html><head><script>\n"
135             + LOG_TITLE_FUNCTION
136             + "function doTest() {\n"
137             + "  log(document.form1.length);\n"
138             + "  for (var i = 0; i < document.form1.length; i++) {\n"
139             + "    var element = document.form1.elements[i];\n"
140             + "    log(element.name);\n"
141             + "  }\n"
142             + "}\n"
143             + "</script></head>\n"
144             + "<body onload='doTest()'>\n"
145 
146             + "<input type='text' name='textInput1' form='myForm'/>\n"
147             + "<input type='text' name='textInput2' form='form1'/>\n"
148 
149             + "<form id='myForm' name='form1'>\n"
150             + "  <input type='button' name='button1' />\n"
151             + "</form>\n"
152 
153             + "<input type='text' name='textInput3' form='myForm'/>\n"
154             + "<input type='text' name='textInput4' form='form1'/>\n"
155             + "</body></html>";
156 
157         loadPageVerifyTitle2(html);
158     }
159 
160     /**
161      * @throws Exception if the test fails
162      */
163     @Test
164     @Alerts({"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false",
165              "undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false"})
166     public void formAccessorOwnPropertyDescriptor() throws Exception {
167         final String html = DOCTYPE_HTML
168             + "<html><head><script>\n"
169             + LOG_TITLE_FUNCTION
170             + "function doTest() {\n"
171             + "  let desc = Object.getOwnPropertyDescriptor(document.form1, 'buttonId');\n"
172             + "  log(desc.get + '/' + desc.set);\n"
173             + "  log(typeof desc.value + '/' + desc.value);\n"
174             + "  log('W-' + desc.writable);\n"
175             + "  log('C-' + desc.configurable);\n"
176             + "  log('E-' + desc.enumerable);\n"
177 
178             + "  desc = Object.getOwnPropertyDescriptor(document.form1, 'buttonName');\n"
179             + "  log(desc.get + '/' + desc.set);\n"
180             + "  log(typeof desc.value + '/' + desc.value);\n"
181             + "  log('W-' + desc.writable);\n"
182             + "  log('C-' + desc.configurable);\n"
183             + "  log('E-' + desc.enumerable);\n"
184             + "}\n"
185             + "</script></head>\n"
186             + "<body onload='doTest()'>\n"
187 
188             + "<form id='myForm' name='form1'>\n"
189             + "  <input type='button' name='buttonName' id='buttonId' />\n"
190             + "</form>\n"
191             + "</body></html>";
192 
193         loadPageVerifyTitle2(html);
194     }
195 
196     /**
197      * @throws Exception if the test fails
198      */
199     @Test
200     @Alerts(DEFAULT = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true",
201                        "undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true"},
202             FF = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false",
203                   "undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false"},
204             FF_ESR = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false",
205                       "undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-false"})
206     @HtmlUnitNYI(
207             FF = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true",
208                   "undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true"},
209             FF_ESR = {"undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true",
210                       "undefined/undefined", "object/[object HTMLInputElement]", "W-false", "C-true", "E-true"})
211     public void elementsAccessorOwnPropertyDescriptor() throws Exception {
212         final String html = DOCTYPE_HTML
213             + "<html><head><script>\n"
214             + LOG_TITLE_FUNCTION
215             + "function doTest() {\n"
216             + "  let desc = Object.getOwnPropertyDescriptor(document.form1.elements, 'buttonId');\n"
217             + "  log(desc.get + '/' + desc.set);\n"
218             + "  log(typeof desc.value + '/' + desc.value);\n"
219             + "  log('W-' + desc.writable);\n"
220             + "  log('C-' + desc.configurable);\n"
221             + "  log('E-' + desc.enumerable);\n"
222 
223             + "  desc = Object.getOwnPropertyDescriptor(document.form1.elements, 'buttonName');\n"
224             + "  log(desc.get + '/' + desc.set);\n"
225             + "  log(typeof desc.value + '/' + desc.value);\n"
226             + "  log('W-' + desc.writable);\n"
227             + "  log('C-' + desc.configurable);\n"
228             + "  log('E-' + desc.enumerable);\n"
229             + "}\n"
230             + "</script></head>\n"
231             + "<body onload='doTest()'>\n"
232 
233             + "<form id='myForm' name='form1'>\n"
234             + "  <input type='button' name='buttonName' id='buttonId' />\n"
235             + "</form>\n"
236             + "</body></html>";
237 
238         loadPageVerifyTitle2(html);
239     }
240 
241     /**
242      * @throws Exception if the test fails
243      */
244     @Test
245     @Alerts({"3", "1", "2", "3"})
246     public void radioButtonArray() throws Exception {
247         final String html = DOCTYPE_HTML
248             + "<html><head><script>\n"
249             + LOG_TITLE_FUNCTION
250             + "function doTest() {\n"
251             + "  var radioArray = document.form1['radio1'];\n"
252             + "  log(radioArray.length);\n"
253             + "  for (var i = 0; i < radioArray.length; i++) {\n"
254             + "    var element = radioArray[i];\n"
255             + "    log(element.value);\n"
256             + "  }\n"
257             + "}\n"
258             + "</script></head>\n"
259             + "<body onload='doTest()'>\n"
260             + "<p>hello world</p>\n"
261             + "<form name='form1'>\n"
262             + "  <input type='radio' name='radio1' value='1'/>\n"
263             + "  <input type='radio' name='radio1' value='2'/>\n"
264             + "  <input type='radio' name='radio1' value='3'/>\n"
265             + "</form>\n"
266             + "</body></html>";
267 
268         loadPageVerifyTitle2(html);
269     }
270 
271     /**
272      * If there is only one radio button with a specified name then that radio
273      * button will be returned for the name, not an array of radio buttons. Test
274      * this.
275      * @throws Exception if the test fails
276      */
277     @Test
278     @Alerts("1")
279     public void radioButton_OnlyOne() throws Exception {
280         final String html = DOCTYPE_HTML
281             + "<html><head><script>\n"
282             + LOG_TITLE_FUNCTION
283             + "function doTest() {\n"
284             + "  log(document.form1['radio1'].value);\n"
285             + "}\n"
286             + "</script></head>\n"
287             + "<body onload='doTest()'>\n"
288             + "<p>hello world</p>\n"
289             + "<form name='form1'>\n"
290             + "  <input type='radio' name='radio1' value='1'/>\n"
291             + "</form>\n"
292             + "</body></html>";
293 
294         loadPageVerifyTitle2(html);
295     }
296 
297     /**
298      * @throws Exception if the test fails
299      */
300     @Test
301     @Alerts({"http://foo.com/", "mailto:me@bar.com", "mailto:me@bar.com"})
302     public void actionProperty() throws Exception {
303         doTestProperty("action", "action", "http://foo.com/", "mailto:me@bar.com");
304     }
305 
306     /**
307      * @throws Exception if the test fails
308      */
309     @Test
310     @Alerts({"myForm", "testForm", "testForm"})
311     public void nameProperty() throws Exception {
312         doTestProperty("name", "name", "myForm", "testForm");
313     }
314 
315     /**
316      * @throws Exception if the test fails
317      */
318     @Test
319     @Alerts("application/x-www-form-urlencoded")
320     public void defaultEnctype() throws Exception {
321         enctype(null);
322     }
323 
324     /**
325      * @throws Exception if the test fails
326      */
327     @Test
328     @Alerts("application/x-www-form-urlencoded")
329     public void emptyEnctype() throws Exception {
330         enctype("");
331     }
332 
333     /**
334      * @throws Exception if the test fails
335      */
336     @Test
337     @Alerts("application/x-www-form-urlencoded")
338     public void blankEnctype() throws Exception {
339         enctype(" ");
340     }
341 
342     /**
343      * @throws Exception if the test fails
344      */
345     @Test
346     @Alerts("application/x-www-form-urlencoded")
347     public void unknownEnctype() throws Exception {
348         enctype("unknown");
349     }
350 
351     /**
352      * @throws Exception if the test fails
353      */
354     @Test
355     @Alerts("application/x-www-form-urlencoded")
356     public void urlencodedEnctype() throws Exception {
357         enctype("application/x-www-form-urlencoded");
358     }
359 
360     /**
361      * @throws Exception if the test fails
362      */
363     @Test
364     @Alerts("multipart/form-data")
365     public void multipartEnctype() throws Exception {
366         enctype("multipart/form-data");
367     }
368 
369     /**
370      * @throws Exception if the test fails
371      */
372     @Test
373     @Alerts("text/plain")
374     public void plainEnctype() throws Exception {
375         enctype("text/plain");
376     }
377 
378     /**
379      * @throws Exception if the test fails
380      */
381     @Test
382     @Alerts("application/x-www-form-urlencoded")
383     public void xmlEnctype() throws Exception {
384         enctype("text/xml");
385     }
386 
387     /**
388      * @throws Exception if the test fails
389      */
390     @Test
391     @Alerts("application/x-www-form-urlencoded")
392     public void jsonEnctype() throws Exception {
393         enctype("application/json");
394     }
395 
396     private void enctype(final String encoding) throws Exception {
397         String html = DOCTYPE_HTML
398             + "<html><head><script>\n"
399             + LOG_TITLE_FUNCTION
400             + "function doTest() {\n"
401             + "  log(document.forms[0].encoding);\n"
402             + "}\n"
403             + "</script></head><body onload='doTest()'>\n"
404             + "<form name='testForm'";
405         if (null != encoding) {
406             html = html + " enctype='" + encoding + "'";
407         }
408         html = html + ">\n"
409             + "    <input type='submit' name='submit1'/>\n"
410             + "</form>\n"
411             + "</body></html>";
412 
413         loadPageVerifyTitle2(html);
414     }
415 
416     /**
417      * @throws Exception if the test fails
418      */
419     @Test
420     @Alerts({"application/x-www-form-urlencoded",
421              "application/x-www-form-urlencoded",
422              "application/x-www-form-urlencoded"})
423     public void jsDefaultEnctype() throws Exception {
424         jsEnctype(null);
425         jsEncoding(null);
426     }
427 
428     /**
429      * @throws Exception if the test fails
430      */
431     @Test
432     @Alerts({"application/x-www-form-urlencoded",
433              "application/x-www-form-urlencoded",
434              "application/x-www-form-urlencoded"})
435     public void jsEmptyEnctype() throws Exception {
436         jsEnctype("");
437         jsEncoding("");
438     }
439 
440     /**
441      * @throws Exception if the test fails
442      */
443     @Test
444     @Alerts({"application/x-www-form-urlencoded",
445              "application/x-www-form-urlencoded",
446              "application/x-www-form-urlencoded"})
447     public void jsBlankEnctype() throws Exception {
448         jsEnctype(" ");
449         jsEncoding(" ");
450     }
451 
452     /**
453      * @throws Exception if the test fails
454      */
455     @Test
456     @Alerts({"application/x-www-form-urlencoded",
457              "application/x-www-form-urlencoded",
458              "application/x-www-form-urlencoded"})
459     public void jsUnknownEnctype() throws Exception {
460         jsEnctype("unknown");
461         jsEncoding("unknown");
462     }
463 
464     /**
465      * @throws Exception if the test fails
466      */
467     @Test
468     @Alerts({"application/x-www-form-urlencoded",
469              "application/x-www-form-urlencoded",
470              "application/x-www-form-urlencoded"})
471     public void jsUrlencodedEnctype() throws Exception {
472         jsEnctype("application/x-www-form-urlencoded");
473         jsEncoding("application/x-www-form-urlencoded");
474     }
475 
476     /**
477      * @throws Exception if the test fails
478      */
479     @Test
480     @Alerts({"multipart/form-data", "multipart/form-data", "multipart/form-data"})
481     public void jsMultipartEnctype() throws Exception {
482         jsEnctype("multipart/form-data");
483         jsEncoding("multipart/form-data");
484     }
485 
486     /**
487      * @throws Exception if the test fails
488      */
489     @Test
490     @Alerts({"text/plain", "text/plain", "text/plain"})
491     public void jsPlainEnctype() throws Exception {
492         jsEnctype("text/plain");
493         jsEncoding("text/plain");
494     }
495 
496     /**
497      * @throws Exception if the test fails
498      */
499     @Test
500     @Alerts({"application/x-www-form-urlencoded",
501              "application/x-www-form-urlencoded",
502              "application/x-www-form-urlencoded"})
503     public void jsXmlEnctype() throws Exception {
504         jsEnctype("text/xml");
505         jsEncoding("text/xml");
506     }
507 
508     /**
509      * @throws Exception if the test fails
510      */
511     @Test
512     @Alerts({"application/x-www-form-urlencoded",
513              "application/x-www-form-urlencoded",
514              "application/x-www-form-urlencoded"})
515     public void jsJsonEnctype() throws Exception {
516         jsEnctype("application/json");
517         jsEncoding("application/json");
518     }
519 
520     private void jsEnctype(final String enctype) throws Exception {
521         final String html = DOCTYPE_HTML
522             + "<html>\n"
523             + "<head>\n"
524             + "  <script>\n"
525             + LOG_TITLE_FUNCTION
526             + "  function doTest() {\n"
527             + "    try {\n"
528             + "      document.forms[0].enctype = '" + enctype + "';\n"
529             + "      log(document.forms[0].enctype);\n"
530             + "    } catch(e) { logEx(e); }\n"
531             + "    log(document.forms[0].encoding);\n"
532             + "  }\n"
533             + "  </script>\n"
534             + "</head>\n"
535             + "<body onload='doTest()'>\n"
536             + "  <form id='testForm' name='testForm' method='post' action = 'page2.html'>\n"
537             + "    <input type='submit' name='submit1' />\n"
538             + "  </form>\n"
539             + "</body></html>";
540 
541         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
542 
543         final WebDriver driver = loadPage2(html);
544         verifyTitle2(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0], getExpectedAlerts()[1]});
545 
546         driver.findElement(By.name("submit1")).click();
547         if (useRealBrowser()) {
548             Thread.sleep(400);
549         }
550         assertTitle(driver, "Response");
551         String headerValue = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
552             .get(HttpHeader.CONTENT_TYPE);
553 
554         if (headerValue.startsWith(FormEncodingType.MULTIPART.getName())) {
555             // Can't test equality for multipart/form-data as it will have the form:
556             // multipart/form-data; boundary=---------------------------42937861433140731107235900
557             headerValue = StringUtils.substringBefore(headerValue, ";");
558             assertEquals(getExpectedAlerts()[2], headerValue);
559         }
560         else {
561             assertEquals(getExpectedAlerts()[2], headerValue);
562         }
563     }
564 
565     private void jsEncoding(final String encoding) throws Exception {
566         final String html = DOCTYPE_HTML
567             + "<html>\n"
568             + "<head>\n"
569             + "  <script>\n"
570             + LOG_TITLE_FUNCTION
571             + "  function doTest() {\n"
572             + "    try {\n"
573             + "      document.forms[0].encoding = '" + encoding + "';\n"
574             + "      log(document.forms[0].encoding);\n"
575             + "    } catch(e) { logEx(e); }\n"
576             + "    log(document.forms[0].enctype);\n"
577             + "  }\n"
578             + "  </script>\n"
579             + "</head>\n"
580             + "<body onload='doTest()'>\n"
581             + "  <form id='testForm' name='testForm' method='post' action = 'page2.html'>\n"
582             + "    <input type='submit' name='submit1' />\n"
583             + "  </form>\n"
584             + "</body></html>";
585 
586         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
587 
588         final WebDriver driver = loadPage2(html);
589         verifyTitle2(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0], getExpectedAlerts()[1]});
590 
591         driver.findElement(By.name("submit1")).click();
592         if (useRealBrowser()) {
593             Thread.sleep(400);
594         }
595         assertTitle(driver, "Response");
596         String headerValue = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
597             .get(HttpHeader.CONTENT_TYPE);
598         if (headerValue.startsWith(FormEncodingType.MULTIPART.getName())) {
599             // Can't test equality for multipart/form-data as it will have the form:
600             // multipart/form-data; boundary=---------------------------42937861433140731107235900
601             headerValue = StringUtils.substringBefore(headerValue, ";");
602             assertEquals(getExpectedAlerts()[2], headerValue);
603         }
604         else {
605             assertEquals(getExpectedAlerts()[2], headerValue);
606         }
607     }
608 
609     /**
610      * @throws Exception if the test fails
611      */
612     @Test
613     @Alerts({"multipart/form-data", "application/x-www-form-urlencoded", "application/x-www-form-urlencoded"})
614     public void encodingProperty() throws Exception {
615         doTestProperty("encoding", "enctype", "multipart/form-data", "application/x-www-form-urlencoded");
616     }
617 
618     /**
619      * @throws Exception if the test fails
620      */
621     @Test
622     @Alerts({"text/plain", "application/x-www-form-urlencoded", "newEncoding"})
623     public void encodingProperty_textPlain() throws Exception {
624         doTestProperty("encoding", "enctype", MimeType.TEXT_PLAIN, "newEncoding");
625     }
626 
627     /**
628      * @throws Exception if the test fails
629      */
630     @Test
631     @Alerts({"application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "newEncoding"})
632     public void encodingProperty_dummyValues() throws Exception {
633         doTestProperty("encoding", "enctype", "myEncoding", "newEncoding");
634     }
635 
636     /**
637      * @throws Exception if the test fails
638      */
639     @Test
640     @Alerts({"get", "post", "post"})
641     public void methodProperty() throws Exception {
642         doTestProperty("method", "method", "get", "post");
643     }
644 
645     /**
646      * @throws Exception if the test fails
647      */
648     @Test
649     @Alerts({"_top", "_parent", "_parent"})
650     public void targetProperty() throws Exception {
651         doTestProperty("target", "target", "_top", "_parent");
652     }
653 
654     private void doTestProperty(final String jsProperty, final String htmlProperty,
655             final String oldValue, final String newValue) throws Exception {
656 
657         final String html = DOCTYPE_HTML
658             + "<html><head><script>\n"
659             + LOG_TITLE_FUNCTION
660             + "function doTest() {\n"
661             + "  log(document.forms[0]." + jsProperty + ");\n"
662             + "  try {\n"
663             + "    document.forms[0]." + jsProperty + "='" + newValue + "';\n"
664             + "    log(document.forms[0]." + jsProperty + ");\n"
665             + "    log(document.forms[0].getAttribute('" + htmlProperty + "'));\n"
666             + "  } catch(e) { logEx(e); }\n"
667             + "}\n"
668             + "</script></head><body onload='doTest()'>\n"
669             + "<p>hello world</p>\n"
670             + "<form " + htmlProperty + "='" + oldValue + "'>\n"
671             + "  <input type='button' name='button1' />\n"
672             + "</form>\n"
673             + "</body></html>";
674 
675         final WebDriver wd = loadPageVerifyTitle2(html);
676 
677         final WebElement form = wd.findElement(By.xpath("//form"));
678         if (wd instanceof HtmlUnitDriver && getExpectedAlerts().length >= 3) {
679             // form.getAttribute("enctype") returns form.getAttribute("encoding") with the FF driver. Bug or feature?
680             assertEquals(getExpectedAlerts()[2], form.getAttribute(htmlProperty));
681         }
682     }
683 
684     /**
685      * @throws Exception if the test fails
686      */
687     @Test
688     @Alerts({"id2", "foo"})
689     public void inputNamedId() throws Exception {
690         doTestInputWithName("id");
691     }
692 
693     /**
694      * @throws Exception if the test fails
695      */
696     @Test
697     @Alerts({"action2", "foo"})
698     public void inputNamedAction() throws Exception {
699         doTestInputWithName("action");
700     }
701 
702     private void doTestInputWithName(final String name) throws Exception {
703         final String html = DOCTYPE_HTML
704             + "<html><head><script>\n"
705             + LOG_TITLE_FUNCTION
706             + "function go() {\n"
707             + "  log(document.simple_form." + name + ".value);\n"
708             + "  document.simple_form." + name + ".value = 'foo';\n"
709             + "  log(document.simple_form." + name + ".value);\n"
710             + "}</script></head>\n"
711             + "<body onload='go()'>\n"
712             + "<p>hello world</p>\n"
713             + "<form action='login.jsp' name='simple_form'>\n"
714             + "  <input name='" + name + "' type='hidden' value='" + name + "2'>\n"
715             + "</form>\n"
716             + "</body></html>";
717 
718         loadPageVerifyTitle2(html);
719     }
720 
721     /**
722      * Regression test that used to blow up on page load.
723      * @throws Exception if the test fails
724      */
725     @Test
726     @Alerts("value = 2")
727     public void accessingRadioButtonArrayByName_Regression() throws Exception {
728         final String html = DOCTYPE_HTML
729             + "<html><head></head>\n"
730             + "<body><form name='whatsnew'>\n"
731             + "<input type='radio' name='second' value='1'>\n"
732             + "<input type='radio' name='second' value='2' checked>\n"
733             + "</form><script>\n"
734             + LOG_TITLE_FUNCTION
735             + "clickAction();\n"
736             + "function clickAction() {\n"
737             + "  var value = -1;\n"
738             + "  radios = document.forms['whatsnew'].elements['second'];\n"
739             + "  for (var i = 0; i < radios.length; i++){\n"
740             + "    if (radios[i].checked == true) {\n"
741             + "      value = radios[i].value;\n"
742             + "      break;\n"
743             + "    }\n"
744             + "  }\n"
745             + "  log('value = ' + value);\n"
746             + "}\n"
747             + "</script></body></html>";
748 
749         loadPageVerifyTitle2(html);
750     }
751 
752     /**
753      * Test for a bug that appeared when visiting mail.yahoo.com. Setting the value of one input
754      * seems to blow away the other input. Also tests that the form input collection does not get
755      * cached before the document is finished loading.
756      * @throws Exception if the test fails
757      */
758     @Test
759     @Alerts("foo")
760     public void findInputWithoutTypeDefined() throws Exception {
761         final String html = DOCTYPE_HTML
762             + "<html><head>\n"
763             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
764             + "</head>\n"
765             + "<body onload='log(document.simple_form.login.value);'>\n"
766             + "<p>hello world</p><table><tr><td>\n"
767             + "<form action='login.jsp' name='simple_form'>\n"
768             + "  <input name='msg' type='hidden' value='0'>\n"
769             + "  <script>document.simple_form.msg.value = 1</script>\n"
770             + "  <input name='login' size='17' value='foo'>\n"
771             + "</form></td></tr></table>\n"
772             + "</body></html>";
773 
774         loadPageVerifyTitle2(html);
775     }
776 
777     /**
778      * Test form.length - This method does not count the type=image
779      * input tags.
780      * @throws Exception if the test fails
781      */
782     @Test
783     @Alerts("2")
784     public void length() throws Exception {
785         final String html = DOCTYPE_HTML
786             + "<html><head><script>\n"
787             + LOG_TITLE_FUNCTION
788             + "function doTest() {\n"
789             + "  log(document.form1.length);\n"
790             + "}\n"
791             + "</script></head><body onload='doTest()'>\n"
792             + "<form name='form1'>\n"
793             + "  <input type='radio' name='radio1' value='1'/>\n"
794             + "  <input type='image' src='foo' value='1'/>\n"
795             + "  <input type='submit' name='submit1' value='1'/>\n"
796             + "</form>\n"
797             + "</body></html>";
798 
799         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
800 
801         loadPageVerifyTitle2(html);
802     }
803 
804     /**
805      * @throws Exception if the test fails
806      */
807     @Test
808     @Alerts("button1")
809     public void get() throws Exception {
810         final String html = DOCTYPE_HTML
811             + "<html><head><script>\n"
812             + LOG_TITLE_FUNCTION
813             + "function doTest() {\n"
814             + "  log(document.form1[0].name);\n"
815             + "}\n"
816             + "</script></head><body onload='doTest()'>\n"
817             + "<p>hello world</p>\n"
818             + "<form name='form1'>\n"
819             + "  <input type='button' name='button1' />\n"
820             + "</form>\n"
821             + "</body></html>";
822 
823         loadPageVerifyTitle2(html);
824     }
825 
826     /**
827      * Test that the elements collection is live.
828      * @throws Exception if the test fails
829      */
830     @Test
831     @Alerts({"0", "1", "1", "true"})
832     public void elementsLive() throws Exception {
833         final String html = DOCTYPE_HTML
834             + "<html>\n"
835             + "<body>\n"
836             + "<form name='myForm'>\n"
837             + "<script>\n"
838             + LOG_TITLE_FUNCTION
839             + "var oElements = document.myForm.elements;\n"
840             + "log(oElements.length);\n"
841             + "</script>\n"
842             + "<input type='text' name='foo'/>\n"
843             + "<script>\n"
844             + "log(oElements.length);\n"
845             + "log(document.myForm.elements.length);\n"
846             + "log(oElements == document.myForm.elements);\n"
847             + "</script>\n"
848             + "</form>\n"
849             + "</body>\n"
850             + "</html>";
851 
852         loadPageVerifyTitle2(html);
853     }
854 
855     /**
856      * @throws Exception if the test fails
857      */
858     @Test
859     @Alerts({"1", "[object HTMLInputElement]/txt"})
860     public void elementsInputImage() throws Exception {
861         final String html = DOCTYPE_HTML
862             + "<html>\n"
863             + "<body>\n"
864             + "<form name='myForm'>\n"
865             + "  <input type='text' name='foo' id='txt'/>\n"
866             + "  <input type='image' name='fooo' id='img'/>\n"
867             + "</form>\n"
868 
869             + "<script>\n"
870             + LOG_TITLE_FUNCTION
871             + "var oElements = document.myForm.elements;\n"
872             + "log(oElements.length);\n"
873             + "log(oElements[0] + '/' + oElements[0].id);\n"
874             + "</script>\n"
875             + "</body>\n"
876             + "</html>";
877 
878         loadPageVerifyTitle2(html);
879     }
880 
881     /**
882      * @throws Exception if the test fails
883      */
884     @Test
885     @Alerts("0")
886     public void elementsImage() throws Exception {
887         final String html = DOCTYPE_HTML
888             + "<html>\n"
889             + "<body>\n"
890             + "<form name='myForm'>\n"
891             + "  <img name='foo' id='txt'>\n"
892             + "</form>\n"
893 
894             + "<script>\n"
895             + LOG_TITLE_FUNCTION
896             + "var oElements = document.myForm.elements;\n"
897             + "log(oElements.length);\n"
898             + "</script>\n"
899             + "</body>\n"
900             + "</html>";
901 
902         loadPageVerifyTitle2(html);
903     }
904 
905     /**
906      * @throws Exception if the test fails
907      */
908     @Test
909     @Alerts({"1", "[object HTMLOutputElement]"})
910     public void elementsOutput() throws Exception {
911         final String html = DOCTYPE_HTML
912             + "<html>\n"
913             + "<body>\n"
914             + "<form name='myForm'>\n"
915             + "  <output name='result'>60</output>\n"
916             + "</form>\n"
917 
918             + "<script>\n"
919             + LOG_TITLE_FUNCTION
920             + "var oElements = document.myForm.elements;\n"
921             + "log(oElements.length);\n"
922             + "log(oElements[0]);\n"
923             + "</script>\n"
924             + "</body>\n"
925             + "</html>";
926 
927         loadPageVerifyTitle2(html);
928     }
929 
930     /**
931      * @throws Exception if the test fails
932      */
933     @Test
934     @Alerts({"2", "[object HTMLFieldSetElement]", "[object HTMLInputElement]"})
935     public void elementsFieldSet() throws Exception {
936         final String html = DOCTYPE_HTML
937             + "<html>\n"
938             + "<body>\n"
939             + "<form name='myForm'>\n"
940             + "  <fieldset id='fs'>\n"
941             + "    <legend>Legend</legend>\n"
942             + "    <input type='text' name='foo'/>\n"
943             + "  </fieldset>\n"
944             + "</form>\n"
945 
946             + "<script>\n"
947             + LOG_TITLE_FUNCTION
948             + "var oElements = document.myForm.elements;\n"
949             + "log(oElements.length);\n"
950             + "log(oElements[0]);\n"
951             + "log(oElements[1]);\n"
952             + "</script>\n"
953             + "</body>\n"
954             + "</html>";
955 
956         loadPageVerifyTitle2(html);
957     }
958 
959     /**
960      * @throws Exception if the test fails
961      */
962     @Test
963     @Alerts({"2", "[object HTMLFieldSetElement]", "[object HTMLInputElement]"})
964     public void elementsFieldSetEmpty() throws Exception {
965         final String html = DOCTYPE_HTML
966             + "<html>\n"
967             + "<body>\n"
968             + "<form name='myForm'>\n"
969             + "  <fieldset id='fs'>\n"
970             + "  </fieldset>\n"
971             + "  <input type='text' name='foo'/>\n"
972             + "</form>\n"
973 
974             + "<script>\n"
975             + LOG_TITLE_FUNCTION
976             + "var oElements = document.myForm.elements;\n"
977             + "log(oElements.length);\n"
978             + "log(oElements[0]);\n"
979             + "log(oElements[1]);\n"
980             + "</script>\n"
981             + "</body>\n"
982             + "</html>";
983 
984         loadPageVerifyTitle2(html);
985     }
986 
987     /**
988      * @throws Exception if the test fails
989      */
990     @Test
991     @Alerts({"4", "[object HTMLFieldSetElement]/fs_outer",
992              "[object HTMLInputElement]/foo",
993              "[object HTMLFieldSetElement]/fs_inner",
994              "[object HTMLInputElement]/fooo"})
995     public void elementsFieldSetInsideFieldSet() throws Exception {
996         final String html = DOCTYPE_HTML
997             + "<html>\n"
998             + "<body>\n"
999             + "<form name='myForm'>\n"
1000             + "  <fieldset id='fs_outer'>\n"
1001             + "    <legend>Legend</legend>\n"
1002             + "    <input type='text' name='foo' id='foo'/>\n"
1003 
1004             + "    <fieldset id='fs_inner'>\n"
1005             + "      <input type='text' name='fooo' id='fooo'/>\n"
1006             + "    </fieldset>\n"
1007             + "  </fieldset>\n"
1008             + "</form>\n"
1009 
1010             + "<script>\n"
1011             + LOG_TITLE_FUNCTION
1012             + "var oElements = document.myForm.elements;\n"
1013             + "log(oElements.length);\n"
1014             + "log(oElements[0] + '/' + oElements[0].id);\n"
1015             + "log(oElements[1] + '/' + oElements[1].id);\n"
1016             + "log(oElements[2] + '/' + oElements[2].id);\n"
1017             + "log(oElements[3] + '/' + oElements[3].id);\n"
1018             + "</script>\n"
1019             + "</body>\n"
1020             + "</html>";
1021 
1022         loadPageVerifyTitle2(html);
1023     }
1024 
1025     /**
1026      * @throws Exception if the test fails
1027      */
1028     @Test
1029     @Alerts("§§URL§§foo.html")
1030     public void getFormFromFormsById() throws Exception {
1031         final String html = DOCTYPE_HTML
1032             + "<html>\n"
1033             + "<head>\n"
1034             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
1035             + "</head>\n"
1036             + "<body onload=\"log(document.forms['myForm'].action)\">\n"
1037             + "<form id='myForm' action='foo.html'>\n"
1038             + "</form>\n"
1039             + "</body>\n"
1040             + "</html>";
1041 
1042         expandExpectedAlertsVariables(URL_FIRST);
1043         loadPageVerifyTitle2(html);
1044     }
1045 
1046     /**
1047      * @throws Exception if the test fails
1048      */
1049     @Test
1050     @Alerts("§§URL§§")
1051     public void action() throws Exception {
1052         final String html = DOCTYPE_HTML
1053             + "<html>\n"
1054             + "<head>\n"
1055             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
1056             + "</head>\n"
1057             + "<body onload=\"log(document.forms['myForm'].action)\">\n"
1058             + "<form id='myForm'>\n"
1059             + "</form>\n"
1060             + "</body>\n"
1061             + "</html>";
1062 
1063         expandExpectedAlertsVariables(URL_FIRST);
1064         loadPageVerifyTitle2(html);
1065     }
1066 
1067     /**
1068      * @throws Exception if the test fails
1069      */
1070     @Test
1071     @Alerts("§§URL§§")
1072     public void actionEmpty() throws Exception {
1073         final String html = DOCTYPE_HTML
1074             + "<html>\n"
1075             + "<head>\n"
1076             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
1077             + "</head>\n"
1078             + "<body onload=\"log(document.forms['myForm'].action)\">\n"
1079             + "<form id='myForm' action=''>\n"
1080             + "</form>\n"
1081             + "</body>\n"
1082             + "</html>";
1083 
1084         expandExpectedAlertsVariables(URL_FIRST);
1085         loadPageVerifyTitle2(html);
1086     }
1087 
1088     /**
1089      * @throws Exception if the test fails
1090      */
1091     @Test
1092     @Alerts("§§URL§§")
1093     public void actionBlank() throws Exception {
1094         final String html = DOCTYPE_HTML
1095             + "<html>\n"
1096             + "<head>\n"
1097             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
1098             + "</head>\n"
1099             + "<body onload=\"log(document.forms['myForm'].action)\">\n"
1100             + "<form id='myForm' action='  '>\n"
1101             + "</form>\n"
1102             + "</body>\n"
1103             + "</html>";
1104 
1105         expandExpectedAlertsVariables(URL_FIRST);
1106         loadPageVerifyTitle2(html);
1107     }
1108 
1109     /**
1110      * @throws Exception if the test fails
1111      */
1112     @Test
1113     @Alerts("text")
1114     public void getFieldNamedLikeForm() throws Exception {
1115         final String html = DOCTYPE_HTML
1116             + "<html>\n"
1117             + "<head>\n"
1118             + "<script>" + LOG_TITLE_FUNCTION + "</script>\n"
1119             + "</head>\n"
1120             + "<body onload='log(document.login.login.type)'>\n"
1121             + "<form name='login' action='foo.html'>\n"
1122             + "<input name='login' type='text'>\n"
1123             + "</form>\n"
1124             + "</body>\n"
1125             + "</html>";
1126 
1127         loadPageVerifyTitle2(html);
1128     }
1129 
1130     /**
1131      * Verifies that document.myForm.submit returns a field name submit or the submit function
1132      * depending on the sort of the field named submit.
1133      * @throws Exception if the test fails
1134      */
1135     @Test
1136     public void fieldNamedSubmit() throws Exception {
1137         fieldNamedSubmit("<input type='text' name='submit'>\n", "INPUT");
1138         fieldNamedSubmit("<input type='password' name='submit'>\n", "INPUT");
1139         fieldNamedSubmit("<input type='submit' name='submit'>\n", "INPUT");
1140         fieldNamedSubmit("<input type='radio' name='submit'>\n", "INPUT");
1141         fieldNamedSubmit("<input type='checkbox' name='submit'>\n", "INPUT");
1142         fieldNamedSubmit("<input type='button' name='submit'>\n", "INPUT");
1143         fieldNamedSubmit("<button type='submit' name='submit'>\n", "BUTTON");
1144         fieldNamedSubmit("<textarea name='submit'></textarea>\n", "TEXTAREA");
1145         fieldNamedSubmit("<select name='submit'></select>\n", "SELECT");
1146 
1147         fieldNamedSubmit("<input type='image' name='submit'>\n", "function");
1148         fieldNamedSubmit("<input type='IMAGE' name='submit'>\n", "function");
1149         fieldNamedSubmit("<input type='IMAGE' name='submit'>\n", "function");
1150 
1151         fieldNamedSubmit("<fieldset name='submit'><legend>Legend</legend></fieldset>\n", "FIELDSET");
1152 
1153         fieldNamedSubmit("<object name='submit'></object>\n", "OBJECT");
1154 
1155         fieldNamedSubmit("<output name='submit'></output>\n", "OUTPUT");
1156 
1157         fieldNamedSubmit("<img name='submit'>\n", "IMG");
1158     }
1159 
1160     /**
1161      * @param htmlSnippet the HTML to embed in the test
1162      * @param expected the expected alert
1163      * @throws Exception if the test fails
1164      */
1165     private void fieldNamedSubmit(final String htmlSnippet, final String expected) throws Exception {
1166         final String html = DOCTYPE_HTML
1167             + "<html>\n"
1168             + "<head>\n"
1169             + "<script>\n"
1170             + LOG_TITLE_FUNCTION
1171             + "function test() {\n"
1172             + "  if (document.login.submit.tagName)\n"
1173             + "    log(document.login.submit.tagName);\n"
1174             + "  else"
1175             + "    log('function');\n"
1176             + "}\n"
1177             + "</script>\n"
1178             + "</head>\n"
1179             + "<body onload='test()'>\n"
1180             + "<form name='login' action='foo.html'>\n"
1181             + htmlSnippet
1182             + "</form>\n"
1183             + "</body>\n"
1184             + "</html>";
1185 
1186         setExpectedAlerts(expected);
1187         loadPageVerifyTitle2(html);
1188     }
1189 
1190     /**
1191      * @throws Exception if the test fails
1192      */
1193     @Test
1194     @Alerts({"before", "2", "undefined"})
1195     public void fieldFoundWithId() throws Exception {
1196         final String html = DOCTYPE_HTML
1197             + "<html><head>\n"
1198             + "<script>\n"
1199             + LOG_TITLE_FUNCTION
1200             + "function test() {\n"
1201             + "  log(IRForm.IRText.value);\n"
1202             + "  log(IRForm.myField.length);\n"
1203             + "  log(IRForm.myDiv);\n"
1204             + "}\n"
1205             + "</script>\n"
1206             + "</head>\n"
1207             + "<body onload='test()'>\n"
1208             + "  <form name='IRForm' action='#'>\n"
1209             + "    <input type='text' id='IRText' value='before'/>\n"
1210             + "    <input type='image' name='myField' src='foo.gif'/>\n"
1211             + "    <input type='image' id='myField' src='foo.gif'/>\n"
1212             + "    <input type='text' name='myField'/>\n"
1213             + "    <input type='text' id='myField'/>\n"
1214             + "    <div id='myDiv'>oooo</div>\n"
1215             + "  </form>\n"
1216             + "</body>\n"
1217             + "</html>";
1218 
1219         loadPageVerifyTitle2(html);
1220     }
1221 
1222     /**
1223      * @throws Exception if the test fails
1224      */
1225     @Test
1226     @Alerts({"[object HTMLInputElement]", "[object HTMLInputElement]"})
1227     public void fieldFoundWithIdByReference() throws Exception {
1228         final String html = DOCTYPE_HTML
1229             + "<html><head>\n"
1230             + "<script>\n"
1231             + LOG_TITLE_FUNCTION
1232             + "function test() {\n"
1233             + "  log(IRForm.IRText);\n"
1234             + "  log(IRForm.myField);\n"
1235             + "}\n"
1236             + "</script>\n"
1237             + "</head>\n"
1238             + "<body onload='test()'>\n"
1239             + "  <form name='IRForm' id='testForm' action='#'>\n"
1240             + "  </form>\n"
1241             + "  <input type='text' id='IRText' value='abc' form='testForm' />\n"
1242             + "  <input type='text' id='myField' value='xy' form='testForm'/>\n"
1243             + "</body>\n"
1244             + "</html>";
1245 
1246         loadPageVerifyTitle2(html);
1247     }
1248 
1249     /**
1250      * @throws Exception if the test fails
1251      */
1252     @Test
1253     @Alerts({"INPUT", "idImg1", "img2", "true"})
1254     public void nonFieldChildFound() throws Exception {
1255         final String html = DOCTYPE_HTML
1256             + "<html><head>\n"
1257             + "<script>\n"
1258             + LOG_TITLE_FUNCTION
1259             + "function test() {\n"
1260             + "  var oForm = document.testForm;\n"
1261             + "  log(oForm.img.tagName);\n"
1262             + "  log(oForm.img1.id);\n"
1263             + "  log(oForm.img2.id);\n"
1264             + "  log(oForm.testSpan == undefined);\n"
1265             + "}\n"
1266             + "</script>\n"
1267             + "</head>\n"
1268             + "<body onload='test()'>\n"
1269             + "  <form name='testForm' action='foo'>\n"
1270             + "    <input type='text' id='img' value='before'/>\n"
1271             + "    <img name='img' id='idImg' src='foo.png'/>\n"
1272             + "    <img name='img1' id='idImg1' src='foo.png'/>\n"
1273             + "    <img id='img2' src='foo.png'/>\n"
1274             + "    <span id='testSpan'>foo</span>\n"
1275             + "  </form>\n"
1276             + "</body>\n"
1277             + "</html>";
1278 
1279         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
1280 
1281         loadPageVerifyTitle2(html);
1282     }
1283 
1284     /**
1285      * @throws Exception if the test fails
1286      */
1287     @Test
1288     @Alerts({"[object HTMLImageElement]", "[object HTMLImageElement]"})
1289     public void findImageWhenNotDirectChild() throws Exception {
1290         final String html = DOCTYPE_HTML
1291             + "<html>\n"
1292             + "<head>\n"
1293             + "<script>\n"
1294             + LOG_TITLE_FUNCTION
1295             + "function doTest() {\n"
1296             + "  log(document.fmLogin.myImgName);\n"
1297             + "  log(document.fmLogin.myImgId);\n"
1298             + "}\n"
1299             + "</script>\n"
1300             + "</head>\n"
1301             + "<body onload='doTest()'>\n"
1302             + "  <form name='fmLogin' action='doLogin' method='POST'>\n"
1303             + "    <div>\n"
1304             + "      <img name='myImgName' src='somewhere'>\n"
1305             + "      <img id='myImgId' src='somewhere'>\n"
1306             + "    <div/>\n"
1307             + "  </form>\n"
1308             + "</body></html>";
1309 
1310         loadPageVerifyTitle2(html);
1311     }
1312 
1313     /**
1314      * This test shows a problem in current implementation of host object with visible constructors
1315      * used to retrieve JS object associated to a particular DOM node. The general problem needs
1316      * later.
1317      * @throws Exception if the test fails
1318      */
1319     @Test
1320     public void formIsNotAConstructor() throws Exception {
1321         final String html = DOCTYPE_HTML
1322             + "<html><head>\n"
1323             + "<script>\n"
1324             + "var Form = {};\n"
1325             + "function test() {\n"
1326             + "  document.getElementById('formId');\n"
1327             + "}\n"
1328             + "</script></head>\n"
1329             + "<body onload='test()'>\n"
1330             + "  <form id='formId' name='formName'>\n"
1331             + "    <input type='text' name='field1' value='barney'>\n"
1332             + "    <input type='submit'>\n"
1333             + "</body>\n"
1334             + "</html>";
1335         loadPageWithAlerts2(html);
1336     }
1337 
1338     /**
1339      * Test that the form from the right page is returned after browsing.
1340      * Regression test for
1341      * http://sourceforge.net/p/htmlunit/bugs/417/
1342      * @throws Exception if the test fails
1343      */
1344     @Test
1345     @Alerts({"page 1: formPage1", "page 2: formPage2"})
1346     public void formAccessAfterBrowsing() throws Exception {
1347         final String html = DOCTYPE_HTML
1348             + "<html><head>\n"
1349             + "<script>\n"
1350             + "function test() {\n"
1351             + "  window.name = 'page 1: ' + document.forms[0].name;\n"
1352             + "  document.location = 'page2.html';\n"
1353             + "}\n"
1354             + "</script>\n"
1355             + "</head><body onload='test()'>\n"
1356             + "<form name='formPage1' action='foo'>\n"
1357             + "</form>\n"
1358             + "</body></html>";
1359         final String secondContent = DOCTYPE_HTML
1360             + "<html><head>\n"
1361             + "<script>\n"
1362             + LOG_TITLE_FUNCTION
1363             + "function test() {\n"
1364             + "  log(window.name);\n"
1365             + "  log('page 2: ' + document.forms[0].name);\n"
1366             + "}\n"
1367             + "</script>\n"
1368             + "</head><body onload='test()'>\n"
1369             + "<form name='formPage2' action='foo'>\n"
1370             + "</form>\n"
1371             + "</body></html>";
1372 
1373         getMockWebConnection().setDefaultResponse(secondContent);
1374         loadPageVerifyTitle2(html);
1375     }
1376 
1377     /**
1378      * @throws Exception if the test fails
1379      */
1380     @Test
1381     @Alerts({"function handler() {}", "null", "null"})
1382     public void onsubmitNull() throws Exception {
1383         final String html = DOCTYPE_HTML
1384             + "<html><head>\n"
1385             + "<script>\n"
1386             + LOG_TITLE_FUNCTION
1387             + "  function handler() {}\n"
1388             + "  function test() {\n"
1389             + "    var form = document.getElementById('myForm');\n"
1390             + "    form.onsubmit = handler;\n"
1391             + "    log(String(form.onsubmit).replace(/\\n/g, ''));\n"
1392             + "    form.onsubmit = null;\n"
1393             + "    log(form.onsubmit);\n"
1394             + "    try {\n"
1395             + "      form.onsubmit = undefined;\n"
1396             + "      log(form.onsubmit);\n"
1397             + "    } catch(e) { logEx(e); }\n"
1398             + "  }\n"
1399             + "</script>\n"
1400             + "<body onload=test()>\n"
1401             + "  <form id='myForm'></form>\n"
1402             + "</body></html>";
1403 
1404         loadPageVerifyTitle2(html);
1405     }
1406 
1407     /**
1408      * @throws Exception if the test fails
1409      */
1410     @Test
1411     @Alerts({"page1.html", "page2.html", "page1.html", "page1.html"})
1412     public void changeFormActionAfterSubmit() throws Exception {
1413         final String[] expectedFiles = getExpectedAlerts();
1414         setExpectedAlerts();
1415 
1416         changeFormActionAfterSubmit("input type='button' value='Test'", expectedFiles[0]);
1417         changeFormActionAfterSubmit("input type='submit' value='Test'", expectedFiles[1]);
1418         changeFormActionAfterSubmit("input type='text' value='Test'", expectedFiles[2]);
1419         changeFormActionAfterSubmit("div", expectedFiles[3]);
1420     }
1421 
1422     private void changeFormActionAfterSubmit(final String clickable, final String expectedFile) throws Exception {
1423         final String html = DOCTYPE_HTML
1424             + "<html>\n"
1425             + "<head>\n"
1426             + "  <script type='text/javascript'>\n"
1427             + "    function submitForm() {\n"
1428             + "      document.myForm.submit();\n"
1429             + "      document.myForm.action = 'page2.html';\n"
1430             + "    }\n"
1431             + "  </script>\n"
1432             + "</head>\n"
1433             + "<body>\n"
1434             + "  <form action='page1.html' name='myForm'>\n"
1435             + "    <" + clickable + " id='x' onclick='submitForm();'>foo\n"
1436             + "  </form>\n"
1437             + "</body>\n"
1438             + "</html>";
1439 
1440         getMockWebConnection().setDefaultResponse("");
1441         final WebDriver driver = loadPageWithAlerts2(html);
1442         driver.findElement(By.id("x")).click();
1443         if (useRealBrowser()) {
1444             Thread.sleep(400);
1445         }
1446         assertEquals(URL_FIRST + expectedFile, driver.getCurrentUrl().replaceAll("\\?", ""));
1447     }
1448 
1449     /**
1450      * @throws Exception if the test fails
1451      */
1452     @Test
1453     @Alerts("TypeError")
1454     public void item() throws Exception {
1455         final String html = DOCTYPE_HTML
1456             + "<html>\n"
1457             + "<head>\n"
1458             + "  <script>\n"
1459             + LOG_TITLE_FUNCTION
1460             + "    function test() {\n"
1461             + "      try {\n"
1462             + "        log(document.forms['myForm'].item('myRadio').type);\n"
1463             + "      } catch(e) { logEx(e) }\n"
1464             + "    }\n"
1465             + "  </script>\n"
1466             + "</head>\n"
1467             + "<body onload='test()'>\n"
1468             + "  <form action='page1.html' name='myForm'>\n"
1469             + "    <input type='radio' name='myRadio'>\n"
1470             + "  </form>\n"
1471             + "</body>\n"
1472             + "</html>";
1473 
1474         loadPageVerifyTitle2(html);
1475     }
1476 
1477     /**
1478      * @throws Exception if the test fails
1479      */
1480     @Test
1481     @Alerts("TypeError")
1482     public void item_many() throws Exception {
1483         final String html = DOCTYPE_HTML
1484             + "<html>\n"
1485             + "<head>\n"
1486             + "  <script>\n"
1487             + LOG_TITLE_FUNCTION
1488             + "    function test() {\n"
1489             + "      try {\n"
1490             + "        log(document.forms['myForm'].item('myRadio').length);\n"
1491             + "      } catch(e) { logEx(e) }\n"
1492             + "    }\n"
1493             + "  </script>\n"
1494             + "</head>\n"
1495             + "<body onload='test()'>\n"
1496             + "  <form action='page1.html' name='myForm'>\n"
1497             + "    <input type='radio' name='myRadio'>\n"
1498             + "    <input type='radio' name='myRadio'>\n"
1499             + "  </form>\n"
1500             + "</body>\n"
1501             + "</html>";
1502 
1503         loadPageVerifyTitle2(html);
1504     }
1505 
1506     /**
1507      * @throws Exception if the test fails
1508      */
1509     @Test
1510     @Alerts("TypeError")
1511     public void item_many_subindex() throws Exception {
1512         final String html = DOCTYPE_HTML
1513             + "<html>\n"
1514             + "<head>\n"
1515             + "  <script>\n"
1516             + LOG_TITLE_FUNCTION
1517             + "    function test() {\n"
1518             + "      try {\n"
1519             + "        log(document.forms['myForm'].item('myRadio', 1).id);\n"
1520             + "      } catch(e) { logEx(e) }\n"
1521             + "    }\n"
1522             + "  </script>\n"
1523             + "</head>\n"
1524             + "<body onload='test()'>\n"
1525             + "  <form action='page1.html' name='myForm'>\n"
1526             + "    <input type='radio' name='myRadio' id='radio1'>\n"
1527             + "    <input type='radio' name='myRadio' id='radio2'>\n"
1528             + "  </form>\n"
1529             + "</body>\n"
1530             + "</html>";
1531 
1532         loadPageVerifyTitle2(html);
1533     }
1534 
1535     /**
1536      * @throws Exception if the test fails
1537      */
1538     @Test
1539     @Alerts("TypeError")
1540     public void item_integer() throws Exception {
1541         final String html = DOCTYPE_HTML
1542             + "<html>\n"
1543             + "<head>\n"
1544             + "  <script>\n"
1545             + LOG_TITLE_FUNCTION
1546             + "    function test() {\n"
1547             + "      try {\n"
1548             + "        log(document.forms['myForm'].item(1).id);\n"
1549             + "      } catch(e) { logEx(e) }\n"
1550             + "    }\n"
1551             + "  </script>\n"
1552             + "</head>\n"
1553             + "<body onload='test()'>\n"
1554             + "  <form action='page1.html' name='myForm'>\n"
1555             + "    <input type='radio' name='myRadio' id='radio1'>\n"
1556             + "    <input type='radio' name='myRadio' id='radio2'>\n"
1557             + "  </form>\n"
1558             + "</body>\n"
1559             + "</html>";
1560 
1561         loadPageVerifyTitle2(html);
1562     }
1563 
1564     /**
1565      * Call to form.submit() should capture the request to be done but the request itself should
1566      * be first done after the script execution... and only if it is still valid.
1567      * @throws Exception if the test fails
1568      */
1569     @Test
1570     @Alerts({"page4.html?f1=v1&f2=v2", "page4.html?f1=v1&f2=v2", "page3.html?f1=v1", "page3.html?f1=v1"})
1571     public void changesAfterCallToSubmit() throws Exception {
1572         final String[] expectedUrlSuffixes = getExpectedAlerts();
1573         setExpectedAlerts();
1574 
1575         changesAfterCallToSubmit("inputSubmitReturnTrue", expectedUrlSuffixes[0]);
1576         changesAfterCallToSubmit("inputSubmitVoid", expectedUrlSuffixes[1]);
1577 
1578         changesAfterCallToSubmit("inputSubmitReturnFalse", expectedUrlSuffixes[2]);
1579         changesAfterCallToSubmit("link", expectedUrlSuffixes[3]);
1580     }
1581 
1582     private void changesAfterCallToSubmit(final String id, final String expectedUrlSuffix) throws Exception {
1583         final String html = DOCTYPE_HTML
1584             + "<html><head><script>\n"
1585             + "function submitForm() {\n"
1586             + "  var f = document.forms[0];\n"
1587             + "  f.action = 'page3.html';\n"
1588             + "\n"
1589             + "  var h = document.createElement('input');\n"
1590             + "  h.name = 'f1';\n"
1591             + "  h.value = 'v1';\n"
1592             + "  f.appendChild(h);\n"
1593             + "\n"
1594             + "  f.submit();\n"
1595             + "\n"
1596             + "  f.action = 'page4.html';\n"
1597             + "  var h = document.createElement('input');\n"
1598             + "  h.name = 'f2';\n"
1599             + "  h.value = 'v2';\n"
1600             + "  f.appendChild(h);\n"
1601             + "  return false;\n"
1602             + "}\n"
1603             + "</script></head><body>\n"
1604             + "<form action='page1.html' name='myForm'>\n"
1605             + "  <input type='submit' id='inputSubmitReturnTrue' value='With on click on the button, return true' "
1606             + "onclick='submitForm(); return true'>\n"
1607             + "  <input type='submit' id='inputSubmitReturnFalse' value='With on click on the button, return false' "
1608             + "onclick='submitForm(); return false'>\n"
1609             + "  <input type='submit' id='inputSubmitVoid' value='With on click on the button, no return' "
1610             + "onclick='submitForm();'>\n"
1611             + "  <a id='link' href='#'  onclick='return submitForm()'><input type='submit' "
1612             + "value='With on click on the link'></a>\n"
1613             + "</form></body></html>";
1614 
1615         getMockWebConnection().setDefaultResponse("");
1616         final WebDriver wd = loadPageWithAlerts2(html);
1617         wd.findElement(By.id(id)).click();
1618         if (useRealBrowser()) {
1619             Thread.sleep(400);
1620         }
1621         assertEquals(URL_FIRST + expectedUrlSuffix, wd.getCurrentUrl());
1622     }
1623 
1624     /**
1625      * @throws Exception if the test fails
1626      */
1627     @Test
1628     @Alerts("2")
1629     public void submit_twice() throws Exception {
1630         final String html = DOCTYPE_HTML
1631             + "<html>\n"
1632             + "<head>\n"
1633             + "<script>\n"
1634             + "  function test() {\n"
1635             + "    var f = document.forms[0];\n"
1636             + "    f.submit();\n"
1637             + "    f.submit();\n"
1638             + "  }\n"
1639             + "</script></head>\n"
1640             + "<body onload='test()'>\n"
1641             + "  <form action='page1.html' name='myForm'>\n"
1642             + "    <input name='myField' value='some value'>\n"
1643             + "  </form>\n"
1644             + "</body></html>";
1645 
1646         getMockWebConnection().setDefaultResponse("");
1647         loadPage2(html);
1648         Thread.sleep(100);
1649 
1650         assertEquals(Integer.parseInt(getExpectedAlerts()[0]), getMockWebConnection().getRequestCount());
1651     }
1652 
1653     /**
1654      * @throws Exception if the test fails
1655      */
1656     @Test
1657     public void targetChangedAfterSubmitCall() throws Exception {
1658         final String html = DOCTYPE_HTML
1659             + "<html><head><script>\n"
1660             + "function test() {\n"
1661             + "  var f = document.forms[0];\n"
1662             + "  f.submit();\n"
1663             + "  f.target = 'foo2';\n"
1664             + "}\n"
1665             + "</script></head><body>\n"
1666             + "<form action='page1.html' name='myForm' target='foo1'>\n"
1667             + "  <input name='myField' value='some value'>\n"
1668             + "</form>\n"
1669             + "<div id='clickMe' onclick='test()'>click me</div></body></html>";
1670 
1671         getMockWebConnection().setDefaultResponse("<html><head>"
1672                 + "<script>document.title = 'Name: ' + window.name</script></head></html>");
1673         final WebDriver driver = loadPage2(html);
1674         driver.findElement(By.id("clickMe")).click();
1675 
1676         try {
1677             driver.switchTo().window("foo2");
1678             fail("Window foo2 found");
1679         }
1680         catch (final NoSuchWindowException e) {
1681             // ok
1682         }
1683         driver.switchTo().window("foo1");
1684         assertTitle(driver, "Name: foo1");
1685     }
1686 
1687     /**
1688      * Verify Content-Type header sent with form submission.
1689      * @throws Exception if the test fails
1690      */
1691     @Test
1692     public void enctypeGet() throws Exception {
1693         // for GET, no Content-Type header should be sent
1694         enctypeTest(false, null, "get", null);
1695         enctypeTest(false, "", "get", null);
1696         enctypeTest(false, "application/x-www-form-urlencoded", "get", null);
1697         enctypeTest(false, "multipart/form-data", "get", null);
1698         enctypeTest(false, MimeType.TEXT_PLAIN, "get", null);
1699 
1700         enctypeTest(true, null, "get", null);
1701         enctypeTest(true, "", "get", null);
1702         enctypeTest(true, "application/x-www-form-urlencoded", "get", null);
1703         enctypeTest(true, "multipart/form-data", "get", null);
1704         enctypeTest(true, MimeType.TEXT_PLAIN, "get", null);
1705     }
1706 
1707     /**
1708      * Verify Content-Type header sent with form submission.
1709      * @throws Exception if the test fails
1710      */
1711     @Test
1712     @Alerts({"application/x-www-form-urlencoded",
1713                 "application/x-www-form-urlencoded",
1714                 "application/x-www-form-urlencoded",
1715                 "multipart/form-data",
1716                 "text/plain"})
1717     public void enctypePost() throws Exception {
1718         enctypeTest(false, null, "post", getExpectedAlerts()[0]);
1719         enctypeTest(false, "", "post", getExpectedAlerts()[1]);
1720         enctypeTest(false, "application/x-www-form-urlencoded", "post", getExpectedAlerts()[2]);
1721         enctypeTest(false, "multipart/form-data", "post", getExpectedAlerts()[3]);
1722         enctypeTest(false, MimeType.TEXT_PLAIN, "post", getExpectedAlerts()[4]);
1723 
1724         enctypeTest(true, null, "post", getExpectedAlerts()[0]);
1725         enctypeTest(true, "", "post", getExpectedAlerts()[1]);
1726         enctypeTest(true, "application/x-www-form-urlencoded", "post", getExpectedAlerts()[2]);
1727         enctypeTest(true, "multipart/form-data", "post", getExpectedAlerts()[3]);
1728         enctypeTest(true, MimeType.TEXT_PLAIN, "post", getExpectedAlerts()[4]);
1729     }
1730 
1731     /**
1732      * Regression test for bug
1733      * <a href="http://sf.net/suppor/tracker.php?aid=2860721">2860721</a>: incorrect enctype form attribute
1734      * should be ignored.
1735      * @throws Exception if the test fails
1736      */
1737     @Test
1738     public void enctype_incorrect() throws Exception {
1739         enctypeTest(false, MimeType.TEXT_HTML, "post", "application/x-www-form-urlencoded");
1740         enctypeTest(false, MimeType.TEXT_HTML, "get", null);
1741 
1742         enctypeTest(true, MimeType.TEXT_HTML, "post", "application/x-www-form-urlencoded");
1743         enctypeTest(true, MimeType.TEXT_HTML, "get", null);
1744 
1745         enctypeTest(false, MimeType.TEXT_XML, "post", "application/x-www-form-urlencoded");
1746         enctypeTest(false, MimeType.TEXT_XML, "get", null);
1747 
1748         enctypeTest(true, MimeType.TEXT_XML, "post", "application/x-www-form-urlencoded");
1749         enctypeTest(true, MimeType.TEXT_XML, "get", null);
1750 
1751         enctypeTest(false, MimeType.APPLICATION_JSON, "post", "application/x-www-form-urlencoded");
1752         enctypeTest(false, MimeType.APPLICATION_JSON, "get", null);
1753 
1754         enctypeTest(true, MimeType.APPLICATION_JSON, "post", "application/x-www-form-urlencoded");
1755         enctypeTest(true, MimeType.APPLICATION_JSON, "get", null);
1756     }
1757 
1758     private void enctypeTest(final boolean html5, final String enctype,
1759                     final String method, final String expectedCntType) throws Exception {
1760         String html = "";
1761         if (html5) {
1762             html += DOCTYPE_HTML;
1763         }
1764         html += "<html><head><script>\n"
1765             + "function test() {\n"
1766             + "  var f = document.forms[0];\n"
1767             + "  f.submit();\n"
1768             + "}\n"
1769             + "</script></head><body onload='test()'>\n"
1770             + "<form action='foo.html' ";
1771         if (enctype != null) {
1772             html += "enctype='" + enctype + "' ";
1773         }
1774         html += "method='" + method + "'>\n"
1775             + "  <input name='myField' value='some value'>\n"
1776             + "</form></body></html>";
1777 
1778         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
1779         final WebDriver driver = loadPage2(html);
1780         assertTitle(driver, "Response");
1781         String headerValue = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
1782             .get(HttpHeader.CONTENT_TYPE);
1783         if (headerValue != null && headerValue.startsWith(FormEncodingType.MULTIPART.getName())) {
1784             // Can't test equality for multipart/form-data as it will have the form:
1785             // multipart/form-data; boundary=---------------------------42937861433140731107235900
1786             headerValue = StringUtils.substringBefore(headerValue, ";");
1787             assertEquals(expectedCntType, headerValue);
1788         }
1789         else {
1790             assertEquals(expectedCntType, headerValue);
1791         }
1792     }
1793 
1794     /**
1795      * Verify the default value of enctype for a newly created form element.
1796      * A similar test is used by jQuery-1.9.1 in its "feature support" detection.
1797      * @throws Exception if the test fails
1798      */
1799     @Test
1800     @Alerts("application/x-www-form-urlencoded")
1801     public void enctype_defaultValue_html5() throws Exception {
1802         final String html = DOCTYPE_HTML
1803             + "<html><body><script>\n"
1804             + LOG_TITLE_FUNCTION
1805             + "log(document.createElement('form').enctype);\n"
1806             + "</script></body></html>";
1807 
1808         loadPageVerifyTitle2(html);
1809     }
1810 
1811     /**
1812      * @throws Exception in case of error
1813      */
1814     @Test
1815     @Alerts("application/x-www-form-urlencoded")
1816     public void enctype_defaultValue() throws Exception {
1817         final String html = DOCTYPE_HTML
1818             + "<html><body><script>\n"
1819             + LOG_TITLE_FUNCTION
1820             + "log(document.createElement('form').enctype);\n"
1821             + "</script></body></html>";
1822 
1823         loadPageVerifyTitle2(html);
1824     }
1825 
1826     /**
1827      * Ensure that Multipart form text fields are correctly encoded.
1828      * @throws Exception if the test fails
1829      */
1830     @Test
1831     public void submitMultipartTextFieldWithRightEncoding() throws Exception {
1832         final String html = DOCTYPE_HTML
1833             + "<html><body onload='document.forms[0].submit()'>\n"
1834             + "<form action='foo.html' enctype='multipart/form-data' method='post'>\n"
1835             + "  <input name='myField' value='éèê\u00e4\u00f6\u00fc'>\n"
1836             + "</form></body></html>";
1837 
1838         getMockWebConnection().setDefaultResponse("");
1839         loadPage2(html);
1840         Thread.sleep(100);
1841 
1842         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
1843         final String expected = "Content-Disposition: form-data; name=\"myField\"\r\n"
1844             + "\r\n"
1845             + "éèê\u00e4\u00f6\u00fc";
1846 
1847         assertTrue("Body: " + body, body.contains(expected));
1848     }
1849 
1850     /**
1851      * Ensure that text/plain form parameters are correctly encoded.
1852      * @throws Exception if the test fails
1853      */
1854     @Test
1855     @Alerts("application/x-www-form-urlencoded")
1856     public void submitUrlEncodedEmptyForm() throws Exception {
1857         final String html = DOCTYPE_HTML
1858                 + "<html>\n"
1859                 + "<body onload='document.forms[0].submit()'>\n"
1860                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
1861                 + "  </form>\n"
1862                 + "</body>\n"
1863                 + "</html>";
1864 
1865         getMockWebConnection().setDefaultResponse("");
1866         loadPage2(html);
1867         Thread.sleep(100);
1868 
1869         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
1870                 .get(HttpHeader.CONTENT_TYPE);
1871         assertEquals(getExpectedAlerts()[0], headerContentType);
1872 
1873         assertEquals(0, getMockWebConnection().getLastWebRequest()
1874                 .getRequestParameters().size());
1875         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
1876     }
1877 
1878     /**
1879      * Ensure that text/plain form parameters are correctly encoded.
1880      * @throws Exception if the test fails
1881      */
1882     @Test
1883     @Alerts({"application/x-www-form-urlencoded", "myField=abcDEF"})
1884     public void submitUrlEncodedAsciiText() throws Exception {
1885         final String html = DOCTYPE_HTML
1886                 + "<html>\n"
1887                 + "<body onload='document.forms[0].submit()'>\n"
1888                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
1889                 + "    <input name='myField' value='abcDEF'>\n"
1890                 + "  </form>\n"
1891                 + "</body>\n"
1892                 + "</html>";
1893 
1894         getMockWebConnection().setDefaultResponse("");
1895         loadPage2(html);
1896         Thread.sleep(100);
1897 
1898         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
1899                 .get(HttpHeader.CONTENT_TYPE);
1900         assertEquals(getExpectedAlerts()[0], headerContentType);
1901 
1902         assertEquals(getExpectedAlerts()[1], getMockWebConnection().getLastWebRequest()
1903                 .getRequestParameters().get(0).toString());
1904         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
1905     }
1906 
1907     /**
1908      * Ensure that text/plain form parameters are correctly encoded.
1909      * @throws Exception if the test fails
1910      */
1911     @Test
1912     @Alerts({"application/x-www-form-urlencoded", "my\tFie ld = a b\tc \t"})
1913     public void submitUrlEncodedSpecialChars() throws Exception {
1914         final String html = DOCTYPE_HTML
1915                 + "<html>\n"
1916                 + "<body onload='document.forms[0].submit()'>\n"
1917                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
1918                 + "    <input name='my\tFie ld ' value=' a b\tc \t'>\n"
1919                 + "  </form>\n"
1920                 + "</body>\n"
1921                 + "</html>";
1922 
1923         getMockWebConnection().setDefaultResponse("");
1924         loadPage2(html);
1925         Thread.sleep(100);
1926 
1927         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
1928                 .get(HttpHeader.CONTENT_TYPE);
1929         assertEquals(getExpectedAlerts()[0], headerContentType);
1930 
1931         assertEquals(getExpectedAlerts()[1], getMockWebConnection().getLastWebRequest()
1932                 .getRequestParameters().get(0).toString());
1933         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
1934     }
1935 
1936     /**
1937      * Ensure that text/plain form parameters are correctly encoded.
1938      * @throws Exception if the test fails
1939      */
1940     @Test
1941     @Alerts({"application/x-www-form-urlencoded", "myField=éèê\u00e4\u00f6\u00fc"})
1942     public void submitUrlEncodedUnicode() throws Exception {
1943         final String html = DOCTYPE_HTML
1944                 + "<html>\n"
1945                 + "<body onload='document.forms[0].submit()'>\n"
1946                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
1947                 + "    <input name='myField' value='éèê\u00e4\u00f6\u00fc'>\n"
1948                 + "  </form>\n"
1949                 + "</body>\n"
1950                 + "</html>";
1951 
1952         getMockWebConnection().setDefaultResponse("");
1953         loadPage2(html, URL_FIRST, "text/html;charset=UTF-8", UTF_8, null);
1954         Thread.sleep(100);
1955 
1956         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
1957                 .get(HttpHeader.CONTENT_TYPE);
1958         assertEquals(getExpectedAlerts()[0], headerContentType);
1959 
1960         assertEquals(getExpectedAlerts()[1], getMockWebConnection().getLastWebRequest()
1961                 .getRequestParameters().get(0).toString());
1962         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
1963     }
1964 
1965     /**
1966      * Ensure that text/plain form parameters are correctly encoded.
1967      * @throws Exception if the test fails
1968      */
1969     @Test
1970     @Alerts({"application/x-www-form-urlencoded", "myField=HtmlUnit \u043B\u0189"})
1971     public void submitUrlEncodedUnicodeUTF8() throws Exception {
1972         final String html = DOCTYPE_HTML
1973                 + "<html>\n"
1974                 + "<body onload='document.forms[0].submit()'>\n"
1975                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
1976                 + "    <input name='myField' value='HtmlUnit \u043B\u0189'>\n"
1977                 + "  </form>\n"
1978                 + "</body>\n"
1979                 + "</html>";
1980 
1981         getMockWebConnection().setDefaultResponse("");
1982         loadPage2(html, URL_FIRST, "text/html;charset=UTF-8", UTF_8, null);
1983         Thread.sleep(100);
1984 
1985         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
1986                 .get(HttpHeader.CONTENT_TYPE);
1987         assertEquals(getExpectedAlerts()[0], headerContentType);
1988 
1989         assertEquals(getExpectedAlerts()[1], getMockWebConnection().getLastWebRequest()
1990                 .getRequestParameters().get(0).toString());
1991         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
1992     }
1993 
1994     /**
1995      * Ensure that text/plain form parameters are correctly encoded.
1996      * @throws Exception if the test fails
1997      */
1998     @Test
1999     @Alerts({"application/x-www-form-urlencoded", "myField=HtmlUnit \u043B\u0189"})
2000     public void submitUrlEncodedUnicodeUTF16() throws Exception {
2001         final String html = DOCTYPE_HTML
2002                 + "<html>\n"
2003                 + "<body onload='document.forms[0].submit()'>\n"
2004                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
2005                 + "    <input name='myField' value='HtmlUnit \u043B\u0189'>\n"
2006                 + "  </form>\n"
2007                 + "</body>\n"
2008                 + "</html>";
2009 
2010         getMockWebConnection().setDefaultResponse("");
2011         loadPage2(html, URL_FIRST, "text/html;charset=UTF-16", UTF_16, null);
2012         Thread.sleep(100);
2013 
2014         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2015                 .get(HttpHeader.CONTENT_TYPE);
2016         assertEquals(getExpectedAlerts()[0], headerContentType);
2017 
2018         assertEquals(getExpectedAlerts()[1], getMockWebConnection().getLastWebRequest()
2019                 .getRequestParameters().get(0).toString());
2020         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
2021     }
2022 
2023     /**
2024      * Ensure that text/plain form parameters are correctly encoded.
2025      * @throws Exception if the test fails
2026      */
2027     @Test
2028     @Alerts({"application/x-www-form-urlencoded", "myFile=htmlunit-test", ".txt"})
2029     public void submitUrlEncodedFile() throws Exception {
2030         final String html = DOCTYPE_HTML
2031                 + "<html>\n"
2032                 + "<body>\n"
2033                 + "  <form action='foo.html' enctype='application/x-www-form-urlencoded' method='post'>\n"
2034                 + "    <input type='file' id='f' name='myFile'>\n"
2035                 + "    <input id='clickMe' type='submit' value='Click Me'>\n"
2036                 + "  </form>\n"
2037                 + "</body>\n"
2038                 + "</html>";
2039 
2040         getMockWebConnection().setDefaultResponse("");
2041 
2042         final WebDriver driver = loadPage2(html);
2043 
2044         final File tmpFile = File.createTempFile("htmlunit-test", ".txt");
2045         try {
2046             final String path = tmpFile.getAbsolutePath();
2047             driver.findElement(By.id("f")).sendKeys(path);
2048             driver.findElement(By.id("clickMe")).click();
2049             if (useRealBrowser()) {
2050                 Thread.sleep(400);
2051             }
2052         }
2053         finally {
2054             assertTrue(tmpFile.delete());
2055         }
2056 
2057         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2058                 .get(HttpHeader.CONTENT_TYPE);
2059         assertEquals(getExpectedAlerts()[0], headerContentType);
2060 
2061         final String body = getMockWebConnection().getLastWebRequest()
2062                 .getRequestParameters().get(0).toString();
2063         assertTrue(body, body.startsWith(getExpectedAlerts()[1]));
2064         assertTrue(body, body.endsWith(getExpectedAlerts()[2]));
2065         assertNull(getMockWebConnection().getLastWebRequest().getRequestBody());
2066     }
2067 
2068     /**
2069      * Ensure that text/plain form parameters are correctly encoded.
2070      * @throws Exception if the test fails
2071      */
2072     @Test
2073     @Alerts("text/plain")
2074     public void submitPlainTextEmptyForm() throws Exception {
2075         final String html = DOCTYPE_HTML
2076                 + "<html>\n"
2077                 + "<body onload='document.forms[0].submit()'>\n"
2078                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2079                 + "  </form>\n"
2080                 + "</body>\n"
2081                 + "</html>";
2082 
2083         getMockWebConnection().setDefaultResponse("");
2084         loadPage2(html);
2085         Thread.sleep(100);
2086 
2087         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2088                 .get(HttpHeader.CONTENT_TYPE);
2089         assertEquals(getExpectedAlerts()[0], headerContentType);
2090 
2091         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2092         assertNull(body);
2093     }
2094 
2095     /**
2096      * Ensure that text/plain form parameters are correctly encoded.
2097      * @throws Exception if the test fails
2098      */
2099     @Test
2100     @Alerts({"text/plain", "myField=abcDEF\r\n"})
2101     public void submitPlainTextAsciiText() throws Exception {
2102         final String html = DOCTYPE_HTML
2103                 + "<html>\n"
2104                 + "<body onload='document.forms[0].submit()'>\n"
2105                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2106                 + "    <input name='myField' value='abcDEF'>\n"
2107                 + "  </form>\n"
2108                 + "</body>\n"
2109                 + "</html>";
2110 
2111         getMockWebConnection().setDefaultResponse("");
2112         loadPage2(html);
2113         Thread.sleep(100);
2114 
2115         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2116                 .get(HttpHeader.CONTENT_TYPE);
2117         assertEquals(getExpectedAlerts()[0], headerContentType);
2118 
2119         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2120         assertEquals(getExpectedAlerts()[1], body);
2121     }
2122 
2123     /**
2124      * Ensure that text/plain form parameters are correctly encoded.
2125      * @throws Exception if the test fails
2126      */
2127     @Test
2128     @Alerts({"text/plain", "my\tField = abcDEF \t\r\n"})
2129     public void submitPlainTextSpecialChars() throws Exception {
2130         final String html = DOCTYPE_HTML
2131                 + "<html>\n"
2132                 + "<body onload='document.forms[0].submit()'>\n"
2133                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2134                 + "    <input name='my\tField ' value=' ab\rcD\nEF \t'>\n"
2135                 + "  </form>\n"
2136                 + "</body>\n"
2137                 + "</html>";
2138 
2139         getMockWebConnection().setDefaultResponse("");
2140         loadPage2(html);
2141         Thread.sleep(100);
2142 
2143         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2144                 .get(HttpHeader.CONTENT_TYPE);
2145         assertEquals(getExpectedAlerts()[0], headerContentType);
2146 
2147         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2148         assertEquals(getExpectedAlerts()[1], body);
2149     }
2150 
2151     /**
2152      * Ensure that text/plain form parameters are correctly encoded.
2153      * @throws Exception if the test fails
2154      */
2155     @Test
2156     @Alerts({"text/plain", "myField=éèê\u00e4\u00f6\u00fc\u00a9\r\n"})
2157     public void submitPlainTextUnicode() throws Exception {
2158         final String html = DOCTYPE_HTML
2159                 + "<html>\n"
2160                 + "<body onload='document.forms[0].submit()'>\n"
2161                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2162                 + "    <input name='myField' value='éèê\u00e4\u00f6\u00fc\u00a9'>\n"
2163                 + "  </form>\n"
2164                 + "</body>\n"
2165                 + "</html>";
2166 
2167         getMockWebConnection().setDefaultResponse("");
2168         loadPage2(html);
2169         Thread.sleep(100);
2170 
2171         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2172                 .get(HttpHeader.CONTENT_TYPE);
2173         assertEquals(getExpectedAlerts()[0], headerContentType);
2174 
2175         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2176         assertEquals(getExpectedAlerts()[1], body);
2177     }
2178 
2179     /**
2180      * Ensure that text/plain form parameters are correctly encoded.
2181      * @throws Exception if the test fails
2182      */
2183     @Test
2184     @Alerts({"text/plain", "myField=éèê\u00e4\u00f6\u00fc\u00a9?\r\n"})
2185     public void submitPlainTextISO_8859_1() throws Exception {
2186         final String html = DOCTYPE_HTML
2187                 + "<html>\n"
2188                 + "<body onload='document.forms[0].submit()'>\n"
2189                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2190                 + "    <input name='myField' value='éèê\u00e4\u00f6\u00fc\u00a9\u05d4'>\n"
2191                 + "  </form>\n"
2192                 + "</body>\n"
2193                 + "</html>";
2194 
2195         getMockWebConnection().setDefaultResponse("");
2196         loadPage2(html, URL_FIRST, "text/html;charset=ISO-8859-1", ISO_8859_1, null);
2197         Thread.sleep(100);
2198 
2199         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2200                 .get(HttpHeader.CONTENT_TYPE);
2201         assertEquals(getExpectedAlerts()[0], headerContentType);
2202 
2203         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2204         assertEquals(getExpectedAlerts()[1], body);
2205         assertNull(getMockWebConnection().getLastWebRequest().getCharset());
2206     }
2207 
2208 
2209     /**
2210      * Ensure that text/plain form parameters are correctly encoded.
2211      * @throws Exception if the test fails
2212      */
2213     @Test
2214     @Alerts({"text/plain", "myField=éèêäöü©?\r\n"})
2215     public void submitPlainTextISO_8859_1_AcceptCharsetUtf8() throws Exception {
2216         final String html = DOCTYPE_HTML
2217                 + "<html>\n"
2218                 + "<body onload='document.forms[0].submit()'>\n"
2219                 + "  <form action='foo.html' enctype='text/plain' accept-charset='utf8' method='post'>\n"
2220                 + "    <input name='myField' value='éèê\u00e4\u00f6\u00fc\u00a9\u05d4'>\n"
2221                 + "  </form>\n"
2222                 + "</body>\n"
2223                 + "</html>";
2224 
2225         getMockWebConnection().setDefaultResponse("");
2226         loadPage2(html, URL_FIRST, "text/html;charset=ISO-8859-1", ISO_8859_1, null);
2227         Thread.sleep(100);
2228 
2229         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2230                 .get(HttpHeader.CONTENT_TYPE);
2231         assertEquals(getExpectedAlerts()[0], headerContentType);
2232 
2233         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2234         assertEquals(getExpectedAlerts()[1], body);
2235         assertNull(getMockWebConnection().getLastWebRequest().getCharset());
2236     }
2237 
2238     /**
2239      * Ensure that text/plain form parameters are correctly encoded.
2240      * @throws Exception if the test fails
2241      */
2242     @Test
2243     @Alerts({"text/plain", "myField=HtmlUnit \u00D0\u00BB\u00C6\u0089\r\n"})
2244     public void submitPlainTextUnicodeUTF8() throws Exception {
2245         final String html = DOCTYPE_HTML
2246                 + "<html>\n"
2247                 + "<body onload='document.forms[0].submit()'>\n"
2248                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2249                 + "    <input name='myField' value='HtmlUnit \u043B\u0189'>\n"
2250                 + "  </form>\n"
2251                 + "</body>\n"
2252                 + "</html>";
2253 
2254         getMockWebConnection().setDefaultResponse("");
2255         loadPage2(html, URL_FIRST, "text/html;charset=UTF-8", UTF_8, null);
2256         Thread.sleep(100);
2257 
2258         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2259                 .get(HttpHeader.CONTENT_TYPE);
2260         assertEquals(getExpectedAlerts()[0], headerContentType);
2261 
2262         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2263         assertEquals(getExpectedAlerts()[1], body);
2264         assertNull(getMockWebConnection().getLastWebRequest().getCharset());
2265     }
2266 
2267     /**
2268      * Ensure that text/plain form parameters are correctly encoded.
2269      * @throws Exception if the test fails
2270      */
2271     @Test
2272     @Alerts({"text/plain", "myField=HtmlUnit \u00D0\u00BB\u00C6\u0089\r\n"})
2273     public void submitPlainTextUnicodeUTF16() throws Exception {
2274         final String html = DOCTYPE_HTML
2275                 + "<html>\n"
2276                 + "<body onload='document.forms[0].submit()'>\n"
2277                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2278                 + "    <input name='myField' value='HtmlUnit \u043B\u0189'>\n"
2279                 + "  </form>\n"
2280                 + "</body>\n"
2281                 + "</html>";
2282 
2283         getMockWebConnection().setDefaultResponse("");
2284         loadPage2(html, URL_FIRST, "text/html;charset=UTF-16", UTF_16, null);
2285         Thread.sleep(100);
2286 
2287         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2288                 .get(HttpHeader.CONTENT_TYPE);
2289         assertEquals(getExpectedAlerts()[0], headerContentType);
2290 
2291         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2292         assertEquals(getExpectedAlerts()[1], body);
2293         assertNull(getMockWebConnection().getLastWebRequest().getCharset());
2294     }
2295 
2296     /**
2297      * Ensure that text/plain form parameters are correctly encoded.
2298      * @throws Exception if the test fails
2299      */
2300     @Test
2301     @Alerts({"text/plain", "myField=HtmlUnit \u00D0\u00BB\u00C6\u0089\r\n"})
2302     public void submitPlainTextUnicodeUTF16AcceptCharsetUtf8() throws Exception {
2303         final String html = DOCTYPE_HTML
2304                 + "<html>\n"
2305                 + "<body onload='document.forms[0].submit()'>\n"
2306                 + "  <form action='foo.html' enctype='text/plain' accept-charset='utf8' method='post'>\n"
2307                 + "    <input name='myField' value='HtmlUnit \u043B\u0189'>\n"
2308                 + "  </form>\n"
2309                 + "</body>\n"
2310                 + "</html>";
2311 
2312         getMockWebConnection().setDefaultResponse("");
2313         loadPage2(html, URL_FIRST, "text/html;charset=UTF-16", UTF_16, null);
2314         Thread.sleep(100);
2315 
2316         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2317                 .get(HttpHeader.CONTENT_TYPE);
2318         assertEquals(getExpectedAlerts()[0], headerContentType);
2319 
2320         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2321         assertEquals(getExpectedAlerts()[1], body);
2322         assertNull(getMockWebConnection().getLastWebRequest().getCharset());
2323     }
2324 
2325     /**
2326      * Ensure that text/plain form parameters are correctly encoded.
2327      * @throws Exception if the test fails
2328      */
2329     @Test
2330     @Alerts({"text/plain", "myFile=htmlunit-test", ".txt\r\n"})
2331     public void submitPlainTextFile() throws Exception {
2332         final String html = DOCTYPE_HTML
2333                 + "<html>\n"
2334                 + "<body>\n"
2335                 + "  <form action='foo.html' enctype='text/plain' method='post'>\n"
2336                 + "    <input type='file' id='f' name='myFile'>\n"
2337                 + "    <input id='clickMe' type='submit' value='Click Me'>\n"
2338                 + "  </form>\n"
2339                 + "</body>\n"
2340                 + "</html>";
2341 
2342         getMockWebConnection().setDefaultResponse("");
2343 
2344         final WebDriver driver = loadPage2(html);
2345 
2346         final File tmpFile = File.createTempFile("htmlunit-test", ".txt");
2347         try {
2348             final String path = tmpFile.getAbsolutePath();
2349             driver.findElement(By.id("f")).sendKeys(path);
2350             driver.findElement(By.id("clickMe")).click();
2351             if (useRealBrowser()) {
2352                 Thread.sleep(400);
2353             }
2354         }
2355         finally {
2356             assertTrue(tmpFile.delete());
2357         }
2358 
2359         final String headerContentType = getMockWebConnection().getLastWebRequest().getAdditionalHeaders()
2360                 .get(HttpHeader.CONTENT_TYPE);
2361         assertEquals(getExpectedAlerts()[0], headerContentType);
2362 
2363         final String body = getMockWebConnection().getLastWebRequest().getRequestBody();
2364         assertTrue(body, body.startsWith(getExpectedAlerts()[1]));
2365         assertTrue(body, body.endsWith(getExpectedAlerts()[2]));
2366     }
2367 
2368     /**
2369      * Failed as of HtmlUnit-2.7-SNAPSHOT 01.12.2009 as the '#' from the
2370      * link together with the fact that submission occurs to the same url
2371      * let HtmlUnit think that it as just navigation to an anchor.
2372      * @throws Exception if the test fails
2373      */
2374     @Test
2375     public void submitToSameUrlFromLinkOnclick_post() throws Exception {
2376         submitToSameUrlFromLinkOnclick("post");
2377     }
2378 
2379     /**
2380      * @throws Exception if the test fails
2381      */
2382     @Test
2383     public void submitToSameUrlFromLinkOnclick_get() throws Exception {
2384         submitToSameUrlFromLinkOnclick("get");
2385     }
2386 
2387     private void submitToSameUrlFromLinkOnclick(final String method) throws Exception {
2388         final String html = DOCTYPE_HTML
2389             + "<html><head><title>foo</title></head><body>\n"
2390             + "<form id='form1' method='" + method + "'>\n"
2391             + "<input name='foo'>\n"
2392             + "<a href='#' onclick='document.forms[0].submit()' id='clickMe'>submit it</a>\n"
2393             + "</form></body></html>";
2394 
2395         final WebDriver driver = loadPage2(html);
2396         driver.findElement(By.id("clickMe")).click();
2397         driver.findElement(By.id("clickMe")).click(); // a second time to be sure to have same resulting Url
2398         if (useRealBrowser()) {
2399             Thread.sleep(400);
2400         }
2401 
2402         assertEquals(3, getMockWebConnection().getRequestCount());
2403     }
2404 
2405     /**
2406      * @throws Exception if the test fails
2407      */
2408     @Test
2409     @Alerts({"", "foo4?foo=", "script4.js"})
2410     @HtmlUnitNYI(CHROME = {"", "foo0?foo=", "foo1?foo=", "foo2?foo=", "foo3?foo=", "foo4?foo=", "script4.js"},
2411             EDGE = {"", "foo0?foo=", "foo1?foo=", "foo2?foo=", "foo3?foo=", "foo4?foo=", "script4.js"},
2412             FF = {"", "foo0?foo=", "foo1?foo=", "foo2?foo=", "foo3?foo=", "foo4?foo=", "script4.js"},
2413             FF_ESR = {"", "foo0?foo=", "foo1?foo=", "foo2?foo=", "foo3?foo=", "foo4?foo=", "script4.js"})
2414     public void submitTriggersRequestNotParsed() throws Exception {
2415         final String html = DOCTYPE_HTML
2416             + "<html><head><script>\n"
2417             + "function test() {\n"
2418             + "  var f = document.forms[0];\n"
2419             + "  for (var i = 0; i < 5; i++) {\n"
2420             + "    f.action = 'foo' + i;\n"
2421             + "    f.submit();\n"
2422             + "  }\n"
2423             + "}\n"
2424             + "</script></head>\n"
2425             + "<body onload='test()'>\n"
2426             + "  <form>\n"
2427             + "    <input name='foo'>\n"
2428             + "  </form>\n"
2429             + "</body></html>";
2430 
2431         final MockWebConnection connection = getMockWebConnection();
2432         for (int i = 0; i < 5; i++) {
2433             final String htmlX = DOCTYPE_HTML
2434                 + "<html><head>\n"
2435                 + "<title>Page " + i + "</title>\n"
2436                 + "<script src='script" + i + ".js'></script>\n"
2437                 + "<script>alert('page" + i + "');</script>\n"
2438                 + "</head></html>";
2439             connection.setResponse(new URL(URL_FIRST, "foo" + i), htmlX);
2440             connection.setResponse(new URL(URL_FIRST, "script" + i + ".js"), "", MimeType.TEXT_JAVASCRIPT);
2441         }
2442         final String[] expectedRequests = getExpectedAlerts();
2443 
2444         setExpectedAlerts("page4");
2445         final WebDriver driver = loadPageWithAlerts2(html); // forces to wait, what is needed for FFdriver
2446 
2447         // NB: comparing the sequence order here is not 100% safe with a real browser
2448         assertEquals(expectedRequests, getMockWebConnection().getRequestedUrls(URL_FIRST));
2449 
2450         assertTitle(driver, "Page 4");
2451     }
2452 
2453     /**
2454      * When the name of a form field changes... it is still reachable through the original name!
2455      * @throws Exception if the test fails
2456      */
2457     @Test
2458     @Alerts({"[object HTMLInputElement]", "undefined",
2459              "[object HTMLInputElement]", "[object HTMLInputElement]",
2460              "[object HTMLInputElement]", "[object HTMLInputElement]", "[object HTMLInputElement]"})
2461     public void accessByNameAfterNameChangeInput() throws Exception {
2462         accessByNameAfterNameChange("<input name='originalName'>");
2463     }
2464 
2465     /**
2466      * When the name of a form field changes... it is still reachable through the original name!
2467      * @throws Exception if the test fails
2468      */
2469     @Test
2470     @Alerts({"undefined", "undefined"})
2471     public void accessByNameAfterNameChangeInputImage() throws Exception {
2472         accessByNameAfterNameChange("<input type='image' name='originalName'>");
2473     }
2474 
2475     /**
2476      * When the name of a form field changes... it is still reachable through the original name!
2477      * @throws Exception if the test fails
2478      */
2479     @Test
2480     @Alerts({"[object HTMLButtonElement]", "undefined",
2481              "[object HTMLButtonElement]", "[object HTMLButtonElement]",
2482              "[object HTMLButtonElement]", "[object HTMLButtonElement]", "[object HTMLButtonElement]"})
2483     public void accessByNameAfterNameChangeButton() throws Exception {
2484         accessByNameAfterNameChange("<button name='originalName'>btn</button>");
2485     }
2486 
2487     /**
2488      * When the name of a form field changes... it is still reachable through the original name!
2489      * @throws Exception if the test fails
2490      */
2491     @Test
2492     @Alerts({"[object HTMLOutputElement]", "undefined",
2493              "[object HTMLOutputElement]", "[object HTMLOutputElement]",
2494              "[object HTMLOutputElement]", "[object HTMLOutputElement]", "[object HTMLOutputElement]"})
2495     public void accessByNameAfterNameChangeOutput() throws Exception {
2496         accessByNameAfterNameChange("<output name='originalName'>4711</output>");
2497     }
2498 
2499     /**
2500      * When the name of a form field changes... it is still reachable through the original name!
2501      * @throws Exception if the test fails
2502      */
2503     @Test
2504     @Alerts({"[object HTMLTextAreaElement]", "undefined",
2505              "[object HTMLTextAreaElement]", "[object HTMLTextAreaElement]",
2506              "[object HTMLTextAreaElement]", "[object HTMLTextAreaElement]", "[object HTMLTextAreaElement]"})
2507     public void accessByNameAfterNameChangeTextarea() throws Exception {
2508         accessByNameAfterNameChange("<textarea name='originalName'>foo</textarea>");
2509     }
2510 
2511     /**
2512      * When the name of a form field changes... it is still reachable through the original name!
2513      * @throws Exception if the test fails
2514      */
2515     @Test
2516     @Alerts({"[object HTMLSelectElement]", "undefined",
2517              "[object HTMLSelectElement]", "[object HTMLSelectElement]",
2518              "[object HTMLSelectElement]", "[object HTMLSelectElement]", "[object HTMLSelectElement]"})
2519     public void accessByNameAfterNameChangeSelect() throws Exception {
2520         accessByNameAfterNameChange("<select name='originalName'><option>foo</option></select>");
2521     }
2522 
2523     /**
2524      * When the name of a form field changes... it is still reachable through the original name!
2525      * @throws Exception if the test fails
2526      */
2527     @Test
2528     @Alerts({"[object HTMLFieldSetElement]", "undefined",
2529              "[object HTMLFieldSetElement]", "[object HTMLFieldSetElement]",
2530              "[object HTMLFieldSetElement]", "[object HTMLFieldSetElement]", "[object HTMLFieldSetElement]"})
2531     public void accessByNameAfterNameChangeFieldSet() throws Exception {
2532         accessByNameAfterNameChange("<fieldset name='originalName'><legend>Legend</legend></fieldset>");
2533     }
2534 
2535     private void accessByNameAfterNameChange(final String htmlElement) throws Exception {
2536         final String html = DOCTYPE_HTML
2537             + "<html><head><script>\n"
2538             + LOG_TITLE_FUNCTION
2539             + "function go() {\n"
2540             + "  log(document.simple_form.originalName);\n"
2541             + "  log(document.simple_form.newName);\n"
2542 
2543             + "  var field = document.simple_form.originalName;\n"
2544             + "  if (field === undefined) return;\n"
2545 
2546             + "  field.name = 'newName';\n"
2547             + "  log(document.simple_form.originalName);\n"
2548             + "  log(document.simple_form.newName);\n"
2549 
2550             + "  field.name = 'brandNewName';\n"
2551             + "  log(document.simple_form.originalName);\n"
2552             + "  log(document.simple_form.newName);\n"
2553             + "  log(document.simple_form.brandNewName);\n"
2554             + "}\n"
2555             + "</script></head>\n"
2556             + "<body onload='go()'>\n"
2557             + "<form name='simple_form'>\n"
2558             + htmlElement + "\n"
2559             + "</form>\n"
2560             + "</body></html>";
2561 
2562         loadPageVerifyTitle2(html);
2563     }
2564 
2565     /**
2566      * Regression test for Bug #1083: lost children should be accessible per name from HTMLFormElement.elements.
2567      * @throws Exception if the test fails
2568      */
2569     @Test
2570     @Alerts({"[object HTMLInputElement]", "[object HTMLInputElement]"})
2571     public void lostChildrenFromElements() throws Exception {
2572         final String html = DOCTYPE_HTML
2573             + "<html><body>\n"
2574             + "<div><form name='form1' >\n"
2575             + "</div>\n"
2576             + "<input name='b'/>\n"
2577             + "</form><script>\n"
2578             + LOG_TITLE_FUNCTION
2579             + "  log(document.form1['b']);\n"
2580             + "  log(document.form1.elements['b']);\n"
2581             + "</script>\n"
2582             + "</body></html>";
2583 
2584         loadPageVerifyTitle2(html);
2585     }
2586 
2587     /**
2588      * @throws Exception if the test fails
2589      */
2590     @Test
2591     @Alerts("function")
2592     public void onchangeHandler() throws Exception {
2593         final String html = DOCTYPE_HTML
2594             + "<html><head><script>\n"
2595             + LOG_TITLE_FUNCTION
2596             + "function test() {\n"
2597             + "  var form = document.getElementsByTagName('form')[0];\n"
2598             + "  log(typeof form.onchange);\n"
2599             + "}\n"
2600             + "</script></head><body onload='test()'>\n"
2601             + "<form onchange='cat=true'></form>\n"
2602             + "</body></html>";
2603 
2604         loadPageVerifyTitle2(html);
2605     }
2606 
2607     /**
2608      * @throws Exception if an error occurs
2609      */
2610     @Test
2611     @Alerts(DEFAULT = "in listener",
2612             FF = {"in listener", "page2 loaded"},
2613             FF_ESR = {"in listener", "page2 loaded"})
2614     public void dispatchEventSubmitTriggersHandlers() throws Exception {
2615         // use an iframe to capture alerts among 2 pages
2616         final String container = DOCTYPE_HTML
2617             + "<html><body><iframe src='page1'></iframe></body></html>\n";
2618         final String page1 = DOCTYPE_HTML
2619             + "<html><body>\n"
2620             + "<form action='page2' id='theForm'><span id='foo'/></form>\n"
2621             + "<script>\n"
2622             + "function listener(e) {\n"
2623             + "  alert('in listener');\n"
2624             + "}\n"
2625             + "try {\n"
2626             + "  document.forms[0].addEventListener('submit', listener, true);\n"
2627             + "  var e = document.createEvent('HTMLEvents');\n"
2628             + "  e.initEvent('submit', true, false);\n"
2629             + "  document.getElementById('theForm').dispatchEvent(e);\n"
2630             + "} catch(e) { alert('exception'); }\n"
2631             + "</script></body></html>";
2632 
2633         final String page2 = DOCTYPE_HTML
2634             + "<html><body><script>alert('page2 loaded');</script></body></html>";
2635 
2636         getMockWebConnection().setResponse(new URL(URL_FIRST, "page1"), page1);
2637         getMockWebConnection().setResponse(new URL(URL_FIRST, "page2"), page2);
2638         loadPageWithAlerts2(container);
2639     }
2640 
2641     /**
2642      * Verifies that the event object is correctly made available.
2643      * Regression test for http://sourceforge.net/p/htmlunit/bugs/425/
2644      * @throws Exception if the test fails
2645      */
2646     @Test
2647     @Alerts({"type: submit", "submitter: [object HTMLInputElement]",
2648              "srcElement null: false", "srcElement==form: true",
2649              "target null: false", "target==form: true"})
2650     public void onSubmitEvent() throws Exception {
2651         final String html = DOCTYPE_HTML
2652             + "<html><head>\n"
2653             + "<script>\n"
2654             + LOG_TITLE_FUNCTION
2655             + "function test(_event) {\n"
2656             + "  var oEvent = _event ? _event : window.event;\n"
2657             + "  log('type: ' + oEvent.type);\n"
2658             + "  log('submitter: ' + oEvent.submitter);\n"
2659             + "  log('srcElement null: ' + (oEvent.srcElement == null));\n"
2660             + "  log('srcElement==form: ' + (oEvent.srcElement == document.forms[0]));\n"
2661             + "  log('target null: ' + (oEvent.target == null));\n"
2662             + "  log('target==form: ' + (oEvent.target == document.forms[0]));\n"
2663 
2664             + "  if (_event.preventDefault) { _event.preventDefault(); }\n"
2665             + "  return false;\n"
2666             + "}\n"
2667             + "</script>\n"
2668             + "</head><body>\n"
2669             + "<form name='formPage1' action='about:blank' onsubmit='return test(event);'>\n"
2670             + "<input type='submit' id='theButton'>\n"
2671             + "</form>\n"
2672             + "</body></html>";
2673 
2674         final WebDriver driver = loadPage2(html);
2675         driver.findElement(By.id("theButton")).click();
2676         verifyTitle2(driver, getExpectedAlerts());
2677     }
2678 
2679     /**
2680      * This test is used to check that when a form having a target is submitted
2681      * and if the target is an iframe and the iframe has an onload event, then
2682      * the onload event is called.
2683      *
2684      * @throws Exception if the test fails
2685      */
2686     @Test
2687     @Alerts({"prepare frame", "submit form", "submitted ok"})
2688     public void submitWithTargetOnIFrameAndOnload_script() throws Exception {
2689         final String html = DOCTYPE_HTML
2690             + "<html><head></head><body>\n"
2691             + "<p>hello world</p>\n"
2692             + "<form id='form1' name='form1' method='get' action='" + URL_SECOND + "'>\n"
2693             + "  <input type='button' name='button1' />\n"
2694             + "</form>\n"
2695             + "<script>\n"
2696             + LOG_TITLE_FUNCTION
2697             + "  // Prepare the iframe for the target\n"
2698             + "  log('prepare frame');\n"
2699             + "  var div = document.createElement('div');\n"
2700             + "  div.style.display = 'none';\n"
2701             + "  div.innerHTML = \"<iframe name='frame' id='frame'></iframe>\";\n"
2702             + "  document.body.appendChild(div);\n"
2703             + "  // Get the form and set the target\n"
2704             + "  var form = document.getElementById('form1');\n"
2705             + "  form.target = 'frame';\n"
2706             + "  // Finally submit the form with a delay to make sure that the onload of the iframe\n"
2707             + "  // is called for the submit and not for the page creation\n"
2708             + "  var t = setTimeout(function() {\n"
2709             + "    clearTimeout(t);\n"
2710             + "    var iframe = document.getElementById('frame');\n"
2711             + "    iframe.onload = function() {\n"
2712             + "      log('submitted ' + iframe.contentWindow.document.body.getAttribute('id'));\n"
2713             + "    };\n"
2714             + "    log('submit form');\n"
2715             + "    form.submit();\n"
2716             + "  }, 1000);\n"
2717             + "</script></body></html>";
2718         final String html2
2719             = "<?xml version='1.0'?>\n"
2720             + "<html xmlns='http://www.w3.org/1999/xhtml'><body id='ok'><span id='result'>OK</span></body></html>";
2721         getMockWebConnection().setDefaultResponse(html2);
2722 
2723         loadPage2(html, URL_FIRST);
2724         verifyTitle2(DEFAULT_WAIT_TIME.multipliedBy(5), getWebDriver(), getExpectedAlerts());
2725     }
2726 
2727     /**
2728      * This test is used to check that when a form having a target is submitted
2729      * and if the target is an iframe and the iframe has an onload event, then
2730      * the onload event is called.
2731      *
2732      * @throws Exception if the test fails
2733      */
2734     @Test
2735     @Alerts({"submit form", "listener: submitted ok"})
2736     public void submitWithTargetOnIFrameAndOnload_bubbling() throws Exception {
2737         final String html = DOCTYPE_HTML
2738             + "<html><head>/head><body>\n"
2739             + "<p>hello world</p>\n"
2740             + "<form id='form1' name='form1' method='get' action='" + URL_SECOND + "' target='frame'>\n"
2741             + "  <input type='button' name='button1' />\n"
2742             + "</form>\n"
2743             + "<div style='display:none;'><iframe name='frame' id='frame'></iframe></div>\n"
2744             + "<script>\n"
2745             + LOG_TITLE_FUNCTION
2746             + "  // Get the form and set the target\n"
2747             + "  var form = document.getElementById('form1');\n"
2748             + "  var iframe = document.getElementById('frame');\n"
2749             + "  // Finally submit the form with a delay to make sure that the onload of the iframe\n"
2750             + "  // is called for the submit and not for the page creation\n"
2751             + "  var t = setTimeout(function() {\n"
2752             + "    clearTimeout(t);\n"
2753             + "    iframe.addEventListener('load', function() {\n"
2754             + "      log('listener: submitted ' + iframe.contentWindow.document.body.getAttribute('id'));\n"
2755             + "    }, true);\n"
2756             + "    log('submit form');\n"
2757             + "    form.submit();\n"
2758             + "  }, 1000);\n"
2759             + "</script>\n"
2760             + "</body></html>";
2761         final String html2
2762             = "<?xml version='1.0'?>\n"
2763             + "<html xmlns='http://www.w3.org/1999/xhtml'><body id='ok'><span id='result'>OK</span></body></html>";
2764         getMockWebConnection().setDefaultResponse(html2);
2765 
2766         loadPage2(html, URL_FIRST);
2767         verifyTitle2(DEFAULT_WAIT_TIME.multipliedBy(5), getWebDriver(), getExpectedAlerts());
2768     }
2769 
2770     /**
2771      * @throws Exception if the test fails
2772      */
2773     @Test
2774     @Alerts({"Response", "param1=value1"})
2775     public void requestSubmit() throws Exception {
2776         final String html = DOCTYPE_HTML
2777             + "<html>\n"
2778             + "<head><title>first</title>\n"
2779             + "<script>\n"
2780             + "function doTest() {\n"
2781             + "  var myForm = document.getElementById('form1');\n"
2782             + "  if (myForm.requestSubmit) {\n"
2783             + "    myForm.requestSubmit();\n"
2784             + "    return;\n"
2785             + "  }\n"
2786             + "  alert('requestSubmit() not available');\n"
2787             + "}\n"
2788             + "</script>\n"
2789             + "</head>\n"
2790 
2791             + "<body onload='doTest()'>\n"
2792             + "  <form id='form1' name='form1' method='get' action='" + URL_SECOND + "' encoding='text/plain'>\n"
2793             + "    <input name='param1' type='hidden' value='value1'>\n"
2794             + "  </form>\n"
2795             + "</body></html>";
2796 
2797         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
2798 
2799         final WebDriver driver = loadPage2(html);
2800         if (getExpectedAlerts().length == 1) {
2801             verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0]});
2802             return;
2803         }
2804 
2805         assertTitle(driver, getExpectedAlerts()[0]);
2806         final String params = getMockWebConnection().getLastWebRequest().getUrl().getQuery();
2807         assertEquals(getExpectedAlerts()[1], params);
2808     }
2809 
2810     /**
2811      * @throws Exception if the test fails
2812      */
2813     @Test
2814     @Alerts({"Response", "param1=value1"})
2815     public void requestSubmitWithSubmit() throws Exception {
2816         final String html = DOCTYPE_HTML
2817             + "<html>\n"
2818             + "<head><title>first</title>\n"
2819             + "<script>\n"
2820             + "function doTest() {\n"
2821             + "  var myForm = document.getElementById('form1');\n"
2822             + "  if (myForm.requestSubmit) {\n"
2823             + "    var sub = document.getElementById('submit1');\n"
2824             + "    myForm.requestSubmit(sub);\n"
2825             + "    return;\n"
2826             + "  }\n"
2827             + "  alert('requestSubmit() not available');\n"
2828             + "}\n"
2829             + "</script>\n"
2830             + "</head>\n"
2831 
2832             + "<body onload='doTest()'>\n"
2833             + "  <form id='form1' name='form1' method='get' action='" + URL_SECOND + "' encoding='text/plain'>\n"
2834             + "    <input name='param1' type='hidden' value='value1'>\n"
2835             + "    <input id='submit1' type='submit' />\n"
2836             + "  </form>\n"
2837             + "</body></html>";
2838 
2839         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
2840 
2841         final WebDriver driver = loadPage2(html);
2842         if (getExpectedAlerts().length == 1) {
2843             verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0]});
2844             return;
2845         }
2846 
2847         assertTitle(driver, getExpectedAlerts()[0]);
2848         final String params = getMockWebConnection().getLastWebRequest().getUrl().getQuery();
2849         assertEquals(getExpectedAlerts()[1], params);
2850     }
2851 
2852     /**
2853      * @throws Exception if the test fails
2854      */
2855     @Test
2856     @Alerts({"Response", "param1=value1&submit1="})
2857     public void requestSubmitWithButton() throws Exception {
2858         final String html = DOCTYPE_HTML
2859             + "<html>\n"
2860             + "<head><title>first</title>\n"
2861             + "<script>\n"
2862             + "function doTest() {\n"
2863             + "  var myForm = document.getElementById('form1');\n"
2864             + "  if (myForm.requestSubmit) {\n"
2865             + "    var sub = document.getElementById('submit1');\n"
2866             + "    try {\n"
2867             + "      myForm.requestSubmit(sub);\n"
2868             + "    } catch(e) { alert('requestSubmit failed' + e); }\n"
2869             + "    return;\n"
2870             + "  }\n"
2871             + "  alert('requestSubmit() not available');\n"
2872             + "}\n"
2873             + "</script>\n"
2874             + "</head>\n"
2875 
2876             + "<body onload='doTest()'>\n"
2877             + "  <form id='form1' name='form1' method='get' action='" + URL_SECOND + "' encoding='text/plain'>\n"
2878             + "    <input name='param1' type='hidden' value='value1'>\n"
2879             + "    <button type='submit' id='submit1' name='submit1'>submit1</button>\n"
2880             + "  </form>\n"
2881             + "</body></html>";
2882 
2883         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
2884 
2885         final WebDriver driver = loadPage2(html);
2886         if (getExpectedAlerts().length == 1) {
2887             verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0]});
2888             return;
2889         }
2890 
2891         assertTitle(driver, getExpectedAlerts()[0]);
2892         final String params = getMockWebConnection().getLastWebRequest().getUrl().getQuery();
2893         assertEquals(getExpectedAlerts()[1], params);
2894     }
2895 
2896     /**
2897      * @throws Exception if the test fails
2898      */
2899     @Test
2900     @Alerts({"first", "requestSubmit failed"})
2901     public void requestSubmitNotMember() throws Exception {
2902         final String html = DOCTYPE_HTML
2903             + "<html>\n"
2904             + "<head><title>first</title>\n"
2905             + "<script>\n"
2906             + "function doTest() {\n"
2907             + "  var myForm = document.getElementById('form1');\n"
2908             + "  if (myForm.requestSubmit) {\n"
2909             + "    var sub = document.getElementById('submit2');\n"
2910             + "    try {\n"
2911             + "      myForm.requestSubmit(sub);\n"
2912             + "    } catch(e) { alert('requestSubmit failed'); }\n"
2913             + "    return;\n"
2914             + "  }\n"
2915             + "  alert('requestSubmit() not available');\n"
2916             + "}\n"
2917             + "</script>\n"
2918             + "</head>\n"
2919 
2920             + "<body onload='doTest()'>\n"
2921             + "  <form id='form1' name='form1' method='get' action='" + URL_SECOND + "' encoding='text/plain'>\n"
2922             + "    <input name='param1' type='hidden' value='value1'>\n"
2923             + "  </form>\n"
2924 
2925             + "  <form id='form2' name='form2' method='get' action='" + URL_SECOND + "' encoding='text/plain'>\n"
2926             + "    <input type='submit' id='submit2' />\n"
2927             + "  </form>\n"
2928             + "</body></html>";
2929 
2930         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
2931 
2932         final WebDriver driver = loadPage2(html);
2933         if (getExpectedAlerts().length == 1) {
2934             verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0]});
2935             return;
2936         }
2937 
2938         verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[1]});
2939         assertTitle(driver, getExpectedAlerts()[0]);
2940     }
2941 
2942     /**
2943      * @throws Exception if the test fails
2944      */
2945     @Test
2946     @Alerts({"first", "requestSubmit failed"})
2947     public void requestSubmitNotSubmit() throws Exception {
2948         final String html = DOCTYPE_HTML
2949             + "<html>\n"
2950             + "<head><title>first</title>\n"
2951             + "<script>\n"
2952             + "function doTest() {\n"
2953             + "  var myForm = document.getElementById('form1');\n"
2954             + "  if (myForm.requestSubmit) {\n"
2955             + "    var sub = document.getElementById('param1');\n"
2956             + "    try {\n"
2957             + "      myForm.requestSubmit(sub);\n"
2958             + "    } catch(e) { alert('requestSubmit failed'); }\n"
2959             + "    return;\n"
2960             + "  }\n"
2961             + "  alert('requestSubmit() not available');\n"
2962             + "}\n"
2963             + "</script>\n"
2964             + "</head>\n"
2965 
2966             + "<body onload='doTest()'>\n"
2967             + "  <form id='form1' name='form1' method='get' action='" + URL_SECOND + "' encoding='text/plain'>\n"
2968             + "    <input id='param1' name='param1' type='hidden' value='value1'>\n"
2969             + "  </form>\n"
2970             + "</body></html>";
2971 
2972         getMockWebConnection().setDefaultResponse("<html><title>Response</title></html>");
2973 
2974         final WebDriver driver = loadPage2(html);
2975         if (getExpectedAlerts().length == 1) {
2976             verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[0]});
2977             return;
2978         }
2979 
2980         verifyAlerts(DEFAULT_WAIT_TIME, driver, new String[] {getExpectedAlerts()[1]});
2981         assertTitle(driver, getExpectedAlerts()[0]);
2982     }
2983 
2984     /**
2985      * @throws Exception if the test fails
2986      */
2987     @Test
2988     @Alerts({"1", "false", "true", "false", "false"})
2989     public void in() throws Exception {
2990         final String html = DOCTYPE_HTML
2991             + "<html>\n"
2992             + "<head>\n"
2993             + "<script>\n"
2994             + LOG_TITLE_FUNCTION
2995             + "function doTest() {\n"
2996             + "  var f = document.testForm;\n"
2997             + "  log(f.length);\n"
2998             + "  log(-1 in f);\n"
2999             + "  log(0 in f);\n"
3000             + "  log(1 in f);\n"
3001             + "  log(42 in f);\n"
3002             + "}\n"
3003             + "</script>\n"
3004             + "</head>\n"
3005             + "<body onload='doTest()'>\n"
3006             + "  <form name='testForm' action='about:blank'>\n"
3007             + "    <input type='submit' id='theButton'>\n"
3008             + "  </form>\n"
3009             + "</body></html>";
3010 
3011         loadPageVerifyTitle2(html);
3012     }
3013 
3014     /**
3015      * @throws Exception if the test fails
3016      */
3017     @Test
3018     @Alerts("second")
3019     public void notRequired() throws Exception {
3020         required("");
3021     }
3022 
3023     /**
3024      * @throws Exception if the test fails
3025      */
3026     @Test
3027     @Alerts("first")
3028     public void required() throws Exception {
3029         required("required");
3030     }
3031 
3032     /**
3033      * @throws Exception if the test fails
3034      */
3035     @Test
3036     @Alerts("first")
3037     public void requiredEmpty() throws Exception {
3038         required("required=''");
3039     }
3040 
3041     /**
3042      * @throws Exception if the test fails
3043      */
3044     @Test
3045     @Alerts("first")
3046     public void requiredBlank() throws Exception {
3047         required("required=' '");
3048     }
3049 
3050     /**
3051      * @throws Exception if the test fails
3052      */
3053     @Test
3054     @Alerts("first")
3055     public void requiredTrue() throws Exception {
3056         required("required=true");
3057         required("required='true'");
3058     }
3059 
3060     /**
3061      * @throws Exception if the test fails
3062      */
3063     @Test
3064     @Alerts("first")
3065     public void requiredFalse() throws Exception {
3066         required("required=false");
3067         required("required='false'");
3068     }
3069 
3070     /**
3071      * @throws Exception if the test fails
3072      */
3073     @Test
3074     @Alerts("first")
3075     public void requiredArbitrary() throws Exception {
3076         required("required='Arbitrary'");
3077     }
3078 
3079     /**
3080      * @throws Exception if the test fails
3081      */
3082     @Test
3083     @Alerts("first")
3084     public void requiredRequired() throws Exception {
3085         required("required='required'");
3086     }
3087 
3088     /**
3089      * @throws Exception if the test fails
3090      */
3091     private void required(final String req) throws Exception {
3092         final String html = DOCTYPE_HTML
3093             + "<html>\n"
3094             + "<head><title>first</title></head>\n"
3095             + "<body>\n"
3096             + "  <form name='testForm' action='\" + URL_SECOND + \"'>\n"
3097             + "    <input type='submit' id='submit'>\n"
3098             + "    <input name='test' value='' " + req + " >"
3099             + "  </form>\n"
3100             + "</body></html>";
3101 
3102         final String html2 = "<?xml version='1.0'?>\n"
3103             + "<html>\n"
3104             + "<head><title>second</title></head>\n"
3105             + "<body>OK</body></html>";
3106         getMockWebConnection().setDefaultResponse(html2);
3107 
3108         final WebDriver driver = loadPage2(html);
3109         driver.findElement(By.id("submit")).click();
3110         if (useRealBrowser()) {
3111             Thread.sleep(400);
3112         }
3113 
3114         assertEquals(getExpectedAlerts()[0], driver.getTitle());
3115     }
3116 
3117     /**
3118      * @throws Exception if the test fails
3119      */
3120     @Test
3121     @Alerts({"second", "second"})
3122     public void notRequiredFileInput() throws Exception {
3123         requiredFileInput("");
3124     }
3125 
3126     /**
3127      * @throws Exception if the test fails
3128      */
3129     @Test
3130     @Alerts({"first", "second"})
3131     public void requiredFileInput() throws Exception {
3132         requiredFileInput("required");
3133     }
3134 
3135     /**
3136      * @throws Exception if the test fails
3137      */
3138     @Test
3139     @Alerts({"first", "second"})
3140     public void requiredFileInputEmpty() throws Exception {
3141         requiredFileInput("required=''");
3142     }
3143 
3144     /**
3145      * @throws Exception if the test fails
3146      */
3147     @Test
3148     @Alerts({"first", "second"})
3149     public void requiredFileInputBlank() throws Exception {
3150         requiredFileInput("required=' '");
3151     }
3152 
3153     /**
3154      * @throws Exception if the test fails
3155      */
3156     @Test
3157     @Alerts({"first", "second"})
3158     public void requiredFileInputTrue() throws Exception {
3159         requiredFileInput("required=true");
3160         requiredFileInput("required='true'");
3161     }
3162 
3163     /**
3164      * @throws Exception if the test fails
3165      */
3166     @Test
3167     @Alerts({"first", "second"})
3168     public void requiredFileInputFalse() throws Exception {
3169         requiredFileInput("required=false");
3170         requiredFileInput("required='false'");
3171     }
3172 
3173     /**
3174      * @throws Exception if the test fails
3175      */
3176     @Test
3177     @Alerts({"first", "second"})
3178     public void requiredFileInputArbitrary() throws Exception {
3179         requiredFileInput("required='Arbitrary'");
3180     }
3181 
3182     /**
3183      * @throws Exception if the test fails
3184      */
3185     @Test
3186     @Alerts({"first", "second"})
3187     public void requiredFileInputRequired() throws Exception {
3188         requiredFileInput("required='required'");
3189     }
3190 
3191     /**
3192      * @throws Exception if the test fails
3193      */
3194     private void requiredFileInput(final String req) throws Exception {
3195         final String html = DOCTYPE_HTML
3196             + "<html>\n"
3197             + "<head><title>first</title></head>\n"
3198             + "<body>\n"
3199             + "  <form name='testForm' action='\" + URL_SECOND + \"'>\n"
3200             + "    <input type='submit' id='submit'>\n"
3201             + "    <input type='file' name='test' value='' " + req + " >"
3202             + "  </form>\n"
3203             + "</body></html>";
3204 
3205         final String html2 = "<?xml version='1.0'?>\n"
3206             + "<html>\n"
3207             + "<head><title>second</title></head>\n"
3208             + "<body>OK</body></html>";
3209         getMockWebConnection().setDefaultResponse(html2);
3210 
3211         final WebDriver driver = loadPage2(html);
3212         driver.findElement(By.id("submit")).click();
3213         if (useRealBrowser()) {
3214             Thread.sleep(400);
3215         }
3216         assertEquals(getExpectedAlerts()[0], driver.getTitle());
3217 
3218         loadPage2(html);
3219         final WebElement e = driver.findElement(By.name("test"));
3220         final String absolutePath = new File("pom.xml").getAbsolutePath();
3221         e.sendKeys(absolutePath);
3222         driver.findElement(By.id("submit")).click();
3223         if (useRealBrowser()) {
3224             Thread.sleep(400);
3225         }
3226         assertEquals(getExpectedAlerts()[1], driver.getTitle());
3227     }
3228 
3229     /**
3230      * @throws Exception if the test fails
3231      */
3232     @Test
3233     @Alerts("first")
3234     public void notNovalidate() throws Exception {
3235         novalidate("");
3236     }
3237 
3238     /**
3239      * @throws Exception if the test fails
3240      */
3241     @Test
3242     @Alerts("second")
3243     public void novalidate() throws Exception {
3244         novalidate("novalidate");
3245     }
3246 
3247     /**
3248      * @throws Exception if the test fails
3249      */
3250     @Test
3251     @Alerts("second")
3252     public void novalidateEmpty() throws Exception {
3253         novalidate("novalidate=''");
3254     }
3255 
3256     /**
3257      * @throws Exception if the test fails
3258      */
3259     @Test
3260     @Alerts("second")
3261     public void novalidateBlank() throws Exception {
3262         novalidate("novalidate=' '");
3263     }
3264 
3265     /**
3266      * @throws Exception if the test fails
3267      */
3268     @Test
3269     @Alerts("second")
3270     public void novalidateTrue() throws Exception {
3271         novalidate("novalidate=true");
3272         novalidate("novalidate='true'");
3273     }
3274 
3275     /**
3276      * @throws Exception if the test fails
3277      */
3278     @Test
3279     @Alerts("second")
3280     public void novalidateFalse() throws Exception {
3281         required("novalidate=false");
3282         required("novalidate='false'");
3283     }
3284 
3285     /**
3286      * @throws Exception if the test fails
3287      */
3288     @Test
3289     @Alerts("second")
3290     public void novalidateArbitrary() throws Exception {
3291         required("novalidate='Arbitrary'");
3292     }
3293 
3294     /**
3295      * @throws Exception if the test fails
3296      */
3297     @Test
3298     @Alerts("second")
3299     public void novalidateNovalidate() throws Exception {
3300         required("novalidate='novalidate'");
3301     }
3302 
3303     /**
3304      * @throws Exception if the test fails
3305      */
3306     private void novalidate(final String novalidate) throws Exception {
3307         final String html = "<html>\n"
3308             + "<head><title>first</title></head>\n"
3309             + "<body>\n"
3310             + "  <form name='testForm' action='\" + URL_SECOND + \"' " + novalidate + " >\n"
3311             + "    <input type='submit' id='submit'>\n"
3312             + "    <input name='test' value='' required >"
3313             + "  </form>\n"
3314             + "</body></html>";
3315 
3316         final String html2 = "<?xml version='1.0'?>\n"
3317             + "<html>\n"
3318             + "<head><title>second</title></head>\n"
3319             + "<body>OK</body></html>";
3320         getMockWebConnection().setDefaultResponse(html2);
3321 
3322         final WebDriver driver = loadPage2(html);
3323         driver.findElement(By.id("submit")).click();
3324         if (useRealBrowser()) {
3325             Thread.sleep(400);
3326         }
3327 
3328         assertEquals(getExpectedAlerts()[0], driver.getTitle());
3329     }
3330 
3331     /**
3332      * @throws Exception if an error occurs
3333      */
3334     @Test
3335     @Alerts({"", "alternate help", "prefetch", "prefetch", "not supported", "notsupported"})
3336     public void readWriteRel() throws Exception {
3337         final String html = DOCTYPE_HTML
3338             + "<html><body><form id='f1'>a1</form><form id='f2' rel='alternate help'>a2</form><script>\n"
3339             + LOG_TITLE_FUNCTION
3340             + "var a1 = document.getElementById('f1'), a2 = document.getElementById('f2');\n"
3341 
3342             + "log(a1.rel);\n"
3343             + "log(a2.rel);\n"
3344 
3345             + "a1.rel = 'prefetch';\n"
3346             + "a2.rel = 'prefetch';\n"
3347             + "log(a1.rel);\n"
3348             + "log(a2.rel);\n"
3349 
3350             + "a1.rel = 'not supported';\n"
3351             + "a2.rel = 'notsupported';\n"
3352             + "log(a1.rel);\n"
3353             + "log(a2.rel);\n"
3354 
3355             + "</script></body></html>";
3356         loadPageVerifyTitle2(html);
3357     }
3358 
3359     /**
3360      * @throws Exception if an error occurs
3361      */
3362     @Test
3363     @Alerts({"0", "2", "alternate", "help"})
3364     public void relList() throws Exception {
3365         final String html = DOCTYPE_HTML
3366             + "<html><body><form id='f1'>a1</form><form id='f2' rel='alternate help'>a2</form><script>\n"
3367             + LOG_TITLE_FUNCTION
3368             + "var a1 = document.getElementById('f1'), a2 = document.getElementById('f2');\n"
3369 
3370             + "try {\n"
3371             + "  log(a1.relList.length);\n"
3372             + "  log(a2.relList.length);\n"
3373 
3374             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
3375             + "    log(a2.relList[i]);\n"
3376             + "  }\n"
3377             + "} catch(e) { logEx(e); }\n"
3378 
3379             + "</script></body></html>";
3380         loadPageVerifyTitle2(html);
3381     }
3382 
3383     /**
3384      * @throws Exception if an error occurs
3385      */
3386     @Test
3387     @Alerts({"0", "2", "2", "1", "alternate", "help", "abc", "alternate help", "abc"})
3388     public void setRelListString() throws Exception {
3389         final String html = DOCTYPE_HTML
3390             + "<html><body><form id='f1'>a1</form><form id='f2' rel='alternate help'>a2</form><script>\n"
3391             + LOG_TITLE_FUNCTION
3392             + "var a1 = document.getElementById('f1'), a2 = document.getElementById('f2');\n"
3393 
3394             + "try {\n"
3395             + "  log(a1.relList.length);\n"
3396             + "  log(a2.relList.length);\n"
3397 
3398             + "  a1.relList = 'alternate help';\n"
3399             + "  a2.relList = 'abc';\n"
3400 
3401             + "  log(a1.relList.length);\n"
3402             + "  log(a2.relList.length);\n"
3403 
3404             + "  for (var i = 0; i < a1.relList.length; i++) {\n"
3405             + "    log(a1.relList[i]);\n"
3406             + "  }\n"
3407 
3408             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
3409             + "    log(a2.relList[i]);\n"
3410             + "  }\n"
3411 
3412             + "  log(a1.rel);\n"
3413             + "  log(a2.rel);\n"
3414             + "} catch(e) { logEx(e); }\n"
3415 
3416             + "</script></body></html>";
3417         loadPageVerifyTitle2(html);
3418     }
3419 
3420     /**
3421      * @throws Exception if an error occurs
3422      */
3423     @Test
3424     @Alerts({"0", "2", "0", "0", "", "\\s\\s\\t"})
3425     public void setRelListStringBlank() throws Exception {
3426         final String html = DOCTYPE_HTML
3427             + "<html><body><form id='f1'>a1</form><form id='f2' rel='alternate help'>a2</form><script>\n"
3428             + LOG_TITLE_FUNCTION_NORMALIZE
3429             + "var a1 = document.getElementById('f1'), a2 = document.getElementById('f2');\n"
3430 
3431             + "try {\n"
3432             + "  log(a1.relList.length);\n"
3433             + "  log(a2.relList.length);\n"
3434 
3435             + "  a1.relList = '';\n"
3436             + "  a2.relList = '  \t';\n"
3437 
3438             + "  log(a1.relList.length);\n"
3439             + "  log(a2.relList.length);\n"
3440 
3441             + "  log(a1.rel);\n"
3442             + "  log(a2.rel);\n"
3443             + "} catch(e) { logEx(e); }\n"
3444 
3445             + "</script></body></html>";
3446         loadPageVerifyTitle2(html);
3447     }
3448 
3449     /**
3450      * @throws Exception if an error occurs
3451      */
3452     @Test
3453     @Alerts({"0", "2", "1", "1", "null", "null", "null", "null"})
3454     public void setRelListNull() throws Exception {
3455         final String html = DOCTYPE_HTML
3456             + "<html><body><form id='f1'>a1</form><form id='f2' rel='alternate help'>a2</form><script>\n"
3457             + LOG_TITLE_FUNCTION_NORMALIZE
3458             + "var a1 = document.getElementById('f1'), a2 = document.getElementById('f2');\n"
3459 
3460             + "try {\n"
3461             + "  log(a1.relList.length);\n"
3462             + "  log(a2.relList.length);\n"
3463 
3464             + "  a1.relList = null;\n"
3465             + "  a2.relList = null;\n"
3466 
3467             + "  log(a1.relList.length);\n"
3468             + "  log(a2.relList.length);\n"
3469 
3470             + "  for (var i = 0; i < a1.relList.length; i++) {\n"
3471             + "    log(a1.relList[i]);\n"
3472             + "  }\n"
3473 
3474             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
3475             + "    log(a2.relList[i]);\n"
3476             + "  }\n"
3477 
3478             + "  log(a1.rel);\n"
3479             + "  log(a2.rel);\n"
3480             + "} catch(e) { logEx(e); }\n"
3481 
3482             + "</script></body></html>";
3483         loadPageVerifyTitle2(html);
3484     }
3485 
3486     /**
3487      * @throws Exception if an error occurs
3488      */
3489     @Test
3490     @Alerts({"0", "2", "1", "1", "undefined", "undefined", "undefined", "undefined"})
3491     public void setRelListUndefined() throws Exception {
3492         final String html = DOCTYPE_HTML
3493             + "<html><body><form id='f1'>a1</form><form id='f2' rel='alternate help'>a2</form><script>\n"
3494             + LOG_TITLE_FUNCTION_NORMALIZE
3495             + "var a1 = document.getElementById('f1'), a2 = document.getElementById('f2');\n"
3496 
3497             + "try {\n"
3498             + "  log(a1.relList.length);\n"
3499             + "  log(a2.relList.length);\n"
3500 
3501             + "  a1.relList = undefined;\n"
3502             + "  a2.relList = undefined;\n"
3503 
3504             + "  log(a1.relList.length);\n"
3505             + "  log(a2.relList.length);\n"
3506 
3507             + "  for (var i = 0; i < a1.relList.length; i++) {\n"
3508             + "    log(a1.relList[i]);\n"
3509             + "  }\n"
3510 
3511             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
3512             + "    log(a2.relList[i]);\n"
3513             + "  }\n"
3514 
3515             + "  log(a1.rel);\n"
3516             + "  log(a2.rel);\n"
3517             + "} catch(e) { logEx(e); }\n"
3518 
3519             + "</script></body></html>";
3520         loadPageVerifyTitle2(html);
3521     }
3522 
3523     /**
3524      * @throws Exception if an error occurs
3525      */
3526     @Test
3527     @Alerts({"[object HTMLInputElement]", "[object HTMLInputElement]"})
3528     public void elementsForOf() throws Exception {
3529         final String html = DOCTYPE_HTML
3530             + "<html>\n"
3531             + "<head>\n"
3532             + "<script>\n"
3533             + LOG_TITLE_FUNCTION
3534             + "  function test() {\n"
3535             + "    var f = document.getElementById('testForm');\n"
3536             + "    for (var attr of f) {\n"
3537             + "      log(attr);\n"
3538             + "    }\n"
3539             + "  }\n"
3540             + "</script>\n"
3541             + "</head>\n"
3542             + "<body onload='test()'>\n"
3543             + "  <form name='testForm' id='testForm'>\n"
3544             + "    <input type='submit' id='submit'>\n"
3545             + "    <input type='text' name='test' value=''>"
3546             + "  </form>\n"
3547             + "</body>\n"
3548             + "</html>";
3549 
3550         loadPageVerifyTitle2(html);
3551     }
3552 }