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.UTF_8;
18  
19  import java.io.BufferedReader;
20  import java.io.IOException;
21  import java.io.StringWriter;
22  import java.net.URL;
23  import java.util.Enumeration;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import javax.servlet.Servlet;
29  import javax.servlet.ServletException;
30  import javax.servlet.http.HttpServlet;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import org.apache.commons.io.IOUtils;
35  import org.htmlunit.HttpHeader;
36  import org.htmlunit.WebDriverTestCase;
37  import org.htmlunit.junit.annotation.Alerts;
38  import org.htmlunit.junit.annotation.BuggyWebDriver;
39  import org.htmlunit.junit.annotation.HtmlUnitNYI;
40  import org.htmlunit.util.MimeType;
41  import org.htmlunit.util.UrlUtils;
42  import org.junit.jupiter.api.Test;
43  import org.openqa.selenium.By;
44  import org.openqa.selenium.WebDriver;
45  
46  /**
47   * Unit tests for {@link HTMLAnchorElement}.
48   *
49   * @author Ahmed Ashour
50   * @author Ronald Brill
51   * @author Marc Guillemot
52   * @author Frank Danek
53   */
54  public class HTMLAnchorElement2Test extends WebDriverTestCase {
55  
56      /**
57       * @throws Exception if an error occurs
58       */
59      @Test
60      @Alerts({"", "", "", "§§URL§§test.css", "stylesheet", "stylesheet1"})
61      public void attributes() throws Exception {
62          final String html = DOCTYPE_HTML
63              + "<html>\n"
64              + "  <body onload='test()'>\n"
65              + "    <script>\n"
66              + LOG_TITLE_FUNCTION
67              + "      function test() {\n"
68              + "        var a = document.createElement('a');\n"
69              + "        log(a.href);\n"
70              + "        log(a.rel);\n"
71              + "        log(a.rev);\n"
72              + "        a.href = 'test.css';\n"
73              + "        a.rel  = 'stylesheet';\n"
74              + "        a.rev  = 'stylesheet1';\n"
75              + "        log(a.href);\n"
76              + "        log(a.rel);\n"
77              + "        log(a.rev);\n"
78              + "      }\n"
79              + "    </script>\n"
80              + "  </body>\n"
81              + "</html>";
82  
83          expandExpectedAlertsVariables(URL_FIRST);
84          loadPageVerifyTitle2(html);
85      }
86  
87      /**
88       * @throws Exception if the test fails
89       */
90      @Test
91      @Alerts({"attachEvent not available", "href"})
92      public void javaScriptPreventDefaultIE() throws Exception {
93          final String html = DOCTYPE_HTML
94              + "<html><head>\n"
95              + "<script>\n"
96              + LOG_TITLE_FUNCTION
97              + "  function test() {\n"
98              + "    var a = document.getElementById('link');\n"
99              + "    if (!a.attachEvent) { log('attachEvent not available'); return }\n"
100             + "    a.attachEvent('onclick', handler);\n"
101             + "  }\n"
102             + "  function handler() {\n"
103             + "    event.returnValue = false;\n"
104             + "    log('onclick');\n"
105             + "  }\n"
106             + "</script>\n"
107             + "<body onload='test()'>\n"
108             + "  <a id='link' href='javascript: log(\"href\");'>link</a>\n"
109             + "</body></html>";
110 
111         final WebDriver driver = loadPage2(html);
112         verifyTitle2(driver, getExpectedAlerts()[0]);
113 
114         driver.findElement(By.id("link")).click();
115         if (useRealBrowser()) {
116             Thread.sleep(400);
117         }
118         verifyTitle2(driver, getExpectedAlerts());
119     }
120 
121     /**
122      * @throws Exception if the test fails
123      */
124     @Test
125     @Alerts("onclick")
126     public void javaScriptPreventDefault() throws Exception {
127         final String html = DOCTYPE_HTML
128             + "<html><head>\n"
129             + "<script>\n"
130             + LOG_TITLE_FUNCTION
131             + "  function test() {\n"
132             + "    var a = document.getElementById('link');\n"
133             + "    a.addEventListener('click', handler);\n"
134             + "  }\n"
135             + "  function handler(event) {\n"
136             + "    event.preventDefault();\n"
137             + "    log('onclick');\n"
138             + "  }\n"
139             + "</script>\n"
140             + "<body onload='test()'>\n"
141             + "<a id='link' href='javascript: log(\"href\");'>link</a>\n"
142             + "</body></html>";
143 
144         final WebDriver driver = loadPage2(html);
145         driver.findElement(By.id("link")).click();
146 
147         verifyTitle2(driver, getExpectedAlerts());
148     }
149 
150     /**
151      * @throws Exception if the test fails
152      */
153     @Test
154     @Alerts({"", "§§URL§§foo.html", "javascript:void(0)", "§§URL§§#", "mailto:"})
155     public void defaultConversionToString() throws Exception {
156         final String html = DOCTYPE_HTML
157             + "<html><head><script>\n"
158             + LOG_TITLE_FUNCTION
159             + "function test() {\n"
160             + "  log(document.getElementById('myAnchor'));\n"
161             + "  for (var i = 0; i < document.links.length; i++)\n"
162             + "  {\n"
163             + "    log(document.links[i]);\n"
164             + "  }\n"
165             + "}</script></head>\n"
166             + "<body onload='test()'>\n"
167             + "<a name='start' id='myAnchor'/>\n"
168             + "<a href='foo.html'>foo</a>\n"
169             + "<a href='javascript:void(0)'>void</a>\n"
170             + "<a href='#'>#</a>\n"
171             + "<a href='mailto:'>mail</a>\n"
172             + "</body></html>";
173 
174         expandExpectedAlertsVariables(URL_FIRST);
175         loadPageVerifyTitle2(html);
176     }
177 
178     /**
179      * @throws Exception if the test fails
180      */
181     @Test
182     @Alerts("Second")
183     public void javaScriptAnchorClick() throws Exception {
184         final String html = DOCTYPE_HTML
185             + "<html><head><title>First</title><script>\n"
186             + "function delegateClick() {\n"
187             + "  try {\n"
188             + "    document.getElementById(\"link1\").click();\n"
189             + "  } catch(e) {}\n"
190             + "}\n"
191             + "</script></head><body>\n"
192             + "<a id='link1' href='#' onclick='document.form1.submit()'>link 1</a>\n"
193             + "<form name='form1' action='" + URL_SECOND + "' method='post'>\n"
194             + "<input type=button id='button1' value='Test' onclick='delegateClick()'>\n"
195             + "<input name='testText'>\n"
196             + "</form>\n"
197             + "</body></html>";
198 
199         final String secondHtml = DOCTYPE_HTML
200             + "<html>\n"
201             + "<head><title>Second</title></head>\n"
202             + "</html>";
203 
204         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
205 
206         final WebDriver driver = loadPage2(html);
207         driver.findElement(By.id("button1")).click();
208 
209         assertTitle(driver, getExpectedAlerts()[0]);
210     }
211 
212     /**
213      * @throws Exception if the test fails
214      */
215     @Test
216     @Alerts({"§§URL§§testsite1.html", "testsite1.html", "§§URL§§testsite2.html",
217              "testsite2.html", "13", "testanchor", "mailto:"})
218     public void getAttribute_and_href() throws Exception {
219         final String html = DOCTYPE_HTML
220             + "<html><head>\n"
221             + "<script>\n"
222             + LOG_TITLE_FUNCTION
223             + "  function doTest(anchorElement) {\n"
224             + "    log(anchorElement.href);\n"
225             + "    log(anchorElement.getAttribute('href'));\n"
226             + "    anchorElement.href = 'testsite2.html';\n"
227             + "    log(anchorElement.href);\n"
228             + "    log(anchorElement.getAttribute('href'));\n"
229             + "    log(anchorElement.getAttribute('id'));\n"
230             + "    log(anchorElement.getAttribute('name'));\n"
231             + "    var link2 = document.getElementById('link2');\n"
232             + "    log(link2.href);\n"
233             + "  }\n</script>\n"
234             + "</head>\n"
235             + "<body>\n"
236             + "  <a href='testsite1.html' id='13' name='testanchor' onClick='doTest(this);return false'>bla</a>\n"
237             + "  <a href='mailto:' id='link2'>mail</a>\n"
238             + "</body></html>";
239 
240         final WebDriver driver = loadPage2(html);
241         driver.findElement(By.name("testanchor")).click();
242 
243         expandExpectedAlertsVariables(URL_FIRST);
244         verifyTitle2(driver, getExpectedAlerts());
245     }
246 
247     /**
248      * @throws Exception if the test fails
249      */
250     @Test
251     @Alerts({"http://htmlunit.sourceforge.net/", "§§URL§§test", "§§URL§§#test",
252              "§§URL§§#", "§§URL§§"})
253     public void getDefaultValue() throws Exception {
254         final String html = DOCTYPE_HTML
255             + "<html><head>\n"
256             + "<script>\n"
257             + LOG_TITLE_FUNCTION
258             + "  function test() {\n"
259             + "    log(document.getElementById('absolute'));\n"
260             + "    log(document.getElementById('relative'));\n"
261             + "    log(document.getElementById('hash'));\n"
262             + "    log(document.getElementById('hashOnly'));\n"
263             + "    log(document.getElementById('empty'));\n"
264             + "  }\n</script>\n"
265             + "</head>\n"
266             + "<body onload='test()'>\n"
267             + "  <a href='http://htmlunit.sourceforge.net/' id='absolute'>bla</a>\n"
268             + "  <a href='test' id='relative'>bla</a>\n"
269             + "  <a href='#test' id='hash'>bla</a>\n"
270             + "  <a href='#' id='hashOnly'>bla</a>\n"
271             + "  <a href='' id='empty'>bla</a>\n"
272             + "</body></html>";
273 
274         final WebDriver driver = loadPage2(html);
275 
276         expandExpectedAlertsVariables(URL_FIRST);
277         verifyTitle2(driver, getExpectedAlerts());
278     }
279 
280     /**
281      * @throws Exception if the test fails
282      */
283     @Test
284     @Alerts({"http://htmlunit.sourceforge.net/", "§§URL§§test", "§§URL§§#test",
285              "§§URL§§#", "§§URL§§"})
286     public void getDefaultValueWithHash() throws Exception {
287         final String html = DOCTYPE_HTML
288             + "<html><head>\n"
289             + "<script>\n"
290             + LOG_TITLE_FUNCTION
291             + "  function test() {\n"
292             + "    log(document.getElementById('absolute'));\n"
293             + "    log(document.getElementById('relative'));\n"
294             + "    log(document.getElementById('hash'));\n"
295             + "    log(document.getElementById('hashOnly'));\n"
296             + "    log(document.getElementById('empty'));\n"
297             + "  }\n</script>\n"
298             + "</head>\n"
299             + "<body onload='test()'>\n"
300             + "  <a href='http://htmlunit.sourceforge.net/' id='absolute'>bla</a>\n"
301             + "  <a href='test' id='relative'>bla</a>\n"
302             + "  <a href='#test' id='hash'>bla</a>\n"
303             + "  <a href='#' id='hashOnly'>bla</a>\n"
304             + "  <a href='' id='empty'>bla</a>\n"
305             + "</body></html>";
306 
307         getMockWebConnection().setDefaultResponse(html);
308         final WebDriver driver = loadPage2(html, UrlUtils.getUrlWithNewRef(URL_FIRST, "ref"));
309 
310         expandExpectedAlertsVariables(URL_FIRST);
311         verifyTitle2(driver, getExpectedAlerts());
312     }
313 
314     /**
315      * @throws Exception if the test fails
316      */
317     @Test
318     @Alerts({"http://htmlunit.sourceforge.net/", "§§URL§§test", "§§URL§§index.html#test",
319              "§§URL§§index.html#", "§§URL§§index.html"})
320     public void getDefaultValueWithHashAndFileName() throws Exception {
321         final String html = DOCTYPE_HTML
322             + "<html><head>\n"
323             + "<script>\n"
324             + "  function test() {\n"
325             + LOG_TITLE_FUNCTION
326             + "    log(document.getElementById('absolute'));\n"
327             + "    log(document.getElementById('relative'));\n"
328             + "    log(document.getElementById('hash'));\n"
329             + "    log(document.getElementById('hashOnly'));\n"
330             + "    log(document.getElementById('empty'));\n"
331             + "  }\n</script>\n"
332             + "</head>\n"
333             + "<body onload='test()'>\n"
334             + "  <a href='http://htmlunit.sourceforge.net/' id='absolute'>bla</a>\n"
335             + "  <a href='test' id='relative'>bla</a>\n"
336             + "  <a href='#test' id='hash'>bla</a>\n"
337             + "  <a href='#' id='hashOnly'>bla</a>\n"
338             + "  <a href='' id='empty'>bla</a>\n"
339             + "</body></html>";
340 
341         getMockWebConnection().setDefaultResponse(html);
342         final WebDriver driver = loadPage2(html, UrlUtils.getUrlWithNewPath(URL_FIRST, "/index.html"));
343 
344         expandExpectedAlertsVariables(URL_FIRST);
345         verifyTitle2(driver, getExpectedAlerts());
346     }
347 
348     /**
349      * @throws Exception if the test fails
350      */
351     @Test
352     @Alerts("function onclick(event) { log(\"on click\") }§not defined")
353     public void onclickToString() throws Exception {
354         final String html = DOCTYPE_HTML
355             + "<html><head>\n"
356             + "<script>\n"
357             + LOG_TITLE_FUNCTION
358             + "  function test() {\n"
359             + "    for (var i = 0; i < document.links.length; i++) {\n"
360             + "      var onclick = document.links[i].onclick;\n"
361             + "      log(onclick ? onclick.toString() : 'not defined');\n"
362             + "    }\n"
363             + "  }\n"
364             + "</script>\n"
365             + "</head>\n"
366             + "<body onload='test()'>\n"
367             + "  <a href='foo.html' onClick='log(\"on click\")'>a1</a>\n"
368             + "  <a href='foo2.html'>a2</a>\n"
369             + "</body></html>";
370 
371         loadPageVerifyTitle2(html);
372     }
373 
374     /**
375      * @throws Exception if an error occurs
376      */
377     @Test
378     @Alerts({"", "A", "a", "A", "a8", "8Afoo", "8", "@"})
379     public void readWriteAccessKey() throws Exception {
380         final String html = DOCTYPE_HTML
381                 + "<html>\n"
382                 + "<body>\n"
383                 + "  <a id='a1' href='#'></a><a id='a2' href='#' accesskey='A'></a>\n"
384                 + "<script>\n"
385                 + LOG_TITLE_FUNCTION
386                 + "  var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
387                 + "  log(a1.accessKey);\n"
388                 + "  log(a2.accessKey);\n"
389                 + "  a1.accessKey = 'a';\n"
390                 + "  a2.accessKey = 'A';\n"
391                 + "  log(a1.accessKey);\n"
392                 + "  log(a2.accessKey);\n"
393                 + "  a1.accessKey = 'a8';\n"
394                 + "  a2.accessKey = '8Afoo';\n"
395                 + "  log(a1.accessKey);\n"
396                 + "  log(a2.accessKey);\n"
397                 + "  a1.accessKey = '8';\n"
398                 + "  a2.accessKey = '@';\n"
399                 + "  log(a1.accessKey);\n"
400                 + "  log(a2.accessKey);\n"
401                 + "</script>\n"
402                 + "</body>\n"
403                 + "</html>";
404         loadPageVerifyTitle2(html);
405     }
406 
407     /**
408      * Verifies that anchor href attributes are trimmed of whitespace (bug 1658064),
409      * just like they are in IE and Firefox.
410      * Verifies that href of anchor without href is empty string.
411      * @throws Exception if an error occurs
412      */
413     @Test
414     @Alerts({"9", "9", "true", "false"})
415     public void hrefTrimmed() throws Exception {
416         final String html = DOCTYPE_HTML
417             + "<html><head>\n"
418             + "<script>\n"
419             + LOG_TITLE_FUNCTION
420             + "  function test() {\n"
421             + "    log(document.getElementById('a').href.length);\n"
422             + "    log(document.getElementById('b').href.length);\n"
423             + "    log(document.getElementById('c').href === '');\n"
424             + "    log(document.getElementById('d').href === '');\n"
425             + "  }\n"
426             + "</script>\n"
427             + "</head>\n"
428             + "<body onload='test()'>\n"
429             + "  <a href=' http://a/ ' id='a'>a</a> "
430             + "  <a href='  http://b/    ' id='b'>b</a>\n"
431             + "  <a name='myAnchor' id='c'>c</a>\n"
432             + "  <a href='' id='d'>d</a>\n"
433             + "</body>\n"
434             + "</html>";
435 
436         loadPageVerifyTitle2(html);
437     }
438 
439     /**
440      * @throws Exception if the test fails
441      */
442     @Test
443     @Alerts({"# inner", "main"})
444     public void javascriptTargetNone() throws Exception {
445         javascriptTarget("", 0, getExpectedAlerts()[0], getExpectedAlerts()[1]);
446     }
447 
448     /**
449      * @throws Exception if the test fails
450      */
451     @Test
452     @Alerts({"# inner", "main"})
453     public void javascriptTargetEmpty() throws Exception {
454         javascriptTarget("target=''", 0, getExpectedAlerts()[0], getExpectedAlerts()[1]);
455     }
456 
457     /**
458      * @throws Exception if the test fails
459      */
460     @Test
461     @Alerts({"1", "inner", "# "})
462     @BuggyWebDriver({"1", "Please run manually", ""})
463     public void javascriptTargetWhitespace() throws Exception {
464         final String[] alerts = getExpectedAlerts();
465         javascriptTarget("target='  '",
466                             Integer.parseInt(alerts[0]),
467                             alerts[1], alerts[2]);
468     }
469 
470     /**
471      * @throws Exception if the test fails
472      */
473     @Test
474     @Alerts({"# inner", "main"})
475     public void javascriptTargetSelf() throws Exception {
476         javascriptTarget("target='_self'", 0, getExpectedAlerts()[0], getExpectedAlerts()[1]);
477     }
478 
479     /**
480      * @throws Exception if the test fails
481      */
482     @Test
483     @Alerts({"1", "inner", "# "})
484     @BuggyWebDriver({"1", "Please run manually", ""})
485     public void javascriptTargetBlank() throws Exception {
486         final String[] alerts = getExpectedAlerts();
487         javascriptTarget("target='_blank'",
488                             Integer.parseInt(alerts[0]),
489                             alerts[1], alerts[2]);
490     }
491 
492     /**
493      * @throws Exception if the test fails
494      */
495     @Test
496     @Alerts({"inner", "# main"})
497     public void javascriptTargetTop() throws Exception {
498         javascriptTarget("target='_top'", 0, getExpectedAlerts()[0], getExpectedAlerts()[1]);
499     }
500 
501     /**
502      * @throws Exception if the test fails
503      */
504     @Test
505     @Alerts({"inner", "# main"})
506     public void javascriptTargetParent() throws Exception {
507         javascriptTarget("target='_parent'", 0, getExpectedAlerts()[0], getExpectedAlerts()[1]);
508     }
509 
510     /**
511      * @throws Exception if the test fails
512      */
513     @Test
514     @Alerts({"1", "inner", "# "})
515     @BuggyWebDriver({"1", "Please run manually", ""})
516     public void javascriptTargetUnknown() throws Exception {
517         final String[] alerts = getExpectedAlerts();
518         javascriptTarget("target='unknown'",
519                             Integer.parseInt(alerts[0]),
520                             alerts[1], alerts[2]);
521     }
522 
523     private void javascriptTarget(final String target, final int newWindows,
524                     final String frameAlerts, final String windowAlerts) throws Exception {
525         assertTrue(newWindows < 2);
526 
527         // real browsers (selenium) are getting confused by this scenario
528         // and as result the stuck in the code that tries to get the body
529         if (newWindows > 0 && useRealBrowser()) {
530             assertEquals(frameAlerts, "Please run manually");
531             return;
532         }
533 
534         final String html = DOCTYPE_HTML
535             + "<html>\n"
536             + "<head><title>main</title></head>\n"
537             + "<body title='main'>\n"
538             + "  <iframe id='testFrame' src='" + URL_SECOND + "'></iframe>\n"
539             + "</body></html>";
540 
541         final String secondHtml = DOCTYPE_HTML
542             + "<html>\n"
543             + "<head><title>inner</title></head>\n"
544             + "<body title='inner'>\n"
545             + "  <a id='tester' " + target
546                 + " href='javascript: try { document.body.setAttribute(\"title\", \"# \" + document.title); } "
547                 + "catch(e) { alert(e); }'>no href</a>\n"
548             + "</body>\n"
549             + "</html>";
550 
551         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
552 
553         final WebDriver driver = loadPage2(html);
554 
555         final String firstWindow = driver.getWindowHandle();
556 
557         driver.switchTo().frame("testFrame");
558         assertEquals(1, driver.getWindowHandles().size());
559         driver.findElement(By.id("tester")).click();
560 
561         String titleVal = driver.findElement(By.tagName("body")).getAttribute("title");
562         assertEquals(frameAlerts, titleVal);
563 
564         // we have to switch back to the outer content
565         // otherwise selenium gets confused
566         driver.switchTo().defaultContent();
567 
568         final Set<String> windows = driver.getWindowHandles();
569         assertEquals(1 + newWindows, windows.size());
570 
571         if (newWindows > 0) {
572             windows.remove(firstWindow);
573             driver.switchTo().window(windows.iterator().next());
574         }
575 
576         titleVal = driver.findElement(By.tagName("body")).getAttribute("title");
577         assertEquals(windowAlerts, titleVal);
578     }
579 
580     /**
581      * Regression test for
582      * <a href="https://sourceforge.net/tracker/?func=detail&atid=448266&aid=1689798&group_id=47038">448</a>.
583      * In href, "this" should be the window and not the link.
584      * @throws Exception if the test fails
585      */
586     @Test
587     @Alerts("true")
588     public void thisInJavascriptHref() throws Exception {
589         final String html = DOCTYPE_HTML
590             + "<html><head>\n"
591             + "<script>\n"
592             + LOG_TITLE_FUNCTION
593             + "</script>\n"
594             + "</head>\n"
595             + "<body>\n"
596             + "  <a href='javascript:log(this === window)'>link 1</a>\n"
597             + "</body></html>";
598 
599         final WebDriver driver = loadPage2(html);
600         driver.findElement(By.tagName("a")).click();
601 
602         assertEquals(1, getMockWebConnection().getRequestCount());
603         verifyTitle2(driver, getExpectedAlerts());
604     }
605 
606     /**
607      * @throws Exception if the test fails
608      */
609     @Test
610     @Alerts({"§§URL§§second/", "object", "function HTMLAnchorElement() { [native code] }"})
611     public void typeof() throws Exception {
612         final String html = DOCTYPE_HTML
613             + "<html><head>\n"
614             + "<script>\n"
615             + LOG_TITLE_FUNCTION
616             + "  function test() {\n"
617             + "    try {\n"
618             + "      log(document.links[0]);\n"
619             + "      log(typeof document.links[0]);\n"
620             + "      log(HTMLAnchorElement);\n"
621             + "    } catch(e) { logEx(e); }\n"
622             + "  }\n"
623             + "</script>\n"
624             + "</head>\n"
625             + "<body onload='test()'>\n"
626             + "  <a id='link' href='" + URL_SECOND + "'>link</a>\n"
627             + "</body></html>";
628 
629         expandExpectedAlertsVariables(URL_FIRST);
630         loadPageVerifyTitle2(html);
631     }
632 
633     /**
634      * @throws Exception if the test fails
635      */
636     @Test
637     @Alerts({"", "", "text/html", "TExT/hTMl", " text/html ", "application/pdf", "unknown"})
638     public void getType() throws Exception {
639         final String html = DOCTYPE_HTML
640             + "<html><head>\n"
641             + "<script>\n"
642             + LOG_TITLE_FUNCTION
643             + "  function test() {\n"
644             + "    alertType('idWithout');\n"
645             + "    alertType('idEmpty');\n"
646             + "    alertType('idText');\n"
647             + "    alertType('idCase');\n"
648             + "    alertType('idWhitespace');\n"
649             + "    alertType('idPdf');\n"
650             + "    alertType('idUnknown');\n"
651             + "  }\n"
652             + "  function alertType(id) {\n"
653             + "    var anchor = document.getElementById(id);\n"
654             + "    log(anchor.type);\n"
655             + "  }\n"
656             + "</script>\n"
657             + "</head>\n"
658             + "<body onload='test()'>\n"
659             + "  <a id='idWithout' href='" + URL_SECOND + "'>link</a>\n"
660             + "  <a id='idEmpty' href='" + URL_SECOND + "' type=''>link</a>\n"
661             + "  <a id='idText' href='" + URL_SECOND + "' type='text/html'>link</a>\n"
662             + "  <a id='idCase' href='" + URL_SECOND + "' type='TExT/hTMl'>link</a>\n"
663             + "  <a id='idWhitespace' href='" + URL_SECOND + "' type=' text/html '>link</a>\n"
664             + "  <a id='idPdf' href='" + URL_SECOND + "' type='application/pdf'>link</a>\n"
665             + "  <a id='idUnknown' href='" + URL_SECOND + "' type='unknown'>link</a>\n"
666             + "</body></html>";
667 
668         loadPageVerifyTitle2(html);
669     }
670 
671     /**
672      * @throws Exception if the test fails
673      */
674     @Test
675     @Alerts({"text/html", "", " TExT/hTMl  ", "unknown", "application/pdf"})
676     public void setType() throws Exception {
677         final String html = DOCTYPE_HTML
678             + "<html><head>\n"
679             + "<script>\n"
680             + LOG_TEXTAREA_FUNCTION
681             + "  function test() {\n"
682             + "    var anchor = document.getElementById('id');\n"
683             + "    log(anchor.type);\n"
684 
685             + "    anchor.type = '';\n"
686             + "    log(anchor.type);\n"
687 
688             + "    anchor.type = ' TExT/hTMl  ';\n"
689             + "    log(anchor.type);\n"
690 
691             + "    anchor.type = 'unknown';\n"
692             + "    log(anchor.type);\n"
693 
694             + "    anchor.type = 'application/pdf';\n"
695             + "    log(anchor.type);\n"
696 
697             + "  }\n"
698             + "  function alertType(id) {\n"
699             + "    var anchor = document.getElementById(id);\n"
700             + "    log(anchor.type);\n"
701             + "  }\n"
702             + "</script>\n"
703             + "</head>\n"
704             + "<body onload='test()'>\n"
705             + "  <a id='id' href='" + URL_SECOND + "' type='text/html'>link</a>\n"
706             + LOG_TEXTAREA
707             + "</body></html>";
708 
709         loadPageVerifyTextArea2(html);
710     }
711 
712     /**
713      * @throws Exception if the test fails
714      */
715     @Test
716     @Alerts(CHROME = {":||||||", ":||||||", "mailto:||||||foo@foo.com", "tel:||||||123456",
717                       "foo:||||||blabla", "file:||||||/P://", "file:||||||/P:/", "file:||||||/P:/TeMp"},
718             EDGE = {":||||||", ":||||||", "mailto:||||||foo@foo.com", "tel:||||||123456",
719                     "foo:||||||blabla", "file:||||||/P://", "file:||||||/P:/", "file:||||||/P:/TeMp"},
720             FF = {":||||||", ":||||||", "mailto:||||||foo@foo.com", "tel:||||||123456",
721                   "foo:||||||blabla", "p:||||||", "p:||||||/", "p:||||||/TeMp"},
722             FF_ESR = {":||||||", ":||||||", "mailto:||||||foo@foo.com", "tel:||||||123456",
723                       "foo:||||||blabla", "p:||||||//", "p:||||||/", "p:||||||/TeMp"})
724     public void propertiesNonStandardHref() throws Exception {
725         final String html = DOCTYPE_HTML
726             + "<html>\n"
727             + "<body>\n"
728             + "  <a href='http://'>http://</a>\n"
729             + "  <a href='https://'>https://</a>\n"
730             + "  <a href='mailto:foo@foo.com'>foo@foo.com</a>\n"
731             + "  <a href='tel:123456'>tel:123456</a>\n"
732             + "  <a href='foo:blabla'>foo:blabla</a>\n"
733             + "  <a href='p://'>p://</a>\n"
734             + "  <a href='p:/'>p:/</a>\n"
735             + "  <a href='p:/TeMp'>p:/TeMp</a>\n"
736 
737             + "  <script>\n"
738             + LOG_TITLE_FUNCTION
739             + "  var links = document.getElementsByTagName('a');\n"
740             + "  for (var i = 0; i < links.length; i++) {\n"
741             + "    var link = links[i];\n"
742             + "    var props = [link.protocol, link.host, link.hostname, \n"
743             + "           link.search, link.hash, link.port, link.pathname];\n"
744             + "    log(props.join('|'));\n"
745             + "  }\n"
746             + "</script>\n"
747             + "</body></html>";
748 
749         loadPageVerifyTitle2(html);
750     }
751 
752     /**
753      * @throws Exception if an error occurs
754      */
755     @Test
756     @Alerts({"", "hi"})
757     public void charset() throws Exception {
758         attribute("charset", "hi");
759     }
760 
761     private void attribute(final String attribute, final String value) throws Exception {
762         final String html = DOCTYPE_HTML
763             + "<html>\n"
764             + "  <body onload='test()'>\n"
765             + "    <script>\n"
766             + LOG_TITLE_FUNCTION
767             + "      function test() {\n"
768             + "        var a = document.createElement('a');\n"
769             + "        log(a." + attribute + ");\n"
770             + "        a." + attribute + " = '" + value + "';\n"
771             + "        log(a." + attribute + ");\n"
772             + "      }\n"
773             + "    </script>\n"
774             + "  </body>\n"
775             + "</html>";
776 
777         loadPageVerifyTitle2(html);
778     }
779 
780     /**
781      * @throws Exception if an error occurs
782      */
783     @Test
784     @Alerts({"", "0,0"})
785     public void coords() throws Exception {
786         attribute("coords", "0,0");
787     }
788 
789     /**
790      * @throws Exception if an error occurs
791      */
792     @Test
793     @Alerts({"", "en"})
794     public void hreflang() throws Exception {
795         attribute("hreflang", "en");
796     }
797 
798     /**
799      * @throws Exception if an error occurs
800      */
801     @Test
802     @Alerts({"", ""})
803     public void origin() throws Exception {
804         attribute(HttpHeader.ORIGIN_LC, "something");
805     }
806 
807     /**
808      * @throws Exception if an error occurs
809      */
810     @Test
811     @Alerts({"", "§§URL§§", "§§URL§§", "§§URL§§", "http://www.htmlunit.org",
812              "http://www.htmlunit.org:1234", "https://www.htmlunit.org:1234"})
813     public void originAttrib() throws Exception {
814         expandExpectedAlertsVariables(new URL("http://localhost:" + PORT));
815 
816         final String html = DOCTYPE_HTML
817                 + "<html>\n"
818                 + "  <head>\n"
819                 + "    <script>\n"
820                 + LOG_TITLE_FUNCTION
821                 + "      function test() {\n"
822                 + "        for(i=0; i<7; i++) {\n"
823                 + "          var a = document.getElementById('a'+i);\n"
824                 + "          log(a.origin);\n"
825                 + "        }\n"
826                 + "      }\n"
827                 + "    </script>\n"
828                 + "  </head>\n"
829                 + "  <body onload='test()'>\n"
830                 + "    <a id='a0'>a0</a>\n"
831                 + "    <a id='a1' href=''>a1</a>\n"
832                 + "    <a id='a2' href='  \t '>a2</a>\n"
833                 + "    <a id='a3' href='relative.html'>a3</a>\n"
834                 + "    <a id='a4' href='http://www.htmlunit.org/index.html'>a4</a>\n"
835                 + "    <a id='a5' href='http://www.htmlunit.org:1234/index.html'>a5</a>\n"
836                 + "    <a id='a6' href='https://www.htmlunit.org:1234/index.html'>a6</a>\n"
837                 + "  </body>\n"
838                 + "</html>";
839 
840         loadPageVerifyTitle2(html);
841     }
842 
843     /**
844      * @throws Exception if an error occurs
845      */
846     @Test
847     @Alerts({"-null", "-", "-  \t ", "no-referrer-no-referrer",
848              "origin-origin", "unsafe-url-unsafe-url", "-unknown"})
849     public void referrerPolicy() throws Exception {
850         final String html = DOCTYPE_HTML
851                 + "<html>\n"
852                 + "  <head>\n"
853                 + "    <script>\n"
854                 + LOG_TEXTAREA_FUNCTION
855                 + "      function test() {\n"
856                 + "        for(i=0; i<7; i++) {\n"
857                 + "          var a = document.getElementById('a'+i);\n"
858                 + "          log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
859                 + "        }\n"
860                 + "      }\n"
861                 + "    </script>\n"
862                 + "  </head>\n"
863                 + "  <body onload='test()'>\n"
864                 + "    <a id='a0'>a0</a>\n"
865                 + "    <a id='a1' referrerPolicy=''>a1</a>\n"
866                 + "    <a id='a2' referrerPolicy='  \t '>a2</a>\n"
867                 + "    <a id='a3' referrerPolicy='no-referrer'>a3</a>\n"
868                 + "    <a id='a4' referrerPolicy='origin'>a4</a>\n"
869                 + "    <a id='a5' referrerPolicy='unsafe-url'>a5</a>\n"
870                 + "    <a id='a6' referrerPolicy='unknown'>a6</a>\n"
871                 + LOG_TEXTAREA
872                 + "  </body>\n"
873                 + "</html>";
874 
875         loadPageVerifyTextArea2(html);
876     }
877 
878     /**
879      * @throws Exception if an error occurs
880      */
881     @Test
882     @Alerts({"origin-origin", "-unknown", "no-referrer-no-referrer",
883              "-", "no-referrer-NO-reFerrer", "origin-origin", "- ", "-unknown"})
884     public void setReferrerPolicy() throws Exception {
885         final String html = DOCTYPE_HTML
886                 + "<html>\n"
887                 + "  <head>\n"
888                 + "    <script>\n"
889                 + LOG_TITLE_FUNCTION
890                 + "      function test() {\n"
891                 + "        var a = document.getElementById('tester');\n"
892                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
893 
894                 + "        a.referrerPolicy = 'unknown';\n"
895                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
896 
897                 + "        a.referrerPolicy = 'no-referrer';\n"
898                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
899 
900                 + "        a.referrerPolicy = '';\n"
901                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
902 
903                 + "        a.referrerPolicy = 'NO-reFerrer';\n"
904                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
905 
906                 + "        a.setAttribute('referrerPolicy', 'origin');\n"
907                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
908 
909                 + "        a.setAttribute('referrerPolicy', ' ');\n"
910                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
911 
912                 + "        a.setAttribute('referrerPolicy', 'unknown');\n"
913                 + "        log(a.referrerPolicy + '-' + a.getAttribute('referrerPolicy'));\n"
914                 + "      }\n"
915                 + "    </script>\n"
916                 + "  </head>\n"
917                 + "  <body onload='test()'>\n"
918                 + "    <a id='tester' referrerPolicy='origin'>a4</a>\n"
919                 + "  </body>\n"
920                 + "</html>";
921 
922         loadPageVerifyTitle2(html);
923     }
924 
925     /**
926      * @throws Exception if the test fails
927      */
928     @Test
929     @Alerts({"[object HTMLButtonElement]", "[object HTMLButtonElement]",
930              "§§URL§§", "http://srv/htmlunit.org"})
931     public void focus() throws Exception {
932         final String html = DOCTYPE_HTML
933             + "<html>\n"
934             + "<head>\n"
935             + "  <script>\n"
936             + LOG_TITLE_FUNCTION
937             + "    function test() {\n"
938             + "      var testNode = document.getElementById('myButton');\n"
939             + "      testNode.focus();\n"
940             + "      log(document.activeElement);\n"
941 
942             + "      testNode = document.getElementById('myA');\n"
943             + "      testNode.focus();\n"
944             + "      log(document.activeElement);\n"
945 
946             + "      testNode = document.getElementById('myHrefEmpty');\n"
947             + "      testNode.focus();\n"
948             + "      log(document.activeElement);\n"
949 
950             + "      testNode = document.getElementById('myHref');\n"
951             + "      testNode.focus();\n"
952             + "      log(document.activeElement);\n"
953             + "    }\n"
954             + "  </script>\n"
955             + "</head>\n"
956             + "<body onload='test()'>\n"
957             + "  <button id='myButton'>Press</button>\n"
958             + "  <a id='myA'>anchor</a>\n"
959             + "  <a id='myHrefEmpty' href=''>anchor</a>\n"
960             + "  <a id='myHref' href='http://srv/htmlunit.org'>anchor</a>\n"
961             + "</body>\n"
962             + "</html>";
963 
964         expandExpectedAlertsVariables(URL_FIRST);
965         loadPageVerifyTitle2(html);
966     }
967 
968     /**
969      * @throws Exception if an error occurs
970      */
971     @Test
972     @Alerts(DEFAULT = {},
973             CHROME = "PING",
974             EDGE = "PING")
975     public void ping() throws Exception {
976         final String html = DOCTYPE_HTML
977             + "<html><body>\n"
978             + "  <a href='" + URL_SECOND + "' ping='test2?h'>clickMe</a>\n"
979             + "</body></html>";
980 
981         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
982         servlets.put("/test2", PingServlet.class);
983 
984         PingServlet.HEADERS_.clear();
985         PingServlet.BODY_ = null;
986 
987         getMockWebConnection().setResponse(URL_SECOND, "something");
988         final WebDriver driver = loadPage2(html, servlets);
989         driver.findElement(By.linkText("clickMe")).click();
990 
991         final String[] expectedAlerts = getExpectedAlerts();
992         final String firstString;
993         final String secondString;
994         final String body;
995         if (expectedAlerts.length != 0) {
996             firstString = URL_FIRST.toString();
997             secondString = URL_SECOND.toString();
998             body = PingServlet.BODY_;
999         }
1000         else {
1001             firstString = null;
1002             secondString = null;
1003             body = null;
1004         }
1005         assertEquals(firstString, PingServlet.HEADERS_.get(HttpHeader.PING_FROM));
1006         assertEquals(secondString, PingServlet.HEADERS_.get(HttpHeader.PING_TO));
1007         assertEquals(body, PingServlet.BODY_);
1008     }
1009 
1010     /**
1011      * Servlet for {@link #ping()}.
1012      */
1013     public static class PingServlet extends HttpServlet {
1014 
1015         private static Map<String, String> HEADERS_ = new HashMap<>();
1016         private static String BODY_;
1017 
1018         /**
1019          * {@inheritDoc}
1020          */
1021         @Override
1022         protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
1023             throws ServletException, IOException {
1024             request.setCharacterEncoding(UTF_8.name());
1025             response.setContentType(MimeType.TEXT_HTML);
1026 
1027             for (final Enumeration<String> en = request.getHeaderNames(); en.hasMoreElements();) {
1028                 final String key = en.nextElement();
1029                 HEADERS_.put(key, request.getHeader(key));
1030             }
1031 
1032             final BufferedReader reader = request.getReader();
1033             final StringWriter stringSriter = new StringWriter();
1034             IOUtils.copy(reader, stringSriter);
1035             BODY_ = stringSriter.toString();
1036         }
1037     }
1038 
1039     /**
1040      * @throws Exception if an error occurs
1041      */
1042     @Test
1043     @Alerts({"", "alternate help", "prefetch", "prefetch", "not supported", "notsupported"})
1044     public void readWriteRel() throws Exception {
1045         final String html = DOCTYPE_HTML
1046             + "<html><body><a id='a1'>a1</a><a id='a2' rel='alternate help'>a2</a><script>\n"
1047             + LOG_TITLE_FUNCTION
1048             + "var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
1049 
1050             + "log(a1.rel);\n"
1051             + "log(a2.rel);\n"
1052 
1053             + "a1.rel = 'prefetch';\n"
1054             + "a2.rel = 'prefetch';\n"
1055             + "log(a1.rel);\n"
1056             + "log(a2.rel);\n"
1057 
1058             + "a1.rel = 'not supported';\n"
1059             + "a2.rel = 'notsupported';\n"
1060             + "log(a1.rel);\n"
1061             + "log(a2.rel);\n"
1062 
1063             + "</script></body></html>";
1064         loadPageVerifyTitle2(html);
1065     }
1066 
1067     /**
1068      * @throws Exception if an error occurs
1069      */
1070     @Test
1071     @Alerts({"0", "2", "alternate", "help"})
1072     public void relList() throws Exception {
1073         final String html = DOCTYPE_HTML
1074             + "<html><body><a id='a1'>a1</a><a id='a2' rel='alternate help'>a2</a><script>\n"
1075             + LOG_TITLE_FUNCTION
1076             + "var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
1077 
1078             + "try {\n"
1079             + "  log(a1.relList.length);\n"
1080             + "  log(a2.relList.length);\n"
1081 
1082             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
1083             + "    log(a2.relList[i]);\n"
1084             + "  }\n"
1085             + "} catch(e) { logEx(e); }\n"
1086 
1087             + "</script></body></html>";
1088         loadPageVerifyTitle2(html);
1089     }
1090 
1091     /**
1092      * @throws Exception if an error occurs
1093      */
1094     @Test
1095     @Alerts({"0", "2", "2", "1", "alternate", "help", "abc", "alternate help", "abc"})
1096     public void setRelListString() throws Exception {
1097         final String html = DOCTYPE_HTML
1098             + "<html><body><a id='a1'>a1</a><a id='a2' rel='alternate help'>a2</a><script>\n"
1099             + LOG_TITLE_FUNCTION
1100             + "var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
1101 
1102             + "try {\n"
1103             + "  log(a1.relList.length);\n"
1104             + "  log(a2.relList.length);\n"
1105 
1106             + "  a1.relList = 'alternate help';\n"
1107             + "  a2.relList = 'abc';\n"
1108 
1109             + "  log(a1.relList.length);\n"
1110             + "  log(a2.relList.length);\n"
1111 
1112             + "  for (var i = 0; i < a1.relList.length; i++) {\n"
1113             + "    log(a1.relList[i]);\n"
1114             + "  }\n"
1115 
1116             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
1117             + "    log(a2.relList[i]);\n"
1118             + "  }\n"
1119 
1120             + "  log(a1.rel);\n"
1121             + "  log(a2.rel);\n"
1122             + "} catch(e) { logEx(e); }\n"
1123 
1124             + "</script></body></html>";
1125         loadPageVerifyTitle2(html);
1126     }
1127 
1128     /**
1129      * @throws Exception if an error occurs
1130      */
1131     @Test
1132     @Alerts({"0", "2", "0", "0", "", "\\s\\s\\t"})
1133     public void setRelListStringBlank() throws Exception {
1134         final String html = DOCTYPE_HTML
1135             + "<html><body><a id='a1'>a1</a><a id='a2' rel='alternate help'>a2</a><script>\n"
1136             + LOG_TITLE_FUNCTION_NORMALIZE
1137             + "var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
1138 
1139             + "try {\n"
1140             + "  log(a1.relList.length);\n"
1141             + "  log(a2.relList.length);\n"
1142 
1143             + "  a1.relList = '';\n"
1144             + "  a2.relList = '  \t';\n"
1145 
1146             + "  log(a1.relList.length);\n"
1147             + "  log(a2.relList.length);\n"
1148 
1149             + "  log(a1.rel);\n"
1150             + "  log(a2.rel);\n"
1151             + "} catch(e) { logEx(e); }\n"
1152 
1153             + "</script></body></html>";
1154         loadPageVerifyTitle2(html);
1155     }
1156 
1157     /**
1158      * @throws Exception if an error occurs
1159      */
1160     @Test
1161     @Alerts({"0", "2", "1", "1", "null", "null", "null", "null"})
1162     public void setRelListNull() throws Exception {
1163         final String html = DOCTYPE_HTML
1164             + "<html><body><a id='a1'>a1</a><a id='a2' rel='alternate help'>a2</a><script>\n"
1165             + LOG_TITLE_FUNCTION_NORMALIZE
1166             + "var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
1167 
1168             + "try {\n"
1169             + "  log(a1.relList.length);\n"
1170             + "  log(a2.relList.length);\n"
1171 
1172             + "  a1.relList = null;\n"
1173             + "  a2.relList = null;\n"
1174 
1175             + "  log(a1.relList.length);\n"
1176             + "  log(a2.relList.length);\n"
1177 
1178             + "  for (var i = 0; i < a1.relList.length; i++) {\n"
1179             + "    log(a1.relList[i]);\n"
1180             + "  }\n"
1181 
1182             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
1183             + "    log(a2.relList[i]);\n"
1184             + "  }\n"
1185 
1186             + "  log(a1.rel);\n"
1187             + "  log(a2.rel);\n"
1188             + "} catch(e) { logEx(e); }\n"
1189 
1190             + "</script></body></html>";
1191         loadPageVerifyTitle2(html);
1192     }
1193 
1194     /**
1195      * @throws Exception if an error occurs
1196      */
1197     @Test
1198     @Alerts({"0", "2", "1", "1", "undefined", "undefined", "undefined", "undefined"})
1199     public void setRelListUndefined() throws Exception {
1200         final String html = DOCTYPE_HTML
1201             + "<html><body><a id='a1'>a1</a><a id='a2' rel='alternate help'>a2</a><script>\n"
1202             + LOG_TITLE_FUNCTION_NORMALIZE
1203             + "var a1 = document.getElementById('a1'), a2 = document.getElementById('a2');\n"
1204 
1205             + "try {\n"
1206             + "  log(a1.relList.length);\n"
1207             + "  log(a2.relList.length);\n"
1208 
1209             + "  a1.relList = undefined;\n"
1210             + "  a2.relList = undefined;\n"
1211 
1212             + "  log(a1.relList.length);\n"
1213             + "  log(a2.relList.length);\n"
1214 
1215             + "  for (var i = 0; i < a1.relList.length; i++) {\n"
1216             + "    log(a1.relList[i]);\n"
1217             + "  }\n"
1218 
1219             + "  for (var i = 0; i < a2.relList.length; i++) {\n"
1220             + "    log(a2.relList[i]);\n"
1221             + "  }\n"
1222 
1223             + "  log(a1.rel);\n"
1224             + "  log(a2.rel);\n"
1225             + "} catch(e) { logEx(e); }\n"
1226 
1227             + "</script></body></html>";
1228         loadPageVerifyTitle2(html);
1229     }
1230 
1231     /**
1232      * @throws Exception if an error occurs
1233      */
1234     @Test
1235     @Alerts({"", "user", "user", "",
1236              "", "",
1237              "Tester", "https://Tester:password@developer.mozilla.org/",
1238              "Tester", "https://Tester@developer.mozilla.org/",
1239              "Tester", "https://Tester@developer.mozilla.org/"})
1240     @HtmlUnitNYI(CHROME = {"", "user", "user", "",
1241                            "", "",
1242                            "Tester", "https://Tester:password@developer.mozilla.org",
1243                            "Tester", "https://Tester@developer.mozilla.org",
1244                            "Tester", "https://Tester@developer.mozilla.org"},
1245             EDGE = {"", "user", "user", "",
1246                     "", "",
1247                     "Tester", "https://Tester:password@developer.mozilla.org",
1248                     "Tester", "https://Tester@developer.mozilla.org",
1249                     "Tester", "https://Tester@developer.mozilla.org"},
1250             FF_ESR = {"", "user", "user", "",
1251                       "", "",
1252                       "Tester", "https://Tester:password@developer.mozilla.org",
1253                       "Tester", "https://Tester@developer.mozilla.org",
1254                       "Tester", "https://Tester@developer.mozilla.org"},
1255             FF = {"", "user", "user", "",
1256                   "", "",
1257                   "Tester", "https://Tester:password@developer.mozilla.org",
1258                   "Tester", "https://Tester@developer.mozilla.org",
1259                   "Tester", "https://Tester@developer.mozilla.org"})
1260     public void readWriteUsername() throws Exception {
1261         final String html = DOCTYPE_HTML
1262                 + "<html><body><a id='a1'>a1</a>"
1263                 + "<a id='a2' href='https://user:password@developer.mozilla.org'>a2</a>"
1264                 + "<a id='a3' href='https://user@developer.mozilla.org'>a3</a>"
1265                 + "<a id='a4' href='https://developer.mozilla.org'>a3</a>"
1266                 + "<script>\n"
1267                 + LOG_TITLE_FUNCTION
1268                 + "var a1 = document.getElementById('a1'),"
1269                     + "a2 = document.getElementById('a2'),"
1270                     + "a3 = document.getElementById('a3'),"
1271                     + "a4 = document.getElementById('a4');\n"
1272 
1273                 + "log(a1.username);\n"
1274                 + "log(a2.username);\n"
1275                 + "log(a3.username);\n"
1276                 + "log(a4.username);\n"
1277 
1278                 + "if (a1.username != undefined) {\n"
1279 
1280                 + "a1.username = 'Tester';\n"
1281                 + "a2.username = 'Tester';\n"
1282                 + "a3.username = 'Tester';\n"
1283                 + "a4.username = 'Tester';\n"
1284 
1285                 + "log(a1.username);\n"
1286                 + "log(a1.href);\n"
1287                 + "log(a2.username);\n"
1288                 + "log(a2.href);\n"
1289                 + "log(a3.username);\n"
1290                 + "log(a3.href);\n"
1291                 + "log(a4.username);\n"
1292                 + "log(a4.href);\n"
1293 
1294                 + "}\n"
1295 
1296                 + "</script></body></html>";
1297         loadPage2(html);
1298     }
1299 
1300     /**
1301      * @throws Exception if an error occurs
1302      */
1303     @Test
1304     @Alerts({"", "password", "password", "",
1305              "", "",
1306              "Tester", "https://user:Tester@developer.mozilla.org/",
1307              "Tester", "https://:Tester@developer.mozilla.org/",
1308              "Tester", "https://:Tester@developer.mozilla.org/"})
1309     @HtmlUnitNYI(CHROME = {"", "password", "password", "",
1310                            "", "",
1311                            "Tester", "https://user:Tester@developer.mozilla.org",
1312                            "Tester", "https://:Tester@developer.mozilla.org",
1313                            "Tester", "https://:Tester@developer.mozilla.org"},
1314             EDGE = {"", "password", "password", "",
1315                     "", "",
1316                     "Tester", "https://user:Tester@developer.mozilla.org",
1317                     "Tester", "https://:Tester@developer.mozilla.org",
1318                     "Tester", "https://:Tester@developer.mozilla.org"},
1319             FF_ESR = {"", "password", "password", "",
1320                       "", "",
1321                       "Tester", "https://user:Tester@developer.mozilla.org",
1322                       "Tester", "https://:Tester@developer.mozilla.org",
1323                       "Tester", "https://:Tester@developer.mozilla.org"},
1324             FF = {"", "password", "password", "",
1325                   "", "",
1326                   "Tester", "https://user:Tester@developer.mozilla.org",
1327                   "Tester", "https://:Tester@developer.mozilla.org",
1328                   "Tester", "https://:Tester@developer.mozilla.org"})
1329     public void readWritePassword() throws Exception {
1330         final String html = DOCTYPE_HTML
1331                 + "<html><body><a id='a1'>a1</a>"
1332                 + "<a id='a2' href='https://user:password@developer.mozilla.org'>a2</a>"
1333                 + "<a id='a3' href='https://:password@developer.mozilla.org'>a3</a>"
1334                 + "<a id='a4' href='https://developer.mozilla.org'>a3</a>"
1335                 + "<script>\n"
1336                 + LOG_TITLE_FUNCTION
1337                 + "var a1 = document.getElementById('a1'),"
1338                     + "a2 = document.getElementById('a2'),"
1339                     + "a3 = document.getElementById('a3'),"
1340                     + "a4 = document.getElementById('a4');\n"
1341 
1342                 + "log(a1.password);\n"
1343                 + "log(a2.password);\n"
1344                 + "log(a3.password);\n"
1345                 + "log(a4.password);\n"
1346 
1347                 + "if (a1.password != undefined) {\n"
1348 
1349                 + "a1.password = 'Tester';\n"
1350                 + "a2.password = 'Tester';\n"
1351                 + "a3.password = 'Tester';\n"
1352                 + "a4.password = 'Tester';\n"
1353 
1354                 + "log(a1.password);\n"
1355                 + "log(a1.href);\n"
1356                 + "log(a2.password);\n"
1357                 + "log(a2.href);\n"
1358                 + "log(a3.password);\n"
1359                 + "log(a3.href);\n"
1360                 + "log(a4.password);\n"
1361                 + "log(a4.href);\n"
1362 
1363                 + "}\n"
1364 
1365                 + "</script></body></html>";
1366         loadPageVerifyTitle2(html);
1367     }
1368 
1369     /**
1370      * @throws Exception if an error occurs
1371      */
1372     @Test
1373     @Alerts({"http:", "https:", "https://§§URL§§/foo.html#O"})
1374     public void readWriteProtocol() throws Exception {
1375         final String html = DOCTYPE_HTML
1376             + "<html>\n"
1377             + "  <head>\n"
1378             + "    <script>\n"
1379             + LOG_TITLE_FUNCTION
1380             + "      function test() {\n"
1381             + "        var tester = document.getElementById('tester');\n"
1382             + "        log(tester.protocol);\n"
1383 
1384             + "        tester.protocol = 'httPS';\n"
1385             + "        log(tester.protocol);\n"
1386             + "        log(tester.href);\n"
1387             + "      }\n"
1388             + "    </script>\n"
1389             + "  <head>\n"
1390             + "  <body onload='test()'>\n"
1391             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1392             + "  </body>\n"
1393             + "</html>";
1394 
1395         expandExpectedAlertsVariables("localhost:" + PORT);
1396         loadPageVerifyTitle2(html);
1397     }
1398 
1399     /**
1400      * @throws Exception if an error occurs
1401      */
1402     @Test
1403     @Alerts({"http:", "http:", "http://§§URL§§/foo.html#O"})
1404     public void readWriteProtocolUnknown() throws Exception {
1405         final String html = DOCTYPE_HTML
1406             + "<html>\n"
1407             + "  <head>\n"
1408             + "    <script>\n"
1409             + LOG_TITLE_FUNCTION
1410             + "      function test() {\n"
1411             + "        var tester = document.getElementById('tester');\n"
1412             + "        log(tester.protocol);\n"
1413 
1414             + "        tester.protocol = 'axdeg';\n"
1415             + "        log(tester.protocol);\n"
1416             + "        log(tester.href);\n"
1417             + "      }\n"
1418             + "    </script>\n"
1419             + "  <head>\n"
1420             + "  <body onload='test()'>\n"
1421             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1422             + "  </body>\n"
1423             + "</html>";
1424 
1425         expandExpectedAlertsVariables("localhost:" + PORT);
1426         loadPageVerifyTitle2(html);
1427     }
1428 
1429     /**
1430      * @throws Exception if an error occurs
1431      */
1432     @Test
1433     @Alerts({"http:", "https:", "https://§§URL§§/foo.html#O"})
1434     public void readWriteProtocolIncludingColon() throws Exception {
1435         final String html = DOCTYPE_HTML
1436             + "<html>\n"
1437             + "  <head>\n"
1438             + "    <script>\n"
1439             + LOG_TITLE_FUNCTION
1440             + "      function test() {\n"
1441             + "        var tester = document.getElementById('tester');\n"
1442             + "        log(tester.protocol);\n"
1443 
1444             + "        tester.protocol = 'https:';\n"
1445             + "        log(tester.protocol);\n"
1446             + "        log(tester.href);\n"
1447             + "      }\n"
1448             + "    </script>\n"
1449             + "  <head>\n"
1450             + "  <body onload='test()'>\n"
1451             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1452             + "  </body>\n"
1453             + "</html>";
1454 
1455         expandExpectedAlertsVariables("localhost:" + PORT);
1456         loadPageVerifyTitle2(html);
1457     }
1458 
1459     /**
1460      * @throws Exception if an error occurs
1461      */
1462     @Test
1463     @Alerts({"http:", "https:", "https://§§URL§§/foo.html#O"})
1464     public void readWriteProtocolWithUrl() throws Exception {
1465         final String html = DOCTYPE_HTML
1466             + "<html>\n"
1467             + "  <head>\n"
1468             + "    <script>\n"
1469             + LOG_TITLE_FUNCTION
1470             + "      function test() {\n"
1471             + "        var tester = document.getElementById('tester');\n"
1472             + "        log(tester.protocol);\n"
1473 
1474             + "        tester.protocol = 'https://www.htmlunit.org';\n"
1475             + "        log(tester.protocol);\n"
1476             + "        log(tester.href);\n"
1477             + "      }\n"
1478             + "    </script>\n"
1479             + "  <head>\n"
1480             + "  <body onload='test()'>\n"
1481             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1482             + "  </body>\n"
1483             + "</html>";
1484 
1485         expandExpectedAlertsVariables("localhost:" + PORT);
1486         loadPageVerifyTitle2(html);
1487     }
1488 
1489     /**
1490      * @throws Exception if an error occurs
1491      */
1492     @Test
1493     @Alerts({"http:", "http:", "http://§§URL§§/foo.html#O",
1494              "http:", "http://§§URL§§/abc_xyz://localhost/foo.html"})
1495     public void readWriteProtocolBroken() throws Exception {
1496         final String html = DOCTYPE_HTML
1497             + "<html>\n"
1498             + "  <head>\n"
1499             + "    <script>\n"
1500             + LOG_TITLE_FUNCTION
1501             + "      function test() {\n"
1502             + "        var tester = document.getElementById('tester');\n"
1503             + "        log(tester.protocol);\n"
1504 
1505             + "        try {\n"
1506             + "          tester.protocol = ' axdeg ';\n"
1507             + "          log(tester.protocol);\n"
1508             + "          log(tester.href);\n"
1509             + "        } catch(e) { log('invalid argument') }\n"
1510 
1511             + "        tester = document.getElementById('invalidHref');\n"
1512             + "        log(tester.protocol);\n"
1513             + "        log(tester.href);\n"
1514             + "      }\n"
1515             + "    </script>\n"
1516             + "  <head>\n"
1517             + "  <body onload='test()'>\n"
1518             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1519             + "    <a id='invalidHref' href='abc_xyz://localhost/foo.html'>link 1</a>\n"
1520             + "  </body>\n"
1521             + "</html>";
1522 
1523         expandExpectedAlertsVariables("localhost:" + PORT);
1524         loadPageVerifyTitle2(html);
1525     }
1526 
1527     /**
1528      * @throws Exception if an error occurs
1529      */
1530     @Test
1531     @Alerts({"localhost", "motion", "http://§§URL§§/foo.html#O"})
1532     public void readWriteAnchorHostname() throws Exception {
1533         final String html = DOCTYPE_HTML
1534             + "<html>\n"
1535             + "  <head>\n"
1536             + "    <script>\n"
1537             + LOG_TITLE_FUNCTION
1538             + "      function test() {\n"
1539             + "        var tester = document.getElementById('tester');\n"
1540             + "        log(tester.hostname);\n"
1541 
1542             + "        tester.hostname = 'motion';\n"
1543             + "        log(tester.hostname);\n"
1544             + "        log(tester.href);\n"
1545             + "      }\n"
1546             + "    </script>\n"
1547             + "  <head>\n"
1548             + "  <body onload='test()'>\n"
1549             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1550             + "  </body>\n"
1551             + "</html>";
1552 
1553         expandExpectedAlertsVariables("motion:" + PORT);
1554         loadPageVerifyTitle2(html);
1555     }
1556 
1557     /**
1558      * @throws Exception if an error occurs
1559      */
1560     @Test
1561     @Alerts(DEFAULT = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O",
1562                        "localhost", "http://localhost:§§URL§§/foo.html#O"},
1563             CHROME =  {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O",
1564                        "%20%20%20%20", "http://%20%20%20%20:§§URL§§/foo.html#O"},
1565             EDGE =  {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O",
1566                      "%20%20%20%20", "http://%20%20%20%20:§§URL§§/foo.html#O"})
1567     @HtmlUnitNYI(CHROME = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O",
1568                            "%20%20%20%20", "http:// :§§URL§§/foo.html#O"},
1569                 EDGE = {"localhost", "localhost", "http://localhost:§§URL§§/foo.html#O",
1570                         "%20%20%20%20", "http:// :§§URL§§/foo.html#O"})
1571     public void readWriteAnchorHostnameEmpty() throws Exception {
1572         final String html = DOCTYPE_HTML
1573             + "<html>\n"
1574             + "  <head>\n"
1575             + "    <script>\n"
1576             + LOG_TITLE_FUNCTION
1577             + "      function test() {\n"
1578             + "        var tester = document.getElementById('tester');\n"
1579             + "        log(tester.hostname);\n"
1580 
1581             + "        tester.hostname = '';\n"
1582             + "        log(tester.hostname);\n"
1583             + "        log(tester.href);\n"
1584 
1585             + "        tester.hostname = '    ';\n"
1586             + "        log(tester.hostname);\n"
1587             + "        log(tester.href);\n"
1588             + "      }\n"
1589             + "    </script>\n"
1590             + "  <head>\n"
1591             + "  <body onload='test()'>\n"
1592             + "    <a id='tester' href='foo.html#O'>link 1</a>\n"
1593             + "  </body>\n"
1594             + "</html>";
1595 
1596         expandExpectedAlertsVariables("" + PORT);
1597         loadPageVerifyTitle2(html);
1598     }
1599 }