diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/html/webappapis/scripting/events | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/webappapis/scripting/events')
49 files changed, 2200 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/body-onload.html b/testing/web-platform/tests/html/webappapis/scripting/events/body-onload.html new file mode 100644 index 0000000000..1e43d1ccd4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/body-onload.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>HTMLBodyElement.onload</title> +<link rel="author" title="Boris Zbarsky" href="mailto:bzbarsky@mit.edu"> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#handler-window-onload"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test("body.onload should set the window.onload handler") +window.onload = t.step_func(function() { + assert_unreached("This handler should be overwritten.") +}) +var b = document.createElement("body") +b.onload = t.step_func(function(e) { + assert_equals(e.currentTarget, window, + "The event should be fired at the window.") + t.done() +}) +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes-form-owner.html b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes-form-owner.html new file mode 100644 index 0000000000..e31bd2496a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes-form-owner.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Form's lexical scope is established only for form-associated elements</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/forms.html#form-associated-element"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<form id="form"> + <input onclick="window.inputOnClickElements = elements;"> + <img onclick="window.imgOnClickElements = elements;" alt="img"> + <div onclick="window.divOnClickElements = elements;">div</div> + <x-foo onclick="window.xFooOnClickElements = elements;">x-foo</x-foo> +</form> + +<script> +"use strict"; + +window.elements = "global_elements"; + +test(() => { + const input = form.querySelector("input"); + input.click(); + assert_equals(window.inputOnClickElements, form.elements); +}, "<input> has a form owner"); + +test(() => { + const img = form.querySelector("img"); + img.click(); + assert_equals(window.imgOnClickElements, form.elements); +}, "<img> has a form owner"); + +test(() => { + const div = form.querySelector("div"); + div.click(); + assert_equals(window.divOnClickElements, window.elements); +}, "<div> doesn't have a form owner"); + +test(() => { + customElements.define("x-foo", class extends HTMLElement { + static formAssociated = true; + }); + + const xFoo = form.querySelector("x-foo"); + xFoo.click(); + assert_equals(window.xFooOnClickElements, form.elements); +}, "form-associated <x-foo> has a form owner"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes.html b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes.html new file mode 100644 index 0000000000..ed6c006651 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes.html @@ -0,0 +1,167 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Lexical scopes when compiling an inline event handler</title> +<link rel="help" href="https://html.spec.whatwg.org/C/#getting-the-current-value-of-the-event-handler"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +setup({allow_uncaught_exception: true}); +</script> + +<!-- test case 1: element, document, and window --> + +<table> + <tr id="test1_outer"> + <td id="test1_target" onclick=" +window.testResults.complete = typeof(complete); +window.testResults.cellIndex = typeof(cellIndex); +window.testResults.cells = typeof(cells); +window.testResults.domain = typeof(domain); +window.testResults.print = typeof(print); +window.testResults.testResults = typeof(testResults); +window.testResults.target_own_property = typeof(target_own_property); +window.testResults.inner_own_property = typeof(inner_own_property); +window.testResults.outer_own_property = typeof(outer_own_property); +window.testResults.event = typeof(event); +"> + <img id="test1_inner"> + </td> + </tr> +</table> + +<script> +"use strict"; + +test(() => { + const target_element = document.getElementById("test1_target"); + const inner_element = document.getElementById("test1_inner"); + const outer_element = document.getElementById("test1_outer"); + + target_element.target_own_property = {}; + inner_element.inner_own_property = {}; + outer_element.outer_own_property = {}; + + const results = window.testResults = {}; + // Clicking an inner element makes the event target where the event handler is + // registered doesn't match the event target that the event is fired. From a + // point of view |target_element|, event.target != event.currentTarget. + inner_element.click(); + // Expected scopes are: |target_element|, document, and window. + assert_equals(results.complete, "undefined", "HTMLImageElement.prototype.complete"); + assert_equals(results.cellIndex, "number", "HTMLTableCellElement.prototype.cellIndex"); + assert_equals(results.cells, "undefined", "HTMLTableRowElement.prototype.cellIndex"); + assert_equals(results.domain, "string", "Document.prototype.domain"); + assert_equals(results.print, "function", "window.print"); + assert_equals(results.testResults, "object"); + assert_equals(results.target_own_property, "object"); + assert_equals(results.inner_own_property, "undefined"); + assert_equals(results.outer_own_property, "undefined"); + assert_equals(results.event, "object", "The argument of event handler"); +}, "The EventHandler is an element's event handler and has no form owner."); +</script> + + +<!-- test case 2: element, form owner, document, and window --> + +<form id="test2_form_owner" onsubmit="return false;"> + <!-- 'button' is a form-associated element and has a form owner. + https://html.spec.whatwg.org/C/#form-associated-element + --> + <button id="test2_target" onclick=" +window.testResults.cite = typeof(cite); +window.testResults.autofocus = typeof(autofocus); +window.testResults.form = typeof(form); +window.testResults.encoding = typeof(encoding); +window.testResults.domain = typeof(domain); +window.testResults.print = typeof(print); +window.testResults.testResults = typeof(testResults); +window.testResults.target_own_property = typeof(target_own_property); +window.testResults.inner_own_property = typeof(inner_own_property); +window.testResults.form_owner_own_property = typeof(form_owner_own_property); +window.testResults.event = typeof(event); +"> + <q id="test2_inner"></q> + </button> +</form> + +<script> +"use strict"; + +test(() => { + const target_element = document.getElementById("test2_target"); + const inner_element = document.getElementById("test2_inner"); + const form_owner_element = document.getElementById("test2_form_owner"); + + target_element.target_own_property = {}; + inner_element.inner_own_property = {}; + form_owner_element.form_owner_own_property = {}; + + const results = window.testResults = {}; + // Clicking an inner element makes the event target where the event handler is + // registered doesn't match the event target that the event is fired. From a + // point of view |target_element|, event.target != event.currentTarget. + inner_element.click(); + // Expected scopes are: |target_element|, form owner, document, and window. + assert_equals(results.cite, "undefined", "HTMLQuoteElement.prototype.cite"); + assert_equals(results.autofocus, "boolean", "HTMLButtonElement.prototype.autofocus"); + assert_equals(results.form, "object", "HTMLButtonElement.prototype.form"); + assert_equals(results.encoding, "string", "HTMLFormElement.prototype.encoding"); + assert_equals(results.domain, "string", "Document.prototype.domain"); + assert_equals(results.print, "function", "window.print"); + assert_equals(results.testResults, "object"); + assert_equals(results.target_own_property, "object"); + assert_equals(results.inner_own_property, "undefined"); + assert_equals(results.form_owner_own_property, "object"); + assert_equals(results.event, "object", "The argument of event handler"); +}, "The EventHandler is an element's event handler and has a form owner."); +</script> + + +<!-- test case 3: element and window --> + +<a id="test3_inner"></a> + +<script> +"use strict"; + +// This test is placed at last so that it can safely use a global variable +// without conflicting other tests. Only this test is asynchronous. +async_test(t => { + const target_element = window; + const inner_element = document.getElementById("test3_inner"); + + target_element.target_own_property = {}; + inner_element.inner_own_property = {}; + document.body.body_own_property = {}; + + // "onerror" is one of the Window-reflecting body element event handler set. + // https://html.spec.whatwg.org/C/#window-reflecting-body-element-event-handler-set + // So, the EventHandler is treated as a Window's event handler. + document.body.setAttribute("onerror", "\ +window.testResults.ping = typeof(ping); \ +window.testResults.domain = typeof(domain); \ +window.testResults.print = typeof(print); \ +window.testResults.testResults = typeof(testResults); \ +window.testResults.target_own_property = typeof(target_own_property); \ +window.testResults.inner_own_property = typeof(inner_own_property); \ +window.testResults.body_own_property = typeof(body_own_property); \ +window.testResults.event = typeof(event); \ +"); + + const results = window.testResults = {}; + window.addEventListener("error", t.step_func_done(() => { + // Expected scopes are: |target_element| and window only. + assert_equals(results.domain, "undefined", "Document.prototype.domain"); + assert_equals(results.print, "function", "window.print"); + assert_equals(results.testResults, "object"); + assert_equals(results.target_own_property, "object"); + assert_equals(results.inner_own_property, "undefined"); + assert_in_array(results.event, ["object", "string"], "The first argument of onerror event handler"); + })); + + // Make a compilation error happen in order to invoke onerror event handler. + inner_element.setAttribute("onclick", "cause a compilation error"); + inner_element.click(); +}, "The EventHandler is not an element's event handler (i.e. Window's event handler) and has no form owner."); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-settings-objects.html b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-settings-objects.html new file mode 100644 index 0000000000..29ac9b8ced --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-settings-objects.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Entry and incumbent settings objects when compiling an inline event handler</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="log"></div> + +<script> +"use strict"; +window.name = "parent frame"; + +async_test(t => { + const iframe = document.createElement("iframe"); + iframe.src = "resources/compiled-event-handler-settings-objects-support.html"; + iframe.onload = t.step_func(() => { + const button = iframe.contentDocument.querySelector("button"); + const compiled = button.onclick; + + assert_equals(compiled.constructor, iframe.contentWindow.Function, "The constructor must be from the iframe"); + assert_not_equals(compiled.constructor, Function, "The constructor must not be from this page"); + + t.done(); + }); + + document.body.appendChild(iframe); + +}, "The Function instance must be created in the Realm of the node document"); + +async_test(t => { + const iframe = document.createElement("iframe"); + iframe.src = "resources/compiled-event-handler-settings-objects-support.html"; + iframe.onload = t.step_func(() => { + const button = iframe.contentDocument.querySelector("button"); + + window.onWindowLoaded = t.step_func_done(url => { + const pathname = new URL(url).pathname; + assert_equals(pathname, + "/html/webappapis/scripting/events/resources/open-window.html"); + // This tests that the entry settings object used to resolve URLs in that window.open() was the same as that + // of the node document (i.e. the iframe document), not e.g. this window. + }); + + button.click(); + }); + + document.body.appendChild(iframe); + +}, "The entry settings object while executing the compiled callback via Web IDL's invoke must be that " + + "of the node document"); + +async_test(t => { + const iframe = document.createElement("iframe"); + iframe.src = "resources/compiled-event-handler-settings-objects-support.html"; + iframe.onload = t.step_func(() => { + window.onmessage = t.step_func_done(event => { + assert_equals(event.data, "PASS"); + assert_equals(event.source.name, "iframe"); + assert_equals(event.source, iframe.contentWindow, "The source must be the iframe"); + }); + + iframe.src = "about:blank"; + }); + + document.body.appendChild(iframe); + +}, "The incumbent settings object while executing the compiled callback via Web IDL's invoke must be that " + + "of the node document"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-symbol-unscopables.html b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-symbol-unscopables.html new file mode 100644 index 0000000000..c840059e68 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-symbol-unscopables.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<meta charset="UTF-8" /> +<title>Inline event handler scopes exclude unscopable properties</title> +<link rel="author" title="ExE Boss" href="https://ExE-Boss.tech" /> +<link rel="help" href="https://html.spec.whatwg.org/multipage/webappapis.html#getting-the-current-value-of-the-event-handler" /> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + "use strict"; + window.testVariable = {}; +</script> + +<!-- test case 1: element, document, and window --> +<div id="test1_target" onclick=' + "use strict"; + + window.testResults.testVariable = testVariable; +'></div> + +<script> + "use strict"; + + test(() => { + const results = window.testResults = {}; + + document[Symbol.unscopables].testVariable = true; + document.testVariable = "FAIL (document)"; + + document.getElementById("test1_target").click(); + assert_equals(results.testVariable, window.testVariable); + }, "unscopable `document.testVariable` doesn't shadow `window.testVariable`"); + + test(() => { + const results = window.testResults = {}; + const element = document.getElementById("test1_target"); + + element[Symbol.unscopables].testVariable = true; + element.testVariable = "FAIL (element)"; + + element.click(); + assert_equals(results.testVariable, window.testVariable); + }, "unscopable `element.testVariable` doesn't shadow `window.testVariable`"); +</script> + +<!-- test case 2: element, form owner, document, and window --> +<form id="test2_form_owner" onsubmit="return false;"> + <!-- <button> is a form-associated element and has a form owner. + https://html.spec.whatwg.org/C/#form-associated-element --> + <button id="test2_target" onclick=' + "use strict"; + + window.testResults.testVariable = testVariable; + '></button> +</form> + +<script> + "use strict"; + + test(() => { + const results = window.testResults = {}; + const element = document.getElementById("test2_target"); + const formOwner = document.getElementById("test2_form_owner"); + + formOwner[Symbol.unscopables].testVariable = true; + formOwner.testVariable = "FAIL (formOwner)"; + + element.click(); + assert_equals(results.testVariable, window.testVariable); + }, "unscopable `formOwner.testVariable` doesn't shadow `window.testVariable`") +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/contextmenu-event-manual.htm b/testing/web-platform/tests/html/webappapis/scripting/events/contextmenu-event-manual.htm new file mode 100644 index 0000000000..2331fa17ee --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/contextmenu-event-manual.htm @@ -0,0 +1,21 @@ +<!doctype html> +<html> + <head> + <title>HTML contextmenu event is a MouseEvent</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <style>#contextmenutarget { width: 100px; height: 100px; background-color: red; }</style> + </head> + <body> + <div id='contextmenutarget'>Trigger context menu in this box.</div> + <div id="log"></div> + <script type="text/javascript"> +var t = async_test('contextmenu event generated from user action is MouseEvent'); +document.querySelector("#contextmenutarget").addEventListener('contextmenu', t.step_func(function (e) { + assert_equals(e.constructor, window.MouseEvent); + document.querySelector("#contextmenutarget").style.backgroundColor = "green"; + t.done(); +})); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-all-global-events.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-all-global-events.html new file mode 100644 index 0000000000..ee8c34ced3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-all-global-events.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<title>GlobalEventHandlers</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#globaleventhandlers"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-idl-attributes"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-content-attributes"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> + +<script> +"use strict"; + +// The prefixed animation events are special; their event types are +// camel-case. +const prefixedAnimationAttributeToEventType = new Map([ + ["webkitanimationend", "webkitAnimationEnd"], + ["webkitanimationiteration", "webkitAnimationIteration"], + ["webkitanimationstart", "webkitAnimationStart"], + ["webkittransitionend", "webkitTransitionEnd"], +]); + +setup({ explicit_done: true }); + +fetch("/interfaces/html.idl").then(res => res.text()).then(htmlIDL => { + const parsedHTMLIDL = WebIDL2.parse(htmlIDL); + const globalEventHandlers = parsedHTMLIDL.find(idl => idl.name === "GlobalEventHandlers"); + + // onerror is too special + const names = globalEventHandlers.members.map(member => member.name).filter(name => name !== "onerror"); + + for (const name of names) { + const withoutOn = name.substring(2); + + test(() => { + for (const location of [window, HTMLElement.prototype, SVGElement.prototype, Document.prototype]) { + assert_true(location.hasOwnProperty(name), + `${location.constructor.name} has an own property named "${name}"`); + } + assert_false(name in Element.prototype, `Element.prototype must not contain a "${name}" property`); + }, `${name}: must be on the appropriate locations for GlobalEventHandlers`); + + test(() => { + const htmlElement = document.createElement("span"); + const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "g"); + + for (var location of [window, htmlElement, svgElement, document]) { + assert_equals(location[name], null, + `The default value of the property is null for a ${location.constructor.name} instance`); + } + }, `${name}: the default value must be null`); + + test(() => { + const el = document.createElement("div"); + el.setAttribute(name, `window.${name}Happened = true;`); + const compiledHandler = el[name]; + + assert_equals(typeof compiledHandler, "function", `The ${name} property must be a function`); + compiledHandler(); + assert_true(window[name + "Happened"], "Calling the handler must run the code"); + }, `${name}: the content attribute must be compiled into a function as the corresponding property`); + + test(() => { + const el = document.createElement("div"); + el.setAttribute(name, `window.${name}Happened2 = true;`); + + let eventType = withoutOn; + if (prefixedAnimationAttributeToEventType.has(eventType)) { + eventType = prefixedAnimationAttributeToEventType.get(eventType); + } + el.dispatchEvent(new Event(eventType)); + + assert_true(window[name + "Happened2"], "Dispatching an event must run the code"); + }, `${name}: the content attribute must execute when an event is dispatched`); + + test(() => { + const element = document.createElement("meta"); + element[name] = e => { + assert_equals(e.currentTarget, element, "The event must be fired at the <meta> element"); + }; + + element.dispatchEvent(new Event(withoutOn)); + }, `${name}: dispatching an Event at a <meta> element must trigger element.${name}`); + } + + done(); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-body-window.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-body-window.html new file mode 100644 index 0000000000..e8055d99f3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-body-window.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>HTMLBodyElement event handlers</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="resources/event-handler-body.js"></script> +<div id="log"></div> +<body> +<script> +setup({ explicit_done: true }); + +handlersListPromise.then(({ shadowedHandlers, notShadowedHandlers }) => { + eventHandlerTest(shadowedHandlers, notShadowedHandlers, "body"); + + done(); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html new file mode 100644 index 0000000000..b583eca52d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>event handlers</title> +<link rel="author" title="Intel" href="http://www.intel.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="resources/event-handler-body.js"></script> +<script> +setup({ explicit_done: true }); + +handlersListPromise.then(({ shadowedHandlers, notShadowedHandlers }) => { + eventHandlerTest(shadowedHandlers, notShadowedHandlers, "frameset"); + + // The testharness framework appends test results to document.body, + // show test results in frame after test done. + add_completion_callback(() => { + const log_elem = document.getElementById("log"); + const frame_elem = document.querySelector("frame"); + if (log_elem) { + frame_elem.contentDocument.body.innerHTML = log_elem.innerHTML; + } + }); + + done(); +}); +</script> +<frameset> + <frame src="/common/blank.html" /> +</frameset> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html new file mode 100644 index 0000000000..9b81d42ff7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html @@ -0,0 +1,71 @@ +<!doctype html> +<meta charset="utf-8"> +<title></title> +<body></body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="resources/event-handler-body.js"></script> +<script> +setup({ explicit_done: true }); +const elements = ['body', 'frameset']; +handlersListPromise.then(({ shadowedHandlers, notShadowedHandlers }) => { + elements.forEach(function (elementName) { + shadowedHandlers.forEach(function (eventName) { + var handlerName = "on" + eventName; + + test(function() { + var windowHandler = function () { return "Handler attached to the window"; }; + window[handlerName] = windowHandler; + + var d = (new DOMParser).parseFromString('', 'text/html'); + var b = d.createElement(elementName); + + assert_equals(b[handlerName], null); + + window[handlerName] = null; + }, "Return null when getting the " + eventName + " event handler of a windowless " + elementName); + + test(function() { + var windowHandler = function () { return "Handler attached to the window"; }; + window[handlerName] = windowHandler; + + var d = (new DOMParser).parseFromString('', 'text/html'); + var b = d.createElement(elementName); + b[handlerName] = function() { return "Handler attached to windowless element"; }; + + assert_equals(window[handlerName], windowHandler); + assert_equals(b[handlerName], null); + + // Clean up window event handler + window[handlerName] = null; + }, "Ignore setting of " + eventName + " window event handlers on windowless " + elementName); + }); + + notShadowedHandlers.forEach(function (eventName) { + var handlerName = "on" + eventName; + + test(function() { + var windowHandler = function () { return "Handler attached to the window"; }; + window[handlerName] = windowHandler; + + var d = (new DOMParser).parseFromString('', 'text/html'); + var b = d.createElement(elementName); + + assert_equals(b[handlerName], null); + + var elementHandler = function () { return "Handler attached to the element"; }; + b[handlerName] = elementHandler; + + assert_equals(window[handlerName], windowHandler); + assert_equals(b[handlerName], elementHandler); + + // Clean up window event handler + window[handlerName] = null; + }, eventName + " is unaffected on a windowless " + elementName); + }); + }); + + done(); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-handleEvent-ignored.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-handleEvent-ignored.html new file mode 100644 index 0000000000..8039bac7ad --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-handleEvent-ignored.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>"handleEvent" property of EventHandler should be ignored</title> +<link rel="help" href="https://html.spec.whatwg.org/#eventhandler"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +"use strict"; + +test(t => { + const handler = Object.create(null, { + handleEvent: { + get: t.unreached_func('"handleEvent" property should not be looked up'), + }, + }); + + const el = document.createElement("div"); + el.onmouseenter = handler; + el.dispatchEvent(new MouseEvent("mouseenter")); +}, 'plain object "mouseenter" handler'); + +async_test(t => { + const handler = Object.create(Function.prototype, { + handleEvent: { + get: t.unreached_func('"handleEvent" property should not be looked up'), + }, + }); + assert_true(handler instanceof Function); + + window.onmessage = handler; + window.postMessage({}, "*"); + + step_timeout(() => { + t.done(); + }, 50); +}, 'non-callable "message" handler that is instance of Function'); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-javascript.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-javascript.html new file mode 100644 index 0000000000..657a37839d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-javascript.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Event handler with labels</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body onload="javascript: + for (var i = 0; i < 2; ++i) { + for (var j = 0; j < 2; ++j) { + t.step(function() { + assert_equals(i, 0); + assert_equals(j, 0); + }); + break javascript; + } + } + t.done(); +"> +<div id="log"></div> +<script> +var t = async_test("Event handlers starting with 'javascript:' should treat that as a label."); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-onresize.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-onresize.html new file mode 100644 index 0000000000..0e44e7272f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-onresize.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<title>HTMLBodyElement.onresize</title> +<link rel="author" title="His-Name-Is-Joof" href="mailto:jeffrharrison@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#handler-window-onresize"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test("body.onresize should set the window.onresize handler") +window.onresize = t.step_func(function() { + assert_unreached("This handler should be overwritten.") +}) + +var body = document.createElement("body") +body.onresize = t.step_func(function(e) { + assert_equals(e.currentTarget, window, + "The event should be fired at the window.") + t.done() +}) +window.dispatchEvent(new Event('resize')); + +t = async_test("document.onresize should set the document.onresize handler"); +document.onresize = t.step_func(function(e) { + assert_equals(e.currentTarget, document, + "The event should be fired at the document") + t.done() +}) +document.dispatchEvent(new Event('resize')); + +t = async_test("meta.onresize should set the meta.onresize handler"); +var meta = document.createElement("meta") +meta.onresize = t.step_func(function(e) { + assert_equals(e.currentTarget, meta, + "The event should be fired at the <meta> object") + t.done() +}) +meta.dispatchEvent(new Event('resize')); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-errorevent.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-errorevent.html new file mode 100644 index 0000000000..9ab0020ec3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-errorevent.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + document.body.onerror = t.step_func((...args) => { + assert_greater_than(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, true); + }); + + document.body.dispatchEvent(new ErrorEvent("error", { bubbles: true, cancelable: true })); + + return promise; +}, "error event is weird (return true cancels; many args) on Window, with a synthetic ErrorEvent"); + +promise_test(t => { + const theError = { the: "error object" }; + + document.body.onerror = t.step_func(function (message, filename, lineno, colno, error) { + assert_equals(arguments.length, 5, "There must be exactly 5 arguments"); + assert_equals(message, "message"); + assert_equals(filename, "filename"); + assert_equals(lineno, 1); + assert_equals(colno, 2); + assert_equals(error, theError); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error"); + + document.body.dispatchEvent(new ErrorEvent("error", { + bubbles: true, + message: "message", + filename: "filename", + lineno: 1, + colno: 2, + error: theError + })); + + return promise; +}, "error event has the right 5 args on Window, with a synthetic ErrorEvent"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-event.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-event.html new file mode 100644 index 0000000000..9ed2638416 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-event.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + document.body.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + document.body.dispatchEvent(new Event("error", { bubbles: true, cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Window, with a synthetic Event"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-errorevent.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-errorevent.html new file mode 100644 index 0000000000..4165beaf63 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-errorevent.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + document.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, document, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + assert_equals(e.message, ""); + assert_equals(e.filename, ""); + assert_equals(e.lineno, 0); + assert_equals(e.colno, 0); + assert_equals(e.error, undefined); + }); + + document.dispatchEvent(new ErrorEvent("error", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Document, with a synthetic ErrorEvent"); + +test(() => { + const e = new ErrorEvent("error"); + assert_equals(e.message, ""); + assert_equals(e.filename, ""); + assert_equals(e.lineno, 0); + assert_equals(e.colno, 0); + assert_equals(e.error, undefined); +}, "Initial values of ErrorEvent members") + +test(() => { + const e = new ErrorEvent("error", {error : null}); + assert_equals(e.error, null); +}, "error member can be set to null") + +test(() => { + const e = new ErrorEvent("error", {error : undefined}); + assert_equals(e.error, undefined); +}, "error member can be set to undefined") + +test(() => { + const e = new ErrorEvent("error", {error : "foo"}); + assert_equals(e.error, "foo"); +}, "error member can be set to arbitrary") + +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-event.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-event.html new file mode 100644 index 0000000000..6cf44e9d35 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-event.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + document.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, document, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + document.dispatchEvent(new Event("error", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Document, with a synthetic Event"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-errorevent.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-errorevent.html new file mode 100644 index 0000000000..20d87dbacf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-errorevent.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> + +<iframe name="framesetWindow" src="resources/frameset-frame.html"></iframe> +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +window.onload = () => { + +const frameset = framesetWindow.document.querySelector("frameset"); + +promise_test(t => { + frameset.onerror = t.step_func((...args) => { + assert_greater_than(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, framesetWindow, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, true); + }); + + frameset.dispatchEvent(new ErrorEvent("error", { bubbles: true, cancelable: true })); + + return promise; +}, "error event is weird (return true cancels; many args) on Window, with a synthetic ErrorEvent"); + +promise_test(t => { + const theError = { the: "error object" }; + + frameset.onerror = t.step_func(function (message, filename, lineno, colno, error) { + assert_equals(arguments.length, 5, "There must be exactly 5 arguments"); + assert_equals(message, "message"); + assert_equals(filename, "filename"); + assert_equals(lineno, 1); + assert_equals(colno, 2); + assert_equals(error, theError); + return true; + }); + + const eventWatcher = new EventWatcher(t, framesetWindow, "error"); + const promise = eventWatcher.wait_for("error"); + + frameset.dispatchEvent(new ErrorEvent("error", { + bubbles: true, + message: "message", + filename: "filename", + lineno: 1, + colno: 2, + error: theError + })); + + return promise; +}, "error event has the right 5 args on Window, with a synthetic ErrorEvent"); + +}; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-event.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-event.html new file mode 100644 index 0000000000..2fdca3ad86 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-event.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> + +<iframe name="framesetWindow" src="resources/frameset-frame.html"></iframe> +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +window.onload = () => { + +const frameset = framesetWindow.document.querySelector("frameset"); + +promise_test(t => { + frameset.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, framesetWindow, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + frameset.dispatchEvent(new Event("error", { bubbles: true, cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Window, with a synthetic Event"); + +}; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/frameset-frame.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/frameset-frame.html new file mode 100644 index 0000000000..028be4919e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/frameset-frame.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> + +<frameset></frameset> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/no-op-worker.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/no-op-worker.js new file mode 100644 index 0000000000..3918c74e44 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/no-op-worker.js @@ -0,0 +1 @@ +"use strict"; diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/worker-with-syntax-error.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/worker-with-syntax-error.js new file mode 100644 index 0000000000..dc9a0dbf4a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/worker-with-syntax-error.js @@ -0,0 +1 @@ +< 3; diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/script-element.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/script-element.html new file mode 100644 index 0000000000..f3ef1165e0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/script-element.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; + +promise_test(t => { + const script = document.createElement("script"); + script.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, script, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.constructor, Event); // not ErrorEvent + assert_equals(e.defaultPrevented, false); + }); + + script.src = "404.js"; + document.body.appendChild(script); + + return promise; +}, "error event behaves normally (return true does not cancel; one arg) on a script element, with a 404 error"); + +promise_test(t => { + const script = document.createElement("script"); + script.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, script, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + script.dispatchEvent(new Event("error", { cancelable: true })); + + return promise; +}, "error event behaves normally (return true does not cancel; one arg) on a script element, with a synthetic Event"); + +promise_test(t => { + const script = document.createElement("script"); + script.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, script, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + script.dispatchEvent(new ErrorEvent("error", { cancelable: true })); + + return promise; +}, "error event behaves normally (return true does not cancel; one arg) on a script element, with a synthetic ErrorEvent"); + +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html new file mode 100644 index 0000000000..75a1772485 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: click events using ErrorEvent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +promise_test(t => { + document.onclick = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, document, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + document.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on Document, with a synthetic ErrorEvent"); + +promise_test(t => { + window.onclick = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + window.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on Window, with a synthetic ErrorEvent"); + +promise_test(t => { + const el = document.createElement("script"); + el.onclick = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, el, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + el.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on a script element, with a synthetic ErrorEvent"); + +promise_test(t => { + const worker = new Worker("resources/no-op-worker.js"); + worker.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, worker, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + worker.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "click event is normal (return true does not cancel; one arg) on Worker, with a synthetic ErrorEvent"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js new file mode 100644 index 0000000000..177a99e2ce --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js @@ -0,0 +1,22 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + self.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, self, "click"); + const promise = eventWatcher.wait_for("click").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + self.dispatchEvent(new ErrorEvent("click", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on WorkerGlobalScope, with a synthetic ErrorEvent"); + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html new file mode 100644 index 0000000000..1b387ca81c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + window.onerror = t.step_func((...args) => { + assert_greater_than(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, true); + }); + + setTimeout(() => thisFunctionDoesNotExist(), 0); + + return promise; +}, "error event is weird (return true cancels; many args) on Window, with a runtime error"); + +promise_test(t => { + window.onerror = t.step_func(function (message, filename, lineno, colno, error) { + assert_equals(arguments.length, 5, "There must be exactly 5 arguments"); + assert_equals(typeof message, "string", "message argument must be a string"); + assert_equals(typeof filename, "string", "filename argument must be a string"); + assert_equals(typeof lineno, "number", "lineno argument must be a number"); + assert_equals(typeof colno, "number", "colno argument must be a number"); + assert_equals(typeof error, "object", "error argument must be an object"); + assert_equals(error.constructor, ReferenceError, "error argument must be a ReferenceError"); + return true; + }); + + setTimeout(() => thisFunctionDoesNotExist(), 0); + + const eventWatcher = new EventWatcher(t, window, "error"); + return eventWatcher.wait_for("error"); +}, "error event has the right 5 args on Window, with a runtime error"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-errorevent.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-errorevent.html new file mode 100644 index 0000000000..2d62d8a204 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-errorevent.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + window.onerror = t.step_func((...args) => { + assert_greater_than(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, true); + }); + + window.dispatchEvent(new ErrorEvent("error", { cancelable: true })); + + return promise; +}, "error event is weird (return true cancels; many args) on Window, with a synthetic ErrorEvent"); + +promise_test(t => { + const theError = { the: "error object" }; + + window.onerror = t.step_func(function (message, filename, lineno, colno, error) { + assert_equals(arguments.length, 5, "There must be exactly 5 arguments"); + assert_equals(message, "message"); + assert_equals(filename, "filename"); + assert_equals(lineno, 1); + assert_equals(colno, 2); + assert_equals(error, theError); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error"); + + window.dispatchEvent(new ErrorEvent("error", { + message: "message", + filename: "filename", + lineno: 1, + colno: 2, + error: theError + })); + + return promise; +}, "error event has the right 5 args on Window, with a synthetic ErrorEvent"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event.html new file mode 100644 index 0000000000..0bcc7defb7 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + window.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, window, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + window.dispatchEvent(new Event("error", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Window, with a synthetic Event"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/worker.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/worker.html new file mode 100644 index 0000000000..a8c0d97ce2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/worker.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: error events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<div id="log"></div> + +<script> +"use strict"; +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + const worker = new Worker("resources/worker-with-syntax-error.js"); + worker.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, worker, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Worker, with a syntax error in the worker code"); + +promise_test(t => { + const worker = new Worker("resources/no-op-worker.js"); + worker.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, worker, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + worker.dispatchEvent(new Event("error", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Worker, with a synthetic Event"); + +promise_test(t => { + const worker = new Worker("resources/no-op-worker.js"); + worker.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, worker, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + worker.dispatchEvent(new ErrorEvent("error", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on Worker, with a synthetic ErrorEvent"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-runtime-error.worker.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-runtime-error.worker.js new file mode 100644 index 0000000000..264fef810d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-runtime-error.worker.js @@ -0,0 +1,40 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + self.onerror = t.step_func((...args) => { + assert_greater_than(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, self, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, true); + }); + + setTimeout(() => thisFunctionDoesNotExist(), 0); + + return promise; +}, "error event is weird (return true cancels; many args) on WorkerGlobalScope, with a runtime error"); + +promise_test(t => { + self.onerror = t.step_func(function (message, filename, lineno, colno, error) { + assert_equals(arguments.length, 5, "There must be exactly 5 arguments"); + assert_equals(typeof message, "string", "message argument must be a string"); + assert_equals(typeof filename, "string", "filename argument must be a string"); + assert_equals(typeof lineno, "number", "lineno argument must be a number"); + assert_equals(typeof colno, "number", "colno argument must be a number"); + assert_equals(typeof error, "object", "error argument must be an object"); + assert_equals(error.constructor, ReferenceError, "error argument must be a ReferenceError"); + return true; + }); + + setTimeout(() => thisFunctionDoesNotExist(), 0); + + const eventWatcher = new EventWatcher(t, self, "error"); + return eventWatcher.wait_for("error"); +}, "error event has the right 5 args on WorkerGlobalScope, with a runtime error"); + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-errorevent.worker.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-errorevent.worker.js new file mode 100644 index 0000000000..a14f6e01a9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-errorevent.worker.js @@ -0,0 +1,49 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + self.onerror = t.step_func((...args) => { + assert_greater_than(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, self, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, true); + }); + + self.dispatchEvent(new ErrorEvent("error", { cancelable: true })); + + return promise; +}, "error event is weird (return true cancels; many args) on WorkerGlobalScope, with a synthetic ErrorEvent"); + +promise_test(t => { + const theError = { the: "error object" }; + + self.onerror = t.step_func(function (message, filename, lineno, colno, error) { + assert_equals(arguments.length, 5, "There must be exactly 5 arguments"); + assert_equals(message, "message"); + assert_equals(filename, "filename"); + assert_equals(lineno, 1); + assert_equals(colno, 2); + assert_equals(error, theError); + return true; + }); + + const eventWatcher = new EventWatcher(t, self, "error"); + const promise = eventWatcher.wait_for("error"); + + self.dispatchEvent(new ErrorEvent("error", { + message: "message", + filename: "filename", + lineno: 1, + colno: 2, + error: theError + })); + + return promise; +}, "error event has the right 5 args on WorkerGlobalScope, with a synthetic ErrorEvent"); + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-event.worker.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-event.worker.js new file mode 100644 index 0000000000..a3e16ded88 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-event.worker.js @@ -0,0 +1,22 @@ +"use strict"; +importScripts("/resources/testharness.js"); + +setup({ allow_uncaught_exception: true }); + +promise_test(t => { + self.onerror = t.step_func((...args) => { + assert_equals(args.length, 1); + return true; + }); + + const eventWatcher = new EventWatcher(t, self, "error"); + const promise = eventWatcher.wait_for("error").then(e => { + assert_equals(e.defaultPrevented, false); + }); + + self.dispatchEvent(new Event("error", { cancelable: true })); + + return promise; +}, "error event is normal (return true does not cancel; one arg) on WorkerGlobalScope, with a synthetic Event"); + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html new file mode 100644 index 0000000000..205e876c1d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event handlers processing algorithm: manual tests</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-event-handler-processing-algorithm"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<style> + div[id^="d"] { + width: 100px; + height: 100px; + background-color: blue; + } +</style> + +<div id="log"></div> + +<p>Mouseover these four divs</p> + +<div id="d1"></div> +<div id="d2"></div> + +<div id="d3" onmouseover="return false"></div> +<div id="d4" onmouseover="return true"></div> + +<script> +"use strict"; +async_test(t => { + const div = document.querySelector("#d1"); + + div.onmouseover = t.step_func(() => false); + div.addEventListener("mouseover", t.step_func_done(e => { + assert_equals(e.defaultPrevented, true); + })); +}, "Listener added via JavaScript, returns false: cancels the event"); + +async_test(t => { + const div = document.querySelector("#d2"); + + div.onmouseover = t.step_func(() => true); + div.addEventListener("mouseover", t.step_func_done(e => { + assert_equals(e.defaultPrevented, false); + })); +}, "Listener added via JavaScript, returns true: does not cancel the event"); + +async_test(t => { + const div = document.querySelector("#d3"); + + div.addEventListener("mouseover", t.step_func_done(e => { + assert_equals(e.defaultPrevented, true); + })); +}, "Listener added via markup, returns false: cancels the event"); + +async_test(t => { + const div = document.querySelector("#d4"); + + div.addEventListener("mouseover", t.step_func_done(e => { + assert_equals(e.defaultPrevented, false); + })); +}, "Listener added via markup, returns true: does not cancel the event"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm.html new file mode 100644 index 0000000000..f5423d7ed4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<title>Event handlers processing algorithm</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + <body> + <div id="foo" style="width: 100px; height: 100px; background-color: black"></div> + <script> + + // Historically mouseover was special in the spec, but now it is not. See https://github.com/whatwg/html/pull/2398. + test(function(t) { + var ev = new Event('mouseover', {cancelable: true}); + document.getElementById("foo").onmouseover = t.step_func(function() { return false }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, true) + }, "mouseover listener returning false cancels event (using Event)"); + + test(function(t) { + var ev = new MouseEvent('mouseover', {cancelable: true}); + document.getElementById("foo").onmouseover = t.step_func(function() { return false }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, true) + }, "mouseover listener returning false cancels event (using MouseEvent)"); + + test(function(t) { + var ev = new Event('mouseover', {cancelable: true}); + document.getElementById("foo").onmouseover = t.step_func(function() { return true }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, false) + }, "mouseover listener returning true doesn't cancel event (using Event)"); + + test(function(t) { + var ev = new MouseEvent('mouseover', {cancelable: true}); + document.getElementById("foo").onmouseover = t.step_func(function() { return true }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, false) + }, "mouseover listener returning true doesn't cancel event (using MouseEvent)"); + + // beforeunload is tested in html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html + + test(function(t) { + var ev = new Event("click", {cancelable: true}); + document.getElementById("foo").onclick = t.step_func(function() { return false; }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, true); + }, "click listener returning false cancels event"); + + test(function(t) { + var ev = new Event("blur", {cancelable: true}); + document.getElementById("foo").onblur = t.step_func(function() { return false; }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, true); + }, "blur listener returning false cancels event"); + + test(function(t) { + var ev = new Event("dblclick", {cancelable: true}); + document.getElementById("foo").ondblclick = t.step_func(function() { return false; }); + document.getElementById("foo").dispatchEvent(ev); + assert_equals(ev.defaultPrevented, true); + }, "dblclick listener returning false cancels event"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-removal.window.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-removal.window.js new file mode 100644 index 0000000000..a20e2ec1d2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-removal.window.js @@ -0,0 +1,76 @@ +let firstEventHandler; + +test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 1) }), false); + button.setAttribute('onclick', uncalled); // event handler is activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 2) }), false); + button.onclick = null; // but de-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 4); }); // and re-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 5) }), false); + button.click() + assert_equals(button.getAttribute("onclick"), uncalled) + assert_equals(i, 5); +}, "Event handler set through content attribute should be removed when they are set to null."); + +let happened = 0; +test(() => { + var script = "happened++;"; + var button = document.createElement('button'); + button.setAttribute('onclick', script); // event handler is activated here + button.onclick = null; // but de-activated here + assert_equals(button.getAttribute("onclick"), script) + button.setAttribute('onclick', script); // and re-activated here + button.click() + assert_equals(happened, 1); +}, "Event handler set through content attribute should be re-activated even if content is the same."); + +test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 1) }), false); + button.setAttribute('onclick', uncalled); // event handler is activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 2) }), false); + button.removeAttribute('onclick'); // but de-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 4); }); // and re-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 5) }), false); + button.click() + assert_equals(i, 5); +}, "Event handler set through content attribute should be deactivated when the content attribute is removed."); +test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 1) }), false); + button.onclick = t.unreached_func('First event handler.'); // event handler is activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 2) }), false); + button.onclick = null; // but de-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 4); }); // and re-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 5) }), false); + button.click() + assert_equals(i, 5); +}, "Event handler set through IDL should be deactivated when the IDL attribute is set to null."); +test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 1) }), false); + button.onclick = t.unreached_func('First event handler.'); // event handler is activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.removeAttribute('onclick'); // and NOT de-activated here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 4) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 2); }); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 5) }), false); + button.click() + assert_equals(i, 5); +}, "Event handler set through IDL should NOT be deactivated when the content attribute is removed."); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-sourcetext.html b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-sourcetext.html new file mode 100644 index 0000000000..57555faa7b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-sourcetext.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Test the sourceText of event handlers</title> +<link rel="help" href="https://github.com/whatwg/html/issues/5500"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +test(() => { + const el = document.createElement("div"); + el.setAttribute("onclick", "foo"); + assert_equals(el.onclick.toString(), "function onclick(event) {\nfoo\n}"); +}, "non-error event handler"); + +test(() => { + const el = document.createElement("div"); + el.setAttribute("onerror", "foo"); + assert_equals(el.onerror.toString(), "function onerror(event) {\nfoo\n}"); +}, "error event handler not on body"); + +test(() => { + const el = document.createElement("body"); + el.setAttribute("onerror", "foo"); + assert_equals(el.onerror.toString(), "function onerror(event, source, lineno, colno, error) {\nfoo\n}"); +}, "error event handler on disconnected body"); + +test(() => { + const el = document.createElement("frameset"); + el.setAttribute("onerror", "foo"); + assert_equals(el.onerror.toString(), "function onerror(event, source, lineno, colno, error) {\nfoo\n}"); +}, "error event handler on disconnected frameset"); + +test(() => { + document.body.setAttribute("onerror", "foo"); + assert_equals(window.onerror.toString(), "function onerror(event, source, lineno, colno, error) {\nfoo\n}"); +}, "error event handler on connected body, reflected to Window"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-spec-example.window.js b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-spec-example.window.js new file mode 100644 index 0000000000..abf46882aa --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/event-handler-spec-example.window.js @@ -0,0 +1,55 @@ +var objects = [{}, function() {}, new Number(42), new String()]; +var primitives = [42, null, undefined, ""]; +var firstEventHandler; +objects.forEach(function(object) { + test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.onclick = object; // event handler listener is registered here + assert_equals(button.onclick, object); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 2) }), false); + button.setAttribute('onclick', uncalled); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 1); }); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 4) }), false); + button.click() + assert_equals(button.getAttribute("onclick"), uncalled) + assert_equals(i, 4); + }, "Event handler listeners should be registered when they are first set to an object value " + + "(" + format_value(object) + ")."); +}); +primitives.forEach(function(primitive) { + test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.onclick = primitive; + assert_equals(button.onclick, null); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 1) }), false); + button.setAttribute('onclick', uncalled); // event handler listener is registered here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 2); }); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 4) }), false); + button.click() + assert_equals(button.getAttribute("onclick"), uncalled) + assert_equals(i, 4); + }, "Event handler listeners should be registered when they are first set to an object value " + + "(" + format_value(primitive) + ")."); +}); +test(t => { + var i = 0; + firstEventHandler = t.unreached_func('First event handler.'); + var uncalled = "firstEventHandler();"; + var button = document.createElement('button'); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 1) }), false); + button.setAttribute('onclick', uncalled); // event handler listener is registered here + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 3) }), false); + button.onclick = t.step_func(() => { assert_equals(++i, 2); }); + button.addEventListener('click', t.step_func(() => { assert_equals(++i, 4) }), false); + button.click() + assert_equals(button.getAttribute("onclick"), uncalled) + assert_equals(i, 4); +}, "Event handler listeners should be registered when they are first set to an object value."); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/eventhandler-cancellation.html b/testing/web-platform/tests/html/webappapis/scripting/events/eventhandler-cancellation.html new file mode 100644 index 0000000000..6be581fa24 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/eventhandler-cancellation.html @@ -0,0 +1,76 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<!-- A window to work with that won't trigger the harness exception detection + when we fire "error" events at it --> +<iframe style="display: none"></iframe> +<script> + test(function() { + var blob = new Blob([""]); + // Most targets disabled for now until + // https://github.com/whatwg/html/issues/2296 is sorted out. + var targets = [ frames[0] /*, document, document.documentElement, + new Worker(URL.createObjectURL(blob) */ ]; + // Event constructors also mostly disabled until + // https://github.com/whatwg/html/issues/2296 is sorted out. + var eventCtors = [ /* Event, */ ErrorEvent /*, MouseEvent */ ]; + var values = [true, false, "", "abc", {}, 0, 1, -1, null, undefined, + 2.5, NaN, Infinity, Symbol.toStringTag ]; + // Event types also mostly disabled pending + // https://github.com/whatwg/html/issues/2296 + var eventTypes = [ "error"/*, "click", "load"*/ ]; + + // Variables that keep track of which subtest we're running. + var curTarget; + var curValue; + var curCtor; + var curType; + + function defaultPreventedTester(event) { + var expectedValue; + if (curTarget === frames[0] && + curCtor === ErrorEvent && + curValue === true && + curType == "error") { + expectedValue = true; + } else { + // This will need adjusting once we allow more targets and event + // constructors above! + expectedValue = false; + } + var valueRepr; + if (typeof curValue == "string") { + valueRepr = '"' + curValue + '"'; + } else { + valueRepr = String(curValue); + } + test(function() { + assert_equals(event.defaultPrevented, expectedValue); + }, "Returning " + valueRepr + + " from " + String(curTarget) + "'s on" + curType + + " event handler while " + curCtor.name + + " is firing should" + + (expectedValue ? "" : " not") + + " cancel the event"); + } + + for (curCtor of eventCtors) { + for (curTarget of targets) { + for (curType of eventTypes) { + for (curValue of values) { + // We have to make sure that defaultPreventedTester is added after + // our event handler. + curTarget["on" + curType] = function() { return curValue; } + curTarget.addEventListener(curType, defaultPreventedTester); + var e = new curCtor(curType, { cancelable: true }); + curTarget.dispatchEvent(e); + curTarget["on" + curType] = null; + curTarget.removeEventListener(curType, defaultPreventedTester); + } + } + } + } + }, "event handler cancellation behavior"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/inline-event-handler-ordering.html b/testing/web-platform/tests/html/webappapis/scripting/events/inline-event-handler-ordering.html new file mode 100644 index 0000000000..aae0f1abf8 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/inline-event-handler-ordering.html @@ -0,0 +1,53 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Inline event handlers retain their ordering even when invalid</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +setup({ allow_uncaught_exception: true }); +var events = []; + +test(function() { + events = []; + var e = document.createElement("div"); + document.body.appendChild(e); + e.addEventListener("click", function() { events.push("ONE") }); + e.setAttribute("onclick", "window.open("); + e.addEventListener("click", function() { events.push("THREE") }); + // Try to compile the event handler. + e.onclick; + e.setAttribute("onclick", "events.push('TWO')"); + e.dispatchEvent(new Event("click")); + var expected_events = ["ONE", "TWO", "THREE"]; + assert_array_equals(events, expected_events); +}, "Inline event handlers retain their ordering when invalid and force-compiled"); + +test(function() { + events = []; + var e = document.createElement("div"); + document.body.appendChild(e); + e.addEventListener("click", function() { events.push("ONE") }); + e.setAttribute("onclick", "window.open("); + e.addEventListener("click", function() { events.push("THREE") }); + e.dispatchEvent(new Event("click")); + e.setAttribute("onclick", "events.push('TWO')"); + e.dispatchEvent(new Event("click")); + var expected_events = ["ONE", "THREE", "ONE", "TWO", "THREE"]; + assert_array_equals(events, expected_events); +}, "Inline event handlers retain their ordering when invalid and force-compiled via dispatch"); + +test(function() { + events = []; + var e = document.createElement("div"); + document.body.appendChild(e); + e.addEventListener("click", function() { events.push("ONE") }); + e.setAttribute("onclick", "window.open("); + e.addEventListener("click", function() { events.push("THREE") }); + e.setAttribute("onclick", "events.push('TWO')"); + e.dispatchEvent(new Event("click")); + var expected_events = ["ONE", "TWO", "THREE"]; + assert_array_equals(events, expected_events); +}, "Inline event handlers retain their ordering when invalid and lazy-compiled"); +</script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late.window.js b/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late.window.js new file mode 100644 index 0000000000..2892a4c3ab --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late.window.js @@ -0,0 +1,16 @@ +setup({ allow_uncaught_exception: true }); + +test(function() { + var events = []; + window.onerror = function() { + events.push("error"); + }; + + var div = document.createElement("div"); + div.addEventListener("click", function (e) { events.push("click 1") }); + div.setAttribute("onclick", "}"); + div.addEventListener("click", function (e) { events.push("click 2") }); + div.dispatchEvent(new Event("click")); + assert_equals(div.onclick, null); + assert_array_equals(events, ["click 1", "error", "click 2"]); +}, "Invalid uncompiled raw handlers should only be compiled when about to call them"); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-once.window.js b/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-once.window.js new file mode 100644 index 0000000000..b39b54b0e9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-once.window.js @@ -0,0 +1,14 @@ +setup({ allow_uncaught_exception: true }); + +var errors = 0; +window.onerror = function() { + errors++; +}; + +test(function() { + var e = document.body; + e.setAttribute("onclick", "window.open("); + assert_equals(e.onclick, null); + assert_equals(e.onclick, null); + assert_equals(errors, 1); +}, "Invalid uncompiled raw handlers should only be compiled once"); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-keeps-position.window.js b/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-keeps-position.window.js new file mode 100644 index 0000000000..f9443bf99a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-keeps-position.window.js @@ -0,0 +1,20 @@ +setup({ allow_uncaught_exception: true }); + +test(function() { + var events = []; + window.onerror = function() { + events.push("error"); + }; + + var div = document.createElement("div"); + div.addEventListener("click", function (e) { events.push("click 1"); }); + div.setAttribute("onclick", "}"); + div.addEventListener("click", function (e) { events.push("click 3"); }); + assert_equals(div.onclick, null); + assert_array_equals(events, ["error"]); + + events = []; + div.onclick = function (e) { events.push("click 2"); }; + div.dispatchEvent(new Event("click")); + assert_array_equals(events, ["click 1", "click 2", "click 3"]); +}, "Compiling invalid uncompiled raw handlers should keep the position in event listener list"); diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/messageevent-constructor.https.html b/testing/web-platform/tests/html/webappapis/scripting/events/messageevent-constructor.https.html new file mode 100644 index 0000000000..ef55886180 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/messageevent-constructor.https.html @@ -0,0 +1,106 @@ +<!DOCTYPE html> +<title>MessageEvent constructor</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> +<script> +test(function() { + var ev = new MessageEvent("test") + assert_equals(ev.type, "test", "type attribute") + assert_equals(ev.target, null, "target attribute") + assert_equals(ev.currentTarget, null, "currentTarget attribute") + assert_equals(ev.eventPhase, Event.NONE, "eventPhase attribute") + assert_equals(ev.bubbles, false, "bubbles attribute") + assert_equals(ev.cancelable, false, "cancelable attribute") + assert_equals(ev.defaultPrevented, false, "defaultPrevented attribute") + assert_equals(ev.isTrusted, false, "isTrusted attribute") + assert_true(ev.timeStamp > 0, "timeStamp attribute") + assert_true("initMessageEvent" in ev, "initMessageEvent operation") + assert_equals(ev.data, null, "data attribute") + assert_equals(ev.origin, "", "origin attribute") + assert_equals(ev.lastEventId, "", "lastEventId attribute") + assert_equals(ev.source, null, "source attribute") + assert_array_equals(ev.ports, [], "ports attribute") +}, "Default event values") + +test(function() { + var channel = new MessageChannel() + var ev = new MessageEvent("test", { data: "testData", origin: "testOrigin", lastEventId: "testId", source: window, ports: [channel.port1] }) + assert_equals(ev.type, "test", "type attribute") + assert_equals(ev.data, "testData", "data attribute") + assert_equals(ev.origin, "testOrigin", "origin attribute") + assert_equals(ev.lastEventId, "testId", "lastEventId attribute") + assert_equals(ev.source, window, "source attribute") + assert_array_equals(ev.ports, [channel.port1], "ports attribute") +}, "MessageEventInit dictionary") + +test(function() { + assert_throws_js(TypeError, function() { + new MessageEvent("test", { ports: null }) + }) +}, "Passing null for ports member") + +test(function() { + var ev = new MessageEvent("test", { ports: [] }) + assert_true(Array.isArray(ev.ports), "Array.isArray() should return true") + assert_true(Object.isFrozen(ev.ports), "Object.isFrozen() should return true") + assert_equals(ev.ports, ev.ports, "ev.ports should return the same object") + + const oldPorts = ev.ports; + ev.initMessageEvent("test", false, false, null, "", "", null, ev.ports); + assert_not_equals(oldPorts, ev.ports, "initMessageEvent() changes ev.ports"); +}, "ports attribute should be a FrozenArray") + +test(function() { + var ev = document.createEvent("messageevent"); + var channel = new MessageChannel() + ev.initMessageEvent("test", true, false, "testData", "testOrigin", "testId", window, [channel.port1]) + assert_equals(ev.type, "test", "type attribute") + assert_equals(ev.bubbles, true, "bubbles attribute") + assert_equals(ev.cancelable, false, "bubbles attribute") + assert_equals(ev.data, "testData", "data attribute") + assert_equals(ev.origin, "testOrigin", "origin attribute") + assert_equals(ev.lastEventId, "testId", "lastEventId attribute") + assert_equals(ev.source, window, "source attribute") + assert_array_equals(ev.ports, [channel.port1], "ports attribute") +}, "initMessageEvent operation") + +test(function() { + var ev = document.createEvent("messageevent") + assert_throws_js(TypeError, function() { + ev.initMessageEvent("test", true, false, "testData", "testOrigin", "testId", window, null) + }) +}, "Passing null for ports parameter to initMessageEvent") + +test(function() { + var ev = document.createEvent("messageevent") + assert_equals(MessageEvent.prototype.initMessageEvent.length, 1, "MessageEvent.prototype.initMessageEvent.length should be 1") + ev.initMessageEvent("test") + assert_equals(ev.type, "test", "type attribute") + assert_equals(ev.bubbles, false, "bubbles attribute") + assert_equals(ev.cancelable, false, "bubbles attribute") + assert_equals(ev.data, null, "data attribute") + assert_equals(ev.origin, "", "origin attribute") + assert_equals(ev.lastEventId, "", "lastEventId attribute") + assert_equals(ev.source, null, "source attribute") + assert_array_equals(ev.ports, [], "ports attribute") +}, "initMessageEvent operation default parameter values") + +promise_test(function(t) { + var worker_url = "/service-workers/service-worker/resources/empty-worker.js"; + var scope = "/service-workers/service-worker/resources/"; + var registration; + + return service_worker_unregister_and_register(t, worker_url, scope) + .then(function(r) { + registration = r; + return wait_for_state(t, r.installing, "activated"); + }) + .then(function() { + var ev = new MessageEvent("test", { source: registration.active }); + assert_equals(ev.source, registration.active, "source attribute should return the ServiceWorker"); + service_worker_unregister(t, scope); + }); + }, "Passing ServiceWorker for source member"); + +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler-frame.html b/testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler-frame.html new file mode 100644 index 0000000000..79e4af3020 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler-frame.html @@ -0,0 +1,56 @@ +<body></body> +<script> +function check1(args, callee) { + parent.t.step(function() { + parent.assert_equals(callee.length, 5); + parent.assert_equals(args.length, 5); + parent.assert_equals(args[0], reference_error.message); + parent.assert_equals(args[1], reference_error.filename); + parent.assert_equals(args[2], reference_error.lineno); + parent.assert_equals(args[3], reference_error.colno); + parent.assert_equals(args[4], reference_error.error); + parent.t.done(); + }); +} + +var reference_error = new ErrorEvent("error", { + filename: "error_file.js", + lineno: 333, + colno: 999, + message: "there was an error", + error: {nondefault: 'some unusual object'}, +}); + +parent.t.step(function() { + document.body.outerHTML = "<body onerror='check1(arguments, arguments.callee)'></body>" + window.dispatchEvent(reference_error); +}); + +function check2(args, callee) { + parent.t2.step(function() { + parent.assert_equals(callee.length, 5); + parent.assert_equals(args.length, 1); + parent.assert_false(args[0] instanceof ErrorEvent); + parent.t2.done() + }); +} + +parent.t2.step(function() { + document.body.outerHTML = "<body onerror='check2(arguments, arguments.callee)'></body>" + window.dispatchEvent(new Event("error")); +}); + +function check3(args, callee) { + parent.t3.step(function() { + parent.assert_equals(args.length, 1); + parent.assert_equals(callee.length, 1); + }); +} + +parent.t3.step(function() { + document.body.outerHTML = "<body><span onerror='check3(arguments, arguments.callee)'></span></body>" + document.body.firstChild.dispatchEvent(reference_error); + document.body.firstChild.dispatchEvent(new Event("error")); + parent.t3.done(); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler.html b/testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler.html new file mode 100644 index 0000000000..60fc674d57 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler.html @@ -0,0 +1,11 @@ +<!doctype html> +<meta charset=utf-8> +<title>OnErrorEventHandler + ErrorEvent is treated differently</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +var t = async_test("onerror + ErrorEvent + Window"); +var t2 = async_test("onerror + !ErrorEvent + Window"); +var t3 = async_test("onerror + Document"); +</script> +<iframe src="onerroreventhandler-frame.html"></iframe> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/resources/compiled-event-handler-settings-objects-support.html b/testing/web-platform/tests/html/webappapis/scripting/events/resources/compiled-event-handler-settings-objects-support.html new file mode 100644 index 0000000000..d40c0b9cce --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/resources/compiled-event-handler-settings-objects-support.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>This will be in an iframe</title> + +<script> +window.name = "iframe"; +</script> + +<body onbeforeunload="return { toString: parent.postMessage.bind(parent, 'PASS', '*') };"> + +<!-- window.open() uses the entry settings object to determine how the URL will be parsed --> +<button onclick="var w = window.open('open-window.html'); w.onload = () => { parent.onWindowLoaded(w.document.URL); };">This will be clicked</button> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/resources/event-handler-body.js b/testing/web-platform/tests/html/webappapis/scripting/events/resources/event-handler-body.js new file mode 100644 index 0000000000..d7889e230e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/resources/event-handler-body.js @@ -0,0 +1,61 @@ +const windowReflectingBodyElementEventHandlerSet = + new Set(['blur', 'error', 'focus', 'load', 'resize', 'scroll']); + +function handlersInInterface(mainIDL, name) { + return mainIDL.find(idl => idl.name === name).members.map(member => member.name.slice(2)); +} + +const handlersListPromise = fetch("/interfaces/html.idl").then(res => res.text()).then(htmlIDL => { + const parsedHTMLIDL = WebIDL2.parse(htmlIDL); + const windowEventHandlers = handlersInInterface(parsedHTMLIDL, "WindowEventHandlers"); + const globalEventHandlers = handlersInInterface(parsedHTMLIDL, "GlobalEventHandlers"); + + const shadowedHandlers = [ + ...windowReflectingBodyElementEventHandlerSet, + ...windowEventHandlers + ]; + const notShadowedHandlers = globalEventHandlers.filter(name => !windowReflectingBodyElementEventHandlerSet.has(name)); + return { + shadowedHandlers, + notShadowedHandlers + }; +}); + +function eventHandlerTest(shadowedHandlers, notShadowedHandlers, element) { + const altBody = document.createElement(element); + for (const [des, obj1, obj2, obj3, des1, des2, des3] of [ + ["document.body", document.body, altBody, window, "body", "alternative body", "window"], + [`document.createElement("${element}")`, altBody, document.body, window, "alternative body", "body", "window"], + ["window", window, document.body, altBody, "window", "body", "alternative body"] + ]) { + const f = () => 0; + + shadowedHandlers.forEach(handler => { + const eventHandler = obj1['on' + handler]; + test(() => { + obj1['on' + handler] = f; + assert_equals(obj2['on' + handler], f, `${des2} should reflect`); + assert_equals(obj3['on' + handler], f, `${des3} should reflect`); + }, `shadowed ${handler} (${des})`); + obj1['on' + handler] = eventHandler; + }); + + notShadowedHandlers.forEach(handler => { + const eventHandler = obj1['on' + handler]; + test(() => { + obj1['on' + handler] = f; + assert_equals(obj2['on' + handler], null, `${des2} should reflect`); + assert_equals(obj3['on' + handler], null, `${des3} should reflect`); + }, `not shadowed ${handler} (${des})`); + obj1['on' + handler] = eventHandler; + }); + + shadowedHandlers.forEach(handler => { + test(() => { + assert_equals(obj1['on' + handler], null, `${des1} should reflect changes to itself`); + assert_equals(obj2['on' + handler], null, `${des2} should reflect`); + assert_equals(obj3['on' + handler], null, `${des3} should reflect`); + }, `shadowed ${handler} removal (${des})`); + }); + } +} diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/resources/open-window.html b/testing/web-platform/tests/html/webappapis/scripting/events/resources/open-window.html new file mode 100644 index 0000000000..1d23263570 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/resources/open-window.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>This window will open during the course of the test</title> +<h1>Hello</h1> diff --git a/testing/web-platform/tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled.html b/testing/web-platform/tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled.html new file mode 100644 index 0000000000..a912b32d7f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled.html @@ -0,0 +1,21 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Uncompiled event handler check that scripting is enabled</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({ allow_uncaught_exception: true }); + test(function() { + var invoked = false; + window.addEventListener("error", function() { + invoked = true; + }); + + // Make sure that `this_will_error` will in fact error when it's referenced + assert_equals(typeof this_will_error, "undefined"); + var dom = (new DOMParser()).parseFromString("<div id=\"has-event-handler\" onclick=\"this_will_error;\"></div>", "text/html"); + var click = new MouseEvent("click"); + dom.getElementById("has-event-handler").dispatchEvent(click); + assert_equals(invoked, false); + }, "when scripting is disabled, the handler is never compiled"); +</script> |