summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/webappapis/scripting/events
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/html/webappapis/scripting/events
parentInitial commit. (diff)
downloadfirefox-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')
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/body-onload.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes-form-owner.html48
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-lexical-scopes.html167
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-settings-objects.html69
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/compile-event-handler-symbol-unscopables.html71
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/contextmenu-event-manual.htm21
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-all-global-events.html88
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-body-window.html18
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html30
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html71
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-handleEvent-ignored.html38
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-javascript.html20
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-onresize.html38
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-errorevent.html57
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/body-element-synthetic-event.html29
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-errorevent.html60
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/document-synthetic-event.html30
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-errorevent.html64
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/frameset-element-synthetic-event.html36
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/frameset-frame.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/no-op-worker.js1
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/resources/worker-with-syntax-error.js1
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/script-element.html67
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.html78
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/synthetic-errorevent-click.worker.js22
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-runtime-error.html48
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-errorevent.html57
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/window-synthetic-event.html30
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/worker.html63
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-runtime-error.worker.js40
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-errorevent.worker.js49
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-error/workerglobalscope-synthetic-event.worker.js22
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html62
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-processing-algorithm.html60
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-removal.window.js76
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-sourcetext.html40
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/event-handler-spec-example.window.js55
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/eventhandler-cancellation.html76
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/inline-event-handler-ordering.html53
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-late.window.js16
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-compiled-once.window.js14
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/invalid-uncompiled-raw-handler-keeps-position.window.js20
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/messageevent-constructor.https.html106
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler-frame.html56
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/onerroreventhandler.html11
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/resources/compiled-event-handler-settings-objects-support.html12
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/resources/event-handler-body.js61
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/resources/open-window.html4
-rw-r--r--testing/web-platform/tests/html/webappapis/scripting/events/uncompiled_event_handler_with_scripting_disabled.html21
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>