com.gargoylesoftware.htmlunit.javascript.host.Event2Test.java Source code

Java tutorial

Introduction

Here is the source code for com.gargoylesoftware.htmlunit.javascript.host.Event2Test.java

Source

/*
 * Copyright (c) 2002-2014 Gargoyle Software Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gargoylesoftware.htmlunit.javascript.host;

import static com.gargoylesoftware.htmlunit.BrowserRunner.Browser.CHROME;
import static com.gargoylesoftware.htmlunit.BrowserRunner.Browser.FF;
import static com.gargoylesoftware.htmlunit.BrowserRunner.Browser.IE11;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import com.gargoylesoftware.htmlunit.BrowserRunner;
import com.gargoylesoftware.htmlunit.BrowserRunner.Alerts;
import com.gargoylesoftware.htmlunit.BrowserRunner.BuggyWebDriver;
import com.gargoylesoftware.htmlunit.BrowserRunner.NotYetImplemented;
import com.gargoylesoftware.htmlunit.WebDriverTestCase;

/**
 * Tests that the events triggered in the right order.
 *
 * @version $Revision$
 * @author Ronald Brill
 * @author Frank Danek
 */
@RunWith(BrowserRunner.class)
public class Event2Test extends WebDriverTestCase {

    /**
     * Test event order for clicking on a select option.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "[object Event] change b:true c:false [select] [-]",
            "[object MouseEvent] click b:true c:true [clickMe] [1]" }, IE = {
                    "[object Event] change b:true c:false [select] [-]",
                    "[object MouseEvent] click b:true c:true [select] [1]" }, IE8 = {
                            "[object] change b:undefined c:undefined [select] [-]",
                            "[object] click b:undefined c:undefined [select] [-]" })
    @BuggyWebDriver({ CHROME, FF })
    // FFDriver wrongly generates a "[object MouseEvent] click b:true c:true [select] [1]" first that doesn't occur
    // manually
    // ChromeDriver wrongly generates a "[object MouseEvent] click b:true c:true [select] [1]" instead of "clickMe"
    @NotYetImplemented(IE11)
    // No idea why the IE11 fires a MouseEvent here instead of a PointerEvent
    public void optionClick() throws Exception {
        final String firstSnippet = "       <select name='select' id='select' size='2'\n";
        final String secondSnippet = ">\n" + "               <option id='o_id1' value='o_value1'>option1</option>\n"
                + "               <option id='clickMe' value='o_value2'>option2</option>\n"
                + "               <option id='o_id3' value='o_value3'>option3</option>\n" + "       </select>\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a select option.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "")
    @BuggyWebDriver(CHROME)
    // ChromeDriver does not generate a "[object MouseEvent] click b:true c:true [clickMe] [1]" but it occurs manually
    public void optionClick2() throws Exception {
        final String firstSnippet = "       <select name='select' id='select' size='2'>\n"
                + "               <option id='o_id1' value='o_value1'>option1</option>\n"
                + "               <option id='clickMe' value='o_value2'\n";
        final String secondSnippet = ">option2</option>\n"
                + "               <option id='o_id3' value='o_value3'>option3</option>\n" + "       </select>\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a radio button.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(CHROME = { "[object Event] change b:true c:false [radio] [-]",
            "[object MouseEvent] click b:true c:true [radio] [1]" }, FF = {
                    "[object MouseEvent] click b:true c:true [radio] [1]",
                    "[object Event] change b:true c:false [radio] [-]" }, IE = {
                            "[object Event] change b:true c:false [radio] [-]",
                            "[object PointerEvent] click b:true c:true [radio] [1]" }, IE8 = {
                                    "[object] click b:undefined c:undefined [radio] [-]" })
    public void radioClick() throws Exception {
        final String firstSnippet = "       <input type='radio' name='radio' id='clickMe' value='2'\n";
        final String secondSnippet = ">Radio\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a check box.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(CHROME = { "[object Event] change b:true c:false [checkbox] [-]",
            "[object MouseEvent] click b:true c:true [checkbox] [1]" }, FF = {
                    "[object MouseEvent] click b:true c:true [checkbox] [1]",
                    "[object Event] change b:true c:false [checkbox] [-]" }, IE = {
                            "[object Event] change b:true c:false [checkbox] [-]",
                            "[object PointerEvent] click b:true c:true [checkbox] [1]" }, IE8 = {
                                    "[object] click b:undefined c:undefined [checkbox] [-]" })
    public void checkboxClick() throws Exception {
        final String firstSnippet = "       <input type='checkbox' name='checkbox' id='clickMe' value='2'\n";
        final String secondSnippet = ">Checkbox\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a entry field.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "[object PointerEvent] click b:true c:true [clickMe] [1]", IE8 = "[object] click b:undefined c:undefined [clickMe] [-]")
    public void inputTextClick() throws Exception {
        final String firstSnippet = "       <input type='text' name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = ">\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a password field.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "[object PointerEvent] click b:true c:true [clickMe] [1]", IE8 = "[object] click b:undefined c:undefined [clickMe] [-]")
    public void inputPasswordClick() throws Exception {
        final String firstSnippet = "       <input type='password' name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = ">\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a text area.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "[object PointerEvent] click b:true c:true [clickMe] [1]", IE8 = "[object] click b:undefined c:undefined [clickMe] [-]")
    public void textareaClick() throws Exception {
        final String firstSnippet = "       <textarea name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = "></textarea>\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a submit button.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts()
    public void submitClick() throws Exception {
        final String firstSnippet = "       <input type='submit' name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = ">\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a reset button.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "[object PointerEvent] click b:true c:true [clickMe] [1]", IE8 = "[object] click b:undefined c:undefined [clickMe] [-]")
    public void resetClick() throws Exception {
        final String firstSnippet = "       <input type='reset' name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = ">\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on a reset button.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "[object PointerEvent] click b:true c:true [clickMe] [1]", IE8 = "[object] click b:undefined c:undefined [clickMe] [-]")
    public void buttonClick() throws Exception {
        final String firstSnippet = "       <input type='button' name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = ">\n";

        testEvents(firstSnippet, secondSnippet);
    }

    /**
     * Test event order for clicking on an anchor.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = "[object MouseEvent] click b:true c:true [clickMe] [1]", IE = "[object PointerEvent] click b:true c:true [clickMe] [1]", IE8 = "[object] click b:undefined c:undefined [clickMe] [-]")
    public void anchorClick() throws Exception {
        final String firstSnippet = "       <a href='#' name='clickMe' id='clickMe' size='2'\n";
        final String secondSnippet = ">anchor</a>\n";

        testEvents(firstSnippet, secondSnippet);
    }

    private void testEvents(final String firstSnippet, final String secondSnippet) throws Exception {
        final String html = "<html>\n" + "<head>\n" + "  <script type='text/javascript'>\n" + "  <!--\n"
                + "    function dumpEvent(event) {\n" + "      var msg = event;\n"
                + "      msg = msg + ' ' + event.type;\n" + "      msg = msg + ' b:' + event.bubbles;\n"
                + "      msg = msg + ' c:' + event.cancelable;\n" + "\n" + "      // target\n"
                + "      var eTarget;\n" + "      if (event.target) {\n" + "        eTarget = event.target;\n"
                + "      } else if (event.srcElement) {\n" + "        eTarget = event.srcElement;\n" + "      }\n"
                + "      // defeat Safari bug\n" + "      if (eTarget.nodeType == 3) {\n"
                + "        eTarget = eTarget.parentNode;\n" + "      }\n" + "\n" + "      if (eTarget.name) {\n"
                + "        msg = msg + ' [' + eTarget.name + ']';\n" + "      } else {\n"
                + "        msg = msg + ' [' + eTarget.id + ']';\n" + "      }\n" + "\n" + "      // key code\n"
                + "      var eCode;\n" + "      if (event.keyCode) {\n" + "        eCode = event.keyCode;\n"
                + "      } else if (event.which) {\n" + "        eCode = event.which;\n"
                + "      } else if (event.button) {\n" + "        eCode = event.button;\n" + "      }\n"
                + "      if (eCode) {\n" + "        var char = String.fromCharCode(eCode);\n"
                + "        msg = msg + ' [' + eCode + ']';\n" + "      } else {\n" + "        msg = msg + ' [-]';\n"
                + "      }\n" + "\n" + "      alert(msg);\n" + "    }\n" + "  //-->\n" + "  </script>\n"
                + "</head>\n" + "    <form id='form' name='form' action='#'>\n"
                + "        <input type='text' id='start' name='startText'/>\n" + "\n" + firstSnippet
                + "           onclick='dumpEvent(event);'\n"
                //                + "           ondblclick='dumpEvent(event);'\n"
                //                + "           oncontextmenu='dumpEvent(event);'\n"
                //                + "           onfocus='dumpEvent(event);'\n"
                //                + "           onblur='dumpEvent(event);'\n"
                //                + "           onmousedown = 'dumpEvent(event);'\n"
                //                + "           onmouseup = 'dumpEvent(event);'\n"
                //                + "           onkeydown = 'dumpEvent(event);'\n"
                //                + "           onkeyup = 'dumpEvent(event);'\n"
                //                + "           onkeypress = 'dumpEvent(event);'\n"
                //                + "           onselect = 'dumpEvent(event);'\n"
                + "           onchange = 'dumpEvent(event);'" + secondSnippet + "   </form>\n" + "</body>\n"
                + "</html>\n";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("clickMe")).click();
        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * Tests that event fires on key press.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "pass", "fail:66", "fail:undefined" }, CHROME = { "pass", "fail:66", "fail:0" })
    public void testEventOnKeyDown() throws Exception {
        final String html = "<html><head></head>\n" + "<body>\n"
                + "  <button type='button' id='clickId'>Click Me</button>\n" + "  <script>\n"
                + "    function handler(_e) {\n" + "      var e = _e ? _e : window.event;\n"
                + "      if (e.keyCode == 65)\n" + "        alert('pass');\n" + "      else\n"
                + "        alert('fail:' + e.keyCode);\n" + "    }\n"
                + "    document.getElementById('clickId').onkeydown = handler;\n"
                + "    document.getElementById('clickId').onclick = handler;\n" + "  </script>\n"
                + "</body></html>";

        final WebDriver driver = loadPage2(html);
        final WebElement element = driver.findElement(By.id("clickId"));
        element.sendKeys("a");
        element.sendKeys("b");
        element.click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * Verifies that in IE, the <tt>shiftKey</tt>, <tt>ctrlKey</tt> and <tt>altKey</tt>
     * event attributes are defined for all events, but <tt>metaKey</tt> is not defined
     * for any events.<br/>
     * Verifies that in FF, the <tt>shiftKey</tt>, <tt>ctrlKey</tt>, <tt>altKey</tt> and
     * <tt>metaKey</tt> attributes are defined for mouse events only.
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts(DEFAULT = { "object", "undefined", "undefined", "undefined", "undefined", "object", "false", "false",
            "false", "false" }, IE8 = { "object", "false", "false", "false", "undefined", "object", "false",
                    "false", "false", "undefined" })
    public void testKeys() throws Exception {
        final String html = "<html><body onload='test(event)'><script>\n" + "    function test(e) {\n"
                + "        alert(typeof e);\n" + "        alert(e.shiftKey);\n" + "        alert(e.ctrlKey);\n"
                + "        alert(e.altKey);\n" + "        alert(e.metaKey);\n" + "    }\n" + "</script>\n"
                + "<div id='div' onclick='test(event)'>abc</div>\n" + "</body></html>";

        final WebDriver driver = loadPage2(html);
        final WebElement element = driver.findElement(By.id("div"));
        element.click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * @throws Exception if an error occurs
     */
    @Test
    public void preventDefault() throws Exception {
        final String html = "<html><head><title>First</title>\n" + "<script>\n" + "function block(e) {\n"
                + "  if (e && e.preventDefault)\n" + "    e.preventDefault();\n" + "  else\n"
                + "    return false;\n" + "}\n" + "\n" + "function test() {\n"
                + "  document.getElementById('myForm').onsubmit = block;\n" + "}\n" + "</script>\n"
                + "</head><body onload='test()'>\n" + "<form id='myForm' action='doesnt_exist.html'>\n"
                + "  <input type='submit' id='mySubmit' value='Continue'></p>\n" + "</form>" + "</body></html>";

        final WebDriver driver = loadPageWithAlerts2(html);
        driver.findElement(By.id("mySubmit"));
        assertEquals(getDefaultUrl().toExternalForm(), driver.getCurrentUrl());
    }

    /**
     * Test Mozilla DOMContentLoaded event.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "DOMContentLoaded type=DOMContentLoaded", "onLoad" }, IE8 = "onLoad")
    public void testDOMContentLoaded() throws Exception {
        final String html = "<html>\n" + "<head>\n" + "<title>DOMContentLoaded</title>\n" + "<script>\n"
                + "  if (document.addEventListener) {\n"
                + "    document.addEventListener('DOMContentLoaded', onDCL, false);\n" + "  }\n"
                + "  function onDCL(e) {\n" + "    alert('DOMContentLoaded type=' + e.type);\n" + "  }\n"
                + "</script>\n" + "</head>\n" + "<body onload='alert(\"onLoad\")'>\n" + "</body></html>";

        loadPageWithAlerts2(html);
    }

    /**
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "false", "not canceled", "true", "canceled", "true" }, IE8 = {})
    public void testPreventDefault() throws Exception {
        final String html = "<html>\n" + "<head>\n" + "<title>preventDefault - copied from mozilla.org</title>\n"
                + "<script>\n" + "  function preventDef(event) {\n" + "    event.preventDefault();\n" + "  }\n"

                + "  function addHandler() {\n"
                + "    document.getElementById('checkbox').addEventListener('click', preventDef, false);\n"
                + "  }\n"

                + "  function simulateClick() {\n" + "    var evt = document.createEvent('MouseEvents');\n"
                + "    evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0,"
                + " false, false, false, false, 0, null);\n" + "    var cb = document.getElementById('checkbox');\n"
                + "    var canceled = !cb.dispatchEvent(evt);\n" + "    if(canceled) {\n"
                + "      // A handler called preventDefault\n" + "      alert('canceled');\n" + "    } else {\n"
                + "      // None of the handlers called preventDefault\n" + "      alert('not canceled');\n"
                + "    }\n" + "  }\n"

                + "  function test() {\n" + "    if (document.createEvent) {\n"
                + "      alert(document.getElementById('checkbox').checked);\n" + "      simulateClick();\n"
                + "      alert(document.getElementById('checkbox').checked);\n" + "      addHandler();\n"
                + "      simulateClick();\n" + "      alert(document.getElementById('checkbox').checked);\n"
                + "    }\n" + "  }\n" + "</script>\n" + "</head>\n" + "<body onload='test()'>\n"
                + "  <input type='checkbox' id='checkbox'/><label for='checkbox'>Checkbox</label>"
                + "</body></html>";

        loadPageWithAlerts2(html);
    }

    /**
     * Test event transmission to event handler.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "false", "false", "SPAN" }, FF = { "false", "true", "SPAN" }, IE8 = { "true", "false",
            "SPAN" })
    public void testEventTransmission() throws Exception {
        final String html = "<html>\n" + "<body>\n" + "  <span id='clickMe'>foo</span>\n" + "  <script>\n"
                + "    function handler(e) {\n" + "      alert(e == null);\n"
                + "      alert(window.event == null);\n" + "      var theEvent = (e != null) ? e : window.event;\n"
                + "      var target = theEvent.target ? theEvent.target : theEvent.srcElement;\n"
                + "      alert(target.tagName);\n" + "    }\n"
                + "    document.getElementById('clickMe').onclick = handler;\n" + "</script>\n" + "</body></html>";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("clickMe")).click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts(DEFAULT = { "capturing", "at target", "bubbling" }, IE8 = "unknown")
    public void testEventPhase() throws Exception {
        final String html = "<html>\n" + "<head><script>\n" + "  function init() {\n"
                + "    var form = document.forms[0];\n" + "    if (form.addEventListener) {\n"
                + "      form.addEventListener('click', alertPhase, true);\n"
                + "      form.addEventListener('click', alertPhase, false);\n" + "    }\n" + "  }\n"

                + "  function alertPhase(e) {\n" + "    switch (e.eventPhase) {\n"
                + "      case 1: alert('capturing'); break;\n" + "      case 2: alert('at target'); break;\n"
                + "      case 3: alert('bubbling'); break;\n" + "      default: alert('unknown');\n" + "    }\n"
                + "  }\n" + "</script></head>\n" + "<body onload='init()'>\n" + "  <form>\n"
                + "    <input type='button' onclick='alertPhase(event)' id='b'>\n" + "  </form>\n"
                + "</body></html>";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("b")).click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * Test for event capturing and bubbling in FF.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "window capturing", "div capturing", "span capturing", "span bubbling", "div",
            "div bubbling", "window bubbling" }, IE8 = "div")
    public void eventCapturingAndBubbling() throws Exception {
        final String html = "<html>\n" + "<head><title>foo</title>\n" + "<script>\n" + "  function t(_s) {\n"
                + "    return function() { alert(_s) };\n" + "  }\n"

                + "  function init() {\n" + "    if (window.addEventListener) {\n"
                + "      window.addEventListener('click', t('window capturing'), true);\n"
                + "      window.addEventListener('click', t('window bubbling'), false);\n" + "    }\n"
                + "    var oDiv = document.getElementById('theDiv');\n" + "    if (oDiv.addEventListener) {\n"
                + "      oDiv.addEventListener('click', t('div capturing'), true);\n"
                + "      oDiv.addEventListener('click', t('div bubbling'), false);\n" + "    }\n"
                + "    var oSpan = document.getElementById('theSpan');\n" + "    if (oSpan.addEventListener) {\n"
                + "      oSpan.addEventListener('click', t('span capturing'), true);\n"
                + "      oSpan.addEventListener('click', t('span bubbling'), false);\n" + "    }\n" + "  }\n"
                + "</script>\n" + "</head>\n" + "<body onload='init()'>\n"
                + "  <div onclick=\"alert('div')\" id='theDiv'>\n" + "    <span id='theSpan'>blabla</span>\n"
                + "  </div>\n" + "</body></html>";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("theSpan")).click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * Test for event capturing and bubbling.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "window capturing", "div capturing", "span capturing", "div",
            "window capturing, false, true" }, CHROME = { "window capturing", "div capturing", "span capturing",
                    "div", "window capturing, false, false" }, IE8 = { "div", "div" })
    public void stopPropagation() throws Exception {
        stopPropagation("stopPropagation()");
    }

    /**
     * Test for event capturing and bubbling in FF.
     * @throws Exception if the test fails
     */
    @Test
    @Alerts(DEFAULT = { "window capturing", "div capturing", "span capturing", "div",
            "window capturing, false, true" }, CHROME = { "window capturing", "div capturing", "span capturing",
                    "div", "window capturing, false, true", "div capturing, true, true",
                    "span capturing, true, true" }, IE11 = { "window capturing", "div capturing", "span capturing",
                            "div", "window capturing, false, false", "div capturing, false, false",
                            "span capturing, false, true" }, IE8 = { "div", "div" })
    public void stopPropagationCancelBubble() throws Exception {
        stopPropagation("cancelBubble=true");
    }

    private void stopPropagation(final String cancelMethod) throws Exception {
        final String html = "<html>\n" + "<head><title>foo</title>\n" + "<script>\n" + "  var counter = 0;\n"
                + "  function t(_s) {\n" + "    return function(e) {\n" + "      alert(_s); counter++;\n"
                + "      if (counter >= 4) {\n" + "        alert(e.cancelBubble);\n" + "        e." + cancelMethod
                + ";\n" + "        alert(e.cancelBubble);\n" + "      };\n" + "    };\n" + "  }\n"
                + "  function init() {\n" + "    if (window.addEventListener) {\n"
                + "      window.addEventListener('click', t('window capturing'), true);\n" + "    }\n"
                + "    var oDiv = document.getElementById('theDiv');\n" + "    if (oDiv.addEventListener) {\n"
                + "      oDiv.addEventListener('click', t('div capturing'), true);\n" + "    }\n"
                + "    var oSpan = document.getElementById('theSpan');\n" + "    if (oSpan.addEventListener) {\n"
                + "      oSpan.addEventListener('click', t('span capturing'), true);\n" + "    }\n" + "  }\n"
                + "</script>\n" + "</head>\n" + "<body onload='init()'>\n"
                + "  <div onclick=\"alert('div')\" id='theDiv'>\n" + "    <span id='theSpan'>blabla</span>\n"
                + "  </div>\n" + "</body></html>";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("theSpan")).click();
        driver.findElement(By.id("theSpan")).click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }

    /**
     * @throws Exception if an error occurs
     */
    @Test
    @Alerts(DEFAULT = { "w", "w 2", "d", "d 2", "s", "s 2", "w", "w 2" }, IE8 = {})
    public void stopPropagation_WithMultipleEventHandlers() throws Exception {
        final String html = "<html>\n" + "<head><title>foo</title>\n" + "<script>\n" + "  var counter = 0;\n"
                + "  function t(_s) {\n"
                + "    return function(e) { alert(_s); counter++; if (counter >= 5) e.stopPropagation(); };\n"
                + "  }\n" + "  function init() {\n" + "    if (window.addEventListener) {\n"
                + "      window.addEventListener('click', t('w'), true);\n"
                + "      window.addEventListener('click', t('w 2'), true);\n" + "    }\n"
                + "    var oDiv = document.getElementById('theDiv');\n" + "    if (oDiv.addEventListener) {\n"
                + "      oDiv.addEventListener('click', t('d'), true);\n"
                + "      oDiv.addEventListener('click', t('d 2'), true);\n" + "    }\n"
                + "    var oSpan = document.getElementById('theSpan');\n" + "    if (oSpan.addEventListener) {\n"
                + "      oSpan.addEventListener('click', t('s'), true);\n"
                + "      oSpan.addEventListener('click', t('s 2'), true);\n" + "    }\n" + "  }\n" + "</script>\n"
                + "</head><body onload='init()'>\n" + "<div id='theDiv'>\n" + "<span id='theSpan'>blabla</span>\n"
                + "</div>\n" + "</body></html>";

        final WebDriver driver = loadPage2(html);
        driver.findElement(By.id("theSpan")).click();
        driver.findElement(By.id("theSpan")).click();

        assertEquals(getExpectedAlerts(), getCollectedAlerts(driver));
    }
}