diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/html/webappapis/scripting/processing-model-2 | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/webappapis/scripting/processing-model-2')
76 files changed, 3293 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/addEventListener.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/addEventListener.html new file mode 100644 index 0000000000..dbb1cdd5a9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/addEventListener.html @@ -0,0 +1,32 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - addEventListener</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = false; + window.addEventListener('error', t.step_func(function(e){ + ran = true; + assert_true(e.isTrusted, 'isTrusted'); + }), false); + </script> + <script> + undefined_variable; + </script> + <script> + for (;) {} + </script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-compile-error-data-url.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-compile-error-data-url.html new file mode 100644 index 0000000000..66e1dfed4d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-compile-error-data-url.html @@ -0,0 +1,37 @@ +<!doctype html> +<html> + <head> + <title><body onerror> - compile error in <script src=data:...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + </script> + <body onerror=" + t.step(function(){ + ran = true; + assert_equals(typeof event, 'string', 'first arg'); + assert_equals(source, 'data:text/javascript,for(;){}', 'second arg'); + assert_equals(typeof lineno, 'number', 'third arg'); + }); + t_col.step(function() { + assert_equals(typeof colno, 'number', 'fourth arg'); + }); + "> + <div id=log></div> + <script src="data:text/javascript,for(;){}"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-compile-error.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-compile-error.html new file mode 100644 index 0000000000..0f65f73999 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-compile-error.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <title><body onerror> - compile error in <script></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + </script> + <body onerror=" + t.step(function(){ + ran = true; + assert_equals(typeof event, 'string', 'first arg'); + assert_equals(source, location.href, 'second arg'); + assert_equals(typeof lineno, 'number', 'third arg'); + }); + t_col.step(function() { + assert_equals(typeof colno, 'number', 'fourth arg'); + }); + "> + <div id=log></div> + <script> + for(;) {} + </script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-runtime-error.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-runtime-error.html new file mode 100644 index 0000000000..faaddd9ed9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/body-onerror-runtime-error.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <title><body onerror> - runtime error in <script></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + </script> + <body onerror=" + t.step(function(){ + ran = true; + assert_equals(typeof event, 'string', 'first arg'); + assert_equals(source, location.href, 'second arg'); + assert_equals(typeof lineno, 'number', 'third arg'); + }); + t_col.step(function(){ + assert_equals(typeof colno, 'number', 'fourth arg'); + }); + "> + <div id=log></div> + <script> + undefined_variable; + </script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin-setInterval.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin-setInterval.html new file mode 100644 index 0000000000..c4028e650b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin-setInterval.html @@ -0,0 +1,25 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in cross-origin setInterval</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = false; + var interval; + window.addEventListener('error', t.step_func(e => { + clearInterval(interval); + ran = true; + assert_equals(e.error.constructor, SyntaxError); + })); + var script = document.createElement('script'); + script.src = location.href.replace('://', '://www1.').replace(/\/[^\/]+$/, '/support/syntax-error-in-setInterval.js'); + document.body.appendChild(script); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin-setTimeout.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin-setTimeout.html new file mode 100644 index 0000000000..1eebf82fbb --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin-setTimeout.html @@ -0,0 +1,23 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in cross-origin setTimeout</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = false; + window.addEventListener('error', t.step_func(e => { + ran = true; + assert_equals(e.error.constructor, SyntaxError); + })); + var script = document.createElement('script'); + script.src = location.href.replace('://', '://www1.').replace(/\/[^\/]+$/, '/support/syntax-error-in-setTimeout.js'); + document.body.appendChild(script); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin.html new file mode 100644 index 0000000000..b7e989529f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-cross-origin.html @@ -0,0 +1,38 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in <script src=//www1...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(a, 'Script error.', 'first arg'); + assert_equals(b, '', 'second arg'); + assert_equals(c, 0, 'third arg'); + }); + var script = document.createElement('script'); + script.src = location.href.replace('://', '://www1.').replace(/\/[^\/]+$/, '/support/syntax-error.js'); + document.body.appendChild(script); + onload = function(){ + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(col_value, 0, 'fourth arg'); + t_col.done(); + }); + }; + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-data-url.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-data-url.html new file mode 100644 index 0000000000..08ce2f348f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-data-url.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in <script src=data:...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, 'data:text/javascript,for(;){}', 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script src="data:text/javascript,for(;){}"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-attribute.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-attribute.html new file mode 100644 index 0000000000..864d09fc1e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-attribute.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in attribute</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <p onclick="{"></p> + <script> + t.step(function(){ + var ev = document.createEvent('Event'); + ev.initEvent('click', false, false); + document.querySelector('p').dispatchEvent(ev); + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-body-onerror.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-body-onerror.html new file mode 100644 index 0000000000..0b094e71c3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-body-onerror.html @@ -0,0 +1,28 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in <body onerror></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = false; + window.onerror = t.step_func(function(){ + ran = true; + }); + </script> + </head> + <body onerror="{"><!-- sets the event handler to null before compiling --> + <div id=log></div> + <script> + for(;) {} + </script> + <script> + t.step(function(){ + assert_false(ran, 'ran'); + t.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-setInterval.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-setInterval.html new file mode 100644 index 0000000000..79ca7d524a --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-setInterval.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in setInterval</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + var interval; + window.onerror = t.step_func(function(a, b, c, d){ + clearInterval(interval); + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + interval = setInterval("{", 10); + step_timeout(function(){ + t.step(function(){ + clearInterval(interval); + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + }, 20); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-setTimeout.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-setTimeout.html new file mode 100644 index 0000000000..1bb730e134 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-in-setTimeout.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in setTimeout</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + setTimeout("{", 10); + setTimeout(function(){ + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + }, 20); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-same-origin-with-hash.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-same-origin-with-hash.html new file mode 100644 index 0000000000..c367e6cb2f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-same-origin-with-hash.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in <script src=...> with hash</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, document.querySelector('script[src="support/syntax-error.js#"]').src, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script src="support/syntax-error.js#"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-same-origin.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-same-origin.html new file mode 100644 index 0000000000..71c28b584d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error-same-origin.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in <script src=...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, document.querySelector('script[src="support/syntax-error.js"]').src, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script src="support/syntax-error.js"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error.html new file mode 100644 index 0000000000..a4bdfd9c47 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/compile-error.html @@ -0,0 +1,38 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - compile error in <script></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script> + for(;) {} + </script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/atomics-wait-async.https.any.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/atomics-wait-async.https.any.js new file mode 100644 index 0000000000..3a3ea40d77 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/atomics-wait-async.https.any.js @@ -0,0 +1,25 @@ +// META: global=window,dedicatedworker + +promise_test(async () => { + const sab = new SharedArrayBuffer(64); + const ta = new Int32Array(sab); + + const waitAsyncObj = Atomics.waitAsync(ta, 0, 0, 10); + assert_equals(waitAsyncObj.async, true); + const v = await waitAsyncObj.value; + assert_equals(v, "timed-out"); +}, `Atomics.waitAsync timeout in a ${self.constructor.name}`); + +promise_test(async () => { + const sab = new SharedArrayBuffer(64); + const ta = new Int32Array(sab); + + const waitAsyncObj = Atomics.waitAsync(ta, 0, 0); + assert_equals(waitAsyncObj.async, true); + + const worker = new Worker("resources/notify-worker.js"); + worker.postMessage(sab); + + const v = await waitAsyncObj.value; + assert_equals(v, "ok"); +}, `Atomics.waitAsync notification in a ${self.constructor.name}`); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/atomics-wait-async.https.any.js.headers b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/atomics-wait-async.https.any.js.headers new file mode 100644 index 0000000000..5f8621ef83 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/atomics-wait-async.https.any.js.headers @@ -0,0 +1,2 @@ +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Opener-Policy: same-origin diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-failure.https.any.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-failure.https.any.js new file mode 100644 index 0000000000..fddf85dbed --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-failure.https.any.js @@ -0,0 +1,11 @@ +// META: global=window,serviceworker + +test(() => { + // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()` + const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer; + const ta = new Int32Array(sab); + + assert_throws_js(TypeError, () => { + Atomics.wait(ta, 0, 0, 10); + }); +}, `[[CanBlock]] in a ${self.constructor.name}`); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-success.any.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-success.any.js new file mode 100644 index 0000000000..0da449a7cf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/requires-success.any.js @@ -0,0 +1,9 @@ +// META: global=dedicatedworker,sharedworker + +test(() => { + // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()` + const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer; + const ta = new Int32Array(sab); + + assert_equals(Atomics.wait(ta, 0, 0, 10), "timed-out"); +}, `[[CanBlock]] in a ${self.constructor.name}`); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/resources/notify-worker.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/resources/notify-worker.js new file mode 100644 index 0000000000..2780e5bc34 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/resources/notify-worker.js @@ -0,0 +1,5 @@ +onmessage = (e) => { + const sab = e.data; + const ta = new Int32Array(sab); + Atomics.notify(ta, 0); +}; diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/resources/notify-worker.js.headers b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/resources/notify-worker.js.headers new file mode 100644 index 0000000000..6604450991 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/resources/notify-worker.js.headers @@ -0,0 +1 @@ +Cross-Origin-Embedder-Policy: require-corp diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-entry-different-function-realm.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-entry-different-function-realm.html new file mode 100644 index 0000000000..71f03a4dcf --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-entry-different-function-realm.html @@ -0,0 +1,112 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Entry settings object for promise jobs when the function realm is different from the test realm</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- https://github.com/whatwg/html/pull/5212 --> +<!-- https://github.com/whatwg/html/issues/1426 --> + +<!-- This is what would normally be considered the entry page. However, we use functions from the + resources/function/function.html realm. So window.open() should resolve relative to that realm + inside promise jobs. --> + +<iframe src="resources/promise-job-entry-incumbent.html"></iframe> +<iframe src="resources/function/function.html" id="function-frame"></iframe> + +<script> +setup({ explicit_done: true }); + +const relativeURL = "resources/window-to-open.html"; +const expectedURL = (new URL(relativeURL, document.querySelector("#function-frame").src)).href; + +const incumbentWindow = frames[0]; +const functionWindow = frames[1]; +const FunctionFromAnotherWindow = frames[1].Function; + +window.onload = () => { + async_test(t => { + const func = FunctionFromAnotherWindow(` + const [incumbentWindow, relativeURL, t, assert_equals, expectedURL] = arguments[0]; + + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + `); + + Promise.resolve([incumbentWindow, relativeURL, t, assert_equals, expectedURL]).then(func); + }, "Fulfillment handler on fulfilled promise"); + + async_test(t => { + const func = FunctionFromAnotherWindow(` + const [incumbentWindow, relativeURL, t, assert_equals, expectedURL] = arguments[0]; + + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + `); + + Promise.reject([incumbentWindow, relativeURL, t, assert_equals, expectedURL]).catch(func); + }, "Rejection handler on rejected promise"); + + async_test(t => { + let resolve; + const p = new Promise(r => { resolve = r; }); + + const func = FunctionFromAnotherWindow(` + const [incumbentWindow, relativeURL, t, assert_equals, expectedURL] = arguments[0]; + + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + `); + + p.then(func); + t.step_timeout(() => resolve([incumbentWindow, relativeURL, t, assert_equals, expectedURL]), 0); + }, "Fulfillment handler on pending-then-fulfilled promise"); + + async_test(t => { + let reject; + const p = new Promise((_, r) => { reject = r; }); + + const func = FunctionFromAnotherWindow(` + const [incumbentWindow, relativeURL, t, assert_equals, expectedURL] = arguments[0]; + + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + `); + + p.catch(func); + t.step_timeout(() => reject([incumbentWindow, relativeURL, t, assert_equals, expectedURL]), 0); + }, "Rejection handler on pending-then-rejected promise"); + + async_test(t => { + t.add_cleanup(() => { delete frames[1].args; }); + frames[1].args = [incumbentWindow, relativeURL, t, assert_equals, expectedURL]; + + const func = FunctionFromAnotherWindow(` + const [incumbentWindow, relativeURL, t, assert_equals, expectedURL] = window.args; + + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + `); + + const thenable = { then: func }; + + Promise.resolve(thenable); + }, "Thenable resolution"); + + done(); +}; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-entry.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-entry.html new file mode 100644 index 0000000000..6d075d674c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-entry.html @@ -0,0 +1,101 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Entry settings object for promise jobs</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- https://github.com/whatwg/html/pull/5212 --> +<!-- https://github.com/whatwg/html/issues/1426 --> + +<!-- This is the entry page, so window.open() should resolve relative to it, even inside promise jobs. --> + +<iframe src="resources/promise-job-entry-incumbent.html"></iframe> + +<script> +setup({ explicit_done: true }); + +const relativeURL = "resources/window-to-open.html"; +const expectedURL = (new URL(relativeURL, location.href)).href; + +const incumbentWindow = frames[0]; + +window.onload = () => { + async_test(t => { + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + }, "Sanity check: this all works as expected with no promises involved"); + + async_test(t => { + // No t.step_func because that could change the realms + Promise.resolve().then(() => { + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + }); + }, "Fulfillment handler on fulfilled promise"); + + async_test(t => { + // No t.step_func because that could change the realms + Promise.reject().catch(() => { + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + }); + }, "Rejection handler on rejected promise"); + + async_test(t => { + let resolve; + const p = new Promise(r => { resolve = r; }); + + // No t.step_func because that could change the realms + p.then(() => { + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + }); + + t.step_timeout(resolve, 0); + }, "Fulfillment handler on pending-then-fulfilled promise"); + + async_test(t => { + let reject; + const p = new Promise((_, r) => { reject = r; }); + + // No t.step_func because that could change the realms + p.catch(() => { + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + }); + + t.step_timeout(reject, 0); + }, "Rejection handler on pending-then-rejected promise"); + + async_test(t => { + const thenable = { + // No t.step_func because that could change the realms + then(f) { + const w = incumbentWindow.runWindowOpenVeryIndirectly(relativeURL); + w.onload = t.step_func_done(() => { + t.add_cleanup(() => w.close()); + assert_equals(w.location.href, expectedURL); + }); + } + }; + + Promise.resolve(thenable); + }, "Thenable resolution"); + + done(); +}; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-incumbent.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-incumbent.html new file mode 100644 index 0000000000..af00f834c1 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/promise-job-incumbent.html @@ -0,0 +1,164 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Incumbent settings object for promise jobs</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- This is the entry page. --> + +<iframe src="resources/promise-job-incumbent-incumbent.html"></iframe> +<iframe src="resources/promise-job-incumbent-resolver.html"></iframe> + +<script> +setup({ explicit_done: true }); + +// postMessage should pick the incumbent page as its .source value to set on the MessageEvent, even +// inside promise jobs. +const expectedURL = (new URL("resources/promise-job-incumbent-incumbent.html", location.href)).href; + +let testId = 0; + +window.onload = () => { + const relevantWindow = frames[0].document.querySelector("#r").contentWindow; + const runInResolver = frames[1].runWhatYouGiveMe; + + function setupTest(t) { + ++testId; + const thisTestId = testId; + + relevantWindow.addEventListener("messagereceived", t.step_func(e => { + const [receivedTestId, receivedSourceURL] = e.detail; + + if (receivedTestId !== thisTestId) { + return; + } + + assert_equals(receivedSourceURL, expectedURL); + t.done(); + })); + + return thisTestId; + } + + async_test(t => { + const thisTestId = setupTest(t); + + frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); + }, "Sanity check: this all works as expected with no promises involved"); + + async_test(t => { + const thisTestId = setupTest(t); + + // No t.step_func because that could change the realms + Promise.resolve().then(() => { + frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); + }); + }, "Fulfillment handler on fulfilled promise"); + + async_test(t => { + const thisTestId = setupTest(t); + + const p = Promise.resolve(); + frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "then", thisTestId, "*"); + }, "Fulfillment handler on fulfilled promise, using backup incumbent settings object stack"); + + async_test(t => { + const thisTestId = setupTest(t); + + // No t.step_func because that could change the realms + Promise.reject().catch(() => { + frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); + }); + }, "Rejection handler on rejected promise"); + + async_test(t => { + const thisTestId = setupTest(t); + + const p = Promise.reject(); + frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "catch", thisTestId, "*"); + }, "Rejection handler on rejected promise, using backup incumbent settings object stack"); + + // The following tests test that we derive the incumbent settings object at promise-job time from + // the incumbent realm at the time the handler was added, not at the time the resolve()/reject() + // was done. See https://github.com/whatwg/html/issues/5213 for the spec side of this issue. + + async_test(t => { + const thisTestId = setupTest(t); + + let resolve; + const p = new Promise(r => { resolve = r; }); + + // No t.step_func because that could change the realms + p.then(() => { + frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); + }); + + t.step_timeout(() => { + runInResolver(resolve); + }, 0); + }, "Fulfillment handler on pending-then-fulfilled promise"); + + async_test(t => { + const thisTestId = setupTest(t); + + let resolve; + const p = new Promise(r => { resolve = r; }); + + frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "then", thisTestId, "*"); + + t.step_timeout(() => { + runInResolver(resolve); + }, 0); + }, "Fulfillment handler on pending-then-fulfilled promise, using backup incumbent settings object stack"); + + async_test(t => { + const thisTestId = setupTest(t); + + let reject; + const p = new Promise((_, r) => { reject = r; }); + + // No t.step_func because that could change the realms + p.catch(() => { + frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); + }); + + t.step_timeout(() => { + runInResolver(reject); + }, 0); + }, "Rejection handler on pending-then-rejected promise"); + + async_test(t => { + const thisTestId = setupTest(t); + + let reject; + const p = new Promise((_, r) => { reject = r; }); + + frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "catch", thisTestId, "*"); + + t.step_timeout(() => { + runInResolver(reject); + }, 0); + }, "Rejection handler on pending-then-rejected promise, using backup incumbent settings object stack"); + + async_test(t => { + const thisTestId = setupTest(t); + + const thenable = { + // No t.step_func because that could change the realms + then(f) { + frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); + } + }; + + Promise.resolve(thenable); + }, "Thenable resolution"); + + async_test(t => { + const thisTestId = setupTest(t); + + frames[0].resolveThenableThatRunsWindowPostMessageVeryIndirectlyWithNoUserCode(testId, "*", []); + }, "Thenable resolution, using backup incumbent settings object stack"); + + done(); +}; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/README.md b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/README.md new file mode 100644 index 0000000000..a89258a4e0 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/README.md @@ -0,0 +1,5 @@ +A couple notes about the files scattered in this `resources/` directory: + +* The nested directory structure is necessary here so that relative URL resolution can be tested; we need different sub-paths for each document. + +* The semi-duplicate `window-to-open.html`s scattered throughout are present because Firefox, at least, does not fire `Window` `load` events for 404s, so we want to ensure that no matter which global is used, `window`'s `load` event is hit and our tests can proceed. diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/current/current.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/current/current.html new file mode 100644 index 0000000000..63d9c437fc --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/current/current.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Current page used as a test helper</title> + diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/current/resources/window-to-open.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/current/resources/window-to-open.html new file mode 100644 index 0000000000..1bc4cca9a3 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/current/resources/window-to-open.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>If the current settings object is used this page will be opened</title> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/function/function.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/function/function.html new file mode 100644 index 0000000000..15841d387d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/function/function.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Realm for a "then" function used as a test helper</title> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/function/resources/window-to-open.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/function/resources/window-to-open.html new file mode 100644 index 0000000000..3928c1f8aa --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/function/resources/window-to-open.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>If the function's settings object is used this page will be opened</title> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-entry-incumbent.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-entry-incumbent.html new file mode 100644 index 0000000000..3740c1467d --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-entry-incumbent.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Incumbent page used as a test helper</title> + +<iframe src="relevant/relevant.html" id="r"></iframe> +<iframe src="current/current.html" id="c"></iframe> + +<script> + const relevant = document.querySelector("#r"); + const current = document.querySelector("#c"); + + window.runWindowOpenVeryIndirectly = (...args) => { + return current.contentWindow.open.call(relevant.contentWindow, ...args); + }; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-incumbent-incumbent.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-incumbent-incumbent.html new file mode 100644 index 0000000000..57dd5dff10 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-incumbent-incumbent.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Incumbent page used as a test helper</title> + +<iframe src="relevant/relevant.html" id="r"></iframe> +<iframe src="current/current.html" id="c"></iframe> + +<script> + const relevant = document.querySelector("#r"); + const current = document.querySelector("#c"); + + window.runWindowPostMessageVeryIndirectly = (...args) => { + return current.contentWindow.postMessage.call(relevant.contentWindow, ...args); + }; + + // This tests the backup incumbent settings object stack scenario, by avoiding putting user code on the stack. + window.runWindowPostMessageVeryIndirectlyWithNoUserCode = (promise, promiseMethod, ...args) => { + const runWindowPostMessage = current.contentWindow.postMessage.bind(relevant.contentWindow, ...args); + promise[promiseMethod](runWindowPostMessage); + }; + + window.resolveThenableThatRunsWindowPostMessageVeryIndirectlyWithNoUserCode = (...args) => { + Promise.resolve({ + then: current.contentWindow.postMessage.bind(relevant.contentWindow, ...args) + }); + }; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-incumbent-resolver.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-incumbent-resolver.html new file mode 100644 index 0000000000..a730b9c3ce --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/promise-job-incumbent-resolver.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Incumbent page used as a test helper</title> + +<script> + window.runWhatYouGiveMe = (func) => { + func(); + }; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/relevant/relevant.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/relevant/relevant.html new file mode 100644 index 0000000000..f5965f2231 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/relevant/relevant.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Relevant page used as a test helper</title> + +<script> +// promise-job-incumbent will end up posting a message to here. We need to signal back the "source". + +window.onmessage = e => { + const testId = e.data; + const sourceURL = e.source.document.URL; + + window.dispatchEvent(new CustomEvent("messagereceived", { detail: [testId, sourceURL] })); +}; +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/relevant/resources/window-to-open.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/relevant/resources/window-to-open.html new file mode 100644 index 0000000000..4138b5a084 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/relevant/resources/window-to-open.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>If the relevant settings object is used this page will be opened</title> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/resources/window-to-open.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/resources/window-to-open.html new file mode 100644 index 0000000000..7743b9b578 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/resources/window-to-open.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>If the incumbent settings object is used this page will be opened</title> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/window-to-open.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/window-to-open.html new file mode 100644 index 0000000000..ce357937f5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-job-queue/resources/window-to-open.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>If the entry settings object is used this page will be opened</title> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setInterval.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setInterval.html new file mode 100644 index 0000000000..8b92f7d148 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setInterval.html @@ -0,0 +1,25 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in cross-origin setInterval</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = false; + var interval; + window.addEventListener('error', t.step_func(e => { + clearInterval(interval); + ran = true; + assert_equals(e.error.constructor, ReferenceError); + })); + var script = document.createElement('script'); + script.src = location.href.replace('://', '://www1.').replace(/\/[^\/]+$/, '/support/undefined-variable-in-setInterval.js'); + document.body.appendChild(script); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setTimeout.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setTimeout.html new file mode 100644 index 0000000000..2e1a9d2315 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin-setTimeout.html @@ -0,0 +1,23 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in cross-origin setTimeout</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = false; + window.addEventListener('error', t.step_func(e => { + ran = true; + assert_equals(e.error.constructor, ReferenceError); + })); + var script = document.createElement('script'); + script.src = location.href.replace('://', '://www1.').replace(/\/[^\/]+$/, '/support/undefined-variable-in-setTimeout.js'); + document.body.appendChild(script); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin.html new file mode 100644 index 0000000000..d63aaa6d3b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-cross-origin.html @@ -0,0 +1,38 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in <script src=//www1...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(a, 'Script error.', 'first arg'); + assert_equals(b, '', 'second arg'); + assert_equals(c, 0, 'third arg'); + }); + var script = document.createElement('script'); + script.src = location.href.replace('://', '://www1.').replace(/\/[^\/]+$/, '/support/undefined-variable.js'); + document.body.appendChild(script); + onload = function(){ + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(col_value, 0, 'fourth arg'); + t_col.done(); + }); + }; + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-data-url.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-data-url.html new file mode 100644 index 0000000000..485ce90aa6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-data-url.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in <script src=data:...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, 'data:text/javascript,undefined_variable;', 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script src="data:text/javascript,undefined_variable;"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-attribute.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-attribute.html new file mode 100644 index 0000000000..b4f69da7a2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-attribute.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in attribute</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <p onclick="undefined_variable;"></p> + <script> + t.step(function(){ + var ev = document.createEvent('Event'); + ev.initEvent('click', false, false); + document.querySelector('p').dispatchEvent(ev); + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-body-onerror.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-body-onerror.html new file mode 100644 index 0000000000..e0fd1dcbd5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-body-onerror.html @@ -0,0 +1,25 @@ +<!doctype html> +<html> + <head> + <title>runtime error in <body onerror></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = 0; + </script> + </head> + <body onerror="ran++; undefined_variable_in_onerror;"> + <div id=log></div> + <script> + undefined_variable; + </script> + <script> + t.step(function(){ + assert_equals(ran, 1, 'ran'); + t.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval.html new file mode 100644 index 0000000000..090e1dd78e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval.html @@ -0,0 +1,39 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in setInterval</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + var interval; + window.onerror = t.step_func(function(a, b, c, d){ + clearInterval(interval); + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + interval = setInterval("undefined_variable;", 10); + step_timeout(function(){ + clearInterval(interval); + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + }, 20); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout.html new file mode 100644 index 0000000000..cebcd4346c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in setTimeout</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + setTimeout("undefined_variable;", 10); + setTimeout(function(){ + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + }, 20); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-window-onerror.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-window-onerror.html new file mode 100644 index 0000000000..150a793b79 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-in-window-onerror.html @@ -0,0 +1,29 @@ +<!doctype html> +<html> + <head> + <title>runtime error in window.onerror</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var ran = 0; + window.onerror = function(){ + ran++; + undefined_variable_in_onerror; + }; + </script> + <script> + undefined_variable; + </script> + <script> + t.step(function(){ + assert_equals(ran, 1, 'ran'); + t.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-same-origin-with-hash.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-same-origin-with-hash.html new file mode 100644 index 0000000000..dc6ec059a5 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-same-origin-with-hash.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in <script src=...> with hash</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, document.querySelector('script[src="support/undefined-variable.js#"]').src, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script src="support/undefined-variable.js#"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-same-origin.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-same-origin.html new file mode 100644 index 0000000000..8f3cfb70b2 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error-same-origin.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in <script src=...></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, document.querySelector('script[src="support/undefined-variable.js"]').src, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script src="support/undefined-variable.js"></script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error.html new file mode 100644 index 0000000000..7907494aa6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/runtime-error.html @@ -0,0 +1,38 @@ +<!doctype html> +<html> + <head> + <title>window.onerror - runtime error in <script></title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id=log></div> + <script> + setup({allow_uncaught_exception:true}); + var t = async_test(); + var t_col = async_test(document.title+' (column)'); + var ran = false; + var col_value; + window.onerror = t.step_func(function(a, b, c, d){ + ran = true; + col_value = d; + assert_equals(typeof a, 'string', 'first arg'); + assert_equals(b, location.href, 'second arg'); + assert_equals(typeof c, 'number', 'third arg'); + }); + </script> + <script> + undefined_variable; + </script> + <script> + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); + t_col.step(function(){ + assert_equals(typeof col_value, 'number', 'fourth arg'); + t_col.done(); + }); + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error-in-setInterval.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error-in-setInterval.js new file mode 100644 index 0000000000..afec114458 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error-in-setInterval.js @@ -0,0 +1,8 @@ +interval = setInterval('{', 10); +step_timeout(function(){ + clearInterval(interval); + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); +}, 20);
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error-in-setTimeout.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error-in-setTimeout.js new file mode 100644 index 0000000000..427542b42e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error-in-setTimeout.js @@ -0,0 +1,7 @@ +setTimeout('{', 10); +setTimeout(function(){ + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); +}, 20); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error.js new file mode 100644 index 0000000000..0f74a6fca6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/syntax-error.js @@ -0,0 +1 @@ +for (;) {}
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable-in-setInterval.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable-in-setInterval.js new file mode 100644 index 0000000000..c2a017a2ab --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable-in-setInterval.js @@ -0,0 +1,8 @@ +interval = setInterval('undefined_variable;', 10); +step_timeout(function(){ + clearInterval(interval); + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); +}, 20);
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable-in-setTimeout.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable-in-setTimeout.js new file mode 100644 index 0000000000..6fa54cda9f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable-in-setTimeout.js @@ -0,0 +1,7 @@ +setTimeout('undefined_variable;', 10); +setTimeout(function(){ + t.step(function(){ + assert_true(ran, 'ran'); + t.done(); + }); +}, 20); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable.js new file mode 100644 index 0000000000..e73a62ceda --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/support/undefined-variable.js @@ -0,0 +1 @@ +undefined_variable;
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/allow-crossorigin.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/allow-crossorigin.html new file mode 100644 index 0000000000..7524604113 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/allow-crossorigin.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/cors/support.js?pipe=sub"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> +<link rel="help" href="https://html.spec.whatwg.org/#muted-errors"> + +<body> +<script> +'use strict'; +setup({ + allow_uncaught_exception: true +}); + +async_test(function(t) { + addEventListener('unhandledrejection', t.step_func(function(e) { + assert_equals(e.reason, 42, 'reason should be the one given by the script'); + t.done(); + })); +}, 'Promise rejection event should be received for the cross-origin CORS script'); + +(function() { + var scriptEl = document.createElement('script'); + scriptEl.src = CROSSDOMAIN + 'support/promise-access-control.py?allow=true'; + scriptEl.crossOrigin = 'anonymous'; + document.body.appendChild(scriptEl); +}()); +</script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html new file mode 100644 index 0000000000..d61618a53e --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/disallow-crossorigin.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/cors/support.js?pipe=sub"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> +<link rel="help" href="https://html.spec.whatwg.org/#muted-errors"> + +<body> +<script> +'use strict'; + +setup({ + allow_uncaught_exception: true +}); + +(function() { + var resolveLoaded; + var loadedPromise = new Promise(function(resolve) { resolveLoaded = resolve; }); + + promise_test(function(t) { + var unreachedUnhandled = t.unreached_func('unhandledrejection event should never be triggered'); + var unreachedHandled = t.unreached_func('rejectionhandled event should never be triggered'); + + addEventListener('unhandledrejection', unreachedUnhandled); + addEventListener('rejectionhandled', unreachedHandled); + ensureCleanup(t, unreachedUnhandled, unreachedHandled); + + return loadedPromise.then(t.step_func(function() { + return new Promise(function(resolve) { + t.step_timeout(function() { + resolve(); + }, 1000); + }); + })); + }, 'Promise rejection event should be muted for cross-origin non-CORS script'); + + promise_test(function(t) { + var unreachedUnhandled = t.unreached_func('unhandledrejection event should never be triggered'); + var unreachedHandled = t.unreached_func('rejectionhandled event should never be triggered'); + + addEventListener('unhandledrejection', unreachedUnhandled); + addEventListener('rejectionhandled', unreachedHandled); + ensureCleanup(t, unreachedUnhandled, unreachedHandled); + + return new Promise(function(resolve) { + handleRejectedPromise(new Promise(function(resolve, reject) { reject(42); })); + t.step_timeout(function() { + resolve(); + }, 1000); + }); + }, 'Promise rejection should be muted if the rejected promise is handled in cross-origin non-CORS script'); + + promise_test(function(t) { + var promise = new Promise(function(resolve, reject) { reject(42); }); + var resolveReceived; + var eventPromise = new Promise(function(resolve) { resolveReceived = resolve; }); + var unhandled = t.step_func(function(e) { + if (e.promise === promise) { + handleRejectedPromise(promise); + resolveReceived(); + } + }); + var unreachedHandled = t.unreached_func('rejectionhandled event should never be triggered'); + + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', unreachedHandled); + ensureCleanup(t, unhandled, unreachedHandled); + + return eventPromise.then(t.step_func(function() { + return new Promise(function(resolve) { + t.step_timeout(function() { + resolve(); + }, 1000); + }); + })); + }, 'Promise rejection should be muted if the rejected promise is handled in unhandledrejection event handler in cross-origin non-CORS script'); + + function ensureCleanup(t, unhandled, handled) { + t.add_cleanup(function() { + if (unhandled) { + removeEventListener('unhandledrejection', unhandled); + } + if (handled) { + removeEventListener('rejectionhandled', handled); + } + }); + } + + var scriptEl = document.createElement('script'); + scriptEl.src = CROSSDOMAIN + 'support/promise-access-control.py?allow=false'; + scriptEl.onload = resolveLoaded; + document.body.appendChild(scriptEl); +}()); +</script> +</body> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-constructor.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-constructor.html new file mode 100644 index 0000000000..4319deee7b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-constructor.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#the-promiserejectionevent-interface"> +<script> +'use strict'; + +test(function() { + var p = new Promise(function(resolve, reject) {}); + + assert_throws_js(TypeError, + function() { + PromiseRejectionEvent('', { promise: p }); + }, + "Calling PromiseRejectionEvent constructor without 'new' must throw"); + + // No custom options are passed (besides required promise). + assert_equals(new PromiseRejectionEvent('eventType', { promise: p }).bubbles, false); + assert_equals(new PromiseRejectionEvent('eventType', { promise: p }).cancelable, false); + assert_equals(new PromiseRejectionEvent('eventType', { promise: p }).promise, p); + assert_equals(new PromiseRejectionEvent('eventType', { promise: p }).reason, undefined); + + // No promise is passed. + assert_throws_js(TypeError, + function() { + new PromiseRejectionEvent('eventType', { bubbles: false }); + }, + 'Cannot construct PromiseRejectionEventInit without promise'); + + // bubbles is passed. + assert_equals(new PromiseRejectionEvent('eventType', { bubbles: false, promise: p }).bubbles, false); + assert_equals(new PromiseRejectionEvent('eventType', { bubbles: true, promise: p }).bubbles, true); + + // cancelable is passed. + assert_equals(new PromiseRejectionEvent('eventType', { cancelable: false, promise: p }).cancelable, false); + assert_equals(new PromiseRejectionEvent('eventType', { cancelable: true, promise: p }).cancelable, true); + + // reason is passed. + var r = new Error(); + assert_equals(new PromiseRejectionEvent('eventType', { promise: p, reason: r }).reason, r); + assert_equals(new PromiseRejectionEvent('eventType', { promise: p, reason: null }).reason, null); + + // All initializers are passed. + assert_equals(new PromiseRejectionEvent('eventType', { bubbles: true, cancelable: true, promise: p, reason: r }).bubbles, true); + assert_equals(new PromiseRejectionEvent('eventType', { bubbles: true, cancelable: true, promise: p, reason: r }).cancelable, true); + assert_equals(new PromiseRejectionEvent('eventType', { bubbles: true, cancelable: true, promise: p, reason: r }).promise, p); + assert_equals(new PromiseRejectionEvent('eventType', { bubbles: true, cancelable: true, promise: p, reason: r }).reason, r); +}, "This tests the constructor for the PromiseRejectionEvent DOM class."); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse.html new file mode 100644 index 0000000000..160dad9b36 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-event-during-parse.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Promise rejection during initial parsing of document</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> +<body> +<p>The script in this test is executed immediately while parsing is ongoing, and +<a +href="https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-script">cleaning +up after running script</a> involves queueing a task on the DOM manipulation +task source to fire the <code>unhandledrejection</code> event. Parsing then +completes, immediately transitioning the document's readiness state to +"interactive," and queuing another task on the DOM manipulation task source to +transition the state to "complete." +</p> +<script> +'use strict'; +setup({ allow_uncaught_exception: true }); + +async_test(function(t) { + const events = []; + document.addEventListener('readystatechange', t.step_func(function() { + events.push('readystatechange:' + document.readyState); + })); + addEventListener('unhandledrejection', t.step_func(function() { + events.push('unhandledrejection'); + })); + + Promise.reject(new Error('this error is intentional')); + + addEventListener('load', t.step_func(function() { + assert_array_equals( + events, + [ + 'readystatechange:interactive', + 'unhandledrejection', + 'readystatechange:complete' + ] + ); + t.done(); + })); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-attached-in-event.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-attached-in-event.html new file mode 100644 index 0000000000..b151bd812f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-attached-in-event.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> +<script> +'use strict'; +setup({ + allow_uncaught_exception: true +}); +async_test(function(t) { + var e = new Error('e'); + var p = Promise.reject(e); + + window.onunhandledrejection = function(evt) { + t.step(function() { + assert_equals(evt.promise, p); + assert_equals(evt.reason, e); + }); + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + t.step_timeout(function() { t.done(); }, 10); + }); + }; + + window.onrejectionhandled = t.unreached_func('rejectionhandled event should not be invoked'); +}, 'Attaching a handler in unhandledrejection should not trigger rejectionhandled.'); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-iframe.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-iframe.html new file mode 100644 index 0000000000..c749eadef4 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-iframe.html @@ -0,0 +1,146 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<div id="log"></div><br> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +'use strict'; + +setup({ + allow_uncaught_exception: true +}); + +async_test(function(t) { + createIframeAndStartTest(t, function(w) { + let e = new Error(); + let promise = new w.Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); + + let unhandled = function(evt) { + if (evt.promise === promise) { + t.step(function() { + assert_equals(evt.reason, e); + assert_equals(evt.promise, promise); + }); + t.done(); + } + }; + let handled = function(evt) { + if (evt.promise === promise) { + t.step(function() { + assert_unreached('rejectionhandled event is not supposed to be triggered'); + }); + } + }; + + w.addEventListener('unhandledrejection', unhandled); + w.addEventListener('rejectionhandled', handled); + ensureCleanup(t, w, unhandled, handled); + }); +}, "unhandledrejection: promise is created in iframe and being rejected elsewhere"); + +async_test(function(t) { + createIframeAndStartTest(t, function(w) { + let e = new Error(); + let promise = w.Promise.reject(e); + + let unhandled = function(evt) { + if (evt.promise === promise) { + t.step(function() { + assert_unreached('unhandledrejection event is not supposed to be triggered'); + }); + } + }; + let handled = function(evt) { + if (evt.promise === promise) { + t.step(function() { + assert_unreached('rejectionhandled event is not supposed to be triggered'); + }); + } + }; + + w.addEventListener('unhandledrejection', unhandled); + w.addEventListener('rejectionhandled', handled); + ensureCleanup(t, w, unhandled, handled); + + promise.catch(function() {}); + setTimeout(function() { + t.done(); + }, 10); + }); +}, 'no unhandledrejection/rejectionhandled: promise is created in iframe and being rejected elsewhere'); + +async_test(function(t) { + createIframeAndStartTest(t, function(w) { + let e = new Error(); + let promise = w.Promise.reject(e); + var unhandledPromises = []; + var unhandledReasons = []; + var handledPromises = []; + var handledReasons = []; + + let unhandled = function(evt) { + if (evt.promise === promise) { + t.step(function() { + unhandledPromises.push(evt.promise); + unhandledReasons.push(evt.reason); + + setTimeout(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + promise.then(unreached, function(reason) { + assert_equals(reason, e); + setTimeout(function() { + assert_array_equals(handledPromises, [promise]); + assert_array_equals(handledReasons, [e]); + t.done(); + }, 10); + }); + }, 10); + }); + } + }; + let handled = function(evt) { + if (evt.promise === promise) { + t.step(function() { + assert_array_equals(unhandledPromises, [promise]); + assert_array_equals(unhandledReasons, [e]); + handledPromises.push(evt.promise); + handledReasons.push(evt.reason); + }); + } + }; + + w.addEventListener('unhandledrejection', unhandled); + w.addEventListener('rejectionhandled', handled); + ensureCleanup(t, w, unhandled, handled); + }); +}, 'delayed handling: promise is created in iframe and being rejected elsewhere'); + +// Helpers + +function createIframeAndStartTest(t, runTest) { + var iframe = document.createElement("iframe"); + iframe.onload = function() { + t.add_cleanup(() => iframe.remove()); + runTest(iframe.contentWindow); + }; + iframe.srcdoc = ''; + document.documentElement.appendChild(iframe); +} + +function ensureCleanup(t, win, unhandled, handled) { + t.add_cleanup(function() { + if (unhandled) { + win.removeEventListener('unhandledrejection', unhandled); + } + if (handled) { + win.removeEventListener('rejectionhandled', handled); + } + }); +} + +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html new file mode 100644 index 0000000000..b6c02d27c9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events-onerror.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#runtime-script-errors"> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> +<script> +'use strict'; +setup({ + allow_uncaught_exception: true +}); +async_test(function(t) { + var e = new Error('e'); + var e2 = new Error('e2'); + + window.onerror = function (msg, url, line, col, error) { + t.step(function() { + assert_true(msg.includes('e2')); + assert_equals(error, e2); + }); + t.done(); + }; + + window.onrejectionhandled = function() { + // This should cause onerror + throw e2; + }; + + var p = Promise.reject(e); + queueTask(function() { + queueTask(t.step_func(function() { + // This will cause onrejectionhandled + p.catch(function() {}); + })); + }); +}, 'Throwing inside an unhandledrejection handler invokes the error handler.'); + +// This function queues a task in "DOM manipulation task source" +function queueTask(f) { + var d = document.createElement("details"); + d.ontoggle = function() { + f(); + }; + + d.setAttribute("open", ""); +} +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.dedicatedworker.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.dedicatedworker.html new file mode 100644 index 0000000000..b6a4a9f3e6 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.dedicatedworker.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Promise rejection events tests: in a dedicated worker context</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> + +<script> +'use strict'; +fetch_tests_from_worker(new Worker('support/promise-rejection-events.js')); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.html new file mode 100644 index 0000000000..2fdfe26025 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Promise rejection events tests: in a Window context</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> + +<script src="support/promise-rejection-events.js"></script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.serviceworker.https.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.serviceworker.https.html new file mode 100644 index 0000000000..9d12125928 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.serviceworker.https.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Promise rejection events tests: in a service worker context</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> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> + +<script> +'use strict'; +service_worker_test('support/promise-rejection-events.js', 'Service worker setup'); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.sharedworker.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.sharedworker.html new file mode 100644 index 0000000000..d832d1822f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.sharedworker.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Promise rejection events tests: in a shared worker context</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/#unhandled-promise-rejections"> + +<script> +'use strict'; +fetch_tests_from_worker(new SharedWorker('support/promise-rejection-events.js')); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-resolution-order.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-resolution-order.html new file mode 100644 index 0000000000..314063025f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-resolution-order.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Promise rejection ordering</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint"> +<body> +<p>A microtask checkpoint should notify about rejected promises. After +<a +href="https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-script">cleaning +up after running script</a> involves running a microtask checkpoint. So the order of unhandledrejection +should occur before error2. +</p> + +<script> +'use strict'; +setup({ allow_uncaught_exception: true }); + +async_test(function(t) { + const events = []; + addEventListener('unhandledrejection', t.step_func(() => { + events.push('unhandledrejection'); + })); + + function insertInvalidScript(id) { + // Inserting <script> with an empty source schedules dispatching an 'error' event on + // the dom manipulation task source. + let script = document.createElement('script'); + script.setAttribute('src', ' '); + script.addEventListener('error', t.step_func(() => { + events.push(`error${id}`); + + // This will be the end of the test. Verify the results are correct. + if (id == 2) { + assert_array_equals( + events, + [ + 'raf1', + 'resolve1', + 'raf2', + 'resolve2', + 'error1', + 'unhandledrejection', + 'error2' + ] + ); + t.done(); + } + })); + document.body.append(script); + } + + requestAnimationFrame(t.step_func(() => { + events.push('raf1'); + Promise.reject(); + Promise.resolve(0).then(t.step_func(() => { + events.push('resolve1'); + })); + insertInvalidScript(1); + })); + + requestAnimationFrame(t.step_func(() => { + events.push('raf2'); + Promise.resolve(0).then(t.step_func(() => { + events.push('resolve2'); + })); + insertInvalidScript(2); + })); +}); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py new file mode 100644 index 0000000000..cf8ed5e492 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py @@ -0,0 +1,18 @@ +def main(request, response): + allow = request.GET.first(b"allow", b"false") + + headers = [(b"Content-Type", b"application/javascript")] + if allow != b"false": + headers.append((b"Access-Control-Allow-Origin", b"*")) + + body = b""" + function handleRejectedPromise(promise) { + promise.catch(() => {}); + } + + (function() { + new Promise(function(resolve, reject) { reject(42); }); + })(); + """ + + return headers, body diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js new file mode 100644 index 0000000000..036e1784db --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js @@ -0,0 +1,961 @@ +'use strict'; + +if (self.importScripts) { + importScripts('/resources/testharness.js'); +} + +setup({ + allow_uncaught_exception: true +}); + +// +// Straightforward unhandledrejection tests +// +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.reject(e); +}, 'unhandledrejection: from Promise.reject'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = new Promise(function(_, reject) { + reject(e); + }); +}, 'unhandledrejection: from a synchronous rejection in new Promise'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = new Promise(function(_, reject) { + queueTask(function() { + reject(e); + }); + }); +}, 'unhandledrejection: from a task-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); +}, 'unhandledrejection: from a setTimeout-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var e2 = new Error(); + var promise2; + + onUnhandledSucceed(t, e2, function() { return promise2; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + promise2 = Promise.reject(e).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + throw e2; + }); +}, 'unhandledrejection: from a throw in a rejection handler chained off of Promise.reject'); + +async_test(function(t) { + var e = new Error(); + var e2 = new Error(); + var promise2; + + onUnhandledSucceed(t, e2, function() { return promise2; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + promise2 = new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + throw e2; + }); +}, 'unhandledrejection: from a throw in a rejection handler chained off of a setTimeout-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var e2 = new Error(); + var promise2; + + onUnhandledSucceed(t, e2, function() { return promise2; }); + + var promise = new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + promise2 = promise.then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + throw e2; + }); + }); + }, 1); + }); +}, 'unhandledrejection: from a throw in a rejection handler attached one microtask after a setTimeout-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.resolve().then(function() { + return Promise.reject(e); + }); +}, 'unhandledrejection: from returning a Promise.reject-created rejection in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.resolve().then(function() { + throw e; + }); +}, 'unhandledrejection: from a throw in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.resolve().then(function() { + return new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); + }); +}, 'unhandledrejection: from returning a setTimeout-delayed rejection in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.all([Promise.reject(e)]); +}, 'unhandledrejection: from Promise.reject, indirected through Promise.all'); + +async_test(function(t) { + var p; + + var unhandled = function(ev) { + if (ev.promise === p) { + t.step(function() { + assert_equals(ev.reason.name, 'InvalidStateError'); + assert_equals(ev.promise, p); + }); + t.done(); + } + }; + addEventListener('unhandledrejection', unhandled); + ensureCleanup(t, unhandled); + + p = createImageBitmap(new Blob()); +}, 'unhandledrejection: from createImageBitmap which is UA triggered'); + +// +// Negative unhandledrejection/rejectionhandled tests with immediate attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.reject(e).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise from Promise.reject'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.all([Promise.reject(e)]).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise from ' + + 'Promise.reject, indirecting through Promise.all'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = new Promise(function(_, reject) { + reject(e); + }).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a synchronously-rejected ' + + 'promise created with new Promise'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.resolve().then(function() { + throw e; + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + }); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'throwing in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.resolve().then(function() { + return Promise.reject(e); + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + }); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'returning a Promise.reject-created promise in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.resolve().then(function() { + return new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + }); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'returning a setTimeout-delayed rejection in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + p = Promise.resolve().then(function() { + return Promise.reject(e); + }) + .catch(function() {}); + }); +}, 'no unhandledrejection/rejectionhandled: all inside a queued task, a rejection handler attached synchronously to ' + + 'a promise created from returning a Promise.reject-created promise in a fulfillment handler'); + +async_test(function(t) { + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = createImageBitmap(new Blob()).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'createImageBitmap'); + +// +// Negative unhandledrejection/rejectionhandled tests with microtask-delayed attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); +}, 'delayed handling: a microtask delay before attaching a handler prevents both events (Promise.reject-created ' + + 'promise)'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = new Promise(function(_, reject) { + reject(e); + }); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); +}, 'delayed handling: a microtask delay before attaching a handler prevents both events (immediately-rejected new ' + + 'Promise-created promise)'); + +async_test(function(t) { + var e = new Error(); + var p1; + var p2; + + onUnhandledFail(t, function() { return p1; }); + onUnhandledFail(t, function() { return p2; }); + + p1 = new Promise(function(_, reject) { + mutationObserverMicrotask(function() { + reject(e); + }); + }); + p2 = Promise.all([p1]); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p2.then(unreached, function() {}); + }); +}, 'delayed handling: a microtask delay before attaching the handler, and before rejecting the promise, indirected ' + + 'through Promise.all'); + +// +// Negative unhandledrejection/rejectionhandled tests with nested-microtask-delayed attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of mutationObserverMicrotask + promise microtasks'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + p = Promise.reject(e); + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of mutationObserverMicrotask + promise microtasks, ' + + 'all inside a queueTask'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + setTimeout(function() { + p = Promise.reject(e); + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }, 0); +}, 'microtask nesting: attaching a handler inside a combination of mutationObserverMicrotask + promise microtasks, ' + + 'all inside a setTimeout'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + p.catch(function() {}); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of promise microtasks + mutationObserverMicrotask'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + p = Promise.reject(e); + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of promise microtasks + mutationObserverMicrotask, ' + + 'all inside a queueTask'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + setTimeout(function() { + p = Promise.reject(e); + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + p.catch(function() {}); + }); + }); + }); + }); + }, 0); +}, 'microtask nesting: attaching a handler inside a combination of promise microtasks + mutationObserverMicrotask, ' + + 'all inside a setTimeout'); + + +// For workers, queueTask() involves posting tasks to other threads, so +// the following tests don't work there. + +if ('document' in self) { + // + // Negative unhandledrejection/rejectionhandled tests with task-delayed attachment + // + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var _reject; + p = new Promise(function(_, reject) { + _reject = reject; + }); + _reject(e); + queueTask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); + }, 'delayed handling: a task delay before attaching a handler prevents unhandledrejection'); + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }, 'delayed handling: queueTask after promise creation/rejection, plus promise microtasks, is not too late to ' + + 'attach a rejection handler'); + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + p = Promise.reject(e); + }, 'delayed handling: queueTask before promise creation/rejection, plus many promise microtasks, is not too ' + + 'late to attach a rejection handler'); + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + }, 'delayed handling: queueTask after promise creation/rejection, plus many promise microtasks, is not too ' + + 'late to attach a rejection handler'); +} + +// +// Positive unhandledrejection/rejectionhandled tests with delayed attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + var _reject; + p = new Promise(function(_, reject) { + _reject = reject; + }); + _reject(e); + queueTask(function() { + queueTask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); + }); +}, 'delayed handling: a nested-task delay before attaching a handler causes unhandledrejection'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + queueTask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); +}, 'delayed handling: a nested-queueTask after promise creation/rejection, plus promise microtasks, is too ' + + 'late to attach a rejection handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + queueTask(function() { + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + }); + p = Promise.reject(e); +}, 'delayed handling: a nested-queueTask before promise creation/rejection, plus many promise microtasks, is ' + + 'too late to attach a rejection handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + }); +}, 'delayed handling: a nested-queueTask after promise creation/rejection, plus many promise microtasks, is ' + + 'too late to attach a rejection handler'); + +async_test(function(t) { + var unhandledPromises = []; + var unhandledReasons = []; + var e = new Error(); + var p; + + var unhandled = function(ev) { + if (ev.promise === p) { + t.step(function() { + unhandledPromises.push(ev.promise); + unhandledReasons.push(ev.reason); + }); + } + }; + var handled = function(ev) { + if (ev.promise === p) { + t.step(function() { + assert_array_equals(unhandledPromises, [p]); + assert_array_equals(unhandledReasons, [e]); + assert_equals(ev.promise, p); + assert_equals(ev.reason, e); + }); + } + }; + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + + p = new Promise(function() { + throw e; + }); + setTimeout(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function(reason) { + assert_equals(reason, e); + setTimeout(function() { t.done(); }, 10); + }); + }, 10); +}, 'delayed handling: delaying handling by setTimeout(,10) will cause both events to fire'); + +async_test(function(t) { + var unhandledPromises = []; + var unhandledReasons = []; + var p; + + var unhandled = function(ev) { + if (ev.promise === p) { + t.step(function() { + unhandledPromises.push(ev.promise); + unhandledReasons.push(ev.reason.name); + }); + } + }; + var handled = function(ev) { + if (ev.promise === p) { + t.step(function() { + assert_array_equals(unhandledPromises, [p]); + assert_array_equals(unhandledReasons, ['InvalidStateError']); + assert_equals(ev.promise, p); + assert_equals(ev.reason.name, 'InvalidStateError'); + }); + } + }; + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + + p = createImageBitmap(new Blob()); + setTimeout(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function(reason) { + assert_equals(reason.name, 'InvalidStateError'); + setTimeout(function() { t.done(); }, 10); + }); + }, 10); +}, 'delayed handling: delaying handling rejected promise created from createImageBitmap will cause both events to fire'); + +// +// Miscellaneous tests about integration with the rest of the platform +// + +async_test(function(t) { + var e = new Error(); + var l = function(ev) { + var order = []; + mutationObserverMicrotask(function() { + order.push(1); + }); + setTimeout(function() { + order.push(2); + t.step(function() { + assert_array_equals(order, [1, 2]); + }); + t.done(); + }, 1); + }; + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); + Promise.reject(e); +}, 'mutationObserverMicrotask vs. queueTask ordering is not disturbed inside unhandledrejection events'); + +// For workers, queueTask() involves posting tasks to other threads, so +// the following tests don't work there. + +if ('document' in self) { + + // For the next two see https://github.com/domenic/unhandled-rejections-browser-spec/issues/2#issuecomment-121121695 + // and the following comments. + + async_test(function(t) { + var sequenceOfEvents = []; + + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); + + var p1 = Promise.reject(); + var p2; + queueTask(function() { + p2 = Promise.reject(); + queueTask(function() { + sequenceOfEvents.push('queueTask'); + checkSequence(); + }); + }); + + function l(ev) { + if (ev.promise === p1 || ev.promise === p2) { + sequenceOfEvents.push(ev.promise); + checkSequence(); + } + } + + function checkSequence() { + if (sequenceOfEvents.length === 3) { + t.step(function() { + assert_array_equals(sequenceOfEvents, [p1, 'queueTask', p2]); + }); + t.done(); + } + } + }, 'queueTask ordering vs. the task queued for unhandled rejection notification (1)'); + + async_test(function(t) { + var sequenceOfEvents = []; + + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); + + var p2; + queueTask(function() { + p2 = Promise.reject(); + queueTask(function() { + sequenceOfEvents.push('queueTask'); + checkSequence(); + }); + }); + + function l(ev) { + if (ev.promise == p2) { + sequenceOfEvents.push(ev.promise); + checkSequence(); + } + } + + function checkSequence() { + if (sequenceOfEvents.length === 2) { + t.step(function() { + assert_array_equals(sequenceOfEvents, ['queueTask', p2]); + }); + t.done(); + } + } + }, 'queueTask ordering vs. the task queued for unhandled rejection notification (2)'); + + async_test(function(t) { + var sequenceOfEvents = []; + + + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + + var p = Promise.reject(); + + function unhandled(ev) { + if (ev.promise === p) { + sequenceOfEvents.push('unhandled'); + checkSequence(); + setTimeout(function() { + queueTask(function() { + sequenceOfEvents.push('task before catch'); + checkSequence(); + }); + + p.catch(function() { + sequenceOfEvents.push('catch'); + checkSequence(); + }); + + queueTask(function() { + sequenceOfEvents.push('task after catch'); + checkSequence(); + }); + + sequenceOfEvents.push('after catch'); + checkSequence(); + }, 10); + } + } + + function handled(ev) { + if (ev.promise === p) { + sequenceOfEvents.push('handled'); + checkSequence(); + } + } + + function checkSequence() { + if (sequenceOfEvents.length === 6) { + t.step(function() { + assert_array_equals(sequenceOfEvents, + ['unhandled', 'after catch', 'catch', 'task before catch', 'handled', 'task after catch']); + }); + t.done(); + } + } + }, 'rejectionhandled is dispatched from a queued task, and not immediately'); +} + +// +// HELPERS +// + +// This function queues a task in "DOM manipulation task source" in window +// context, but not in workers. +function queueTask(f) { + if ('document' in self) { + var d = document.createElement("details"); + d.ontoggle = function() { + f(); + }; + d.setAttribute("open", ""); + } else { + // We need to fix this to use something that can queue tasks in + // "DOM manipulation task source" to ensure the order is correct + var channel = new MessageChannel(); + channel.port1.onmessage = function() { channel.port1.close(); f(); }; + channel.port2.postMessage('abusingpostmessageforfunandprofit'); + channel.port2.close(); + } +} + +function mutationObserverMicrotask(f) { + if ('document' in self) { + var observer = new MutationObserver(function() { f(); }); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + node.data = 'foo'; + } else { + // We don't have mutation observers on workers, so just post a promise-based + // microtask. + Promise.resolve().then(function() { f(); }); + } +} + +function onUnhandledSucceed(t, expectedReason, expectedPromiseGetter) { + var l = function(ev) { + if (ev.promise === expectedPromiseGetter()) { + t.step(function() { + assert_equals(ev.reason, expectedReason); + assert_equals(ev.promise, expectedPromiseGetter()); + }); + t.done(); + } + }; + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); +} + +function onUnhandledFail(t, expectedPromiseGetter) { + var unhandled = function(evt) { + if (evt.promise === expectedPromiseGetter()) { + t.step(function() { + assert_unreached('unhandledrejection event is not supposed to be triggered'); + }); + } + }; + var handled = function(evt) { + if (evt.promise === expectedPromiseGetter()) { + t.step(function() { + assert_unreached('rejectionhandled event is not supposed to be triggered'); + }); + } + }; + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + setTimeout(function() { + t.done(); + }, 10); +} + +function ensureCleanup(t, unhandled, handled) { + t.add_cleanup(function() { + if (unhandled) + removeEventListener('unhandledrejection', unhandled); + if (handled) + removeEventListener('rejectionhandled', handled); + }); +} + +done(); diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-parse-error.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-parse-error.html new file mode 100644 index 0000000000..3c21df49c9 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-parse-error.html @@ -0,0 +1,40 @@ +<!doctype html> +<html> + <head> + <title>window.onerror: parse errors</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- + + In https://html.spec.whatwg.org/multipage/#creating-scripts , + step 3 describes parsing the script, and step 5 says: + # Otherwise, report the error using the onerror event handler of + # the script's global object. If the error is still not handled + # after this, then the error may be reported to the user. + which links to + https://html.spec.whatwg.org/multipage/#report-the-error , + which describes what to do when onerror is a Function. + + --> + </head> + <body> + + <div id="log"></div> + <script> + setup({allow_uncaught_exception:true}); + var error_count = 0; + window.onerror = function(msg, url, lineno) { + ++error_count; + test(function() {assert_equals(url, window.location.href)}, + "correct url passed to window.onerror"); + test(function() {assert_equals(lineno, 34)}, + "correct line number passed to window.onerror"); + }; + </script> + <script>This script does not parse correctly.</script> + <script> + test(function() {assert_equals(error_count, 1)}, + "correct number of calls to window.onerror"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-runtime-error-throw.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-runtime-error-throw.html new file mode 100644 index 0000000000..4b2bc1f22c --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-runtime-error-throw.html @@ -0,0 +1,43 @@ +<!doctype html> +<html> + <head> + <title>window.onerror: runtime scripterrors</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- + + https://html.spec.whatwg.org/multipage/#runtime-script-errors + says what to do for uncaught runtime script errors, and just below + describes what to do when onerror is a Function. + + --> + </head> + <body> + + <div id="log"></div> + <script> + setup({allow_uncaught_exception:true}); + var error_count = 0; + window.onerror = function(msg, url, lineno) { + ++error_count; + test(function() {assert_equals(url, window.location.href)}, + "correct url passed to window.onerror"); + test(function() {assert_equals(lineno, 36)}, + "correct line number passed to window.onerror"); + }; + </script> + <script> + try { + // This error is caught, so it should NOT trigger onerror. + throw "foo"; + } catch (ex) { + } + // This error is NOT caught, so it should trigger onerror. + throw "bar"; + </script> + <script> + test(function() {assert_equals(error_count, 1)}, + "correct number of calls to window.onerror"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-runtime-error.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-runtime-error.html new file mode 100644 index 0000000000..1fdab521ae --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-runtime-error.html @@ -0,0 +1,43 @@ +<!doctype html> +<html> + <head> + <title>window.onerror: runtime scripterrors</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- + + https://html.spec.whatwg.org/multipage/#runtime-script-errors + says what to do for uncaught runtime script errors, and just below + describes what to do when onerror is a Function. + + --> + </head> + <body> + + <div id="log"></div> + <script> + setup({allow_uncaught_exception:true}); + var error_count = 0; + window.onerror = function(msg, url, lineno) { + ++error_count; + test(function() {assert_equals(url, window.location.href)}, + "correct url passed to window.onerror"); + test(function() {assert_equals(lineno, 36)}, + "correct line number passed to window.onerror"); + }; + </script> + <script> + try { + // This error is caught, so it should NOT trigger onerror. + window.nonexistentproperty.oops(); + } catch (ex) { + } + // This error is NOT caught, so it should trigger onerror. + window.nonexistentproperty.oops(); + </script> + <script> + test(function() {assert_equals(error_count, 1)}, + "correct number of calls to window.onerror"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-1.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-1.html new file mode 100644 index 0000000000..65a1a02b11 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-1.html @@ -0,0 +1,33 @@ +<!doctype html> +<meta charset=utf-8> +<title> + When a listener from window A is added to an event target in window B via the + addEventListener function from window B, errors in that listener should be + reported to window A. +</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe></iframe> +<iframe></iframe> +<script> +test(function() { + var f = new frames[0].Function("thereIsNoSuchCallable()"); + frames[1].document.addEventListener("myevent", f); + var frame0ErrorFired = false; + var frame1ErrorFired = false; + var ourErrorFired = false; + frames[0].addEventListener("error", function() { + frame0ErrorFired = true; + }); + frames[1].addEventListener("error", function() { + frame1ErrorFired = true; + }); + addEventListener("error", function() { + ourErrorFired = true; + }); + frames[1].document.dispatchEvent(new Event("myevent")); + assert_true(frame0ErrorFired); + assert_false(frame1ErrorFired); + assert_false(ourErrorFired); +}, "The error event from an event listener should fire on that listener's global"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-2.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-2.html new file mode 100644 index 0000000000..6c5476542b --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-2.html @@ -0,0 +1,33 @@ +<!doctype html> +<meta charset=utf-8> +<title> + When a listener from window A is added to an event target in window B via the + addEventListener function from window A, errors in that listener should be + reported to window A. +</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe></iframe> +<iframe></iframe> +<script> +test(function() { + var f = new frames[0].Function("thereIsNoSuchCallable()"); + frames[0].document.addEventListener.call(frames[1].document, "myevent", f); + var frame0ErrorFired = false; + var frame1ErrorFired = false; + var ourErrorFired = false; + frames[0].addEventListener("error", function() { + frame0ErrorFired = true; + }); + frames[1].addEventListener("error", function() { + frame1ErrorFired = true; + }); + addEventListener("error", function() { + ourErrorFired = true; + }); + frames[1].document.dispatchEvent(new Event("myevent")); + assert_true(frame0ErrorFired); + assert_false(frame1ErrorFired); + assert_false(ourErrorFired); +}, "The error event from an event listener should fire on that listener's global"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-3.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-3.html new file mode 100644 index 0000000000..5e78baa8de --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-3.html @@ -0,0 +1,33 @@ +<!doctype html> +<meta charset=utf-8> +<title> + When a listener from window A is added to an event target in window A via the + addEventListener function from window A, errors in that listener should be + reported to window A. +</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe></iframe> +<iframe></iframe> +<script> +test(function() { + var f = new frames[1].Function("thereIsNoSuchCallable()"); + frames[1].document.addEventListener("myevent", f); + var frame0ErrorFired = false; + var frame1ErrorFired = false; + var ourErrorFired = false; + frames[0].addEventListener("error", function() { + frame0ErrorFired = true; + }); + frames[1].addEventListener("error", function() { + frame1ErrorFired = true; + }); + addEventListener("error", function() { + ourErrorFired = true; + }); + frames[1].document.dispatchEvent(new Event("myevent")); + assert_false(frame0ErrorFired); + assert_true(frame1ErrorFired); + assert_false(ourErrorFired); +}, "The error event from an event listener should fire on that listener's global"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-4.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-4.html new file mode 100644 index 0000000000..a5f35d613f --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-4.html @@ -0,0 +1,33 @@ +<!doctype html> +<meta charset=utf-8> +<title> + When a listener from window A is added to an event target in window A via the + addEventListener function from window B, errors in that listener should be + reported to window A. +</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe></iframe> +<iframe></iframe> +<script> +test(function() { + var f = new frames[1].Function("thereIsNoSuchCallable()"); + frames[0].document.addEventListener.call(frames[1].document, "myevent", f); + var frame0ErrorFired = false; + var frame1ErrorFired = false; + var ourErrorFired = false; + frames[0].addEventListener("error", function() { + frame0ErrorFired = true; + }); + frames[1].addEventListener("error", function() { + frame1ErrorFired = true; + }); + addEventListener("error", function() { + ourErrorFired = true; + }); + frames[1].document.dispatchEvent(new Event("myevent")); + assert_false(frame0ErrorFired); + assert_true(frame1ErrorFired); + assert_false(ourErrorFired); +}, "The error event from an event listener should fire on that listener's global"); +</script> diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-5.html b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-5.html new file mode 100644 index 0000000000..da93e782ca --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/window-onerror-with-cross-frame-event-listeners-5.html @@ -0,0 +1,25 @@ +<!doctype html> +<meta charset=utf-8> +<title>window.onerror listener reports the exception in global object of its callback</title> +<link rel=help href="https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe></iframe> +<iframe></iframe> +<iframe></iframe> +<script> +setup({ allow_uncaught_exception: true }); + +window.onload = () => { + test(() => { + window.onerrorCalls = []; + window.onerror = () => { onerrorCalls.push("top"); }; + frames[0].onerror = new frames[1].Function(`top.onerrorCalls.push("frame0"); throw new parent.frames[2].Error("PASS");`); + frames[1].onerror = () => { onerrorCalls.push("frame1"); }; + frames[2].onerror = () => { onerrorCalls.push("frame2"); }; + + frames[0].dispatchEvent(new ErrorEvent("error", { error: new Error("foo") })); + assert_array_equals(onerrorCalls, ["frame0", "frame1"]); + }); +}; +</script> |