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