View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import static java.nio.charset.StandardCharsets.UTF_8;
18  
19  import java.io.InputStream;
20  import java.net.URL;
21  import java.net.URLEncoder;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.commons.io.IOUtils;
27  import org.htmlunit.HttpHeader;
28  import org.htmlunit.HttpMethod;
29  import org.htmlunit.MockWebConnection;
30  import org.htmlunit.WebDriverTestCase;
31  import org.htmlunit.junit.BrowserRunner;
32  import org.htmlunit.junit.annotation.Alerts;
33  import org.htmlunit.junit.annotation.BuggyWebDriver;
34  import org.htmlunit.junit.annotation.HtmlUnitNYI;
35  import org.htmlunit.util.MimeType;
36  import org.htmlunit.util.NameValuePair;
37  import org.junit.Test;
38  import org.junit.runner.RunWith;
39  import org.openqa.selenium.By;
40  import org.openqa.selenium.Keys;
41  import org.openqa.selenium.WebDriver;
42  import org.openqa.selenium.WebElement;
43  import org.openqa.selenium.interactions.Actions;
44  
45  /**
46   * Tests for {@link HtmlAnchor}.
47   *
48   * @author Ahmed Ashour
49   * @author Ronald Brill
50   * @author Frank Danek
51   */
52  @RunWith(BrowserRunner.class)
53  public class HtmlAnchorTest extends WebDriverTestCase {
54  
55      /**
56       * @throws Exception if an error occurs
57       */
58      @Test
59      @Alerts({"hi", "%28%29"})
60      public void href_js_escaping() throws Exception {
61          final String html = DOCTYPE_HTML
62              + "<html><head>\n"
63              + "<script>\n"
64              + LOG_TITLE_FUNCTION
65              + "  function sayHello(text) {\n"
66              + "    log(text);\n"
67              + "  }\n"
68              + "</script></head>\n"
69              + "<body>\n"
70              + "  <a id='myAnchor' href=\"javascript:sayHello%28'hi'%29\">My Link</a>\n"
71              + "  <input id='myButton' type=button onclick=\"javascript:sayHello('%28%29')\" value='My Button'>\n"
72              + "</body></html>";
73  
74          final WebDriver driver = loadPage2(html);
75  
76          driver.findElement(By.id("myAnchor")).click();
77          verifyTitle2(driver, getExpectedAlerts()[0]);
78  
79          driver.findElement(By.id("myButton")).click();
80          verifyTitle2(driver, getExpectedAlerts());
81      }
82  
83      /**
84       * @throws Exception if an error occurs
85       */
86      @Test
87      @Alerts({"(*%a", "%28%A"})
88      public void href_js_escaping2() throws Exception {
89          final String html = DOCTYPE_HTML
90              + "<html><head><script>\n"
91              + "  function sayHello(text) {\n"
92              + "    alert(text);\n"
93              + "  }\n"
94              + "</script></head>\n"
95              + "<body>\n"
96              + "  <a id='myAnchor' href=\"javascript:sayHello%28'%28%2a%a'%29\">My Link</a>\n"
97              + "  <input id='myButton' type=button onclick=\"javascript:sayHello('%28%A')\" value='My Button'>\n"
98              + "</body></html>";
99  
100         final WebDriver driver = loadPage2(html);
101         driver.findElement(By.id("myAnchor")).click();
102         verifyAlerts(driver, getExpectedAlerts()[0]);
103         driver.findElement(By.id("myButton")).click();
104         verifyAlerts(driver, getExpectedAlerts()[1]);
105     }
106 
107     /**
108      * @throws Exception if an error occurs
109      */
110     @Test
111     public void clickNestedElement() throws Exception {
112         final String html = DOCTYPE_HTML
113             + "<html>\n"
114             + "<body>\n"
115             + "  <a href='page2.html'>\n"
116             + "    <span id='theSpan'>My Link</span>\n"
117             + "  </a>\n"
118             + "</body></html>";
119 
120         getMockWebConnection().setDefaultResponse("");
121         final WebDriver driver = loadPage2(html);
122         final WebElement span = driver.findElement(By.id("theSpan"));
123         assertEquals("span", span.getTagName());
124         span.click();
125         assertEquals(URL_FIRST + "page2.html", driver.getCurrentUrl());
126     }
127 
128     /**
129      * @throws Exception if an error occurs
130      */
131     @Test
132     @Alerts("§§URL§§page2.html")
133     public void clickNestedButtonElement() throws Exception {
134         final String html = DOCTYPE_HTML
135             + "<html>\n"
136             + "<body>\n"
137             + "  <a href='page2.html'>\n"
138             + "    <button id='theButton'></button>\n"
139             + "  </a>\n"
140             + "</body></html>";
141 
142         expandExpectedAlertsVariables(URL_FIRST);
143         getMockWebConnection().setDefaultResponse("");
144         final WebDriver driver = loadPage2(html);
145         final WebElement button = driver.findElement(By.id("theButton"));
146         assertEquals("button", button.getTagName());
147         button.click();
148         assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
149     }
150 
151     /**
152      * @throws Exception if an error occurs
153      */
154     @Test
155     @Alerts("")
156     public void clickNestedCheckboxElement() throws Exception {
157         final String html = DOCTYPE_HTML
158             + "<html>\n"
159             + "<body>\n"
160             + "  <a href='page2.html'>\n"
161             + "    <input type='checkbox' id='theCheckbox' name='myCheckbox' value='Milk'>\n"
162             + "  </a>\n"
163             + "</body></html>";
164 
165         getMockWebConnection().setDefaultResponse("");
166         final WebDriver driver = loadPage2(html);
167         final WebElement checkbox = driver.findElement(By.id("theCheckbox"));
168         assertEquals("input", checkbox.getTagName());
169         checkbox.click();
170         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
171     }
172 
173     /**
174      * @throws Exception if an error occurs
175      */
176     @Test
177     public void clickNestedImageElement() throws Exception {
178         final URL urlImage = new URL(URL_FIRST, "img.jpg");
179         try (InputStream is = getClass().getClassLoader().
180                 getResourceAsStream("testfiles/not_supported_type.jpg")) {
181             final byte[] directBytes = IOUtils.toByteArray(is);
182             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
183         }
184 
185         final String html = DOCTYPE_HTML
186             + "<html>\n"
187             + "<body>\n"
188             + "  <a href='page2.html'>\n"
189             + "    <img id='theImage' src='" + urlImage + "' />\n"
190             + "  </a>\n"
191             + "</body></html>";
192 
193         getMockWebConnection().setDefaultResponse("");
194         final WebDriver driver = loadPage2(html);
195         final WebElement img = driver.findElement(By.id("theImage"));
196         assertEquals("img", img.getTagName());
197         img.click();
198         assertEquals(URL_FIRST + "page2.html", driver.getCurrentUrl());
199     }
200 
201     /**
202      * @throws Exception if an error occurs
203      */
204     @Test
205     @Alerts("page2.html")
206     public void clickNestedInputImageElement() throws Exception {
207         final String html = DOCTYPE_HTML
208             + "<html>\n"
209             + "<body>\n"
210             + "  <a href='page2.html'>\n"
211             + "    <input type='image' id='theInput' />\n"
212             + "  </a>\n"
213             + "</body></html>";
214 
215         getMockWebConnection().setDefaultResponse("");
216         final WebDriver driver = loadPage2(html);
217         final WebElement input = driver.findElement(By.id("theInput"));
218         assertEquals("input", input.getTagName());
219         input.click();
220         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
221     }
222 
223     /**
224      * @throws Exception if an error occurs
225      */
226     @Test
227     @Alerts("page2.html")
228     public void clickNestedInputTextElement() throws Exception {
229         final String html = DOCTYPE_HTML
230             + "<html>\n"
231             + "<body>\n"
232             + "  <a href='page2.html'>\n"
233             + "    <input type='text' id='theInput' />\n"
234             + "  </a>\n"
235             + "</body></html>";
236 
237         getMockWebConnection().setDefaultResponse("");
238         final WebDriver driver = loadPage2(html);
239         final WebElement input = driver.findElement(By.id("theInput"));
240         assertEquals("input", input.getTagName());
241         input.click();
242         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
243     }
244 
245     /**
246      * @throws Exception if an error occurs
247      */
248     @Test
249     @Alerts("page2.html")
250     public void clickNestedInputPasswordElement() throws Exception {
251         final String html = DOCTYPE_HTML
252             + "<html>\n"
253             + "<body>\n"
254             + "  <a href='page2.html'>\n"
255             + "    <input type='password' id='theInput' />\n"
256             + "  </a>\n"
257             + "</body></html>";
258 
259         getMockWebConnection().setDefaultResponse("");
260         final WebDriver driver = loadPage2(html);
261         final WebElement input = driver.findElement(By.id("theInput"));
262         assertEquals("input", input.getTagName());
263         input.click();
264         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
265     }
266 
267     /**
268      * @throws Exception if an error occurs
269      */
270     @Test
271     @Alerts("§§URL§§page2.html")
272     @BuggyWebDriver(FF = "§§URL§§",
273                     FF_ESR = "§§URL§§")
274     public void clickNestedOptionElement() throws Exception {
275         final String html = DOCTYPE_HTML
276             + "<html>\n"
277             + "<body>\n"
278             + "  <a href='page2.html'>\n"
279             + "    <select size=2>\n"
280             + "      <option id='theOption'>test</option>\n"
281             + "    </select>\n"
282             + "  </a>\n"
283             + "</body></html>";
284 
285         expandExpectedAlertsVariables(URL_FIRST);
286         getMockWebConnection().setDefaultResponse("");
287         final WebDriver driver = loadPage2(html);
288         final WebElement option = driver.findElement(By.id("theOption"));
289         assertEquals("option", option.getTagName());
290         option.click();
291 
292         assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
293     }
294 
295     /**
296      * @throws Exception if an error occurs
297      */
298     @Test
299     @Alerts("")
300     public void clickNestedRadioElement() throws Exception {
301         final String html = DOCTYPE_HTML
302             + "<html>\n"
303             + "<body>\n"
304             + "  <a href='page2.html'>\n"
305             + "    <input type='radio' id='theRadio' name='myRadio' value='Milk'>\n"
306             + "  </a>\n"
307             + "</body></html>";
308 
309         getMockWebConnection().setDefaultResponse("");
310         final WebDriver driver = loadPage2(html);
311         final WebElement radio = driver.findElement(By.id("theRadio"));
312         assertEquals("input", radio.getTagName());
313         radio.click();
314         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
315     }
316 
317     /**
318      * @throws Exception if an error occurs
319      */
320     @Test
321     @Alerts("page2.html")
322     public void clickNestedResetElement() throws Exception {
323         final String html = DOCTYPE_HTML
324             + "<html>\n"
325             + "<body>\n"
326             + "  <a href='page2.html'>\n"
327             + "    <input type='reset' id='theInput' />\n"
328             + "  </a>\n"
329             + "</body></html>";
330 
331         getMockWebConnection().setDefaultResponse("");
332         final WebDriver driver = loadPage2(html);
333         final WebElement input = driver.findElement(By.id("theInput"));
334         assertEquals("input", input.getTagName());
335         input.click();
336         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
337     }
338 
339     /**
340      * @throws Exception if an error occurs
341      */
342     @Test
343     @Alerts("page2.html")
344     public void clickNestedSubmitElement() throws Exception {
345         final String html = DOCTYPE_HTML
346             + "<html>\n"
347             + "<body>\n"
348             + "  <a href='page2.html'>\n"
349             + "    <input type='submit' id='theInput' />\n"
350             + "  </a>\n"
351             + "</body></html>";
352 
353         getMockWebConnection().setDefaultResponse("");
354         final WebDriver driver = loadPage2(html);
355         final WebElement input = driver.findElement(By.id("theInput"));
356         assertEquals("input", input.getTagName());
357         input.click();
358         assertEquals(URL_FIRST + getExpectedAlerts()[0], driver.getCurrentUrl());
359     }
360 
361     /**
362      * @throws Exception if an error occurs
363      */
364     @Test
365     public void clickBlankTargetHashOnly() throws Exception {
366         final String html = DOCTYPE_HTML
367                 + "<html>\n"
368                 + "<head><title>foo</title></head>\n"
369                 + "<body>\n"
370                 + "<a id='a' target='_blank' href='#'>Foo</a>\n"
371                 + "</body></html>\n";
372 
373         final WebDriver driver = loadPage2(html);
374         assertEquals(1, driver.getWindowHandles().size());
375 
376         final WebElement tester = driver.findElement(By.id("a"));
377         tester.click();
378 
379         Thread.sleep(100);
380         assertEquals(2, driver.getWindowHandles().size());
381     }
382 
383     /**
384      * @throws Exception if an error occurs
385      */
386     @Test
387     @Alerts({"My Link", "", "abcd"})
388     public void getText() throws Exception {
389         final String html = DOCTYPE_HTML
390             + "<html><head><script>\n"
391             + LOG_TITLE_FUNCTION
392             + "  function test() {\n"
393             + "    log(document.getElementById('myAnchor').text);\n"
394             + "    log(document.getElementById('myImgAnchor').text);\n"
395             + "    log(document.getElementById('myImgTxtAnchor').text);\n"
396             + "  }\n"
397             + "</script></head>\n"
398             + "<body onload=test()>\n"
399             + "  <a id='myAnchor'>My Link</a>\n"
400             + "  <a id='myImgAnchor'><img src='test.png' /></a>\n"
401             + "  <a id='myImgTxtAnchor'>ab<img src='test.png' />cd</a>\n"
402             + "</body></html>";
403         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
404 
405         loadPageVerifyTitle2(html);
406     }
407 
408     /**
409      * @throws Exception if an error occurs
410      */
411     @Test
412     @Alerts({"My Link 0", "Hello 0", " 1", "Hello 0", "a 2", "Hello 0"})
413     public void setText() throws Exception {
414         final String html = DOCTYPE_HTML
415             + "<html><head><script>\n"
416             + LOG_TITLE_FUNCTION
417             + "  function test() {\n"
418             + "    try {\n"
419             + "      var anchor = document.getElementById('myAnchor');\n"
420             + "      log(anchor.text + ' ' + anchor.children.length);\n"
421             + "      anchor.text = 'Hello';\n"
422             + "      log(anchor.text + ' ' + anchor.children.length);\n"
423 
424             + "      anchor = document.getElementById('myImgAnchor');\n"
425             + "      log(anchor.text + ' ' + anchor.children.length);\n"
426             + "      anchor.text = 'Hello';\n"
427             + "      log(anchor.text + ' ' + anchor.children.length);\n"
428 
429             + "      anchor = document.getElementById('myImgTxtAnchor');\n"
430             + "      log(anchor.text + ' ' + anchor.children.length);\n"
431             + "      anchor.text = 'Hello';\n"
432             + "      log(anchor.text + ' ' + anchor.children.length);\n"
433             + "    } catch(e) { log('exception' + e) }\n"
434             + "  }\n"
435             + "</script></head>\n"
436             + "<body onload=test()>\n"
437             + "  <a id='myAnchor'>My Link</a>\n"
438             + "  <a id='myImgAnchor'><img src='test.png' /></a>\n"
439             + "  <a id='myImgTxtAnchor'><img src='test.png' />a<img src='test.png' /></a>\n"
440             + "</body></html>";
441         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found", MimeType.TEXT_HTML);
442 
443         loadPageVerifyTitle2(html);
444     }
445 
446     /**
447      * Attributes aren't usually quoted in IE, but <tt>href</tt> attributes of anchor elements are.
448      * @throws Exception if the test fails
449      */
450     @Test
451     @Alerts("<a\\sid=\"a\"\\shref=\"#x\">foo</a>")
452     public void innerHtmlHrefQuotedEvenInIE() throws Exception {
453         final String html = DOCTYPE_HTML
454             + "<html>\n"
455             + "<head><script>\n"
456             + LOG_TITLE_FUNCTION_NORMALIZE
457             + "</script></head>\n"
458             + "<body onload='log(document.getElementById(\"d\").innerHTML)'>\n"
459             + "<div id='d'><a id='a' href='#x'>foo</a></div></body></html>";
460 
461         loadPageVerifyTitle2(html);
462     }
463 
464     /**
465      * @throws Exception if the test fails
466      */
467     @Test
468     public void click() throws Exception {
469         final String html = DOCTYPE_HTML
470             + "<html>\n"
471             + "<head><title>foo</title></head>\n"
472             + "<body>\n"
473             + "<a href='http://www.foo1.com' id='a1'>link to foo1</a>\n"
474             + "<a href='" + URL_SECOND + "' id='a2'>link to foo2</a>\n"
475             + "</body></html>";
476 
477         final String secondContent = DOCTYPE_HTML
478             + "<html><head><title>Second</title></head><body></body></html>";
479 
480         final MockWebConnection webConnection = getMockWebConnection();
481         webConnection.setDefaultResponse(secondContent);
482 
483         final WebDriver driver = loadPage2(html);
484         assertEquals(1, webConnection.getRequestCount());
485 
486         // Test that the correct value is being passed back up to the server
487         driver.findElement(By.id("a2")).click();
488 
489         assertEquals(URL_SECOND.toExternalForm(), driver.getCurrentUrl());
490         assertSame("method", HttpMethod.GET, webConnection.getLastMethod());
491         assertTrue(webConnection.getLastParameters().isEmpty());
492 
493         assertEquals(2, webConnection.getRequestCount());
494     }
495 
496     /**
497      * @throws Exception if the test fails
498      */
499     @Test
500     public void clickAnchorName() throws Exception {
501         final String html = DOCTYPE_HTML
502             + "<html>\n"
503             + "<head><title>foo</title></head>\n"
504             + "<body>\n"
505             + "  <a href='#clickedAnchor' id='a1'>link to foo1</a>\n"
506             + "</body></html>";
507 
508         final MockWebConnection webConnection = getMockWebConnection();
509         final WebDriver driver = loadPage2(html);
510 
511         assertEquals(1, webConnection.getRequestCount());
512 
513         driver.findElement(By.id("a1")).click();
514         assertEquals(1, webConnection.getRequestCount()); // no second server hit
515     }
516 
517     /**
518      * @throws Exception if the test fails
519      */
520     @Test
521     @Alerts({"", "#anchor", "#!bang"})
522     public void dontReloadHashBang() throws Exception {
523         final String html = DOCTYPE_HTML
524             + "<html>\n"
525             + "<head></head>\n"
526             + "<body>\n"
527             + "  <a href='" + URL_FIRST + "test' id='a1'>link1</a>\n"
528             + "  <a href='" + URL_FIRST + "test#anchor' id='a2'>link2</a>\n"
529             + "  <a href='" + URL_FIRST + "test#!bang' id='a3'>link3</a>\n"
530             + "  <script>\n"
531             + LOG_TITLE_FUNCTION
532             + "    log(document.getElementById('a1').hash);\n"
533             + "    log(document.getElementById('a2').hash);\n"
534             + "    log(document.getElementById('a3').hash);\n"
535             + "  </script>\n"
536             + "</body></html>";
537 
538         final MockWebConnection webConnection = getMockWebConnection();
539         webConnection.setDefaultResponse(html);
540 
541         final WebDriver driver = loadPageVerifyTitle2(html);
542 
543         assertEquals(1, webConnection.getRequestCount());
544 
545         driver.findElement(By.id("a1")).click();
546         assertEquals(2, webConnection.getRequestCount());
547         verifyTitle2(driver, getExpectedAlerts());
548 
549         driver.findElement(By.id("a2")).click();
550         assertEquals(2, webConnection.getRequestCount());
551 
552         driver.findElement(By.id("a3")).click();
553         assertEquals(2, webConnection.getRequestCount());
554     }
555 
556     /**
557      * Test case for issue #1492.
558      *
559      * @throws Exception if the test fails
560      */
561     @Test
562     @Alerts({"#!board/WebDev", "#!article/WebDev/35", "#!article/WebDev/35"})
563     public void dontReloadHashBang2() throws Exception {
564         final String html = DOCTYPE_HTML
565             + "<html>\n"
566             + "<head></head>\n"
567             + "<body>\n"
568             + "  <a href='" + URL_FIRST + "test/#!board/WebDev' id='a1'>link1</a>\n"
569             + "  <a href='" + URL_FIRST + "test/#!article/WebDev/35' id='a2'>link2</a>\n"
570             + "  <a href='" + URL_FIRST + "test#!article/WebDev/35' id='a3'>link2</a>\n"
571             + "  <script>\n"
572             + LOG_TITLE_FUNCTION
573             + "    log(document.getElementById('a1').hash);\n"
574             + "    log(document.getElementById('a2').hash);\n"
575             + "    log(document.getElementById('a3').hash);\n"
576             + "  </script>\n"
577             + "</body></html>";
578 
579         final MockWebConnection webConnection = getMockWebConnection();
580         webConnection.setDefaultResponse(html);
581 
582         final WebDriver driver = loadPageVerifyTitle2(html);
583 
584         assertEquals(1, webConnection.getRequestCount());
585 
586         driver.findElement(By.id("a1")).click();
587         assertEquals(2, webConnection.getRequestCount());
588         verifyTitle2(driver, getExpectedAlerts());
589 
590         driver.findElement(By.id("a2")).click();
591         assertEquals(2, webConnection.getRequestCount());
592 
593         driver.findElement(By.id("a3")).click();
594         assertEquals(3, webConnection.getRequestCount());
595         verifyTitle2(driver, getExpectedAlerts());
596     }
597 
598     /**
599      * FF behaves is different.
600      * @throws Exception if an error occurs
601      */
602     @Test
603     @Alerts({"click", "href", "click", "doubleClick", "href"})
604     @BuggyWebDriver(FF_ESR = {"click", "click", "doubleClick", "href", "href"})
605     @HtmlUnitNYI(CHROME = {"click", "href", "click", "href", "doubleClick"},
606             EDGE = {"click", "href", "click", "href", "doubleClick"},
607             FF = {"click", "href", "click", "href", "doubleClick"},
608             FF_ESR = {"click", "href", "click", "href", "doubleClick"})
609     public void doubleClick() throws Exception {
610         final String html = DOCTYPE_HTML
611               + "<html>\n"
612               + "<head>\n"
613               + "<script>\n"
614               + LOG_TEXTAREA_FUNCTION
615               + "</script>\n"
616               + "</head>\n"
617             + "<body>\n"
618             + "  <a id='myAnchor' "
619             +       "href=\"javascript:log('href');void(0);\" "
620             +       "onClick=\"log('click');\" "
621             +       "onDblClick=\"log('doubleClick');\">foo</a>\n"
622             + LOG_TEXTAREA
623             + "</body></html>";
624 
625         final WebDriver driver = loadPage2(html);
626 
627         final Actions action = new Actions(driver);
628         action.doubleClick(driver.findElement(By.id("myAnchor")));
629         action.perform();
630 
631         verifyTextArea2(driver, getExpectedAlerts());
632     }
633 
634     /**
635      * @throws Exception if the test fails
636      */
637     @Test
638     @Alerts({"§§URL§§bug.html?h%C3%B6=G%C3%BCnter", "h\u00F6", "G\u00FCnter"})
639     public void encoding() throws Exception {
640         final String href = "bug.html?" + URLEncoder.encode("h\u00F6", "UTF-8")
641                 + '=' + URLEncoder.encode("G\u00FCnter", "UTF-8");
642         final String html = DOCTYPE_HTML
643             + "<html>\n"
644             + "<head>\n"
645             + "  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>\n"
646             + "</head>\n"
647             + "<body>\n"
648             + "  <a href='" + href + "' id='myLink'>Click me</a>\n"
649             + "</body></html>";
650 
651         getMockWebConnection().setDefaultResponse(html, MimeType.TEXT_HTML, UTF_8);
652 
653         expandExpectedAlertsVariables(URL_FIRST);
654         final WebDriver driver = loadPage2(html, URL_FIRST);
655         driver.findElement(By.id("myLink")).click();
656 
657         assertEquals(getExpectedAlerts()[0], driver.getCurrentUrl());
658 
659         final List<NameValuePair> requestedParams =
660                 getMockWebConnection().getLastWebRequest().getRequestParameters();
661         assertEquals(1, requestedParams.size());
662         assertEquals(getExpectedAlerts()[1], requestedParams.get(0).getName());
663         assertEquals(getExpectedAlerts()[2], requestedParams.get(0).getValue());
664     }
665 
666     /**
667      * @throws Exception if the test fails
668      */
669     @Test
670     public void javascriptWithReturn() throws Exception {
671         final String html = DOCTYPE_HTML
672             + "<html><head><title>First</title></head><body>\n"
673             + "  <a id='myLink' href='javascript:return true'>hi</a>\n"
674             + "</body></html>";
675         final WebDriver webDriver = loadPage2(html);
676         webDriver.findElement(By.id("myLink")).click();
677     }
678 
679     /**
680      * @throws Exception if the test fails
681      */
682     @Test
683     public void javascriptWithReturnWhitespace() throws Exception {
684         final String html = DOCTYPE_HTML
685             + "<html><head><title>First</title></head><body>\n"
686             + "  <a id='myLink' href='javascript: return true'>hi</a>\n"
687             + "</body></html>";
688         final WebDriver webDriver = loadPage2(html);
689         webDriver.findElement(By.id("myLink")).click();
690     }
691 
692     /**
693      * @exception Exception If the test fails
694      */
695     @Test
696     @Alerts({"1", "First"})
697     public void shiftClick() throws Exception {
698         final String html = DOCTYPE_HTML
699             + "<html><head><title>First</title></head><body>\n"
700             + "<a href='" + URL_SECOND + "'>Click Me</a>\n"
701             + "</form></body></html>";
702 
703         getMockWebConnection().setResponse(URL_SECOND, "<head><title>Second</title>");
704         final WebDriver driver = loadPage2(html);
705 
706         final WebElement link = driver.findElement(By.linkText("Click Me"));
707 
708         final int windowsSize = driver.getWindowHandles().size();
709 
710         new Actions(driver)
711             .moveToElement(link)
712             .keyDown(Keys.SHIFT)
713             .click()
714             .keyUp(Keys.SHIFT)
715             .perform();
716 
717         Thread.sleep(100);
718         assertEquals("Should have opened a new window",
719                 windowsSize + Integer.parseInt(getExpectedAlerts()[0]), driver.getWindowHandles().size());
720         assertEquals("Should not have navigated away", getExpectedAlerts()[1], driver.getTitle());
721     }
722 
723     /**
724      * @exception Exception If the test fails
725      */
726     @Test
727     @Alerts({"1", "First"})
728     public void ctrlClick() throws Exception {
729         final String html = DOCTYPE_HTML
730             + "<html><head><title>First</title></head><body>\n"
731             + "<a href='" + URL_SECOND + "'>Click Me</a>\n"
732             + "</form></body></html>";
733 
734         getMockWebConnection().setResponse(URL_SECOND, "<head><title>Second</title>");
735         final WebDriver driver = loadPage2(html);
736 
737         final WebElement link = driver.findElement(By.linkText("Click Me"));
738 
739         final int windowsSize = driver.getWindowHandles().size();
740 
741         new Actions(driver)
742                 .moveToElement(link)
743                 .keyDown(Keys.CONTROL)
744                 .click()
745                 .keyUp(Keys.CONTROL)
746                 .perform();
747 
748         Thread.sleep(DEFAULT_WAIT_TIME.toMillis());
749         assertEquals("Should have opened a new window",
750                 windowsSize + Integer.parseInt(getExpectedAlerts()[0]), driver.getWindowHandles().size());
751         assertEquals("Should not have navigated away", getExpectedAlerts()[1], driver.getTitle());
752     }
753 
754     /**
755      * Tests the 'Referer' HTTP header.
756      * @throws Exception on test failure
757      */
758     @Test
759     @Alerts("§§URL§§index.html?test")
760     public void click_refererHeader() throws Exception {
761         final String firstContent = DOCTYPE_HTML
762             + "<html><head><title>Page A</title></head>\n"
763             + "<body><a href='" + URL_SECOND + "' id='link'>link</a></body>\n"
764             + "</html>";
765         final String secondContent = DOCTYPE_HTML
766             + "<html><head><title>Page B</title></head>\n"
767             + "<body></body>\n"
768             + "</html>";
769 
770         expandExpectedAlertsVariables(URL_FIRST);
771 
772         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
773 
774         getMockWebConnection().setResponse(indexUrl, firstContent);
775         getMockWebConnection().setResponse(URL_SECOND, secondContent);
776 
777         final WebDriver driver = loadPage2(firstContent, new URL(URL_FIRST.toString() + "index.html?test#ref"));
778         driver.findElement(By.id("link")).click();
779 
780         assertEquals(2, getMockWebConnection().getRequestCount());
781 
782         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
783         assertEquals(getExpectedAlerts()[0], lastAdditionalHeaders.get(HttpHeader.REFERER));
784     }
785 
786     /**
787      * Tests the 'Referer' HTTP header for rel='noreferrer'.
788      * @throws Exception on test failure
789      */
790     @Test
791     public void click_refererHeaderNoReferrer() throws Exception {
792         final String firstContent = DOCTYPE_HTML
793             + "<html><head><title>Page A</title></head>\n"
794             + "<body><a href='" + URL_SECOND + "' id='link' rel='noreferrer'>link</a></body>\n"
795             + "</html>";
796         final String secondContent = DOCTYPE_HTML
797             + "<html><head><title>Page B</title></head>\n"
798             + "<body></body>\n"
799             + "</html>";
800 
801         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
802 
803         getMockWebConnection().setResponse(indexUrl, firstContent);
804         getMockWebConnection().setResponse(URL_SECOND, secondContent);
805 
806         final WebDriver driver = loadPage2(firstContent, new URL(URL_FIRST.toString() + "index.html?test#ref"));
807         driver.findElement(By.id("link")).click();
808 
809         assertEquals(2, getMockWebConnection().getRequestCount());
810 
811         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
812         assertNull(lastAdditionalHeaders.get(HttpHeader.REFERER));
813     }
814 
815     /**
816      * Tests the 'Referer' HTTP header for rel='noreferrer'.
817      * @throws Exception on test failure
818      */
819     @Test
820     public void click_refererHeaderNoReferrerCaseSensitive() throws Exception {
821         final String firstContent = DOCTYPE_HTML
822             + "<html><head><title>Page A</title></head>\n"
823             + "<body><a href='" + URL_SECOND + "' id='link' rel='NoReferrer'>link</a></body>\n"
824             + "</html>";
825         final String secondContent = DOCTYPE_HTML
826             + "<html><head><title>Page B</title></head>\n"
827             + "<body></body>\n"
828             + "</html>";
829 
830         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
831 
832         getMockWebConnection().setResponse(indexUrl, firstContent);
833         getMockWebConnection().setResponse(URL_SECOND, secondContent);
834 
835         final WebDriver driver = loadPage2(firstContent, new URL(URL_FIRST.toString() + "index.html?test#ref"));
836         driver.findElement(By.id("link")).click();
837 
838         assertEquals(2, getMockWebConnection().getRequestCount());
839 
840         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
841         assertNull(lastAdditionalHeaders.get(HttpHeader.REFERER));
842     }
843 
844     /**
845      * @throws Exception if the test fails
846      */
847     @Test
848     @Alerts("§§URL§§index.html?test")
849     public void controlClick_refererHeader() throws Exception {
850         final String firstContent = DOCTYPE_HTML
851             + "<html><head><title>Page A</title></head>\n"
852             + "<body>\n"
853             + "  <a href='" + URL_SECOND + "' id='link'>link</a>\n"
854             + "</body>\n"
855             + "</html>";
856         final String secondContent = DOCTYPE_HTML
857             + "<html><head><title>Page B</title></head>\n"
858             + "<body></body>\n"
859             + "</html>";
860 
861         expandExpectedAlertsVariables(URL_FIRST);
862 
863         final URL indexUrl = new URL(URL_FIRST.toString() + "index.html");
864 
865         getMockWebConnection().setResponse(indexUrl, firstContent);
866         getMockWebConnection().setResponse(URL_SECOND, secondContent);
867 
868         final WebDriver driver = loadPage2(firstContent, new URL(URL_FIRST.toString() + "index.html?test#ref"));
869         new Actions(driver)
870                 .keyDown(Keys.CONTROL)
871                 .click(driver.findElement(By.id("link")))
872                 .keyUp(Keys.CONTROL)
873                 .build().perform();
874 
875         Thread.sleep(DEFAULT_WAIT_TIME.toMillis() / 10);
876 
877         assertEquals(2, getMockWebConnection().getRequestCount());
878 
879         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
880         assertEquals(getExpectedAlerts()[0], lastAdditionalHeaders.get(HttpHeader.REFERER));
881     }
882 
883 }