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 java.net.URL;
18  import java.nio.charset.StandardCharsets;
19  
20  import org.htmlunit.WebDriverTestCase;
21  import org.htmlunit.junit.BrowserRunner;
22  import org.htmlunit.junit.annotation.Alerts;
23  import org.htmlunit.junit.annotation.HtmlUnitNYI;
24  import org.htmlunit.util.MimeType;
25  import org.junit.Test;
26  import org.junit.runner.RunWith;
27  import org.openqa.selenium.By;
28  import org.openqa.selenium.WebDriver;
29  import org.openqa.selenium.htmlunit.HtmlUnitDriver;
30  
31  /**
32   * Unit tests for {@link HTMLScriptElement}.
33   * TODO: check event order with defer in real browser WITHOUT using alert(...) as it impacts ordering.
34   * Some expectations seems to be incorrect.
35   * @author Daniel Gredler
36   * @author Ahmed Ashour
37   * @author Marc Guillemot
38   * @author Frank Danek
39   * @author Ronald Brill
40   */
41  @RunWith(BrowserRunner.class)
42  public class HTMLScriptElementTest extends WebDriverTestCase {
43  
44      /**
45       * Verifies that the <tt>onreadystatechange</tt> handler is invoked correctly.
46       * @throws Exception if an error occurs
47       */
48      @Test
49      @Alerts({"1", "2", "3", "4", "onload"})
50      public void onReadyStateChangeHandler() throws Exception {
51          final String html = DOCTYPE_HTML
52              + "<html>\n"
53              + "  <head>\n"
54              + "    <script>\n"
55              + LOG_TITLE_FUNCTION
56              + "      function test() {\n"
57              + "        var script = document.createElement('script');\n"
58              + "        script.id = 'b';\n"
59              + "        script.type = 'text/javascript';\n"
60              + "        script.onreadystatechange = null;\n"
61              + "        script.onreadystatechange = function() {\n"
62              + "          log('onreadystatechange ' + script.readyState);\n"
63              + "        }\n"
64              + "        script.onload = function() {\n"
65              + "          log('onload');\n"
66              + "        }\n"
67              + "        log('1');\n"
68              + "        script.src = 'script.js';\n"
69              + "        log('2');\n"
70              + "        document.getElementsByTagName('head')[0].appendChild(script);\n"
71              + "        log('3');\n"
72              + "      }\n"
73              + "    </script>\n"
74              + "  </head>\n"
75              + "  <body onload='test()'>\n"
76              + "  </body></html>";
77  
78          getMockWebConnection().setDefaultResponse("log('4');", MimeType.TEXT_JAVASCRIPT);
79  
80          loadPage2(html);
81          verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
82      }
83  
84      /**
85       * Test for bug
86       * <a href="https://sourceforge.net/tracker/?func=detail&atid=448266&aid=1782719&group_id=47038">issue 514</a>.
87       * @throws Exception if the test fails
88       */
89      @Test
90      public void srcWithJavaScriptProtocol_Static() throws Exception {
91          final String html = DOCTYPE_HTML
92                  + "<html><head><script src='javascript:\"alert(1)\"'></script></head><body></body></html>";
93          loadPageWithAlerts2(html);
94      }
95  
96      /**
97       * @throws Exception if the test fails
98       */
99      @Test
100     @Alerts({"§§URL§§foo.js", "foo.js", "§§URL§§", ""})
101     public void srcPropertyShouldBeAFullUrl() throws Exception {
102         final String html = DOCTYPE_HTML
103                 + "<html>\n"
104                 + "<head>\n"
105                 + "  <script>\n"
106                 + LOG_TITLE_FUNCTION
107                 + "    function test() {\n"
108                 + "      var script = document.getElementById('my');\n"
109                 + "      log(script.src);\n"
110                 + "      log(script.getAttribute('src'));\n"
111 
112                 + "      var script2 = document.getElementById('my2');\n"
113                 + "      log(script2.src);\n"
114                 + "      log(script2.getAttribute('src'));\n"
115                 + "    }\n"
116                 + "  </script>\n"
117                 + "</head>\n"
118                 + "<body onload='test()'>\n"
119                 + "  <script id='my' src='foo.js'></script>\n"
120                 + "  <script id='my2' src=''></script>\n"
121                 + "</body></html>";
122 
123         getMockWebConnection().setDefaultResponse("", "text/javascript");
124 
125         expandExpectedAlertsVariables(URL_FIRST);
126         loadPageVerifyTitle2(html);
127     }
128 
129     /**
130      * @throws Exception if the test fails
131      */
132     @Test
133     @Alerts({"", "null", "", "null"})
134     public void srcPropertyNoSource() throws Exception {
135         final String html = DOCTYPE_HTML
136                 + "<html>\n"
137                 + "<head>\n"
138                 + "  <script>\n"
139                 + LOG_TITLE_FUNCTION
140                 + "    function test() {\n"
141                 + "      var script = document.getElementById('my');\n"
142                 + "      log(script.src);\n"
143                 + "      log(script.getAttribute('src'));\n"
144 
145                 + "      var script2 = document.createElement('script');\n"
146                 + "      log(script2.src);\n"
147                 + "      log(script2.getAttribute('src'));\n"
148                 + "    }\n"
149                 + "  </script>\n"
150                 + "</head>\n"
151                 + "<body onload='test()'>\n"
152                 + "  <script id='my'></script>\n"
153                 + "</body></html>";
154 
155         getMockWebConnection().setDefaultResponse("", "text/javascript");
156 
157         loadPageVerifyTitle2(html);
158     }
159 
160     /**
161      * Test for bug
162      * <a href="https://sourceforge.net/tracker/?func=detail&atid=448266&aid=1782719&group_id=47038">issue 514</a>.
163      * @throws Exception if the test fails
164      */
165     @Test
166     public void srcWithJavaScriptProtocol_Dynamic() throws Exception {
167         final String html = DOCTYPE_HTML
168             + "<html><head><script>\n"
169             + LOG_TITLE_FUNCTION
170             + "  function test() {\n"
171             + "    var script=document.createElement('script');\n"
172             + "    script.src = \"javascript: 'log(1)'\";\n"
173             + "    document.getElementsByTagName('head')[0].appendChild(script);\n"
174             + "  }\n"
175             + "</script></head><body onload='test()'>\n"
176             + "</body></html>";
177 
178         loadPageVerifyTitle2(html);
179     }
180 
181     /**
182      * Test for bug 2993940.
183      * @throws Exception if the test fails
184      */
185     @Test
186     @Alerts({"start", "end"})
187     public void reexecuteModifiedScript() throws Exception {
188         final String html = DOCTYPE_HTML
189             + "<html><head></head><body>\n"
190             + "<script>\n"
191             + LOG_TITLE_FUNCTION
192             + "  log('start');\n"
193             + "  var script = document.getElementsByTagName('script')[0];\n"
194             + "  script.text = \"log('executed');\";\n"
195             + "  log('end');\n"
196             + "</script>\n"
197             + "</body></html>";
198 
199         loadPageVerifyTitle2(html);
200     }
201 
202     /**
203      * @throws Exception if the test fails
204      */
205     @Test
206     @Alerts({"hello", "hello", "world", "-"})
207     public void scriptInCdataXHtml() throws Exception {
208         final String html =
209             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
210             + "<!DOCTYPE html PUBLIC \n"
211             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
212             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
213             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
214             + "<head></head>\n"
215             + "<body>\n"
216             + "<script>\n"
217             // do not use LOG_TITLE_FUNCTION here
218             + "    function log(msg) { window.document.title += msg + '\\u00a7'; }\n"
219             + "</script>\n"
220             + "  <script>\n"
221             + "    //<![CDATA[\n"
222             + "    log('hello');\n"
223             + "    //]]>\n"
224             + "  </script>\n"
225             + "  <script>\n"
226             + "    /*<![CDATA[*/log('hello');/*]]>*/\n"
227             + "  </script>\n"
228             + "  <script>\n"
229             + "    <![CDATA[\n"
230             + "    log('world');\n"
231             + "    ]]>\n"
232             + "  </script>\n"
233             + "  <script>log('-');</script>\n"
234             + "</body></html>";
235 
236         if (getWebDriver() instanceof HtmlUnitDriver) {
237             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
238         }
239 
240         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.APPLICATION_XHTML, StandardCharsets.UTF_8);
241         verifyTitle2(driver, getExpectedAlerts());
242     }
243 
244     /**
245      * @throws Exception if the test fails
246      */
247     @Test
248     @Alerts({"hello", "hello", "world", "-"})
249     public void scriptInCdataXml() throws Exception {
250         final String html =
251             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
252             + "<!DOCTYPE html PUBLIC \n"
253             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
254             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
255             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
256             + "<head></head>\n"
257             + "<body>\n"
258             + "<script>\n"
259             // do not use LOG_TITLE_FUNCTION here
260             + "    function log(msg) { window.document.title += msg + '\\u00a7'; }\n"
261             + "</script>\n"
262             + "  <script>\n"
263             + "    //<![CDATA[\n"
264             + "    log('hello');\n"
265             + "    //]]>\n"
266             + "  </script>\n"
267             + "  <script>\n"
268             + "    /*<![CDATA[*/log('hello');/*]]>*/\n"
269             + "  </script>\n"
270             + "  <script>\n"
271             + "    <![CDATA[\n"
272             + "    log('world');\n"
273             + "    ]]>\n"
274             + "  </script>\n"
275             + "  <script>log('-');</script>\n"
276             + "</body></html>";
277 
278         if (getWebDriver() instanceof HtmlUnitDriver) {
279             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
280         }
281         final WebDriver driver = loadPage2(html, URL_FIRST, MimeType.TEXT_XML, StandardCharsets.UTF_8);
282         verifyTitle2(driver, getExpectedAlerts());
283     }
284 
285     /**
286      * @throws Exception if the test fails
287      */
288     @Test
289     @Alerts({"hello", "hello", "-"})
290     public void scriptInCdataHtml() throws Exception {
291         final String html = DOCTYPE_HTML
292             + "<html>\n"
293             + "<head></head>\n"
294             + "<body>\n"
295             + "<script>\n"
296             + LOG_TITLE_FUNCTION
297             + "</script>\n"
298             + "  <script>\n"
299             + "    //<![CDATA[\n"
300             + "    log('hello');\n"
301             + "    //]]>\n"
302             + "  </script>\n"
303             + "  <script>\n"
304             + "    /*<![CDATA[*/log('hello');/*]]>*/\n"
305             + "  </script>\n"
306             + "  <script>\n"
307             + "    <![CDATA[\n"
308             + "    log('world');\n"
309             + "    ]]>\n"
310             + "  </script>\n"
311             + "  <script>log('-');</script>\n"
312             + "</body></html>";
313 
314         if (getWebDriver() instanceof HtmlUnitDriver) {
315             getWebClient().getOptions().setThrowExceptionOnScriptError(false);
316         }
317         loadPageVerifyTitle2(html);
318     }
319 
320     /**
321      * Creates a new script element and adds the source using <code>createTextNode</code> and <code>appendChild</code>.
322      * @throws Exception if the test fails
323      */
324     @Test
325     @Alerts({"start", "end"})
326     public void createElementWithCreateTextNode() throws Exception {
327         final String html = DOCTYPE_HTML
328               + "<html><head></head><body>\n"
329               + "<script>\n"
330               + LOG_TITLE_FUNCTION
331               + "  log('start');\n"
332               + "  var script = document.createElement('script');\n"
333               + "  var source = document.createTextNode(\"log('executed');\");\n"
334               + "  try {\n"
335               + "    script.appendChild(source);\n"
336               + "  } catch(e) {logEx(e); }\n"
337               + "  log('end');\n"
338               + "</script>\n"
339               + "</body></html>";
340 
341         loadPageVerifyTitle2(html);
342     }
343 
344     /**
345      * Creates a new script element and adds the source using <code>createTextNode</code> and <code>appendChild</code>.
346      * After that it appends the script element to the body.
347      * @throws Exception if the test fails
348      */
349     @Test
350     @Alerts({"start", "middle", "executed", "end"})
351     public void createElementWithCreateTextNodeAndAppend() throws Exception {
352         final String html = DOCTYPE_HTML
353               + "<html><head></head><body>\n"
354               + "<script>\n"
355               + LOG_TITLE_FUNCTION
356               + "  log('start');\n"
357               + "  var script = document.createElement('script');\n"
358               + "  var source = document.createTextNode(\"log('executed');\");\n"
359               + "  try {\n"
360               + "    script.appendChild(source);\n"
361               + "  } catch(e) {logEx(e); }\n"
362               + "  log('middle');\n"
363               + "  document.body.appendChild(script);\n"
364               + "  log('end');\n"
365               + "</script>\n"
366               + "</body></html>";
367 
368         loadPageVerifyTitle2(html);
369     }
370 
371     /**
372      * Creates a new script element and adds the source using <code>.text</code>.
373      * @throws Exception if the test fails
374      */
375     @Test
376     @Alerts({"start", "end"})
377     public void createElementWithSetText() throws Exception {
378         final String html = DOCTYPE_HTML
379               + "<html><head></head><body>\n"
380               + "<script>\n"
381               + LOG_TITLE_FUNCTION
382               + "  log('start');\n"
383               + "  var script = document.createElement('script');\n"
384               + "  script.text = \"log('executed');\";\n"
385               + "  log('end');\n"
386               + "</script>\n"
387               + "</body></html>";
388 
389         loadPageVerifyTitle2(html);
390     }
391 
392     /**
393      * Creates a new script element and adds the source using <code>.text</code>.
394      * After that it appends the script element to the body.
395      * @throws Exception if the test fails
396      */
397     @Test
398     @Alerts({"start", "middle", "executed", "end"})
399     public void createElementWithSetTextAndAppend() throws Exception {
400         final String html = DOCTYPE_HTML
401               + "<html><head></head><body>\n"
402               + "<script>\n"
403               + LOG_TITLE_FUNCTION
404               + "  log('start');\n"
405               + "  var script = document.createElement('script');\n"
406               + "  script.text = \"log('executed');\";\n"
407               + "  log('middle');\n"
408               + "  document.body.appendChild(script);\n"
409               + "  log('end');\n"
410               + "</script>\n"
411               + "</body></html>";
412 
413         loadPageVerifyTitle2(html);
414     }
415 
416     /**
417      * Creates a new script element and adds the source using <code>.src</code>.
418      * @throws Exception if the test fails
419      */
420     @Test
421     @Alerts({"start", "end"})
422     public void createElementWithSetSrc() throws Exception {
423         final String html = DOCTYPE_HTML
424               + "<html><head></head><body>\n"
425               + "<script>\n"
426               + LOG_TITLE_FUNCTION
427               + "  log('start');\n"
428               + "  var script = document.createElement('script');\n"
429               + "  script.src = \"" + URL_SECOND + "\";\n"
430               + "  log('end');\n"
431               + "</script>\n"
432               + "</body></html>";
433 
434         final String js = "log('executed');";
435         getMockWebConnection().setResponse(URL_SECOND, js);
436 
437         loadPageVerifyTitle2(html);
438     }
439 
440     /**
441      * Creates a new script element and adds the source using <code>.src</code>.
442      * After that it appends the script element to the body.
443      * @throws Exception if the test fails
444      */
445     @Test
446     @Alerts({"start", "middle", "end", "executed"})
447     public void createElementWithSetSrcAndAppend() throws Exception {
448         final String html = DOCTYPE_HTML
449               + "<html><head></head><body>\n"
450               + "<script>\n"
451               + LOG_TITLE_FUNCTION
452               + "  log('start');\n"
453               + "  var script = document.createElement('script');\n"
454               + "  script.src = \"" + URL_SECOND + "\";\n"
455               + "  log('middle');\n"
456               + "  document.body.appendChild(script);\n"
457               + "  log('end');\n"
458               + "</script>\n"
459               + "</body></html>";
460 
461         final String js = "log('executed');";
462         getMockWebConnection().setResponse(URL_SECOND, js);
463 
464         final WebDriver driver = loadPage2(html);
465         verifyTitle2(driver, getExpectedAlerts());
466     }
467 
468     /**
469      * Replaces the source of the current script element using <code>createTextNode</code> and <code>appendChild</code>.
470      * @throws Exception if the test fails
471      */
472     @Test
473     @Alerts({"start", "end"})
474     public void replaceSelfWithCreateTextNode() throws Exception {
475         final String html = DOCTYPE_HTML
476               + "<html><head></head><body>\n"
477               + "<script>\n"
478               + LOG_TITLE_FUNCTION
479               + "  log('start');\n"
480               + "  var script = document.getElementsByTagName('script')[0];\n"
481               + "  var source = document.createTextNode(\"log('executed');\");\n"
482               + "  try {\n"
483               + "    script.appendChild(source);\n"
484               + "  } catch(e) {logEx(e); }\n"
485               + "  log('end');\n"
486               + "</script>\n"
487               + "</body></html>";
488 
489         loadPageVerifyTitle2(html);
490     }
491 
492     /**
493      * Replaces the source of the current script element using <code>.text</code>.
494      * @throws Exception if the test fails
495      */
496     @Test
497     @Alerts({"start", "end"})
498     public void replaceSelfWithSetText() throws Exception {
499         // TODO this test is the same as #reexecuteModifiedScriptWhenReappending()
500         final String html = DOCTYPE_HTML
501               + "<html><head></head><body>\n"
502               + "<script>\n"
503               + LOG_TITLE_FUNCTION
504               + "  log('start');\n"
505               + "  var script = document.getElementsByTagName('script')[0];\n"
506               + "  var source = document.createTextNode(\"log('executed');\");\n"
507               + "  script.text = \"log('executed');\";\n"
508               + "  log('end');\n"
509               + "</script>\n"
510               + "</body></html>";
511 
512         loadPageVerifyTitle2(html);
513     }
514 
515     /**
516      * Replaces the source of the current script element using <code>.src</code>.
517      * @throws Exception if the test fails
518      */
519     @Test
520     @Alerts({"start", "end"})
521     public void replaceSelfWithSetSrc() throws Exception {
522         final String html = DOCTYPE_HTML
523               + "<html><head></head><body>\n"
524               + "<script>\n"
525               + LOG_TITLE_FUNCTION
526               + "  log('start');\n"
527               + "  var script = document.getElementsByTagName('script')[0];\n"
528               + "  var source = document.createTextNode(\"log('executed');\");\n"
529               + "  script.src = \"" + URL_SECOND + "\";\n"
530               + "  log('end');\n"
531               + "</script>\n"
532               + "</body></html>";
533 
534         final String js = "log('executed');";
535         getMockWebConnection().setResponse(URL_SECOND, js);
536 
537         loadPageVerifyTitle2(html);
538     }
539 
540     /**
541      * Replaces the empty source of another script element using <code>createTextNode</code> and <code>appendChild</code>.
542      * @throws Exception if the test fails
543      */
544     @Test
545     @Alerts({"start", "executed", "end"})
546     public void replaceWithCreateTextNodeEmpty() throws Exception {
547         final String html = DOCTYPE_HTML
548               + "<html><head></head><body>\n"
549               + "<script id='js1'></script>\n"
550               + "<script>\n"
551               + LOG_TITLE_FUNCTION
552               + "  log('start');\n"
553               + "  var script = document.getElementById('js1');\n"
554               + "  var source = document.createTextNode(\"log('executed');\");\n"
555               + "  try {\n"
556               + "    script.appendChild(source);\n"
557               + "  } catch(e) {logEx(e); }\n"
558               + "  log('end');\n"
559               + "</script>\n"
560               + "</body></html>";
561 
562         loadPageVerifyTitle2(html);
563     }
564 
565     /**
566      * Replaces the source containing just a blank of another script element using <code>createTextNode</code> and <code>appendChild</code>.
567      * @throws Exception if the test fails
568      */
569     @Test
570     @Alerts({"start", "end"})
571     public void replaceWithCreateTextNodeBlank() throws Exception {
572         final String html = DOCTYPE_HTML
573               + "<html><head></head><body>\n"
574               + "<script id='js1'> </script>\n"
575               + "<script>\n"
576               + LOG_TITLE_FUNCTION
577               + "  log('start');\n"
578               + "  var script = document.getElementById('js1');\n"
579               + "  var source = document.createTextNode(\"log('executed');\");\n"
580               + "  try {\n"
581               + "    script.appendChild(source);\n"
582               + "  } catch(e) {logEx(e); }\n"
583               + "  log('end');\n"
584               + "</script>\n"
585               + "</body></html>";
586 
587         loadPageVerifyTitle2(html);
588     }
589 
590     /**
591      * Replaces the source containing a script of another script element using <code>createTextNode</code> and <code>appendChild</code>.
592      * @throws Exception if the test fails
593      */
594     @Test
595     @Alerts({"script", "start", "end"})
596     public void replaceWithCreateTextNodeScript() throws Exception {
597         final String html = DOCTYPE_HTML
598               + "<html><head></head><body>\n"
599               + "<script id='js1'>\n"
600               + LOG_TITLE_FUNCTION
601               + "  log('script');\n"
602               + "</script>\n"
603               + "<script>\n"
604               + "  log('start');\n"
605               + "  var script = document.getElementById('js1');\n"
606               + "  var source = document.createTextNode(\"log('executed');\");\n"
607               + "  try {\n"
608               + "    script.appendChild(source);\n"
609               + "  } catch(e) {logEx(e); }\n"
610               + "  log('end');\n"
611               + "</script>\n"
612               + "</body></html>";
613 
614         loadPageVerifyTitle2(html);
615     }
616 
617     /**
618      * Replaces the empty source of another script element using <code>.text</code>.
619      * @throws Exception if the test fails
620      */
621     @Test
622     @Alerts({"start", "executed", "end"})
623     public void replaceWithSetTextEmpty() throws Exception {
624         final String html = DOCTYPE_HTML
625               + "<html><head></head><body>\n"
626               + "<script id='js1'></script>\n"
627               + "<script>\n"
628               + LOG_TITLE_FUNCTION
629               + "  log('start');\n"
630               + "  var script = document.getElementById('js1');\n"
631               + "  script.text = \"log('executed');\";\n"
632               + "  log('end');\n"
633               + "</script>\n"
634               + "</body></html>";
635 
636         loadPageVerifyTitle2(html);
637     }
638 
639     /**
640      * Replaces the source containing just a blank of another script element using <code>.text</code>.
641      * @throws Exception if the test fails
642      */
643     @Test
644     @Alerts({"start", "end"})
645     public void replaceWithSetTextBlank() throws Exception {
646         final String html = DOCTYPE_HTML
647               + "<html><head></head><body>\n"
648               + "<script id='js1'> </script>\n"
649               + "<script>\n"
650               + LOG_TITLE_FUNCTION
651               + "  log('start');\n"
652               + "  var script = document.getElementById('js1');\n"
653               + "  script.text = \"log('executed');\";\n"
654               + "  log('end');\n"
655               + "</script>\n"
656               + "</body></html>";
657 
658         loadPageVerifyTitle2(html);
659     }
660 
661     /**
662      * Replaces the source containing a script of another script element using <code>.text</code>.
663      * @throws Exception if the test fails
664      */
665     @Test
666     @Alerts({"script", "start", "end"})
667     public void replaceWithSetTextScript() throws Exception {
668         final String html = DOCTYPE_HTML
669               + "<html><head></head><body>\n"
670               + "<script id='js1'>\n"
671               + LOG_TITLE_FUNCTION
672               + "  log('script');\n"
673               + "</script>\n"
674               + "<script>\n"
675               + "  log('start');\n"
676               + "  var script = document.getElementById('js1');\n"
677               + "  script.text = \"log('executed');\";\n"
678               + "  log('end');\n"
679               + "</script>\n"
680               + "</body></html>";
681 
682         loadPageVerifyTitle2(html);
683     }
684 
685     /**
686      * Replaces the empty source of another script element using <code>.src</code>.
687      * @throws Exception if the test fails
688      */
689     @Test
690     @Alerts({"start", "end", "executed"})
691     public void replaceWithSetSrcEmpty() throws Exception {
692         final String html = DOCTYPE_HTML
693               + "<html><head></head><body>\n"
694               + "<script>\n"
695               + LOG_TITLE_FUNCTION
696               + "</script>\n"
697               + "<script id='js1'></script>\n"
698               + "<script>\n"
699               + "  log('start');\n"
700               + "  var script = document.getElementById('js1');\n"
701               + "  script.src = \"" + URL_SECOND + "\";\n"
702               + "  log('end');\n"
703               + "</script>\n"
704               + "</body></html>";
705 
706         final String js = "log('executed');";
707         getMockWebConnection().setResponse(URL_SECOND, js);
708 
709         loadPageVerifyTitle2(html);
710     }
711 
712     /**
713      * Replaces the source containing just a blank of another script element using <code>.src</code>.
714      * @throws Exception if the test fails
715      */
716     @Test
717     @Alerts({"start", "end"})
718     public void replaceWithSetSrcBlank() throws Exception {
719         final String html = DOCTYPE_HTML
720               + "<html><head></head><body>\n"
721               + "<script id='js1'> </script>\n"
722               + "<script>\n"
723               + LOG_TITLE_FUNCTION
724               + "  log('start');\n"
725               + "  var script = document.getElementById('js1');\n"
726               + "  script.src = \"" + URL_SECOND + "\";\n"
727               + "  log('end');\n"
728               + "</script>\n"
729               + "</body></html>";
730 
731         final String js = "log('executed');";
732         getMockWebConnection().setResponse(URL_SECOND, js);
733 
734         loadPageVerifyTitle2(html);
735     }
736 
737     /**
738      * Replaces the source containing a script of another script element using <code>.text</code>.
739      * @throws Exception if the test fails
740      */
741     @Test
742     @Alerts({"script", "start", "end"})
743     public void replaceWithSetSrcScript() throws Exception {
744         final String html = DOCTYPE_HTML
745               + "<html><head></head><body>\n"
746               + "<script id='js1'>\n"
747               + LOG_TITLE_FUNCTION
748               + "  log('script');\n"
749               + "</script>\n"
750               + "<script>\n"
751               + "  log('start');\n"
752               + "  var script = document.getElementById('js1');\n"
753               + "  script.src = \"" + URL_SECOND + "\";\n"
754               + "  log('end');\n"
755               + "</script>\n"
756               + "</body></html>";
757 
758         final String js = "log('executed');";
759         getMockWebConnection().setResponse(URL_SECOND, js);
760 
761         loadPageVerifyTitle2(html);
762     }
763 
764     /**
765      * Moves a script element from a div element to the body element using <code>appendChild</code>.
766      * @throws Exception if the test fails
767      */
768     @Test
769     @Alerts({"executed", "start", "end"})
770     public void moveWithAppend() throws Exception {
771         final String html = DOCTYPE_HTML
772               + "<html><head></head><body>\n"
773               + "<div>\n"
774               + "<script>\n"
775               + LOG_TITLE_FUNCTION
776               + "</script>\n"
777               + "<script id='js1'>log('executed');</script>\n"
778               + "<script>\n"
779               + "  log('start');\n"
780               + "  var script = document.getElementById('js1');\n"
781               + "  document.body.appendChild(script);\n"
782               + "  log('end');\n"
783               + "</script>\n"
784               + "</div>\n"
785               + "</body></html>";
786 
787         loadPageVerifyTitle2(html);
788     }
789 
790     /**
791      * Moves a script element from a div element to the body element using <code>insertBefore</code>.
792      * @throws Exception if the test fails
793      */
794     @Test
795     @Alerts({"executed", "start", "end"})
796     public void moveWithInsert() throws Exception {
797         final String html = DOCTYPE_HTML
798               + "<html><head></head><body>\n"
799               + "<div>\n"
800               + "<script id='js1'>\n"
801               + LOG_TITLE_FUNCTION
802               + "  log('executed');\n"
803               + "</script>\n"
804               + "<script>\n"
805               + "  log('start');\n"
806               + "  var script = document.getElementById('js1');\n"
807               + "  document.body.insertBefore(script, null);\n"
808               + "  log('end');\n"
809               + "</script>\n"
810               + "</div>\n"
811               + "</body></html>";
812 
813         loadPageVerifyTitle2(html);
814     }
815 
816     /**
817      * @throws Exception if the test fails
818      */
819     @Test
820     @Alerts({"script-for", "TypeError", "script-body"})
821     public void scriptForEvent() throws Exception {
822         // IE accepts it with () or without
823         scriptForEvent("onload");
824         scriptForEvent("onload()");
825     }
826 
827     private void scriptForEvent(final String eventName) throws Exception {
828         final String html = DOCTYPE_HTML
829             + "<html><head>\n"
830             + "<script>\n"
831             + LOG_TITLE_FUNCTION
832             + "</script>\n"
833             + "<script FOR='window' EVENT='" + eventName + "' LANGUAGE='javascript'>\n"
834             + "  log('script-for');\n"
835             + "  try {\n"
836             + "    document.form1.txt.value = 'hello';\n"
837             + "    log(document.form1.txt.value);\n"
838             + "  } catch(e) {logEx(e); }\n"
839             + "</script></head>\n"
840             + "<body>\n"
841             + "  <form name='form1'><input type='text' name='txt'></form>\n"
842             + "  <script>\n"
843             + "    log('script-body');\n"
844             + "  </script>\n"
845             + "</body></html>";
846 
847         loadPageVerifyTitle2(html);
848     }
849 
850     /**
851      * Verifies the correct the ordering of script element execution, deferred script element
852      * execution, script ready state changes, deferred script ready state changes, and onload
853      * handlers.
854      *
855      * @throws Exception if an error occurs
856      */
857     @Test
858     @Alerts({"3", "4", "2", "5"})
859     public void onReadyStateChange_Order() throws Exception {
860         final String html = DOCTYPE_HTML
861             + "<html>\n"
862             + "  <head>\n"
863             + "    <script>\n"
864             + LOG_TITLE_FUNCTION
865             + "    </script>\n"
866             + "    <script defer=''>log('3');</script>\n"
867             + "    <script defer onreadystatechange='if(this.readyState==\"complete\") log(\"6\");'>log('4');</script>\n"
868             + "    <script src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"1\");'></script>\n"
869             + "    <script defer='' src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"7\");'></script>\n"
870             + "    <script>log('2')</script>\n"
871             + "  </head>\n"
872             + "  <body onload='log(5)'></body>\n"
873             + "</html>";
874 
875         loadPageVerifyTitle2(html);
876     }
877 
878     /**
879      * @throws Exception if an error occurs
880      */
881     @Test
882     public void onReadyStateChange_EventAvailable() throws Exception {
883         final String html = DOCTYPE_HTML
884             + "<html><body><script>\n"
885             + LOG_TITLE_FUNCTION
886             + "var s = document.createElement('script');\n"
887             + "s.src = '//:';\n"
888             + "s.onreadystatechange = function() {log(window.event);};\n"
889             + "document.body.appendChild(s);\n"
890             + "</script></body></html>";
891 
892         loadPageVerifyTitle2(html);
893     }
894 
895     /**
896      * Verifies the correct the ordering of script element execution, deferred script element
897      * execution, script ready state changes, deferred script ready state changes, and onload
898      * handlers when the document doesn't have an explicit <tt>body</tt> element.
899      *
900      * @throws Exception if an error occurs
901      */
902     @Test
903     @Alerts({"3", "4", "2"})
904     public void onReadyStateChange_Order_NoBody() throws Exception {
905         final String html = DOCTYPE_HTML
906             + "<html>\n"
907             + "  <head>\n"
908             + "    <script>\n"
909             + LOG_TITLE_FUNCTION
910             + "    </script>\n"
911             + "    <script defer=''>log('3');</script>\n"
912             + "    <script defer='' onreadystatechange='if(this.readyState==\"complete\") log(\"5\");'>log('4');</script>\n"
913             + "    <script src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"1\");'></script>\n"
914             + "    <script defer='' src='//:' onreadystatechange='if(this.readyState==\"complete\") log(\"6\");'></script>\n"
915             + "    <script>log('2')</script>\n"
916             + "  </head>\n"
917             + "</html>";
918 
919         loadPageVerifyTitle2(html);
920     }
921 
922     /**
923      * @throws Exception if the test fails
924      */
925     @Test
926     @Alerts("1")
927     public void text() throws Exception {
928         final String html = DOCTYPE_HTML
929             + "<html>\n"
930             + "  <head>\n"
931             + "    <script>\n"
932             + LOG_TITLE_FUNCTION
933             + "      function test() {\n"
934             + "        execMe('log(1)');\n"
935             + "      }\n"
936             + "      function execMe(text) {\n"
937             + "        document.head = document.getElementsByTagName('head')[0];\n"
938             + "        var script = document.createElement('script');\n"
939             + "        script.text = text;\n"
940             + "        document.head.appendChild(script);\n"
941             + "        document.head.removeChild(script);\n"
942             + "      }\n"
943             + "    </script>\n"
944             + "  </head>\n"
945             + "  <body onload='test()'>\n"
946             + "  </body>\n"
947             + "</html>";
948 
949         loadPageVerifyTitle2(html);
950     }
951 
952     /**
953      * @throws Exception if the test fails
954      */
955     @Test
956     @Alerts("onload")
957     public void onload_after_deferReadStateComplete() throws Exception {
958         final String html = DOCTYPE_HTML
959             + "<html>\n"
960             + "  <head>\n"
961             + "    <script>\n"
962             + LOG_TITLE_FUNCTION
963             + "    </script>\n"
964             + "    <script onreadystatechange='if(this.readyState==\"complete\") log(\"defer\");' defer></script>\n"
965             + "  </head>\n"
966             + "  <body onload='log(\"onload\")'>\n"
967             + "  </body>\n"
968             + "</html>";
969 
970         loadPageVerifyTitle2(html);
971     }
972 
973     /**
974      * Regression test for bug 47038.
975      * <a href="http://sourceforge.net/tracker/?func=detail&atid=448266&aid=3403860&group_id=47038">issue</a>
976      * @throws Exception if the test fails
977      */
978     @Test
979     @Alerts({"1", "2", "3"})
980     public void scriptType() throws Exception {
981         final String html = DOCTYPE_HTML
982             + "<html>\n"
983             + "<head>\n"
984             + "<script>\n"
985             + LOG_TITLE_FUNCTION
986             + "</script>\n"
987             + "<script type='text/javascript'>log(1)</script>\n"
988             + "<script type=' text/javascript'>log(2)</script>\n"
989             + "<script type=' text/javascript '>log(3)</script>\n"
990             + "<script type=' text / javascript '>log(4)</script>\n"
991             + "</head>\n"
992             + "<body>\n"
993             + "</body></html>";
994 
995         loadPageVerifyTitle2(html);
996     }
997 
998     /**
999      * @throws Exception if the test fails
1000      */
1001     @Test
1002     @Alerts("\\n\\s\\s<ul>{{for\\speople}}\\n\\s\\s\\s\\s<li>Name:\\s{{:name}}</li>\\n\\s\\s{{/for}}</ul>\\n")
1003     public void specialScriptType() throws Exception {
1004         final String html = DOCTYPE_HTML
1005             + "<html>\n"
1006             + "<head>\n"
1007             + "<script>\n"
1008             + LOG_TITLE_FUNCTION_NORMALIZE
1009             + "</script>\n"
1010             + "<script id='template' type='text/x-jsrender'>\n"
1011             + "  <ul>{{for people}}\n"
1012             + "    <li>Name: {{:name}}</li>\n"
1013             + "  {{/for}}</ul>\n"
1014             + "</script>\n"
1015 
1016             + "<script>\n"
1017             + "function doTest() {\n"
1018             + "  script = document.getElementById('template');\n"
1019             + "  log(script.innerHTML);\n"
1020             + "}\n"
1021             + "</script>\n"
1022 
1023             + "</head>\n"
1024             + "<body onload='doTest()'>\n"
1025             + "</body></html>";
1026 
1027         loadPageVerifyTitle2(html);
1028     }
1029 
1030     /**
1031      * Test exception throw by IE when calling <code>appendChild</code>.
1032      * @throws Exception if the test fails
1033      */
1034     @Test
1035     public void appendChild_UnexpectedCall() throws Exception {
1036         final String html = DOCTYPE_HTML
1037               + "<html><head></head><body>\n"
1038               + "<script>\n"
1039               + LOG_TITLE_FUNCTION
1040               + "  var script = document.createElement('script');\n"
1041               + "  var source = document.createTextNode(\"log('executed');\");\n"
1042               + "  try {\n"
1043               + "    script.appendChild(source);\n"
1044               + "  } catch(e) {\n"
1045               + "    log(e.message.slice(0,44));\n"
1046               + "  }\n"
1047               + "</script>\n"
1048               + "</body></html>";
1049 
1050         loadPageVerifyTitle2(html);
1051     }
1052 
1053     /**
1054      * Test exception throw by IE when calling <code>insertBefore</code>.
1055      * @throws Exception if the test fails
1056      */
1057     @Test
1058     public void insertBeforeUnexpectedCall() throws Exception {
1059         final String html = DOCTYPE_HTML
1060               + "<html><head><title>foo</title></head><body>\n"
1061               + "<script>\n"
1062               + LOG_TITLE_FUNCTION
1063               + "  var script = document.createElement('script');\n"
1064               + "  var source = document.createTextNode(\"log('executed');\");\n"
1065               + "  try {\n"
1066               + "    script.insertBefore(source, null);\n"
1067               + "  } catch(e) {\n"
1068               + "    log(e.message.slice(0,44));\n"
1069               + "  }\n"
1070               + "</script>\n"
1071               + "</body></html>";
1072 
1073         loadPageWithAlerts2(html);
1074     }
1075 
1076     /**
1077      * Firefox should not run scripts with "event" and "for" attributes.
1078      *
1079      * @throws Exception if the test fails
1080      */
1081     @Test
1082     @Alerts("onload for window")
1083     public void scriptEventFor() throws Exception {
1084         final String html = DOCTYPE_HTML
1085             + "<html>\n"
1086             + "<head>\n"
1087             + "<script>\n"
1088             + LOG_TITLE_FUNCTION
1089             + "</script>\n"
1090             + "</head><body>\n"
1091             + "  <script event='onload' for='window'>\n"
1092             + "    log('onload for window');\n"
1093             + "  </script>\n"
1094             + "  <div id='div1'>the div 1</div>\n"
1095             + "  <div id='div2'>the div 2</div>\n"
1096             + "  <script event='onclick' for='div1'>\n"
1097             + "    log('onclick for div1');\n"
1098             + "  </script>\n"
1099             + "  <script event='onclick' for='document.all.div2'>\n"
1100             + "    log('onclick for div2');\n"
1101             + "  </script>\n"
1102             + "</body></html>";
1103 
1104         final WebDriver webDriver = loadPage2(html);
1105         webDriver.findElement(By.id("div1")).click();
1106         webDriver.findElement(By.id("div2")).click();
1107 
1108         verifyTitle2(webDriver, getExpectedAlerts());
1109     }
1110 
1111     /**
1112      * @throws Exception if the test fails
1113      */
1114     @Test
1115     @Alerts({"function foo() { return a > b}", "function mce() { return a &gt; b}"})
1116     public void innerHtml() throws Exception {
1117         final String html = DOCTYPE_HTML
1118             + "<html><head>\n"
1119 
1120             + "<script id='script1'>function foo() { return a > b}</script>\n"
1121 
1122             + "<script>\n"
1123             + LOG_TITLE_FUNCTION
1124             + "function doTest() {\n"
1125             + "  script = document.getElementById('script1');\n"
1126             + "  log(script.innerHTML);\n"
1127 
1128             + "  script = document.getElementById('mce');\n"
1129             + "  log(script.innerHTML);\n"
1130 
1131             + "}\n"
1132             + "</script>\n"
1133             + "</head><body onload='doTest()'>\n"
1134             // this is done by TinyMce
1135             + "<script>document.write('<mce:script id=\"mce\">function mce() { return a > b}</mce:script>');</script>\n"
1136 
1137             + "</body></html>";
1138 
1139         loadPageVerifyTitle2(html);
1140     }
1141 
1142     /**
1143      * @throws Exception if the test fails
1144      */
1145     @Test
1146     @Alerts("\\n\\s\\s\\s\\s<script\\sid=\"testScript\">function\\sfoo()\\s{\\sreturn\\sa\\s>\\sb}</script>\\n\\s\\s")
1147     public void innerHTMLGetSet() throws Exception {
1148         final String html = DOCTYPE_HTML
1149             + "<html>\n"
1150             + "<head></head>\n"
1151             + "<body>\n"
1152 
1153             + "  <div id='tester'>\n"
1154             + "    <script id='testScript'>function foo() { return a > b}</script>\n"
1155             + "  </div>\n"
1156 
1157             + "  <script type='text/javascript'>\n"
1158             + LOG_TITLE_FUNCTION_NORMALIZE
1159             + "    var div = document.getElementById('tester');\n"
1160             + "    try {\n"
1161             + "      div.innerHTML = div.innerHTML;\n"
1162             + "    } catch(e) { logEx(e); }\n"
1163             + "    log(div.innerHTML);\n"
1164             + "  </script>\n"
1165 
1166             + "</body>\n"
1167             + "</html>\n";
1168 
1169         loadPageVerifyTitle2(html);
1170     }
1171 
1172     /**
1173      * @throws Exception if the test fails
1174      */
1175     @Test
1176     @Alerts("1 3 2")
1177     public void async() throws Exception {
1178         final String html = DOCTYPE_HTML
1179             + "<html><body>\n"
1180             + "<script src='js1.js'></script>\n"
1181             + "<script src='js2.js' async></script>\n"
1182             + "<script src='js3.js'></script>\n"
1183             + "</body></html>\n";
1184 
1185         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1186         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1187         getMockWebConnection().setResponse(new URL(URL_FIRST, "js3.js"), "document.title += ' 3';");
1188 
1189         final WebDriver driver = loadPage2(html);
1190         assertTitle(driver, getExpectedAlerts()[0]);
1191     }
1192 
1193     /**
1194      * The async attribute must not be used if the src attribute is absent (i.e. for inline scripts)
1195      * for classic scripts, in this case it would have no effect.
1196      *
1197      * @throws Exception if the test fails
1198      */
1199     @Test
1200     @Alerts("1 two 3 5 4")
1201     public void asyncWithoutSrc() throws Exception {
1202         final String html = DOCTYPE_HTML
1203             + "<html><body>\n"
1204             + "<script src='js1.js'></script>\n"
1205             + "<script async>document.title += ' two';</script>\n"
1206             + "<script src='js3.js'></script>\n"
1207             + "<script src='js4.js' async>document.title += ' four';</script>\n"
1208             + "<script src='js5.js'></script>\n"
1209             + "</body></html>\n";
1210 
1211         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1212         getMockWebConnection().setResponse(new URL(URL_FIRST, "js3.js"), "document.title += ' 3';");
1213         getMockWebConnection().setResponse(new URL(URL_FIRST, "js4.js"), "document.title += ' 4';");
1214         getMockWebConnection().setResponse(new URL(URL_FIRST, "js5.js"), "document.title += ' 5';");
1215 
1216         final WebDriver driver = loadPage2(html);
1217         assertTitle(driver, getExpectedAlerts()[0]);
1218     }
1219 
1220     /**
1221      * @throws Exception if the test fails
1222      */
1223     @Test
1224     @Alerts("2 1")
1225     @HtmlUnitNYI(CHROME = "1 2",
1226             EDGE = "1 2",
1227             FF = "1 2",
1228             FF_ESR = "1 2")
1229     public void async2() throws Exception {
1230         final String html = DOCTYPE_HTML
1231             + "<html><body>\n"
1232             + "<script>\n"
1233             + "  var s1 = document.createElement('script');\n"
1234             + "  s1.src = 'js1.js';\n"
1235             + "  s1.async = true;\n"
1236             + "  document.body.appendChild(s1);\n"
1237             + "</script>\n"
1238             + "<script src='js2.js'></script>\n"
1239             + "</body></html>\n";
1240 
1241         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1242         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1243 
1244         final WebDriver driver = loadPage2(html);
1245         assertTitle(driver, getExpectedAlerts()[0]);
1246     }
1247 
1248     /**
1249      * @throws Exception if the test fails
1250      */
1251     @Test
1252     @Alerts("0 3 2 1")
1253     @HtmlUnitNYI(CHROME = "0 3 1 2",
1254             EDGE = "0 3 1 2",
1255             FF = "0 3 1 2",
1256             FF_ESR = "0 3 1 2")
1257     public void syncLoadsAsync() throws Exception {
1258         final String html = DOCTYPE_HTML
1259             + "<html><body>\n"
1260             + "<script>\n"
1261             + "  document.title += ' 0';"
1262             + "  var s1 = document.createElement('script');\n"
1263             + "  s1.src = 'js1.js';\n"
1264             + "  s1.async = true;\n"
1265             + "  document.body.appendChild(s1);\n"
1266             + "  document.title += ' 3';"
1267             + "</script>\n"
1268             + "<script src='js2.js'></script>\n"
1269             + "</body></html>\n";
1270 
1271         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1272         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1273 
1274         final WebDriver driver = loadPage2(html);
1275         assertTitle(driver, getExpectedAlerts()[0]);
1276     }
1277 
1278     /**
1279      * @throws Exception if the test fails
1280      */
1281     @Test
1282     @Alerts(DEFAULT = "2 0 3 1",
1283             FF_ESR = "0 3 2 1")
1284     @HtmlUnitNYI(FF_ESR = "2 0 3 1")
1285     public void asyncLoadsAsync() throws Exception {
1286         final String html = DOCTYPE_HTML
1287             + "<html><body>\n"
1288             + "<script src='script.js' async></script>\n"
1289             + "<script src='js2.js'></script>\n"
1290             + "</body></html>\n";
1291 
1292         final String script =
1293                 "  document.title += ' 0';"
1294                 + "  var s1 = document.createElement('script');\n"
1295                 + "  s1.src = 'js1.js';\n"
1296                 + "  s1.async = true;\n"
1297                 + "  document.body.appendChild(s1);\n"
1298                 + "  document.title += ' 3';\n";
1299 
1300         getMockWebConnection().setResponse(new URL(URL_FIRST, "script.js"), script);
1301 
1302         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "document.title += ' 1';");
1303         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "document.title += ' 2';");
1304 
1305         final WebDriver driver = loadPage2(html);
1306         assertTitle(driver, getExpectedAlerts()[0]);
1307     }
1308 
1309     /**
1310      * @throws Exception if the test fails
1311      */
1312     @Test
1313     @Alerts({"1", "2", "3"})
1314     public void syncFromAsyncTask() throws Exception {
1315         final String html = DOCTYPE_HTML
1316             + "<html><body><script>\n"
1317             + LOG_TITLE_FUNCTION
1318             + "function addScript() {\n"
1319             + "  var script = document.createElement('script');\n"
1320             + "  script.src = 'js.js';\n"
1321             + "  document.head.appendChild(script);\n"
1322             + "  log('2');\n"
1323             + "}\n"
1324             + "setTimeout(addScript, 5);\n"
1325             + "  log('1');\n"
1326             + "</script></body></html>\n";
1327 
1328         getMockWebConnection().setResponse(new URL(URL_FIRST, "js.js"), "log('3')");
1329 
1330         final WebDriver driver = loadPage2(html);
1331         verifyTitle2(DEFAULT_WAIT_TIME, driver, getExpectedAlerts());
1332     }
1333 
1334     /**
1335      * @throws Exception if the test fails
1336      */
1337     @Test
1338     @Alerts({"1", "2", "3"})
1339     public void asyncFromAsyncTask() throws Exception {
1340         final String html = DOCTYPE_HTML
1341             + "<html><body><script>\n"
1342             + LOG_TITLE_FUNCTION
1343             + "function addAsyncScript() {\n"
1344             + "  var script = document.createElement('script');\n"
1345             + "  script.src = 'js.js';\n"
1346             + "  script.async = true;\n"
1347             + "  document.head.appendChild(script);\n"
1348             + "  log('2');\n"
1349             + "}\n"
1350             + "setTimeout(addAsyncScript, 5);\n"
1351             + "  log('1');\n"
1352             + "</script></body></html>\n";
1353 
1354         getMockWebConnection().setResponse(new URL(URL_FIRST, "js.js"), "log('3')");
1355 
1356         final WebDriver driver = loadPage2(html);
1357         verifyTitle2(DEFAULT_WAIT_TIME, driver, getExpectedAlerts());
1358     }
1359 
1360     /**
1361      * @throws Exception if the test fails
1362      */
1363     @Test
1364     @Alerts({"undefined", "append", "append done", "from script", "undefined"})
1365     public void asyncOnLoad() throws Exception {
1366         final String html = DOCTYPE_HTML
1367                 + "<html><body>\n"
1368                 + "<script>\n"
1369                 + LOG_TITLE_FUNCTION
1370                 + "</script>\n"
1371                 + "<script>\n"
1372                 + "  var script = document.createElement('script');\n"
1373                 + "  log(script.readyState);\n"
1374                 + "  script.src = 'js.js';\n"
1375                 + "  script.async = true;\n"
1376                 + "  script.onload = function () {\n"
1377                 + "    log(this.readyState);\n"
1378                 + "  };\n"
1379                 + "  log('append');\n"
1380                 + "  document.body.appendChild(script);\n"
1381                 + "  log('append done');\n"
1382                 + "</script>\n"
1383                 + "</body></html>\n";
1384 
1385         getMockWebConnection().setResponse(new URL(URL_FIRST, "js.js"), "log('from script');");
1386 
1387         final WebDriver driver = loadPage2(html);
1388         verifyTitle2(driver, getExpectedAlerts());
1389     }
1390 
1391     /**
1392      * @throws Exception if the test fails
1393      */
1394     @Test
1395     @Alerts({"false", "null", "true", "", "true", "", "false", "null"})
1396     public void asyncProperty() throws Exception {
1397         final String html = DOCTYPE_HTML
1398             + "<html>\n"
1399             + "<head>\n"
1400             + "<script id='script1' src='js1.js'></script>\n"
1401             + "<script id='script2' src='js2.js' async></script>\n"
1402             + "<script>\n"
1403             + LOG_TITLE_FUNCTION
1404             + "function doTest() {\n"
1405             + "  var script = document.getElementById('script1');\n"
1406             + "  log(script.async);\n"
1407             + "  log(script.getAttribute('async'));\n"
1408 
1409             + "  script.async = true;\n"
1410             + "  log(script.async);\n"
1411             + "  log(script.getAttribute('async'));\n"
1412 
1413             + "  script = document.getElementById('script2');\n"
1414             + "  log(script.async);\n"
1415             + "  log(script.getAttribute('async'));\n"
1416 
1417             + "  script.async = false;\n"
1418             + "  log(script.async);\n"
1419             + "  log(script.getAttribute('async'));\n"
1420 
1421             + "}\n"
1422             + "</script>\n"
1423             + "</head><body onload='doTest()'>\n"
1424             + "</body></html>\n";
1425 
1426         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "");
1427         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "");
1428 
1429         loadPageVerifyTitle2(html);
1430     }
1431 
1432     /**
1433      * @throws Exception if the test fails
1434      */
1435     @Test
1436     @Alerts({"false", "null", "true", "true", "true", "", "true", "true", "false", "null"})
1437     public void asyncAttribute() throws Exception {
1438         final String html = DOCTYPE_HTML
1439             + "<html>\n"
1440             + "<head>\n"
1441             + "<script id='script1' src='js1.js'></script>\n"
1442             + "<script id='script2' src='js2.js' async></script>\n"
1443             + "<script>\n"
1444             + LOG_TITLE_FUNCTION
1445             + "function doTest() {\n"
1446             + "  var script = document.getElementById('script1');\n"
1447             + "  log(script.async);\n"
1448             + "  log(script.getAttribute('async'));\n"
1449 
1450             + "  script.setAttribute('async', true);\n"
1451             + "  log(script.async);\n"
1452             + "  log(script.getAttribute('async'));\n"
1453 
1454             + "  script = document.getElementById('script2');\n"
1455             + "  log(script.async);\n"
1456             + "  log(script.getAttribute('async'));\n"
1457 
1458             + "  script.setAttribute('async', true);\n"
1459             + "  log(script.async);\n"
1460             + "  log(script.getAttribute('async'));\n"
1461 
1462             + "  script.removeAttribute('async');\n"
1463             + "  log(script.async);\n"
1464             + "  log(script.getAttribute('async'));\n"
1465             + "}\n"
1466             + "</script>\n"
1467             + "</head><body onload='doTest()'>\n"
1468             + "</body></html>\n";
1469 
1470         getMockWebConnection().setResponse(new URL(URL_FIRST, "js1.js"), "");
1471         getMockWebConnection().setResponse(new URL(URL_FIRST, "js2.js"), "");
1472 
1473         loadPageVerifyTitle2(html);
1474     }
1475 
1476     /**
1477      * <a href="https://github.com/HtmlUnit/htmlunit/issues/11">issue #11</a>.
1478      * @throws Exception if an error occurs
1479      */
1480     @Test
1481     @Alerts("inside script.js")
1482     public void loadScriptDynamicallyAdded() 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             + "        var script = document.createElement('script');\n"
1490             + "        script.type = 'text/javascript';\n"
1491             + "        script.async = true;\n"
1492             + "        script.src = 'script.js';\n"
1493 
1494             + "        var s = document.getElementsByTagName('script')[0];\n"
1495             + "        s.parentNode.insertBefore(script, s);\n"
1496             + "      }\n"
1497             + "    </script>\n"
1498             + "  </head>\n"
1499             + "  <body onload='test()'>\n"
1500             + "  </body></html>";
1501 
1502         final String js = "log('inside script.js');";
1503 
1504         getMockWebConnection().setDefaultResponse(js, MimeType.TEXT_JAVASCRIPT);
1505 
1506         loadPageVerifyTitle2(html);
1507     }
1508 
1509     /**
1510      * JQuery disables script execution this way.
1511      * @throws Exception if an error occurs
1512      */
1513     @Test
1514     @Alerts({"change type", "type changed"})
1515     public void loadScriptDynamicallyAddedUnsupportedType() throws Exception {
1516         final String html = DOCTYPE_HTML
1517             + "<html>\n"
1518             + "  <head>\n"
1519             + "    <script>\n"
1520             + LOG_TITLE_FUNCTION
1521             + "      function test() {\n"
1522             + "        var script = document.createElement('script');\n"
1523             + "        script.type = 'true/text/javascript';\n"
1524             + "        script.src = 'script.js';\n"
1525 
1526             + "        var s = document.getElementsByTagName('script')[0];\n"
1527             + "        s.parentNode.insertBefore(script, s);\n"
1528 
1529             + "        log('change type');\n"
1530             + "        s.type = 'text/javascript';\n"
1531             + "        log('type changed');\n"
1532             + "      }\n"
1533             + "    </script>\n"
1534             + "  </head>\n"
1535             + "  <body onload='test()'>\n"
1536             + "  </body></html>";
1537 
1538         final String js = "log('inside script.js');";
1539 
1540         getMockWebConnection().setDefaultResponse(js, MimeType.TEXT_JAVASCRIPT);
1541 
1542         loadPageVerifyTitle2(html);
1543     }
1544 
1545     /**
1546      * @throws Exception if the test fails
1547      */
1548     @Test
1549     @Alerts({"out", "\\n\\s\\s\\s\\s<!--\\syy\\s--!>\\n\\s\\s\\s\\slog('out');\\n\\s\\s"})
1550     public void incorrectlyClosedComment() throws Exception {
1551         final String html = DOCTYPE_HTML
1552             + "<html>\n"
1553             + "<head>\n"
1554             + "  <script>\n"
1555             + LOG_TITLE_FUNCTION_NORMALIZE
1556             + "  </script>\n"
1557             + "  <script id='testScript'>\n"
1558             + "    <!-- yy --!>\n"
1559             + "    log('out');\n"
1560             + "  </script>\n"
1561             + "</head>\n"
1562             + "<body>\n"
1563             + "  <!-- xx -->\n"
1564 
1565             + "  <script >\n"
1566             + "    log(document.getElementById('testScript').innerHTML);\n"
1567             + "  </script>\n"
1568 
1569             + "</body>\n"
1570             + "</html>\n";
1571 
1572         loadPageVerifyTitle2(html);
1573     }
1574 
1575     /**
1576      * @throws Exception if the test fails
1577      */
1578     @Test
1579     @Alerts({"null-", "testType-testType", "-"})
1580     public void modifyType() throws Exception {
1581         final String html = DOCTYPE_HTML
1582             + "<html>\n"
1583             + "<head>\n"
1584             + "  <script id='testScript'></script>\n"
1585             + "</head>\n"
1586             + "<body>\n"
1587 
1588             + "  <script >\n"
1589             + LOG_TITLE_FUNCTION
1590             + "    var script = document.getElementById('testScript');\n"
1591             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1592 
1593             + "    script.type = 'testType';\n"
1594             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1595 
1596             + "    script.type = '';\n"
1597             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1598 
1599             + "  </script>\n"
1600 
1601             + "</body>\n"
1602             + "</html>\n";
1603 
1604         loadPageVerifyTitle2(html);
1605     }
1606 
1607     /**
1608      * @throws Exception if the test fails
1609      */
1610     @Test
1611     @Alerts({"typeAttr-typeAttr", "null-", "newType-newType", "null-null"})
1612     public void modifyTypeAttribute() throws Exception {
1613         final String html = DOCTYPE_HTML
1614             + "<html>\n"
1615             + "<head>\n"
1616             + "  <script id='testScript' type='typeAttr'></script>\n"
1617             + "</head>\n"
1618             + "<body>\n"
1619 
1620             + "  <script >\n"
1621             + LOG_TITLE_FUNCTION
1622             + "    var script = document.getElementById('testScript');\n"
1623             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1624 
1625             + "    script.removeAttribute('type');\n"
1626             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1627 
1628             + "    script.setAttribute('type', 'newType');\n"
1629             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1630 
1631             + "    script.setAttribute('type', null);\n"
1632             + "    log(script.getAttribute('type') + '-' + script.type);\n"
1633 
1634             + "  </script>\n"
1635 
1636             + "</body>\n"
1637             + "</html>\n";
1638 
1639         loadPageVerifyTitle2(html);
1640     }
1641 
1642     /**
1643      * @throws Exception if the test fails
1644      */
1645     @Test
1646     @Alerts({"typeAttr", "text/javascript"})
1647     public void modifyTypeToJs() throws Exception {
1648         final String html = DOCTYPE_HTML
1649             + "<html>\n"
1650             + "<head>\n"
1651             + "<script>\n"
1652             + LOG_TITLE_FUNCTION
1653             + "</script>\n"
1654             + "  <script id='testScript' type='typeAttr'>log('exec');</script>\n"
1655             + "</head>\n"
1656             + "<body>\n"
1657 
1658             + "  <script >\n"
1659             + "    var script = document.getElementById('testScript');\n"
1660             + "    log(script.getAttribute('type'));\n"
1661 
1662             + "    script.type = 'text/javascript';\n"
1663             + "    log(script.getAttribute('type'));\n"
1664             + "  </script>\n"
1665 
1666             + "</body>\n"
1667             + "</html>\n";
1668 
1669         loadPageVerifyTitle2(html);
1670     }
1671 
1672     /**
1673      * @throws Exception if an error occurs
1674      */
1675     @Test
1676     @Alerts("onerror")
1677     public void onErrorHandler() throws Exception {
1678         final String html = DOCTYPE_HTML
1679             + "<html>\n"
1680             + "  <head>\n"
1681             + "    <script>\n"
1682             + LOG_TITLE_FUNCTION
1683             + "    </script>\n"
1684             + "    <script src='http://www.unknown-host.xyz' onload='log(\"onload\")' onerror='log(\"onerror\")'></script>\n"
1685             + "  </head>\n"
1686             + "  <body>\n"
1687             + "  </body></html>";
1688 
1689         loadPageVerifyTitle2(html);
1690     }
1691 
1692     /**
1693      * @throws Exception if the test fails
1694      */
1695     @Test
1696     @Alerts({"var x = 'HtmlUnit'", "</> htmx rocks!"})
1697     public void innerHtml1() throws Exception {
1698         final String html = DOCTYPE_HTML
1699             + "<html>\n"
1700             + "  <head>\n"
1701             + "    <title>Page Title</title>\n"
1702             + "    <script>\n"
1703             + LOG_TEXTAREA_FUNCTION
1704             + "      function test() {\n"
1705             + "        var script = document.getElementsByTagName('script')[1];\n"
1706             + "        log(script.innerHTML);\n"
1707             + "        script.innerHTML = '</> htmx rocks!';\n"
1708             + "        log(script.innerHTML);\n"
1709             + "      }\n"
1710             + "    </script>\n"
1711             + "  </head>\n"
1712             + "  <body onload='test()'>"
1713             + "    <script>var x = 'HtmlUnit'</script>\n"
1714             + LOG_TEXTAREA
1715             + "  </body>\n"
1716             + "</html>";
1717 
1718         loadPageVerifyTextArea2(html);
1719     }
1720 
1721     /**
1722      * @throws Exception if the test fails
1723      */
1724     @Test
1725     @Alerts({"var x = 'HtmlUnit'", "<div>htmx rocks</div>"})
1726     public void innerHtmlTag() throws Exception {
1727         final String html = DOCTYPE_HTML
1728             + "<html>\n"
1729             + "  <head>\n"
1730             + "    <title>Page Title</title>\n"
1731             + "    <script>\n"
1732             + LOG_TEXTAREA_FUNCTION
1733             + "      function test() {\n"
1734             + "        var script = document.getElementsByTagName('script')[1];\n"
1735             + "        log(script.innerHTML);\n"
1736             + "        script.innerHTML = '<div>htmx rocks</div>';\n"
1737             + "        log(script.innerHTML);\n"
1738             + "      }\n"
1739             + "    </script>\n"
1740             + "  </head>\n"
1741             + "  <body onload='test()'>\n"
1742             + "    <script>var x = 'HtmlUnit'</script>\n"
1743             + LOG_TEXTAREA
1744             + "  </body>\n"
1745             + "</html>";
1746 
1747         loadPageVerifyTextArea2(html);
1748     }
1749 
1750     /**
1751      * @throws Exception if the test fails
1752      */
1753     @Test
1754     @Alerts({"", "&lt;/> htmx rocks!"})
1755     public void innerHtmlEscaping() throws Exception {
1756         final String html = DOCTYPE_HTML
1757             + "<html>\n"
1758             + "  <head>\n"
1759             + "    <title>Page Title</title>\n"
1760             + "    <script>\n"
1761             + LOG_TEXTAREA_FUNCTION
1762             + "      function test() {\n"
1763             + "        var script = document.getElementsByTagName('script')[1];\n"
1764             + "        log(script.innerHTML);\n"
1765             + "        script.innerHTML = '&lt;/> htmx rocks!';\n"
1766             + "        log(script.innerHTML);\n"
1767             + "      }\n"
1768             + "    </script>\n"
1769             + "  </head>\n"
1770             + "  <body onload='test()'>\n"
1771             + "    <script></script>\n"
1772             + LOG_TEXTAREA
1773             + "  </body>\n"
1774             + "</html>";
1775 
1776         loadPageVerifyTextArea2(html);
1777     }
1778 }