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