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/semantics/scripting-1/the-script-element/module | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module')
264 files changed, 5020 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js new file mode 100644 index 0000000000..a53a3bebe7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js @@ -0,0 +1,3 @@ +import "string-without-dot-slash-prefix"; +import "./this.js"; +log.push("bad-module-specifier"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html new file mode 100644 index 0000000000..7cd4916309 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Root module scripts should always use UTF-8</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module" src="../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript&dummy=1"></script> +<script type="module"> +test(function() { + assert_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'UTF-8 module script'); +</script> + +<script type="module" src="../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript&dummy=2" charset="windows-1250"></script> +<script type="module"> +test(function() { + assert_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'UTF-8 module script with wrong charset in attribute'); +</script> + +<script type="module" src="../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript%3Bcharset=windows-1250&dummy=3"></script> +<script type="module"> +test(function() { + assert_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'UTF-8 module script with wrong charset in Content-Type'); +</script> + +<script type="module" src="../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript&dummy=1"></script> +<script type="module"> +test(function() { + assert_not_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'Non-UTF-8 module script'); +</script> + +<script type="module" src="../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript&dummy=2" charset="windows-1250"></script> +<script type="module"> +test(function() { + assert_not_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'Non-UTF-8 module script with charset in attribute'); +</script> + +<script type="module" src="../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript%3Bcharset=windows-1250"></script> +<script type="module"> +test(function() { + assert_not_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'Non-UTF-8 module script with charset in Content-Type'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html new file mode 100644 index 0000000000..c7c4517ad3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>Module scripts should ignore BOMs and always use UTF-8</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +setup({allow_uncaught_exception: true}); +</script> +<script type="module" src="../serve-with-content-type.py?fn=resources/bom-utf-8.js&ct=text/javascript"></script> +<script type="module" src="../serve-with-content-type.py?fn=resources/bom-utf-16be.js&ct=text/javascript"></script> +<script type="module" src="../serve-with-content-type.py?fn=resources/bom-utf-16le.js&ct=text/javascript"></script> +<script type="module"> +test(function() { + assert_equals(window.executed_utf8_bom, '\u4e09\u6751\u304b\u306a\u5b50', + 'Should be decoded as UTF-8'); +}, 'UTF-8 module script with UTF-8 BOM'); + +test(function() { + assert_equals(window.executed_utf16be_bom, undefined, + 'Should result in compile error because of UTF-16BE BOM'); +}, 'UTF-16 module script with UTF-16BE BOM'); + +test(function() { + assert_equals(window.executed_utf16le_bom, undefined, + 'Should result in compile error because of UTF-16LE BOM'); +}, 'UTF-16 module script with UTF-16LE BOM'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html new file mode 100644 index 0000000000..666cb2e68b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Imported module scripts should always use UTF-8</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script type="module" src="resources/import-utf8.js"></script> +<script type="module"> +test(function() { + assert_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'UTF-8 imported module script'); +</script> + +<script type="module" src="resources/import-utf8-with-charset-header.js"></script> +<script type="module"> +test(function() { + assert_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'UTF-8 imported module script with wrong charset in Content-Type'); +</script> + +<script type="module" src="resources/import-non-utf8.js"></script> +<script type="module"> +test(function() { + assert_not_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'Non-UTF-8 imported module script'); +</script> + +<script type="module" src="resources/import-non-utf8-with-charset-header.js"></script> +<script type="module"> +test(function() { + assert_not_equals(window.getSomeString(), "śćążź", + 'Should be decoded as UTF-8'); +}, 'Non-UTF-8 imported module script with charset in Content-Type'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html new file mode 100644 index 0000000000..50933da2c1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Choice of parse errors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Parse errors in different files should be reported " + + "depending on different roots"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 4); + + // Two different parse errors from different module scripts + // should be reported for each <script> element. + assert_equals(log[0].constructor, SyntaxError); + assert_equals(log[1], 1); + + assert_equals(log[2].constructor, SyntaxError); + assert_equals(log[3], 2); + + assert_not_equals(log[0], log[2], + 'two different parse errors should be reported'); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./choice-of-error-1a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./choice-of-error-1b.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js new file mode 100644 index 0000000000..f479e5e1fa --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js @@ -0,0 +1,2 @@ +import './choice-of-error-1b.js'; +import './syntaxerror.js?1c'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js new file mode 100644 index 0000000000..257f4a4678 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js @@ -0,0 +1,2 @@ +import './choice-of-error-1a.js'; +import './syntaxerror.js?1d'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html new file mode 100644 index 0000000000..51adb09d11 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Choice of instantiation errors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Instantiation errors in different files should be reported " + + "depending on different roots"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 4); + + // Two different instantiation errors from different module scripts + // should be reported for each <script> element. + assert_equals(log[0].constructor, SyntaxError); + assert_equals(log[1], 1); + + assert_equals(log[2].constructor, SyntaxError); + assert_equals(log[3], 2); + + assert_not_equals(log[0], log[2], + 'two different instantiation errors should be reported'); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./choice-of-error-2a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./choice-of-error-2b.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js new file mode 100644 index 0000000000..2dc7aac11a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js @@ -0,0 +1,2 @@ +import './choice-of-error-2b.js'; +import './instantiation-error-1.js?2c'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js new file mode 100644 index 0000000000..2adb9eea59 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js @@ -0,0 +1,2 @@ +import './choice-of-error-2a.js'; +import './instantiation-error-1.js?2d'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html new file mode 100644 index 0000000000..bc52119bfe --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<title>Choice of evaluation errors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Evaluation errors are cached in intermediate module scripts"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 5); + + // Evaluation errors, unlike parse/instantiation errors, are remembered + // and cached in module scripts between the root and the script that + // caused an evaluation error, and thus the same evaluation error + // is reported for both <script> elements. + assert_equals(log[0], "throw2"); + assert_true(log[1].bar); + assert_equals(log[2], 1); + + assert_true(log[3].bar); + assert_equals(log[4], 2); + + assert_equals(log[1], log[3], 'evaluation errors must be the same'); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./choice-of-error-3a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./choice-of-error-3b.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js new file mode 100644 index 0000000000..71154674a3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js @@ -0,0 +1,2 @@ +import './choice-of-error-3b.js'; +import './throw.js?3c'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js new file mode 100644 index 0000000000..2131a35eff --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js @@ -0,0 +1,2 @@ +import './choice-of-error-3a.js'; +import './throw2.js?3d'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html new file mode 100644 index 0000000000..ff580d4899 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Handling of compilation errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that syntax errors lead to SyntaxError events on window, " + + "and that exceptions are remembered."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 5); + assert_equals(log[0].constructor, SyntaxError); + assert_true(log.every(exn => exn === log[0])); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html new file mode 100644 index 0000000000..131a6e439f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Handling of compilation errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that syntax errors lead to SyntaxError events on window, " + + "and that exceptions are remembered."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 5); + assert_equals(log[0].constructor, SyntaxError); + assert_true(log.every(exn => exn === log[0])); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script> +<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html new file mode 100644 index 0000000000..983961ae44 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +document.cookie = 'same=1'; + +const setCookiePromise = fetch( + 'http://{{domains[www2]}}:{{ports[http][0]}}/cookies/resources/set-cookie.py?name=cross&path=/html/semantics/scripting-1/the-script-element/module/', + { + mode: 'no-cors', + credentials: 'include', + }); + +const windowLoadPromise = new Promise(resolve => { + window.addEventListener('load', () => { + resolve(); + }); +}); + +promise_test(t => { + const iframe = document.createElement('iframe'); + + return Promise.all([setCookiePromise, windowLoadPromise]).then(() => { + const messagePromise = new Promise(resolve => { + window.addEventListener('message', event => { + resolve(); + }); + }); + + iframe.src = 'resources/credentials-iframe.sub.html'; + document.body.appendChild(iframe); + + return messagePromise; + }).then(() => { + const w = iframe.contentWindow; + + assert_equals(w.sameOriginNone, 'found', + 'Modules should be loaded with the credentials when the crossOrigin attribute is not specified and the target is same-origin'); + assert_equals(w.sameOriginAnonymous, 'found', + 'Modules should be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is same-origin'); + assert_equals(w.sameOriginUseCredentials, 'found', + 'Modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is same-origin'); + assert_equals(w.crossOriginNone, 'not found', + 'Modules should not be loaded with the credentials when the crossOrigin attribute is not specified and the target is cross-origin'); + assert_equals(w.crossOriginAnonymous, 'not found', + 'Modules should not be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is cross-origin'); + assert_equals(w.crossOriginUseCredentials, 'found', + 'Modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is cross-origin'); + + assert_equals(w.sameOriginNoneDescendant, 'found', + 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is not specified and the target is same-origin'); + assert_equals(w.sameOriginAnonymousDescendant, 'found', + 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is same-origin'); + assert_equals(w.sameOriginUseCredentialsDescendant, 'found', + 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is same-origin'); + assert_equals(w.crossOriginNoneDescendant, 'not found', + 'Descendant modules should not be loaded with the credentials when the crossOrigin attribute is not specified and the target is cross-origin'); + assert_equals(w.crossOriginAnonymousDescendant, 'not found', + 'Descendant modules should not be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is cross-origin'); + assert_equals(w.crossOriginUseCredentialsDescendant, 'found', + 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is cross-origin'); +}); +}, 'Modules should be loaded with or without the credentials based on the same-origin-ness and the crossOrigin attribute'); +</script> +<body> +</body> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js new file mode 100644 index 0000000000..59bf0fd42f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js @@ -0,0 +1,8 @@ +document._log = []; +window.addEventListener("error", function (ev) { + var errorSerialized = ev.lineno + "-" + ev.colno; + document._log.push(errorSerialized); +}); +window.addEventListener("load", function () { + document._log = document._log.join(","); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html new file mode 100644 index 0000000000..8eb3292e89 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-import-NoCORS</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-import-NoCORS</h1> + <script type="module" onerror="document._log.push('error');"> + + import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js"; + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html new file mode 100644 index 0000000000..cccb30f718 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-BlockedMissingHeader</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-BlockedMissingHeader</h1> + <script type="module" onerror="document._log.push('error');" crossorigin> + + import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js"; + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html new file mode 100644 index 0000000000..84f4de1d7e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-WithCORS</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-WithCORS</h1> + <script type="module" crossorigin> + + import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,*)"; + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html new file mode 100644 index 0000000000..5743a9e304 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-BlockedWrongHeader</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-BlockedWrongHeader</h1> + <script type="module" onerror="document._log.push('error');" crossorigin> + + import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,http://{{domains[www2]}}:{{ports[http][0]}})"; + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html new file mode 100644 index 0000000000..54d4354c53 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-NoCORS</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-NoCORS</h1> + <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js" onerror="document._log.push('error');"></script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html new file mode 100644 index 0000000000..03943002ba --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-BlockedMissingHeader</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-BlockedMissingHeader</h1> + <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js" onerror="document._log.push('error');" crossorigin></script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html new file mode 100644 index 0000000000..3ec839e9a9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-WithCORS</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-WithCORS</h1> + <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,*)" crossorigin></script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html new file mode 100644 index 0000000000..c45736a896 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-crossOrigin-root-BlockedWrongHeader</title> + <script src="crossorigin-common.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin-root-BlockedWrongHeader</h1> + <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,http://{{domains[www2]}}:{{ports[http][0]}})" onerror="document._log.push('error');" crossorigin></script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js new file mode 100644 index 0000000000..29d04ec619 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js @@ -0,0 +1,8 @@ +export var foo = {}; + +// Push an event to the log indicating that the script was executed. +document._log.push("running"); + +// Deliberately trigger an error to test what details of the error +// the (possibly) cross-origin parent can listen to. +nonExistentMethod(); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html new file mode 100644 index 0000000000..5c8d6667b0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html @@ -0,0 +1,43 @@ +<!doctype html> +<html> +<head> + <title>html-script-module-crossOrigin</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> + <h1>html-script-module-crossOrigin</h1> + <iframe id="root-WithCORS" src="crossorigin-root-same.sub.html"></iframe> + <iframe id="root-NoCORS" src="crossorigin-root-different.sub.html"></iframe> + <iframe id="root-BlockedMissingHeader" src="crossorigin-root-missingheader.sub.html"></iframe> + <iframe id="root-BlockedWrongHeader" src="crossorigin-root-wrongheader.sub.html"></iframe> + <iframe id="import-WithCORS" src="crossorigin-import-same.sub.html"></iframe> + <iframe id="import-NoCORS" src="crossorigin-import-different.sub.html"></iframe> + <iframe id="import-BlockedMissingHeader" src="crossorigin-import-missingheader.sub.html"></iframe> + <iframe id="import-BlockedWrongHeader" src="crossorigin-import-wrongheader.sub.html"></iframe> + <script> + + var tests = [ + { "obj": async_test("Root module, Error in CORS-same-origin script"), "id": "root-WithCORS", "expected": "running,8-1" }, + { "obj": async_test("Root module, Blocked script download, missing CORS ACAO header"), "id": "root-NoCORS", "expected": "error" }, + { "obj": async_test("Root module, Blocked script download, crossorigin attribute with missing CORS ACAO header"), "id": "root-BlockedMissingHeader", "expected": "error" }, + { "obj": async_test("Root module, Blocked script download, mismatched CORS ACAO header"), "id": "root-BlockedWrongHeader", "expected": "error" }, + { "obj": async_test("Imported module, Error in CORS-same-origin script"), "id": "import-WithCORS", "expected": "running,8-1" }, + { "obj": async_test("Imported module, Blocked script download, missing CORS ACAO header"), "id": "import-NoCORS", "expected": "error" }, + { "obj": async_test("Imported module, Blocked script download, crossorigin attribute with missing CORS ACAO header"), "id": "import-BlockedMissingHeader", "expected": "error" }, + { "obj": async_test("Imported module, Blocked script download, mismatched CORS ACAO header"), "id": "import-BlockedWrongHeader", "expected": "error" }, + ]; + + window.addEventListener("load", function () { + tests.forEach(function (test) { + var target = document.getElementById(test.id); + test.obj.step(function () { + assert_equals(target.contentDocument._log, test.expected, "Unexpected _log value"); + }); + test.obj.done(); + }); + }); + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html new file mode 100644 index 0000000000..146a9db60d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module" src="set-currentScript-on-window.js"></script> +<script type="module"> +import { currentScriptOnImportedModule } from "./currentscript.js"; + +test(() => { + assert_equals(document.currentScript, null, "document.currentScript on inline scripts should be null"); + assert_equals(currentScriptOnImportedModule, null, "document.currentScript on imported scripts should be null"); + assert_equals(window.currentScriptRecorded, null, "document.currentScript on external module scripts should be null"); +}, "currentScript on script type=module should be all null"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js new file mode 100644 index 0000000000..547359ff96 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js @@ -0,0 +1 @@ +export let currentScriptOnImportedModule = window.document.currentScript; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html new file mode 100644 index 0000000000..bd77a8f1bb --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<title>Handling of exceptions in custom element constructors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that exceptions from the constructor of a custom element " + + "inside a module are propagated as expected.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(1, log.length); + const exception = log[0]; + assert_true(exception instanceof Error); + assert_equals(exception.message, "custom element error"); + })); +</script> +<script type="module"> + class XThrower extends HTMLElement { + constructor() { + super(); + throw new Error("custom element error"); + } + } + customElements.define("x-thrower", XThrower); + document.createElement("x-thrower"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js new file mode 100644 index 0000000000..1f91f93eb1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js @@ -0,0 +1,3 @@ +log.push("cycle-tdz-access-a"); +import { Y } from "./cycle-tdz-access.js"; +export var X = Y; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js new file mode 100644 index 0000000000..9df68b3b27 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js @@ -0,0 +1,3 @@ +log.push("cycle-tdz-access"); +import { X } from "./cycle-tdz-access-a.js"; +export let Y = X; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js new file mode 100644 index 0000000000..12994f23d0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js @@ -0,0 +1,2 @@ +export {x} from "./cycle-unresolvable.js"; +log.push("cycle-unresolvable-a"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js new file mode 100644 index 0000000000..61c6d8dcb0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js @@ -0,0 +1,2 @@ +export {x} from "./cycle-unresolvable-a.js"; +log.push("cycle-unresolvable"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html new file mode 100644 index 0000000000..57002a3e07 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<title>Importing a module multiple times with the same specifier</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +window.log = []; +</script> +<script type="module"> +import { foo } from './export-something.js'; +import { set_foo } from './export-something.js'; +import default1 from './export-default.js'; +import default2 from './export-default.js'; + +test(() => { + assert_array_equals(log, ['export-something', 'export-default']); + assert_equals(foo, 42); + set_foo(43); + assert_equals(foo, 43); + assert_equals(default1, "fox"); + assert_equals(default2, "fox"); +}, 'Duplicated imports with the same specifier'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html new file mode 100644 index 0000000000..6a01495c33 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<title>Importing a module multiple times with the different specifier</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +window.log = []; +</script> +<script type="module"> +import { foo } from './export-something.js'; +import { set_foo } from '../module/export-something.js'; +import default1 from './export-default.js'; +import default2 from '../module/export-default.js'; + +test(() => { + assert_array_equals(log, ['export-something', 'export-default']); + assert_equals(foo, 42); + set_foo(43); + assert_equals(foo, 43); + assert_equals(default1, "fox"); + assert_equals(default2, "fox"); +}, 'Duplicated imports with the different specifier'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html new file mode 100644 index 0000000000..817cf6d5dd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<title>Base URLs used in resolving specifiers in dynamic imports from importScripts()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +fetch_tests_from_worker(new Worker("./worker-importScripts.sub.js")); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html new file mode 100644 index 0000000000..a12204281c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<title>Base URLs used in resolving specifiers in dynamic imports from workers</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +fetch_tests_from_worker(new Worker( + "../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js")); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html new file mode 100644 index 0000000000..f7d4927a10 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Base URLs used in resolving specifiers in dynamic imports</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +self.testName = "same origin classic <script>"; +self.baseUrlSanitized = false; +</script> +<script src="../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script> + +<script> +self.testName = "cross origin classic <script> without crossorigin attribute"; +self.baseUrlSanitized = true; +</script> +<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script> + +<script> +self.testName = "cross origin classic <script> with crossorigin attribute"; +self.baseUrlSanitized = false; +</script> +<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" crossorigin></script> + +<script> +self.testName = "cross origin module <script>"; +self.baseUrlSanitized = false; +</script> +<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" type="module"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js new file mode 100644 index 0000000000..8a8530c9b6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js @@ -0,0 +1,9 @@ +promise_test(() => { + return (new Function('w', 'return import(w)'))("./import.js?Function") + .then(module => assert_equals(module.A.from, 'alpha/import.js')); +}, 'alpha - Function'); + +promise_test(() => { + return eval('import("./import.js?eval")') + .then(module => assert_equals(module.A.from, 'alpha/import.js')); +}, 'alpha - eval'); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js new file mode 100644 index 0000000000..b2ac52df2a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js @@ -0,0 +1 @@ +export const A = { "from": "alpha/import.js" }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js new file mode 100644 index 0000000000..904d32f9bf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js @@ -0,0 +1,15 @@ +"use strict"; + +importScripts("/resources/testharness.js"); + +// CORS-same-origin +self.testName = "same-origin importScripts()"; +self.baseUrlSanitized = false; +importScripts("../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"); + +// CORS-cross-origin +self.testName = "cross-origin importScripts()"; +self.baseUrlSanitized = true; +importScripts("../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"); + +done(); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js new file mode 100644 index 0000000000..1c2a2b636a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js @@ -0,0 +1,9 @@ +promise_test(() => { + return (new Function('w', 'return import(w)'))("./import.js?Function") + .then(module => assert_equals(module.A.from, 'beta/import.js')); +}, 'beta - Function'); + +promise_test(() => { + return eval('import("./import.js?eval")') + .then(module => assert_equals(module.A.from, 'beta/import.js')); +}, 'beta - eval'); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js new file mode 100644 index 0000000000..7de1c68182 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js @@ -0,0 +1 @@ +export const A = { "from": "beta/import.js" }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py new file mode 100644 index 0000000000..f2fd1ebd51 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py @@ -0,0 +1,19 @@ +def main(request, response): + """Simple handler that causes redirection. + + The request should typically have two query parameters: + status - The status to use for the redirection. Defaults to 302. + location - The resource to redirect to. + """ + status = 302 + if b"status" in request.GET: + try: + status = int(request.GET.first(b"status")) + except ValueError: + pass + + response.status = status + + location = request.GET.first(b"location") + + response.headers.set(b"Location", location) diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js new file mode 100644 index 0000000000..70cb20fa57 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js @@ -0,0 +1,60 @@ +function objectUrlFromModule(module) { + const blob = new Blob([module], { type: "text/javascript" }); + return URL.createObjectURL(blob); +} + +const moduleText = `export const foo = "bar";`; + +async_test((t) => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + t.add_cleanup(() => URL.revokeObjectURL(moduleBlobUrl)); + + const worker = new Worker("./resources/blob-url-worker.js"); + worker.postMessage(moduleBlobUrl); + + worker.addEventListener( + "message", + t.step_func_done((evt) => { + assert_true(evt.data.importSucceeded); + assert_equals(evt.data.module.foo, "bar"); + }) + ); +}, "A blob URL created in a window agent can be imported from a worker"); + +async_test((t) => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + URL.revokeObjectURL(moduleBlobUrl); + + const worker = new Worker("./resources/blob-url-worker.js"); + worker.postMessage(moduleBlobUrl); + + worker.addEventListener( + "message", + t.step_func_done((evt) => { + assert_false(evt.data.importSucceeded); + assert_equals(evt.data.errorName, "TypeError"); + }) + ); +}, "A blob URL revoked in a window agent will not resolve in a worker"); + +promise_test(async (t) => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + + await import(moduleBlobUrl); + + URL.revokeObjectURL(moduleBlobUrl); + + const worker = new Worker("./resources/blob-url-worker.js"); + worker.postMessage(moduleBlobUrl); + + await new Promise((resolve) => { + worker.addEventListener( + "message", + t.step_func((evt) => { + assert_false(evt.data.importSucceeded); + assert_equals(evt.data.errorName, "TypeError"); + resolve(); + }) + ); + }); +}, "A revoked blob URL will not resolve in a worker even if it's in the window's module graph"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js new file mode 100644 index 0000000000..0719a18bf1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js @@ -0,0 +1,66 @@ +// META: global=window,dedicatedworker,sharedworker,dedicatedworker-module,sharedworker-module + +function objectUrlFromModule(module) { + const blob = new Blob([module], { type: "text/javascript" }); + return URL.createObjectURL(blob); +} + +const moduleText = `export const foo = "bar";`; + +promise_test(async (t) => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + t.add_cleanup(() => URL.revokeObjectURL(moduleBlobUrl)); + + const module = await import(moduleBlobUrl); + assert_equals(module.foo, "bar"); +}, "Blob URLs are supported in dynamic imports"); + +promise_test(async (t) => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + t.add_cleanup(() => URL.revokeObjectURL(moduleBlobUrl)); + + const module1 = await import(moduleBlobUrl); + const module2 = await import(moduleBlobUrl); + assert_equals(module1, module2); +}, "Identical blob URLs resolve to the same module"); + +promise_test(async (t) => { + const moduleBlob = new Blob([moduleText], { type: "text/javascript" }); + const moduleBlobUrl1 = URL.createObjectURL(moduleBlob); + const moduleBlobUrl2 = URL.createObjectURL(moduleBlob); + t.add_cleanup(() => { + URL.revokeObjectURL(moduleBlobUrl1); + URL.revokeObjectURL(moduleBlobUrl2); + }); + + const module1 = await import(moduleBlobUrl1); + const module2 = await import(moduleBlobUrl2); + assert_not_equals(module1, module2); +}, "Different blob URLs pointing to the same blob resolve to different modules"); + +promise_test(async (t) => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + URL.revokeObjectURL(moduleBlobUrl); + + await promise_rejects_js(t, TypeError, import(moduleBlobUrl)); +}, "A revoked blob URL will not resolve"); + +promise_test(async () => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + const module1 = await import(moduleBlobUrl); + + URL.revokeObjectURL(moduleBlobUrl); + + const module2 = await import(moduleBlobUrl); + assert_equals(module1, module2); +}, "A revoked blob URL will resolve if it's already in the module graph"); + +promise_test(async () => { + const moduleBlobUrl = objectUrlFromModule(moduleText); + + const importPromise = import(moduleBlobUrl); + URL.revokeObjectURL(moduleBlobUrl); + + const module = await importPromise; + assert_equals(module.foo, "bar"); +}, "Revoking a blob URL immediately after calling import will not fail"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html new file mode 100644 index 0000000000..688a6193a5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- +Regression test for https://crbug.com/990810: +Functions with the same source code shouldn't be cached if their referencing +scripts and host defined options are different. + +Each Function in the following three scripts should have different base URLs +respectively, but in https://crbug.com/990810 the Function in +`gamma/code-cache.js` reuses the Function in `beta/code-cache.js`, resulting in +wrong base URL. +--> + +<script src="alpha/code-cache.js"></script> +<script src="beta/code-cache.js"></script> +<script src="gamma/code-cache.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html new file mode 100644 index 0000000000..bd920f8107 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +// Regression test for https://crbug.com/979351: +// This test loads a same script file (`resources/code-cache-nonce.js`) +// with three different nonces (i.e. different host defined options). +// Dynamic imports from the script therefore should have different nonces, +// but when code caching ignores the difference in nonces, the first nonce +// ('abc') is reused incorrectly for subsequent dynamic imports, causing +// CSP violation (and thus dynamic import rejection). + +function runTest(nonce, description) { + // Perform a dynamic import with nonce=`nonce` + // from a page (`iframe`) with a matching CSP script-src 'nonce-`nonce`'. + // This should be successful. + promise_test(t => { + return new Promise((resolve, reject) => { + const iframe = document.createElement('iframe'); + iframe.src = 'resources/code-cache-nonce-iframe.sub.html?nonce=' + nonce; + iframe.onload = () => { + // `globalThis.promise` is set by `resources/code-cache-nonce.js`. + // `t.step_timeout()` is workaround for https://crbug.com/1247801. + globalThis.promise.then( + v => t.step_timeout(() => resolve(v), 0), + v => t.step_timeout(() => reject(v), 0) + ); + }; + document.body.appendChild(iframe); + t.add_cleanup(() => iframe.remove()); + }); + }, description); +} + +// As `promise_test` are serialized, each iframe is created after previous +// iframes and scripts are completely loaded. +runTest('abc', 'First dynamic import should use nonce=abc'); +runTest('def', 'Second dynamic import should use nonce=def'); +runTest('ghi', 'Third dynamic import should use nonce=ghi'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html new file mode 100644 index 0000000000..5ec6433e65 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>Dynamic imports don't delay the load event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// Dynamic imports don't #delay-the-load-event. +// Therefore, Window load event would be fired +// just after the dynamic import() below starts. +window.loaded = []; +window.addEventListener('load', () => loaded.push('Window load event')); +promise_test(t => { + loaded.push('import start'); + // This 'loading' log is added to detect the previous Chromium behavior + // where the Window load event is delayed until just before script + // element's load event. + t.step_timeout(() => loaded.push('loading'), 1000); + return import("../resources/slow-module.js?pipe=trickle(d2)") + .then(() => { + assert_array_equals( + loaded, + ['import start', 'Window load event', 'loading', 'slow'], + "Window load event shouldn't be delayed by dynamic imports"); + }); +}, "Dynamic imports don't delay the load event."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html new file mode 100644 index 0000000000..189aa819fa --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/dynamic-import-credentials-helper.sub.js"></script> + +<script type="text/javascript"> +runTestsFromIframe('../resources/dynamic-import-credentials-setTimeout-iframe.sub.html'); +</script> +<body> +</body> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html new file mode 100644 index 0000000000..910644531c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/dynamic-import-credentials-helper.sub.js"></script> + +<script type="text/javascript"> +runTestsFromIframe('../resources/dynamic-import-credentials-iframe.sub.html'); +</script> +<body> +</body> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html new file mode 100644 index 0000000000..12738c7b97 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<title>import(): error cases occuring during fetching</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script type="module"> +const cases = [ + ["wrong MIME type", "../errorhandling-wrongMimetype.js?pipe=header(Content-Type,text/plain)"], + ["wrong MIME type of a dependency", "../errorhandling-wrongMimetype-import.js"], + ["404", "../resources/404-but-js.asis"], + ["404 of a dependency", "../resources/imports-404-but-js.js"], + ["500", "../resources/500-but-js.asis"], + ["500 of a dependency", "../resources/imports-500-but-js.js"], + ["cross-origin module (without CORS)", "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/imports-a.js"], + ["cross-origin module dependency (without CORS)", "../resources/imports-b-cross-origin.sub.js"] +]; + +for (const [label, specifier] of cases) { + promise_test(t => { + return promise_rejects_js(t, TypeError, import(specifier)); + }, "import() must reject when there is a " + label); + + promise_test(async t => { + // The use of ?x is used to separate tests so they don't interfere with each other. + // (However, it shouldn't matter anyway, in a spec-compliant implementation.) + const suffix = (specifier.includes("?") ? "&" : "?") + "x"; + const promise1 = import(specifier + suffix); + const promise2 = import(specifier + suffix); + + await promise_rejects_js(t, TypeError, promise1, "It must reject the first time"); + await promise_rejects_js(t, TypeError, promise2, "It must reject the second time"); + + const error1 = await promise1.catch(e => e); + const error2 = await promise2.catch(e => e); + + assert_not_equals(error1, error2, "The error objects must be different"); + }, "import() must reject with a different error object for each import when there is a " + label); +} + +promise_test(async t => { + const id = token(); + const url = `./resources/status-changing-script.py?id=${id}`; + + // Serve HTTP 404 for the first import(). + await fetch(url + '&newStatus=404'); + const promise1 = import(url); + await promise_rejects_js(t, TypeError, promise1, + "First import() must be rejected due to 404"); + + // Serve HTTP 200 after the first import() completes. + await fetch(url + '&newStatus=200'); + const r = await fetch(url, { cache: 'no-cache' }); + assert_equals(r.status, 200); + + const promise2 = import(url); + await promise_rejects_js(t, TypeError, promise2, + "Second import() must be rejected, because the result of " + + "the first import() is cached in the module map"); +}, "import() fetch errors must be cached"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html new file mode 100644 index 0000000000..e9b10e3bab --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<title>import(): error cases caused by the imported module script</title> +<link rel="author" title="Kouhei Ueno" href="mailto:kouhei@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script type="module"> +const cases = [ + ["parse error", "../syntaxerror.js", SyntaxError], + ["bad module specifier", "does-not-start-with-dot.js", TypeError, { differentErrorObjects: true }], + ["bad module specifier in a dependency", "../bad-module-specifier.js", TypeError], + ["instantiation error", "../instantiation-error-1.js", SyntaxError, { differentErrorObjects: true }], + ["evaluation error", "../throw-error.js", Error] +]; + +for (const [label, specifier, error, { differentErrorObjects } = {}] of cases) { + promise_test(t => { + return promise_rejects_js(t, error, import(specifier)); + }, "import() must reject when there is a " + label); + + const errorObjectsLabel = differentErrorObjects ? "different error objects" : "the same error object"; + promise_test(async t => { + // The use of ?x is used to separate tests so they don't interfere with each other. + // (However, it shouldn't matter anyway, in a spec-compliant implementation.) + const promise1 = import(specifier + "?x"); + const promise2 = import(specifier + "?x"); + + await promise_rejects_js(t, error, promise1, "It must reject the first time"); + await promise_rejects_js(t, error, promise2, "It must reject the second time"); + + const error1 = await promise1.catch(e => e); + const error2 = await promise2.catch(e => e); + + if (differentErrorObjects) { + assert_not_equals(error1, error2, "The error objects must be different"); + } else { + assert_equals(error1, error2, "The error objects must be equal"); + } + }, `import() must reject with ${errorObjectsLabel} for each import when there is a ${label}`); +} + +promise_test(t => { + delete window.before_throwing_error; + delete window.after_throwing_error; + + return promise_rejects_js(t, Error, import("../throw-error.js?y")).then(() => { + assert_true(window.before_throwing_error, + "the module script should run to a point where it throws exception"); + assert_equals(window.after_throwing_error, undefined, + "the module script should not run after it throws exception"); + }); +}, "import()ing a module with an evaluation error must stop evaluation"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html new file mode 100644 index 0000000000..9807e21b0d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<title>Basic dynamic imports</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module"> +promise_test(t => { + return import("./../imports-a.js").then(module => { + assert_true(window.evaluated_imports_a); + assert_equals(module.A["from"], "imports-a.js"); + }); +}, "Dynamic imports should resolve module."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js new file mode 100644 index 0000000000..ec7784983d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js @@ -0,0 +1,58 @@ +"use strict"; + +// This script triggers import(), and thus the base URL of this script +// (either loaded by `<script>` or `importScripts()`) is used as the base URL +// of resolving relative URL-like specifiers in `import()`. + +// The following fields should be set by the callers of this script +// (unless loaded as the worker top-level script): +// - self.testName (string) +// - self.baseUrlSanitized (boolean) + +// When this script is loaded as the worker top-level script: +if ('DedicatedWorkerGlobalScope' in self && + self instanceof DedicatedWorkerGlobalScope && + !self.testName) { + importScripts("/resources/testharness.js"); + self.testName = 'worker top-level script'; + // Worker top-level scripts are always same-origin. + self.baseUrlSanitized = false; +} + +{ + // This could change by the time the test is executed, so we save it now. + // As this script is loaded multiple times, savedBaseUrlSanitized is scoped. + const savedBaseUrlSanitized = self.baseUrlSanitized; + + promise_test(() => { + const promise = import("./import.js?pipe=header(Access-Control-Allow-Origin,*)&label=relative-" + self.testName); + if (savedBaseUrlSanitized) { + // The base URL is "about:blank" and thus import() here should fail. + return promise.then(module => { + // This code should be unreached, but assert_equals() is used here + // to log `module.A["from"]` in case of unexpected resolution. + assert_equals(module.A["from"], "(unreached)", + "Relative URL-like specifier resolution should fail"); + assert_unreached(); + }, + () => {}); + } else { + // The base URL is the response URL of this script, i.e. + // `.../gamma/base-url.sub.js`. + return promise.then(module => { + assert_equals(module.A["from"], "gamma/import.js"); + }); + } + }, + "Relative URL-like from " + self.testName); +} + +promise_test(() => { + return import("http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js?pipe=header(Access-Control-Allow-Origin,*)&label=absolute-" + self.testName) + .then(module => { + assert_equals(module.A["from"], "gamma/import.js"); + }) + }, + "Absolute URL-like from " + self.testName); + +done(); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js new file mode 100644 index 0000000000..b470bc8ae5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js @@ -0,0 +1,9 @@ +promise_test(() => { + return (new Function('w', 'return import(w)'))("./import.js?Function") + .then(module => assert_equals(module.A.from, 'gamma/import.js')); +}, 'gamma - Function'); + +promise_test(() => { + return eval('import("./import.js?eval")') + .then(module => assert_equals(module.A.from, 'gamma/import.js')); +}, 'gamma - eval'); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js new file mode 100644 index 0000000000..435c1369be --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js @@ -0,0 +1 @@ +export const A = { "from": "gamma/import.js" }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html new file mode 100644 index 0000000000..13cc8b6624 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id='div' onmousedown='import("./../imports-a.js").then(window.continueTest);'></div> +<script> +const div = document.getElementById('div'); + +promise_test(t => { + const promise = new Promise(resolve => window.continueTest = resolve); + + const event = new MouseEvent('mousedown', {'button': 1}); + div.dispatchEvent(event); + + return promise.then(() => { + assert_true(window.evaluated_imports_a); + div.parentNode.removeChild(div); + }); +}, "dynamic import should work when triggered from inline event handlers"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js new file mode 100644 index 0000000000..82cb3b215d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js @@ -0,0 +1,32 @@ +// META: global=window,dedicatedworker,sharedworker +// META: script=ticker.js + +promise_test(async t => { + const getCount = ticker(1000); + + const importP = import("<invalid>"); + await promise_rejects_js(t, TypeError, importP, 'import() should reject'); + + assert_less_than(getCount(), 1000); +}, "import() should not drain the microtask queue if it fails during specifier resolution"); + +promise_test(async t => { + // Use Date.now() to ensure that the module is not in the module map + const specifier = "./empty-module.js?" + Date.now(); + + await import(specifier); + + const getCount = ticker(1000); + await import(specifier); + assert_less_than(getCount(), 1000); +}, "import() should not drain the microtask queue when loading an already loaded module"); + +promise_test(async t => { + // Use Date.now() to ensure that the module is not in the module map + const specifier = "./empty-module.js?" + Date.now(); + + const getCount = ticker(1e7); + await import(specifier); + assert_equals(getCount(), 1e7); +}, "import() should drain the microtask queue when fetching a new module"); + diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js new file mode 100644 index 0000000000..bd6f5d092f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js @@ -0,0 +1,14 @@ +// META: global=dedicatedworker,sharedworker +// META: script=ticker.js + +promise_test(async t => { + // Use Date.now() to ensure that the module is not in the module map + const specifier = "./empty-module.css?" + Date.now(); + + const getCount = ticker(1000); + + const importP = import(specifier, { assert: { type: "css" } }); + await promise_rejects_js(t, TypeError, importP, 'import() should reject'); + + assert_less_than(getCount(), 1000); +}, "import() should not drain the microtask queue if it fails because of the 'type: css' assertion in a worker"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css new file mode 100644 index 0000000000..108e7649bd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css @@ -0,0 +1,4 @@ +/* +This file is empty, because all it matters is if the +dynamic import that loads it fails or succedes. +*/ diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js new file mode 100644 index 0000000000..108e7649bd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js @@ -0,0 +1,4 @@ +/* +This file is empty, because all it matters is if the +dynamic import that loads it fails or succedes. +*/ diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js new file mode 100644 index 0000000000..4c75cab1b6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js @@ -0,0 +1,14 @@ +// META: global=serviceworker +// META: script=ticker.js + +promise_test(async t => { + // Use Date.now() to ensure that the module is not in the module map + const specifier = "./empty-module.js?" + Date.now(); + + const getCount = ticker(1000); + + const importP = import(specifier); + await promise_rejects_js(t, TypeError, importP, 'import() should reject'); + + assert_less_than(getCount(), 1000); +}, "import() should not drain the microtask queue if it fails because it's used in a ServiceWorker"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js new file mode 100644 index 0000000000..42619b6e70 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js @@ -0,0 +1,13 @@ +globalThis.ticker = function ticker(max) { + let i = 0; + let stop = false; + Promise.resolve().then(function loop() { + if (stop || i >= max) return; + i++; + Promise.resolve().then(loop); + }); + return () => { + stop = true; + return i; + }; +}; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js new file mode 100644 index 0000000000..f67ba9a1ae --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js @@ -0,0 +1,15 @@ +// META: global=window,dedicatedworker,sharedworker +// META: script=ticker.js + +promise_test(async t => { + // Use Date.now() to ensure that the module is not in the module map + const specifier = "./empty-module.js?" + Date.now(); + + const getCount = ticker(1000); + + const importP = import(specifier, { assert: { type: "<invalid>" } }); + await promise_rejects_js(t, TypeError, importP, 'import() should reject'); + + assert_less_than(getCount(), 1000); +}, "import() should not drain the microtask queue if it fails while validating the 'type' assertion"); + diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html new file mode 100644 index 0000000000..6c598aee39 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<canvas id ="output" width="100" height="100" style="background: blue;"></canvas> +<script> +"use strict"; +const canvas = document.getElementById('output'); +const ctx = canvas.getContext('2d'); + +ctx.fillStyle = 'green'; +ctx.fillRect(0, 0, 100, 100); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html new file mode 100644 index 0000000000..5cd59f86dc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html class="reftest-wait"> +<link rel="help" href="https://html.spec.whatwg.org/#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability)"> +<link rel="match" href="worklet-ref.https.html"> +<style> +#output { + width: 100px; + height: 100px; + background-image: paint(rects); + background-color: blue; +} +</style> +<script src="/common/reftest-wait.js"></script> +<script src="/common/worklet-reftest.js"></script> +<body> +<div id="output"></div> + +<script id="code" type="text/worklet"> +registerPaint('rects', class { + async paint(ctx, geom) { + ctx.fillStyle = 'red'; + + const getCount = ticker(1000); + + try { + // Use Date.now() to ensure that the module is not in the module map + await import("./empty-module.js?" + Date.now()); + } catch (e) { + if (getCount() < 1000) { + ctx.fillStyle = 'green'; + } + } + ctx.fillRect(0, 0, geom.width, geom.height); + } +}); +</script> + +<script> +"use strict"; +CSS.paintWorklet.addModule("./ticker.js").then(() => + importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent) +); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html new file mode 100644 index 0000000000..b01f595c03 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Dynamic import when there is no active script</title> +<link rel="help" href="https://github.com/whatwg/html/pull/4181"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<p>Click these buttons in sequence:</p> + +<button id="button1">Click me 1</button> + +<button id="button2">Click me 2</button> + +<p>The result will be pass/fail per the testharness.js results</p> + +<!-- We set the attributes from a separate script to specifically make + sure that it's not that script's base URL that gets used, but instead this page's. --> +<script src="scripts/no-active-script.js"></script> + +<script> +"use strict"; +setup({ explicit_timeout: true }); + +promise_test(t => { + t.add_cleanup(() => { + delete window.evaluated_imports_a; + }); + + const promise = new Promise((resolve, reject) => { + window.continueTest1 = resolve; + window.errorTest1 = reject; + }); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); +}, "onclick that directly imports should successfully import, using page's base URL"); + +promise_test(t => { + t.add_cleanup(() => { + delete window.evaluated_imports_a; + }); + + const promise = new Promise((resolve, reject) => { + window.continueTest2 = resolve; + window.errorTest2 = reject; + }); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); +}, "onclick that indirectly imports after a task should successfully import, using page's base URL"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html new file mode 100644 index 0000000000..359b71d821 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Dynamic import when there is no active script</title> +<link rel="help" href="https://github.com/whatwg/html/pull/4181"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<p>Click these buttons in sequence:</p> + +<button id="button1">Click me 1</button> + +<button id="button2">Click me 2</button> + +<p>The result will be pass/fail per the testharness.js results</p> + +<!-- We set the attributes from a separate script to specifically make + sure that it's not that script's base URL that gets used, but instead this page's. --> +<script src="scripts/no-active-script.js" type="module"></script> + +<script type="module"> +"use strict"; +setup({ explicit_timeout: true }); + +promise_test(t => { + t.add_cleanup(() => { + delete window.evaluated_imports_a; + }); + + const promise = new Promise((resolve, reject) => { + window.continueTest1 = resolve; + window.errorTest1 = reject; + }); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); +}, "onclick that directly imports should successfully import, using page's base URL"); + +promise_test(t => { + t.add_cleanup(() => { + delete window.evaluated_imports_a; + }); + + const promise = new Promise((resolve, reject) => { + window.continueTest2 = resolve; + window.errorTest2 = reject; + }); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); +}, "onclick that indirectly imports after a task should successfully import, using page's base URL"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html new file mode 100644 index 0000000000..0958cfbeba --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'"> +<script nonce="correct" src="/resources/testharness.js"></script> +<script nonce="correct" src="/resources/testharnessreport.js"></script> +<script nonce="correct" src="./propagate-nonce-external.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html new file mode 100644 index 0000000000..47c422e59c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'"> +<script nonce="correct" src="/resources/testharness.js"></script> +<script nonce="correct" src="/resources/testharnessreport.js"></script> +<script type="module" nonce="correct" src="./propagate-nonce-external.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js new file mode 100644 index 0000000000..3b97d2f40e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js @@ -0,0 +1,7 @@ +// This file is loaded both as a module and as a classic script. +promise_test(t => { + return import("../imports-a.js").then(module => { + assert_true(window.evaluated_imports_a); + assert_equals(module.A["from"], "imports-a.js"); + }); +}, "Dynamically imported module should eval when imported from script w/ a valid nonce."); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html new file mode 100644 index 0000000000..754110cb5e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'"> +<script nonce="correct" src="/resources/testharness.js"></script> +<script nonce="correct" src="/resources/testharnessreport.js"></script> +<script nonce="correct"> +promise_test(t => { + return import("./../imports-a.js").then(module => { + assert_true(window.evaluated_imports_a); + assert_equals(module.A["from"], "imports-a.js"); + }); +}, "Dynamically imported module should eval when imported from script w/ a valid nonce."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html new file mode 100644 index 0000000000..f3322773a4 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'"> +<script nonce="correct" src="/resources/testharness.js"></script> +<script nonce="correct" src="/resources/testharnessreport.js"></script> +<script type="module" nonce="correct"> +promise_test(t => { + return import("./../imports-a.js").then(module => { + assert_true(window.evaluated_imports_a); + assert_equals(module.A["from"], "imports-a.js"); + }); +}, "Dynamically imported module should eval when imported from script w/ a valid nonce."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js new file mode 100644 index 0000000000..07071e05ce --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js @@ -0,0 +1,11 @@ +self.addEventListener("message", (evt) => { + const importModule = import(evt.data); + importModule.then( + (module) => { + self.postMessage({ importSucceeded: true, module: { ...module } }); + }, + (error) => { + self.postMessage({ importSucceeded: false, errorName: error.name }); + } + ); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html new file mode 100644 index 0000000000..56f915aac1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta http-equiv="content-security-policy" + content="script-src 'unsafe-eval' 'nonce-{{GET[nonce]}}'"> +<script src="code-cache-nonce.js" nonce="{{GET[nonce]}}"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js new file mode 100644 index 0000000000..e9983fb6cd --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js @@ -0,0 +1,4 @@ +// Note that the function source text is intentionally different from e.g. +// ../alpha/code-cache.js to avoid caching Functions between different sets +// of tests. +parent.promise = (new Function('x', 'return import(x)'))('../../imports-a.js'); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html new file mode 100644 index 0000000000..ad5ab30eda --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + </head> + <body> + <div id="dummy"></div> + </body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py new file mode 100644 index 0000000000..a44d3dd3eb --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py @@ -0,0 +1,18 @@ +def main(request, response): + headers = [(b"Content-Type", b"text/javascript"), + (b"Cache-Control", b"private, no-store")] + + id = request.GET.first(b"id") + + with request.server.stash.lock: + status = request.server.stash.take(id) + if status is None: + status = 200 + + new_status = request.GET.first(b"newStatus", None) + if new_status is not None: + status = int(new_status) + + request.server.stash.put(id, status) + + return status, headers, b"" diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html new file mode 100644 index 0000000000..c3a870b3f1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<meta http-equiv="content-security-policy" + content="script-src 'nonce-{{GET[nonce]}}'"> +<!-- +base element to make the base URLs of the Document and the script different +--> +<base href="../"> +<script src="resources/v8-code-cache.js?pipe=header(Cache-Control,max-age=1000)" + nonce="{{GET[nonce]}}" type="{{GET[type]}}"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js new file mode 100644 index 0000000000..1d3e88a51d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js @@ -0,0 +1,74 @@ +parent.promise = import('../../imports-a.js'); + +// Padding for triggering V8 Code Cache on Chromium. +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ +// ============================================================================ diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js new file mode 100644 index 0000000000..447e5060b1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js @@ -0,0 +1,2 @@ +// import()s in a dynamically created function are resolved relative to the script. +Function(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`)(); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js new file mode 100644 index 0000000000..100602733a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js @@ -0,0 +1,2 @@ +// import()s in eval are resolved relative to the script. +eval(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js new file mode 100644 index 0000000000..3202ce47b9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js @@ -0,0 +1,3 @@ +// import()s in an event handler are resolved relative to the document base. +window.dummyDiv.setAttribute("onclick", `import('./imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`); +window.dummyDiv.click(); // different from **on**click() diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js new file mode 100644 index 0000000000..85d8ac29ec --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js @@ -0,0 +1,5 @@ +"use strict"; + +document.querySelector("#button1").setAttribute("onclick", "import('../imports-a.js?label=button1').then(window.continueTest1, window.errorTest1)"); + +document.querySelector("#button2").setAttribute("onclick", "Promise.resolve(`import('../imports-a.js?label=button2')`).then(eval).then(window.continueTest2, window.errorTest2);"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js new file mode 100644 index 0000000000..923eb7d8b6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js @@ -0,0 +1,3 @@ +// import()s in an event handler are resolved relative to the document base. +window.dummyDiv.setAttribute("onclick", `import('./imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`); +window.dummyDiv.onclick(); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js new file mode 100644 index 0000000000..342b342e8e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js @@ -0,0 +1,2 @@ +// import()s in a timeout handler are resolved relative to the script. +setTimeout(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`, 0); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html new file mode 100644 index 0000000000..855705e585 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings uses the script base URL inside a classic script that is loaded from a file</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="dummy"></div> + +<base href="scripts/foo/"> +<script> +// Tweak the base URL of the document here to distinguish: +// - document URL +// - document base URL = ../ +// - External scripts' base URL = ./scripts/eval.js etc. +// - This inline script's base URL = ./scripts/foo/ +document.querySelector("base").remove(); +const base = document.createElement("base"); +base.setAttribute("href", "../"); +document.body.appendChild(base); + +function load(scriptSrc) { + const el = document.createElement("script"); + el.src = scriptSrc; + document.body.appendChild(el); +} + +function createTestPromise() { + return new Promise((resolve, reject) => { + window.dummyDiv.removeAttribute("onclick"); + delete window.evaluated_imports_a; + delete window.label; + + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +window.dummyDiv = document.querySelector("#dummy"); + +const evaluators = [ + "setTimeout", + "eval", + "Function", + "reflected-inline-event-handlers", + "inline-event-handlers-UA-code" +]; + +for (const label of evaluators) { + promise_test(() => { + const promise = createTestPromise(); + + window.label = label; + load(`dynamic-import/scripts/${label}.js`); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); +}; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html new file mode 100644 index 0000000000..d90af9c96a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings uses the script base URL inside a module script that is loaded from a file</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="dummy"></div> + +<base href="scripts/foo/"> +<script type="module"> +// Tweak the base URL of the document here to distinguish: +// - document URL +// - document base URL = ../ +// - External scripts' base URL = ./scripts/eval.js etc. +// - This inline script's base URL = ./scripts/foo/ +document.querySelector("base").remove(); +const base = document.createElement("base"); +base.setAttribute("href", "../"); +document.body.appendChild(base); + +function load(scriptSrc) { + const el = document.createElement("script"); + el.type = "module"; + el.src = scriptSrc; + document.body.appendChild(el); +} + +function createTestPromise() { + return new Promise((resolve, reject) => { + window.dummyDiv.removeAttribute("onclick"); + delete window.evaluated_imports_a; + delete window.label; + + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +window.dummyDiv = document.querySelector("#dummy"); + +const evaluators = [ + "setTimeout", + "eval", + "Function", + "reflected-inline-event-handlers", + "inline-event-handlers-UA-code" +]; + +for (const label of evaluators) { + promise_test(() => { + const promise = createTestPromise(); + + window.label = label; + load(`dynamic-import/scripts/${label}.js`); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); +}; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html new file mode 100644 index 0000000000..2fe1f75535 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings uses the script base URL (= document base URL) inside an inline classic script</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<div id="dummy"></div> + +<base href="scripts/foo/"> +<script> +// Tweak the base URL of the document here to distinguish: +// - document URL +// - document base URL = ../ +// - This inline script's base URL = ./scripts/foo/ +document.querySelector("base").remove(); +const base = document.createElement("base"); +base.setAttribute("href", "../"); +document.body.appendChild(base); + +function createTestPromise() { + return new Promise((resolve, reject) => { + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +const dummyDiv = document.querySelector("#dummy"); + +function doTest(label, evaluator, path) { + promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + delete window.evaluated_imports_a; + }); + + const promise = createTestPromise(); + + evaluator(`import('${path}/imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); +} + +// Inline script's base URL should be used. +doTest("setTimeout", setTimeout, "../../.."); +doTest("eval", eval, "../../.."); +doTest("the Function constructor", + (x) => { + Function(x)(); + }, + "../../.."); + +// Document's base URL should be used, as there are no active scripts. +doTest("reflected inline event handlers", + (x) => { + dummyDiv.setAttribute("onclick", x); + dummyDiv.onclick(); + }, + "."); + +doTest("inline event handlers triggered via UA code", + (x) => { + dummyDiv.setAttribute("onclick", x); + dummyDiv.click(); // different from .**on**click() + }, + "."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html new file mode 100644 index 0000000000..1691550ecb --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings uses the script base URL (= document base URL) inside an inline module script</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<div id="dummy"></div> + +<base href="scripts/foo/"> +<script type="module"> +// Tweak the base URL of the document here to distinguish: +// - document URL +// - document base URL = ../ +// - This inline script's base URL = ./scripts/foo/ +document.querySelector("base").remove(); +const base = document.createElement("base"); +base.setAttribute("href", "../"); +document.body.appendChild(base); + +function createTestPromise() { + return new Promise((resolve, reject) => { + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +const dummyDiv = document.querySelector("#dummy"); + +function doTest(label, evaluator, path) { + promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + delete window.evaluated_imports_a; + }); + + const promise = createTestPromise(); + + evaluator(`import('${path}/imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); +} + +// Inline script's base URL should be used. +doTest("setTimeout", setTimeout, "../../.."); +doTest("eval", eval, "../../.."); +doTest("the Function constructor", + (x) => { + Function(x)(); + }, + "../../.."); + +// Document's base URL should be used, as there are no active scripts. +doTest("reflected inline event handlers", + (x) => { + dummyDiv.setAttribute("onclick", x); + dummyDiv.onclick(); + }, + "."); + +doTest("inline event handlers triggered via UA code", + (x) => { + dummyDiv.setAttribute("onclick", x); + dummyDiv.click(); // different from .**on**click() + }, + "."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html new file mode 100644 index 0000000000..34ea00abc8 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings inside a classic script</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="dummy"></div> + +<script> +function createTestPromise() { + return new Promise((resolve, reject) => { + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +const dummyDiv = document.querySelector("#dummy"); + +const evaluators = { + eval, + setTimeout, + "the Function constructor"(x) { + Function(x)(); + }, + "reflected inline event handlers"(x) { + dummyDiv.setAttribute("onclick", x); + dummyDiv.onclick(); + }, + "inline event handlers triggered via UA code"(x) { + dummyDiv.setAttribute("onclick", x); + dummyDiv.click(); // different from .**on**click() + } +}; + +for (const [label, evaluator] of Object.entries(evaluators)) { + promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + delete window.evaluated_imports_a; + }); + + const promise = createTestPromise(); + + evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); +}; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html new file mode 100644 index 0000000000..b85d446d8d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings inside a module script</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="dummy"></div> + +<script type="module"> +function createTestPromise() { + return new Promise((resolve, reject) => { + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +const dummyDiv = document.querySelector("#dummy"); + +const evaluators = { + eval, + setTimeout, + "the Function constructor"(x) { + Function(x)(); + }, + "reflected inline event handlers"(x) { + dummyDiv.setAttribute("onclick", x); + dummyDiv.onclick(); + }, + "inline event handlers triggered via UA code"(x) { + dummyDiv.setAttribute("onclick", x); + dummyDiv.click(); // different from .**on**click() + } +}; + +for (const [label, evaluator] of Object.entries(evaluators)) { + promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + delete window.evaluated_imports_a; + }); + + const promise = createTestPromise(); + + evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); + + return promise.then(module => { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); +}; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html new file mode 100644 index 0000000000..b582eba8b0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html @@ -0,0 +1,104 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings uses the appropriate nonce inside a classic script</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<meta http-equiv="content-security-policy" content="script-src 'nonce-correct' 'unsafe-eval' 'unsafe-hashes' 'sha256-cAMzxBL19bKt4KwKGbxy/ZOFIIjH5AmRjlVbsD5pvNw=' 'sha256-3VjoJYNK/9HJMS8rrZHlqSZgUssDY+GPyc7AU8lNM3k='"> + +<script nonce="correct" src="/resources/testharness.js"></script> +<script nonce="correct" src="/resources/testharnessreport.js"></script> + +<div id="dummy"></div> + +<script nonce="correct"> +"use strict"; +const dummyDiv = document.querySelector("#dummy"); + +function createTestPromise(t) { + t.add_cleanup(() => { + delete window.evaluated_imports_a; + delete window.unreached; + delete window.continueTest; + delete window.errorTest; + }); + + return new Promise((resolve, reject) => { + window.unreached = t.unreached_func("Must not reach this"); + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +function assertSuccessful(module) { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); +} + +promise_test(t => { + const promise = createTestPromise(t); + + setTimeout(`import('../imports-a.js?label=setTimeout').then(window.continueTest, window.errorTest)`, 0); + + return promise.then(assertSuccessful); +}, "setTimeout must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + const promise = createTestPromise(t); + + eval(`import('../imports-a.js?label=direct eval').then(window.continueTest, window.errorTest)`); + + return promise.then(assertSuccessful); +}, "direct eval must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + const promise = createTestPromise(t); + + const evalAlias = eval; + evalAlias(`import('../imports-a.js?label=indirect eval').then(window.continueTest, window.errorTest)`); + + return promise.then(assertSuccessful); +}, "indirect eval must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + const promise = createTestPromise(t); + + Function(`import('../imports-a.js?label=the Function constructor').then(window.continueTest, window.errorTest)`)(); + + return promise.then(assertSuccessful); +}, "the Function constructor must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + }); + + const promise = createTestPromise(t); + + // This only works because of the 'unsafe-hashes' and the hash in the CSP policy + dummyDiv.setAttribute( + "onclick", + `import('../imports-a.js?label=reflected inline event handlers').then(window.continueTest, window.errorTest)` + ); + dummyDiv.onclick(); + + return promise_rejects_js(t, TypeError, promise); +}, "reflected inline event handlers must not inherit the nonce from the triggering script, thus fail"); + +promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + }); + + const promise = createTestPromise(t); + + // This only works because of the 'unsafe-hashes' and the hash in the CSP policy + dummyDiv.setAttribute( + "onclick", + `import('../imports-a.js?label=inline event handlers triggered via UA code').then(window.continueTest, window.errorTest)` + ); + assert_equals(typeof dummyDiv.onclick, "function", "the browser must be able to parse a string containing the import() syntax into a function"); + dummyDiv.click(); // different from **on**click() + + return promise_rejects_js(t, TypeError, promise); +}, "inline event handlers triggered via UA code must not inherit the nonce from the triggering script, thus fail"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html new file mode 100644 index 0000000000..4fa1cc5877 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html @@ -0,0 +1,103 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings uses the appropriate nonce inside a module script</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<meta http-equiv="content-security-policy" content="script-src 'nonce-correct' 'unsafe-eval' 'unsafe-hashes' 'sha256-cAMzxBL19bKt4KwKGbxy/ZOFIIjH5AmRjlVbsD5pvNw=' 'sha256-3VjoJYNK/9HJMS8rrZHlqSZgUssDY+GPyc7AU8lNM3k='"> + +<script nonce="correct" src="/resources/testharness.js"></script> +<script nonce="correct" src="/resources/testharnessreport.js"></script> + +<div id="dummy"></div> + +<script type="module" nonce="correct"> +const dummyDiv = document.querySelector("#dummy"); + +function createTestPromise(t) { + t.add_cleanup(() => { + delete window.evaluated_imports_a; + delete window.unreached; + delete window.continueTest; + delete window.errorTest; + }); + + return new Promise((resolve, reject) => { + window.unreached = t.unreached_func("Must not reach this"); + window.continueTest = resolve; + window.errorTest = reject; + }); +} + +function assertSuccessful(module) { + assert_true(window.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); +} + +promise_test(t => { + const promise = createTestPromise(t); + + setTimeout(`import('../imports-a.js?label=setTimeout').then(window.continueTest, window.errorTest)`, 0); + + return promise.then(assertSuccessful); +}, "setTimeout must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + const promise = createTestPromise(t); + + eval(`import('../imports-a.js?label=direct eval').then(window.continueTest, window.errorTest)`); + + return promise.then(assertSuccessful); +}, "direct eval must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + const promise = createTestPromise(t); + + const evalAlias = eval; + evalAlias(`import('../imports-a.js?label=indirect eval').then(window.continueTest, window.errorTest)`); + + return promise.then(assertSuccessful); +}, "indirect eval must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + const promise = createTestPromise(t); + + Function(`import('../imports-a.js?label=the Function constructor').then(window.continueTest, window.errorTest)`)(); + + return promise.then(assertSuccessful); +}, "the Function constructor must inherit the nonce from the triggering script, thus execute"); + +promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + }); + + const promise = createTestPromise(t); + + // This only works because of the 'unsafe-hashes' and the hash in the CSP policy + dummyDiv.setAttribute( + "onclick", + `import('../imports-a.js?label=reflected inline event handlers').then(window.continueTest, window.errorTest)` + ); + dummyDiv.onclick(); + + return promise_rejects_js(t, TypeError, promise); +}, "reflected inline event handlers must not inherit the nonce from the triggering script, thus fail"); + +promise_test(t => { + t.add_cleanup(() => { + dummyDiv.removeAttribute("onclick"); + }); + + const promise = createTestPromise(t); + + // This only works because of the 'unsafe-hashes' and the hash in the CSP policy + dummyDiv.setAttribute( + "onclick", + `import('../imports-a.js?label=inline event handlers triggered via UA code').then(window.continueTest, window.errorTest)` + ); + assert_equals(typeof dummyDiv.onclick, 'function', "the browser must be able to parse a string containing the import() syntax into a function"); + dummyDiv.click(); // different from **on**click() + + return promise_rejects_js(t, TypeError, promise); +}, "inline event handlers triggered via UA code must not inherit the nonce from the triggering script, thus fail"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html new file mode 100644 index 0000000000..5514049c78 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>import() inside compiled strings inside a classic script</title> +<link rel="help" href="https://github.com/whatwg/html/pull/3163"> +<link rel="help" href="https://github.com/tc39/ecma262/issues/871#issuecomment-292493142"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<base href="scripts/foo/"> +<script> +"use strict"; + +// This test is based on the current specification, but all browser +// implementations aren't conformant. See +// https://bugs.chromium.org/p/chromium/issues/detail?id=1245063 +// https://github.com/heycam/webidl/pull/902 + +// Tweak the base URL of the document here to distinguish: +// - document URL +// - document base URL = ../ +// - This inline script's base URL = ./scripts/foo/ +document.querySelector("base").remove(); +const base = document.createElement("base"); +base.setAttribute("href", "../"); +document.body.appendChild(base); + +self.ran = false; + +// The active script for the dynamic import is this inline script +// (see https://html.spec.whatwg.org/C/#hostmakejobcallback). +promise_test(t => { + t.add_cleanup(() => { + self.ran = false; + }) + + return Promise.resolve(`import("../../../imports-a.js?1").then(() => { self.ran = true; })`) + .then(eval) + .then(() => { + assert_true(self.ran); + }); +}, "Evaled the script via eval, successful import"); + +promise_test(t => { + t.add_cleanup(() => { + self.ran = false; + }) + + return Promise.resolve(`import("bad-specifier?1").catch(() => { self.ran = true; })`) + .then(eval) + .then(() => { + assert_true(self.ran); + }); +}, "Evaled the script via eval, failed import"); + +promise_test(t => { + t.add_cleanup(() => { + self.ran = false; + }) + + return Promise.resolve(`return import("../../../imports-a.js?2").then(() => { self.ran = true; })`) + .then(Function) + .then(Function.prototype.call.bind(Function.prototype.call)) + .then(() => { + assert_true(self.ran); + }); +}, "Evaled the script via Function, successful import"); + +promise_test(t => { + t.add_cleanup(() => { + self.ran = false; + }) + + return Promise.resolve(`return import("bad-specifier?2").catch(() => { self.ran = true; })`) + .then(Function) + .then(Function.prototype.call.bind(Function.prototype.call)) + .then(() => { + assert_true(self.ran); + }); +}, "Evaled the script via Function, failed import"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html new file mode 100644 index 0000000000..3b1d98f6b1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html @@ -0,0 +1,79 @@ +<!doctype html> +<meta charset=utf-8> +<title>Check import() works when active script is in another document</title> +<link rel="author" title="Jon Coppeard" href="mailto:jcoppeard@mozilla.com"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<iframe id="frame" src="resources/empty-iframe.html"></iframe> + +<script> + +function startTest() { + const otherWindow = document.getElementById("frame").contentWindow; + const otherDiv = otherWindow.document.getElementById("dummy"); + + function createTestPromise() { + return new Promise((resolve, reject) => { + otherWindow.continueTest = resolve; + otherWindow.errorTest = reject; + }); + } + + const evaluators = { + eval: otherWindow.eval, + setTimeout: otherWindow.setTimeout, + "the Function constructor"(x) { + otherWindow.Function(x)(); + }, + }; + + for (const [label, evaluator] of Object.entries(evaluators)) { + promise_test(t => { + t.add_cleanup(() => { + otherDiv.removeAttribute("onclick"); + delete otherWindow.evaluated_imports_a; + }); + + const promise = createTestPromise(); + + evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); + + return promise.then(module => { + assert_true(otherWindow.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); + }; + + const eventHandlerEvaluators = { + "reflected inline event handlers"(x) { + otherDiv.setAttribute("onclick", x); + otherDiv.onclick(); + }, + "inline event handlers triggered by JS"(x) { + otherDiv.setAttribute("onclick", x); + otherDiv.click(); // different from .**on**click() + } + }; + + for (const [label, evaluator] of Object.entries(eventHandlerEvaluators)) { + promise_test(t => { + t.add_cleanup(() => { + otherDiv.removeAttribute("onclick"); + delete otherWindow.evaluated_imports_a; + }); + + const promise = createTestPromise(); + + evaluator(`import('../../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`); + + return promise.then(module => { + assert_true(otherWindow.evaluated_imports_a, "The module must have been evaluated"); + assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct"); + }); + }, label + " should successfully import"); + }; +} +</script> +<body onLoad="startTest()"></body> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html new file mode 100644 index 0000000000..77de19e74b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +// Regression test for https://crbug.com/1244145: +// This test loads a same script file (`resources/v8-code-cache.js`) +// multiple times to trigger V8 Code Cache. +// Host defined options (including base URLs and nonces) are lost when the +// script is compiled using the cached metadata, and thus causing +// dynamic import failures due to wrong base URLs and wrong nonces. + +function runTest(type, nonce, description) { + promise_test(t => { + return new Promise((resolve, reject) => { + const iframe = document.createElement('iframe'); + iframe.src = 'resources/v8-code-cache-iframe.sub.html?nonce=' + nonce + '&type=' + type; + iframe.onload = () => { + // `window.promise` is set by `resources/v8-code-cache.js`. + window.promise.then(resolve, reject); + }; + document.body.appendChild(iframe); + t.add_cleanup(() => iframe.remove()); + }); + }, type + ': ' + description); +} + +// As `promise_test` are serialized, each iframe is created after previous +// iframes and scripts are completely loaded. +for (const type of ['text/javascript', 'module']) { + // Cache the script in V8 Code Cache by running multiple times. + runTest(type, 'abc', 'Run #1'); + runTest(type, 'abc', 'Run #2'); + runTest(type, 'abc', 'Run #3'); + runTest(type, 'abc', 'Run #4'); + // Changing the nonce seems to disable compilation cache, trigger compilation + // using V8 Code Cache and thus expose the bug. + runTest(type, 'def', 'Run #5'); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html new file mode 100644 index 0000000000..f336276f3f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Module importing syntax error script and slow script should not crash UA</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module"> +setup({allow_uncaught_exception: true}); +window.log = []; +window.loaded = false; +</script> +<script type="module"> +import "./syntaxerror.js"; +import "./resources/delayed-modulescript.py"; + +window.loaded = true; +</script> +<script type="module"> +test(() => { + assert_false(loaded); + }, "module graph with a syntax error should not evaulate but should not crash UA."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html new file mode 100644 index 0000000000..2480a60d6d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>Handling of different types of errors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "network error has higher priority than parse error"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 3); + + // A parse error is reported for the first top-level + // <script> element for syntaxerror.js. + assert_equals(log[0].constructor, SyntaxError); + assert_equals(log[1], 1); + + // onerror is called (with no errors reported) due to a network error + // for the second top-level <script>. + assert_equals(log[2], 2); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./syntaxerror.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./error-type-1.js" + onerror="log.push(2)" onload="unreachable()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js new file mode 100644 index 0000000000..4882d3f2a5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js @@ -0,0 +1,2 @@ +import './syntaxerror.js'; +import './404.js'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html new file mode 100644 index 0000000000..673bf28ca2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Handling of different types of errors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "parse error has higher priority than instantiation error"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 4); + + // An instantiation error is reported for the first top-level + // <script> element for instantiation-error-1.js. + assert_equals(log[0].constructor, SyntaxError); + assert_equals(log[1], 1); + + // A parse error is reported for the second top-level <script>. + assert_equals(log[2].constructor, SyntaxError); + assert_equals(log[3], 2); + assert_not_equals(log[0], log[2]); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./instantiation-error-1.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./error-type-2.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js new file mode 100644 index 0000000000..6b11397300 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js @@ -0,0 +1,2 @@ +import './instantiation-error-1.js'; +import './syntaxerror.js'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html new file mode 100644 index 0000000000..8a16266f4c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Handling of different types of errors</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "instantiation error has higher priority than evaluation error"); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 5); + + // An evaluation error is reported for the first top-level + // <script> element for throw.js. + assert_equals(log[0], 'throw'); + assert_true(log[1].foo); + assert_equals(log[2], 1); + + // An instantiation error is reported for the second top-level <script>. + assert_equals(log[3].constructor, SyntaxError); + assert_equals(log[4], 2); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./throw.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./error-type-3.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js new file mode 100644 index 0000000000..542be52846 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js @@ -0,0 +1,2 @@ +import './throw.js'; +import './instantiation-error-1.js'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js new file mode 100644 index 0000000000..4eb5597a58 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js @@ -0,0 +1,10 @@ +function errorHandler(ev) +{ + document._errorReported.push("error"); +} + +document._errorReported = []; +window.addEventListener("error", errorHandler); +window.addEventListener("load", function () { + document._errorReported = document._errorReported.join(","); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html new file mode 100644 index 0000000000..3a00f62f00 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> +<head> + <title>html-script-module-errorHandling-parseError-Dependent</title> + <script src="errorhandling-parseerror-common.js"></script> +</head> +<body> + <script type="module" onerror="errorHandler(event);"> + + // No parse errors in the root module, just in the dependent module + import test from "./errorhandling-parseerror-dependent.js"; + document._errorReported = "shouldn't have run dependent module"; + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js new file mode 100644 index 0000000000..71872c47cf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js @@ -0,0 +1,2 @@ +// Parse error in a dependent module +1A diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html new file mode 100644 index 0000000000..7775aeabb4 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html @@ -0,0 +1,24 @@ +<!doctype html> +<html> +<head> + <title>html-script-module-errorHandling-parseError-DependentMultiple</title> + <script src="errorhandling-parseerror-common.js"></script> +</head> +<body> + <script type="module" onerror="errorHandler(event)"> + + // No parse errors in the root module, just in the dependent module + import test from "./errorhandling-parseerror-dependentmultiple.js"; + document._errorReported = "shouldn't have run dependent module"; + + </script> + <script type="module" onerror="errorHandler(event)"> + + // With the broken dependent module already acquired, try to import it + // again from another root. This root should be unwound appropriately. + import test from "./errorhandling-parseerror-dependentmultiple.js"; + document._errorReported = "really shouldn't have run dependent module"; + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js new file mode 100644 index 0000000000..71872c47cf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js @@ -0,0 +1,2 @@ +// Parse error in a dependent module +1A diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html new file mode 100644 index 0000000000..012f3e9b8c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html @@ -0,0 +1,15 @@ +<!doctype html> +<html> +<head> + <title>html-script-module-errorHandling-parseError-Root</title> + <script src="errorhandling-parseerror-common.js"></script> +</head> +<body> + <script type="module"> + + // Parse error in a root module + 1A + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js new file mode 100644 index 0000000000..286e1a4229 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js @@ -0,0 +1,8 @@ +import foo from "./errorhandling-wrongMimetype.js?pipe=header(Content-Type,text/plain)"; + +// We don't expect this code to run, the import above should fail! +// If we do run though, don't trigger an error that the testharness +// might misinterpret as the import itself failing to load. + +var A = null; +export { A }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js new file mode 100644 index 0000000000..373a532445 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js @@ -0,0 +1,7 @@ +// This is a plain JavaScript file, but since it will only be accessed with +// a Content-Type of text/plain and nosniff, it will be seen as invalid. +// The file itself will have no errors/effects, so if it does actually run, +// no error will be detected, and the test will fail. + +var foo = null; +export foo;
\ No newline at end of file diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html new file mode 100644 index 0000000000..cf47465b49 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html @@ -0,0 +1,60 @@ +<!doctype html> +<html> +<head> + <title>html-script-module-errorHandling</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <style> + + iframe + { display: none; } + + </style> +</head> +<body> + <h1>html-script-module-errorHandling</h1> + <iframe id="iframe_parseError_Root" src="errorhandling-parseerror-root.html"></iframe> + <iframe id="iframe_parseError_Dependent" src="errorhandling-parseerror-dependent.html"></iframe> + <iframe id="iframe_parseError_DependentMultiple" src="errorhandling-parseerror-dependentmultiple.html"></iframe> + <script> + + var tests = [ + { "id": "iframe_parseError_Root", "expected": "error" }, + { "id": "iframe_parseError_Dependent", "expected": "error" }, + { "id": "iframe_parseError_DependentMultiple", "expected": "error,error" }, + ]; + tests.forEach(function (testObj) { + var testHandle = async_test("IFrame test: '" + testObj.id + "'"); + var testTarget = document.getElementById(testObj.id); + testTarget.addEventListener("load", testHandle.step_func(function () { + assert_equals(testTarget.contentDocument._errorReported, testObj.expected, "Unexpected _errorReported value"); + testHandle.done(); + })); + }); + + var test_wrongMimetype_root = async_test("External root module with non-script mimetype"); + var script_wrongMimetype_root = document.createElement("script"); + script_wrongMimetype_root.type = "module"; + script_wrongMimetype_root.src = "errorhandling-wrongMimetype.js?pipe=header(Content-Type,text/plain)"; + script_wrongMimetype_root.addEventListener("error", test_wrongMimetype_root.step_func(function () { + test_wrongMimetype_root.done(); + })); + script_wrongMimetype_root.addEventListener("load", test_wrongMimetype_root.step_func(function () { + assert_unreached("This script should not have loaded!"); + })); + document.body.appendChild(script_wrongMimetype_root); + + var test_wrongMimetype_import = async_test("Module with imported non-script mimetype"); + var script_wrongMimetype_import = document.createElement("script"); + script_wrongMimetype_import.type = "module"; + script_wrongMimetype_import.src = "errorhandling-wrongMimetype-import.js"; + script_wrongMimetype_import.addEventListener("error", test_wrongMimetype_import.step_func(function () { + test_wrongMimetype_import.done(); + })); + script_wrongMimetype_import.addEventListener("load", test_wrongMimetype_import.step_func(function () { + assert_unreached("This script should not have loaded!"); + })); + document.body.appendChild(script_wrongMimetype_import); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html new file mode 100644 index 0000000000..3f2bb35f4e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Test that exceptions during evaluation lead to error events on " + + "window, and that exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, + ["throw", exn, "load", exn, "load", exn, "load", exn, "load"]); + assert_true(exn.foo); + })); + + function logLoad() { log.push("load") } + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="throw.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="throw.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="throw.js" async onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="throw.js" nomodule onerror="unreachable()" + onload="logLoad()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html new file mode 100644 index 0000000000..4f2b3c5a74 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Test that ill-founded cyclic dependencies cause ReferenceError " + + "during evaluation, which leads to error events on window, and that " + + "exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, + ["cycle-tdz-access-a", exn, "load", exn, "load", exn, "load"]); + assert_equals(exn.constructor, ReferenceError); + })); + + function logLoad() { log.push("load"); } + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="cycle-tdz-access.js" async onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="cycle-tdz-access.js" nomodule onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="cycle-tdz-access.js" onerror="unreachable()" + onload="logLoad()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html new file mode 100644 index 0000000000..9bfb5df2cf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 3</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Test that exceptions during evaluation lead to error events on " + + "window, and that exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, + ["throw", exn, "load", exn, "load", exn, "load", exn, "load", + exn, "load"]); + assert_true(exn.foo); + })); + + function logLoad() { log.push("load"); } + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./throw.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()" + onload="logLoad()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html new file mode 100644 index 0000000000..0b4b7d1662 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Handling of evaluation errors, 4</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + window.addEventListener("onunhandledrejection", unreachable); + + const test_load = async_test( + "Test that exceptions during evaluation lead to error events on " + + "window, and that exceptions are remembered.\n"); + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[1]; + assert_array_equals(log, + ["throw", exn, "load", exn, "load", exn, "load", exn, "load", + exn, "load"]); + assert_true(exn.foo); + })); + + function logLoad() { log.push("load"); } + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./throw-nested.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw-nested.js" onerror="unreachable()" + onload="logLoad()"></script> +<script type="module" src="./throw.js" onerror="unreachable()" + onload="logLoad()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js new file mode 100644 index 0000000000..d7115a2ac6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js @@ -0,0 +1,3 @@ +test_dynamicOrdered.step(function() { + assert_execCount(1, 2, "External script element (#1) should have fired second"); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js new file mode 100644 index 0000000000..c04e101bb8 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js @@ -0,0 +1,3 @@ +test_dynamicOrdered.step(function() { + assert_execCount(1, 3, "External script element (#2) should have fired third"); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js new file mode 100644 index 0000000000..958736a3d8 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js @@ -0,0 +1,3 @@ +test_dynamicOrdered.step(function() { + assert_execCount(1, 4, "External script element (#3) should have fired fourth"); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js new file mode 100644 index 0000000000..a54cb7a303 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js @@ -0,0 +1,3 @@ +test_dynamicUnordered1.step(function() { + test_dynamicUnordered1.done(); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js new file mode 100644 index 0000000000..df0cd85421 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js @@ -0,0 +1,3 @@ +test_dynamicUnordered2.step(function() { + test_dynamicUnordered2.done(); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js new file mode 100644 index 0000000000..fca73bd9db --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js @@ -0,0 +1,3 @@ +test_parsedOrdered.step(function() { + assert_execCount(0, 2, "External deferred (#1) script element should have fired second"); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js new file mode 100644 index 0000000000..6435333bb9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js @@ -0,0 +1,3 @@ +test_parsedOrdered.step(function() { + assert_execCount(0, 4, "External deferred (#2) script element should have fired fourth"); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js new file mode 100644 index 0000000000..ea0bb1b486 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js @@ -0,0 +1,3 @@ +test_parsedUnordered1.step(function() { + test_parsedUnordered1.done(); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js new file mode 100644 index 0000000000..ce219ee0ea --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js @@ -0,0 +1,3 @@ +test_parsedUnordered2.step(function() { + test_parsedUnordered2.done(); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html new file mode 100644 index 0000000000..6a7513dc13 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html @@ -0,0 +1,106 @@ +<!doctype html> +<html> +<head> + <title>html-script-module-execOrder</title> + <meta name=timeout content=long> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script> + + var execCounts = [ + 0, // test_parsedOrdered + 0, // test_dynamicOrdered + ]; + function assert_execCount(set, expected, description) + { + if (!execCounts[set]) + { + execCounts[set] = 0; + } + assert_equals(++execCounts[set], expected, description); + } + + function create_script(src, opts) + { + var element = document.createElement("script"); + element.src = src; + element.async = (opts.asyncOrdered ? false : true); + element.type = (opts.module ? "module" : "text/javascript"); + document.body.appendChild(element); + } + + </script> +</head> +<body> + <h1>html-script-module-execOrder</h1> + <script> + + ///// + // Start test_parsedUnordered* + ///// + var test_parsedUnordered1 = async_test("Unordered module script execution (parsed, unordered #1)"); + var test_parsedUnordered2 = async_test("Unordered module script execution (parsed, unordered #2)"); + </script> + <script type="module" src="execorder-parsedunordered1.js"></script> + <script type="module" src="execorder-parsedunordered2.js"></script> + <script> + ///// + // End test_parsedUnordered* + ///// + + ///// + // Start test_dynamicUnordered* + ///// + var test_dynamicUnordered1 = async_test("Unordered module script execution (dynamic, unordered #1)"); + var test_dynamicUnordered2 = async_test("Unordered module script execution (dynamic, unordered #2)"); + create_script("execorder-dynamicunordered1.js", { module: true }); + create_script("execorder-dynamicunordered2.js", { module: true }); + ///// + // End test_dynamicUnordered* + ///// + + ///// + // Begin test_parsedOrdered + ///// + var test_parsedOrdered = async_test("Interlaced module/non-module script execution (parsed, async-ordered)"); + window.addEventListener("load", test_parsedOrdered.step_func(function() { + assert_execCount(0, 5, "onload should have fired fifth"); + test_parsedOrdered.done(); + })); + </script> + <script src="execorder-parsedordered2.js" defer></script> + <script type="module"> + test_parsedOrdered.step(function() { + assert_execCount(0, 3, "Inline module-typed script element should have fired third"); + }); + </script> + <script src="execorder-parsedordered4.js" defer></script> + <script> + test_parsedOrdered.step(function() { + assert_execCount(0, 1, "Inline untyped script element should have fired first"); + }); + ///// + // End test_parsedOrdered + ///// + + ///// + // Start test_dynamicOrdered + ///// + var test_dynamicOrdered = async_test("Interlaced module/non-module script execution (dynamic, async-ordered)"); + window.addEventListener("load", test_dynamicOrdered.step_func(function() { + assert_execCount(1, 5, "onload should have fired fifth (last)"); + test_dynamicOrdered.done(); + })); + create_script("execorder-dynamicordered2.js", { asyncOrdered: true, module: false }); + create_script("execorder-dynamicordered3.js", { asyncOrdered: true, module: true }); + create_script("execorder-dynamicordered4.js", { asyncOrdered: true, module: false }); + test_dynamicOrdered.step(function() { + assert_execCount(1, 1, "Inline untyped script element should have fired first"); + }); + ///// + // End test_dynamicOrdered + ///// + + </script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js new file mode 100644 index 0000000000..283830ab28 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js @@ -0,0 +1,2 @@ +log.push("export-default"); +export default "fox"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js new file mode 100644 index 0000000000..ca806eb8b1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js @@ -0,0 +1,2 @@ +log.push("export-something-nested"); +export * from "./export-something.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js new file mode 100644 index 0000000000..cf2c3a99fe --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js @@ -0,0 +1,3 @@ +log.push("export-something"); +export let foo = 42; +export function set_foo(x) { foo = x }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html new file mode 100644 index 0000000000..170bb665ff --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Handling of fetch errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that failure to fetch root leads to error event on script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, ["script"]); + })); +</script> +<script type="module" src="./no-such-file.js" onerror="log.push('script')"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html new file mode 100644 index 0000000000..9386ce603a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Handling of fetch errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that failure to fetch dependency leads to error event on script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, ["script"]); + })); +</script> +<script type="module" src="./fetch-error-2.js" onerror="log.push('script')"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js new file mode 100644 index 0000000000..20c0ea6402 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js @@ -0,0 +1,2 @@ +import "./no-such-file.js" +import "./this.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js new file mode 100644 index 0000000000..cfaeabc47e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js @@ -0,0 +1 @@ +export let importMetaOnDependentModule = import.meta; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js new file mode 100644 index 0000000000..494e168102 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js @@ -0,0 +1,20 @@ +// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module + +test(() => { + assert_equals(typeof import.meta, "object"); + assert_not_equals(import.meta, null); +}, "import.meta is an object"); + +test(() => { + import.meta.newProperty = 1; + assert_true(Object.isExtensible(import.meta)); +}, "import.meta is extensible"); + +test(() => { + for (const name of Reflect.ownKeys(import.meta)) { + const desc = Object.getOwnPropertyDescriptor(import.meta, name); + assert_equals(desc.writable, true); + assert_equals(desc.enumerable, true); + assert_equals(desc.configurable, true); + } +}, "import.meta's properties are writable, configurable, and enumerable"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html new file mode 100644 index 0000000000..214b9bb59c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<!-- + More extensive tests of import maps and import.meta.resolve() will be + located in the import maps test suite. This contains some basic tests plus + tests some tricky parts of the import.meta.resolve() algorithm around string + conversion which are only testable with import maps. +--> + +<script type="importmap"> +{ + "imports": { + "bare": "https://example.com/", + "https://example.com/rewrite": "https://example.com/rewritten", + + "1": "https://example.com/PASS-1", + "null": "https://example.com/PASS-null", + "undefined": "https://example.com/PASS-undefined", + "[object Object]": "https://example.com/PASS-object", + + "./start": "./resources/export-1.mjs", + "./resources/export-1.mjs": "./resources/export-2.mjs" + } +} +</script> + +<script type="module"> +test(() => { + assert_equals(import.meta.resolve("bare"), "https://example.com/"); +}, "import.meta.resolve() given an import mapped bare specifier"); + +test(() => { + assert_equals(import.meta.resolve("https://example.com/rewrite"), "https://example.com/rewritten"); +}, "import.meta.resolve() given an import mapped URL-like specifier"); + +test(() => { + assert_equals(import.meta.resolve(), "https://example.com/PASS-undefined", "no-arg case"); + + assert_equals(import.meta.resolve(1), "https://example.com/PASS-1"); + assert_equals(import.meta.resolve(null), "https://example.com/PASS-null"); + assert_equals(import.meta.resolve(undefined), "https://example.com/PASS-undefined"); + + // Only toString() methods are consulted by ToString, not valueOf() ones. + // So this becomes "[object Object]". + assert_equals(import.meta.resolve({ valueOf() { return "./x"; } }), "https://example.com/PASS-object"); +}, "Testing the ToString() step of import.meta.resolve() via import maps"); + +promise_test(async () => { + const one = (await import("./start")).default; + assert_equals(one, 1); + + const two = (await import(import.meta.resolve("./start"))).default; + assert_equals(two, 2); +}, "import(import.meta.resolve(x)) can be different from import(x)"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html new file mode 100644 index 0000000000..d2e0f185e0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="resources/store-import-meta.html"></iframe> + +<script type="module"> +import * as otherImportMeta from "./resources/export-import-meta.mjs"; +setup({ explicit_done: true }); + +window.onload = () => { + test(() => { + assert_not_equals(frames[0].importMetaURL, import.meta.url, + "Precondition check: we've set things up so that the other script has a different import.meta.url"); + + const expected = (new URL("resources/x", location.href)).href; + assert_equals(frames[0].importMetaResolve("./x"), expected); + }, "import.meta.resolve resolves URLs relative to the import.meta.url, not relative to the active script when it is called: another global's inline script"); + + test(() => { + const otherFrameImportMetaResolve = frames[0].importMetaResolve; + + document.querySelector("iframe").remove(); + + const expected = (new URL("resources/x", location.href)).href; + assert_equals(otherFrameImportMetaResolve("./x"), expected); + }, "import.meta.resolve still works if its global has been destroyed (by detaching the iframe)"); + + test(() => { + assert_not_equals(otherImportMeta.url, import.meta.url, + "Precondition check: we've set things up so that the other script has a different import.meta.url"); + + const expected = (new URL("resources/x", location.href)).href; + assert_equals(otherImportMeta.resolve("./x"), expected); + }, "import.meta.resolve resolves URLs relative to the import.meta.url, not relative to the active script when it is called: another module script"); + + done(); +}; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js new file mode 100644 index 0000000000..5b8a84efaf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js @@ -0,0 +1,77 @@ +// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module + +import { importMetaOnRootModule, importMetaOnDependentModule } + from "./import-meta-root.js"; + +test(() => { + assert_equals(typeof import.meta.resolve, "function"); + assert_equals(import.meta.resolve.name, "resolve"); + assert_equals(import.meta.resolve.length, 1); + assert_equals(Object.getPrototypeOf(import.meta.resolve), Function.prototype); +}, "import.meta.resolve is a function with the right properties"); + +test(() => { + assert_false(isConstructor(import.meta.resolve)); + + assert_throws_js(TypeError, () => new import.meta.resolve("./x")); +}, "import.meta.resolve is not a constructor"); + +test(() => { + // See also tests in ./import-meta-resolve-importmap.html. + + assert_equals(import.meta.resolve({ toString() { return "./x"; } }), resolveURL("x")); + assert_throws_js(TypeError, () => import.meta.resolve(Symbol("./x")), + "symbol"); + assert_throws_js(TypeError, () => import.meta.resolve(), + "no argument (which is treated like \"undefined\")"); +}, "import.meta.resolve ToString()s its argument"); + +test(() => { + assert_equals(import.meta.resolve("./x"), resolveURL("x"), + "current module import.meta"); + assert_equals(importMetaOnRootModule.resolve("./x"), resolveURL("x"), + "sibling module import.meta"); + assert_equals(importMetaOnDependentModule.resolve("./x"), resolveURL("x"), + "dependency module import.meta"); +}, "Relative URL-like specifier resolution"); + +test(() => { + assert_equals(import.meta.resolve("https://example.com/"), "https://example.com/", + "current module import.meta"); + assert_equals(importMetaOnRootModule.resolve("https://example.com/"), "https://example.com/", + "sibling module import.meta"); + assert_equals(importMetaOnDependentModule.resolve("https://example.com/"), "https://example.com/", + "dependency module import.meta"); +}, "Absolute URL-like specifier resolution"); + +test(() => { + const invalidSpecifiers = [ + "https://eggplant:b/c", + "pumpkins.js", + ".tomato", + "..zuccini.mjs", + ".\\yam.es" + ]; + + for (const specifier of invalidSpecifiers) { + assert_throws_js(TypeError, () => import.meta.resolve(specifier), specifier); + } +}, "Invalid module specifiers"); + +test(() => { + const { resolve } = import.meta; + assert_equals(resolve("https://example.com/"), "https://example.com/", "current module import.meta"); +}, "Works fine with no this value"); + +function resolveURL(urlRelativeToThisTest) { + return (new URL(urlRelativeToThisTest, location.href)).href; +} + +function isConstructor(o) { + try { + new (new Proxy(o, { construct: () => ({}) })); + return true; + } catch { + return false; + } +} diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js new file mode 100644 index 0000000000..62ec082a8e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js @@ -0,0 +1,2 @@ +export let importMetaOnRootModule = import.meta; +export { importMetaOnDependentModule } from "./import-meta-dependent.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js new file mode 100644 index 0000000000..61d96f35af --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js @@ -0,0 +1,38 @@ +// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module + +import { importMetaOnRootModule, importMetaOnDependentModule } + from "./import-meta-root.js"; + +const base = location.href.slice(0, location.href.lastIndexOf('/')); + +test(() => { + assert_equals(importMetaOnRootModule.url, + base + "/import-meta-root.js"); +}, "import.meta.url in a root external script"); + +test(() => { + assert_equals(importMetaOnDependentModule.url, + base + "/import-meta-dependent.js"); +}, "import.meta.url in a dependent external script"); + + +import { importMetaOnRootModule as hashedImportMetaOnRootModule1, + importMetaOnDependentModule as hashedImportMetaOnDependentModule1 } + from "./import-meta-root.js#1"; + +import { importMetaOnRootModule as hashedImportMetaOnRootModule2, + importMetaOnDependentModule as hashedImportMetaOnDependentModule2 } + from "./import-meta-root.js#2"; + +test(() => { + assert_equals(hashedImportMetaOnRootModule1.url, + base + "/import-meta-root.js#1"); + assert_equals(hashedImportMetaOnRootModule2.url, + base + "/import-meta-root.js#2"); + + // Must not be affected + assert_equals(hashedImportMetaOnDependentModule1.url, + base + "/import-meta-dependent.js"); + assert_equals(hashedImportMetaOnDependentModule2.url, + base + "/import-meta-dependent.js"); +}, "import.meta.url when importing the module with different fragments"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html new file mode 100644 index 0000000000..284a15f2b2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module" src="import-meta-url.any.js"></script> + +<script type="module"> +const base = location.href.slice(0, location.href.lastIndexOf('/')); + +test(() => { + assert_equals(import.meta.url, location.href); +}, "import.meta.url in a root inline script"); + +for (const workerType of ['DedicatedWorker', 'SharedWorker']) { + promise_test(async t => { + const worker_request_url = + new URL(`postmessage-worker.js?${workerType}`, location); + let w; + let port; + if (workerType === 'DedicatedWorker') { + w = new Worker(worker_request_url.href, {type: 'module'}); + port = w; + } else { + w = new SharedWorker(worker_request_url.href, {type: 'module'}); + port = w.port; + w.port.start(); + } + w.onerror = t.unreached_func('Worker error'); + const url = await new Promise(resolve => { + port.onmessage = evt => resolve(evt.data); + }); + assert_equals(url, worker_request_url.href); + }, `import.meta.url at top-level module ${workerType}`); +} +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js new file mode 100644 index 0000000000..3618137aef --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js @@ -0,0 +1,12 @@ +if ('DedicatedWorkerGlobalScope' in self && + self instanceof DedicatedWorkerGlobalScope) { + postMessage(import.meta.url); +} else if ( + 'SharedWorkerGlobalScope' in self && + self instanceof SharedWorkerGlobalScope) { + self.onconnect = function(e) { + const port = e.ports[0]; + port.start(); + port.postMessage(import.meta.url); + }; +} diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs new file mode 100644 index 0000000000..aef22247d7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs @@ -0,0 +1 @@ +export default 1; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs new file mode 100644 index 0000000000..842e368a0a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs @@ -0,0 +1 @@ +export default 2; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs new file mode 100644 index 0000000000..488ca74c93 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs @@ -0,0 +1,2 @@ +export const url = import.meta.url; +export const resolve = import.meta.resolve; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html new file mode 100644 index 0000000000..c9751da408 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<script type="module"> +window.importMetaURL = import.meta.url; +window.importMetaResolve = import.meta.resolve; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js new file mode 100644 index 0000000000..32d90287d7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js @@ -0,0 +1,5 @@ +log.push("import-something-namespace"); +log.push(m.foo); +m.set_foo(43); +log.push(m.foo); +import * as m from "./export-something.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html new file mode 100644 index 0000000000..4911a071a0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module"> +import { delayedLoaded } from "./resources/delayed-modulescript.py"; +import { A } from "./404.js"; +window.loadSuccess = delayedLoaded; +</script> +<script type="module"> +test(function () { + assert_equals(window.loadSuccess, undefined, + "module tree w/ its sub graph 404 should fail to load without crashing"); +}, "Import a module graph w/ sub-graph 404."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js new file mode 100644 index 0000000000..44d1ac96c2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js @@ -0,0 +1,3 @@ +var A = { "from": "imports-a.js" }; +window.evaluated_imports_a = true; +export { A }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js new file mode 100644 index 0000000000..ae194e4d8a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js @@ -0,0 +1 @@ +export var B = { "from": "imports-b.js" }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js new file mode 100644 index 0000000000..8bd8526f76 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js @@ -0,0 +1,2 @@ +import { CycleB } from "./imports-cycle-b.js"; +export var CycleA = "CycleA"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js new file mode 100644 index 0000000000..218f350c39 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js @@ -0,0 +1,2 @@ +import { CycleA } from "./imports-cycle-a.js"; +export var CycleB = "CycleB"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js new file mode 100644 index 0000000000..88a77a4d67 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js @@ -0,0 +1,6 @@ +import { CycleA } from "./imports-cycle-a.js"; + +test_importCycle.step(function () { + assert_equals(CycleA, "CycleA"); + test_importCycle.done(); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js new file mode 100644 index 0000000000..8cb2298e8a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js @@ -0,0 +1,2 @@ +import { A } from "./imports-a.js"; +export { A as INC_A }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js new file mode 100644 index 0000000000..b7d84005c5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js @@ -0,0 +1,5 @@ +import { A } from "./imports-a.js"; +export { A as INC_AB_A }; + +import { B } from "./imports-b.js"; +export { B as INC_AB_B }; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js new file mode 100644 index 0000000000..243b84fdd0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js @@ -0,0 +1,2 @@ +import { B } from "./imports-b.js"; +export { B as INC_B };
\ No newline at end of file diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js new file mode 100644 index 0000000000..40eca1c8df --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js @@ -0,0 +1,2 @@ +import { SelfInner as SelfInnerA } from "./imports-self-inner.js"; +export var SelfInner = "SelfInner"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js new file mode 100644 index 0000000000..05fa60e2dc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js @@ -0,0 +1,6 @@ +import { SelfInner } from "./imports-self-inner.js"; + +test_importSelf.step(function () { + assert_equals(SelfInner, "SelfInner"); + test_importSelf.done(); +}); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html new file mode 100644 index 0000000000..ca6900744d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html> +<head> + <title>html-script-module-imports</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> + <h1>html-script-module-imports</h1> + + <script type="module"> + + import { A } from "./imports-a.js"; + + test(function () { + assert_equals(A.from, "imports-a.js", "Unexpected A"); + }, "Import a simple module"); + + </script> + <script type="module"> + + import { B as B_RENAMED } from "./imports-b.js"; + + test(function () { + assert_equals(B_RENAMED.from, "imports-b.js", "Unexpected B_RENAMED"); + + try + { + B; + assert_unreached("Unexpectedly defined B"); + } + catch (ex) + {} + }, "Import a simple module, renamed"); + + </script> + <script type="module"> + + import { INC_A } from "./imports-inc-a.js"; + import { INC_B } from "./imports-inc-b.js"; + import { INC_AB_A, INC_AB_B } from "./imports-inc-ab.js"; + + test(function () { + assert_equals(INC_A.from, "imports-a.js", "Unexpected INC_A"); + assert_equals(INC_B.from, "imports-b.js", "Unexpected INC_A"); + assert_equals(INC_AB_A.from, "imports-a.js", "Unexpected INC_A"); + assert_equals(INC_AB_B.from, "imports-b.js", "Unexpected INC_A"); + assert_equals(INC_A, INC_AB_A, "INC_A and INC_AB_A should be the same"); + assert_equals(INC_B, INC_AB_B, "INC_B and INC_AB_B should be the same"); + }, "Import the same module multiple times"); + + </script> + + <script> + var test_importSelf = async_test("Import a module that validly imports itself"); + </script> + <script type="module" src="imports-self.js"></script> + + <script> + var test_importCycle = async_test("Import a module with a valid cyclical module dependency"); + </script> + <script type="module" src="imports-cycle.js"></script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html new file mode 100644 index 0000000000..ce88c0a152 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Dynamic import triggered from inactive context should not crash</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="container"> +<iframe></iframe> +</div> + +<script> +test(() => { + const iframe = document.querySelector('iframe'); + const otherWindow = iframe.contentWindow; + iframe.remove(); + + // Below should not crash + otherWindow.eval(`import('foobar');`); +}, 'dynamic import from inactive context should not crash'); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html new file mode 100644 index 0000000000..db03612e82 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html @@ -0,0 +1,29 @@ +<html> + <head> + <title>Inline async module script execution order</title> + <meta name=timeout content=long> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <script> + let loaded = []; + let test = async_test("Inline async module script execution order"); + window.addEventListener("load", test.step_func(function() { + assert_array_equals(loaded, + ["fast", "fast", "fast", "slow", "slow", "slow"]); + test.done(); + })); + </script> + <script type="module" async src="resources/slow-module.js?pipe=trickle(d2)&unique=1"></script> + <script type="module" async> + import "./resources/slow-module.js?pipe=trickle(d2)&unique=2"; + loaded.push("slow"); + </script> + <script type="module" async src="resources/fast-module.js?unique=1"></script> + <script type="module" async> + import "./resources/fast-module.js?unique=2"; + loaded.push("fast"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html new file mode 100644 index 0000000000..57b40f5baa --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + const test_load = async_test( + "Test that missing exports lead to SyntaxError events on window and " + + "load events on script"); + + window.log = []; + window.addEventListener("error", ev => { + test_load.step(() => assert_equals(ev.error.constructor, SyntaxError)); + log.push(ev.message); + }); + + window.addEventListener("load", test_load.step_func_done(ev => { + const msg = log[0]; + assert_array_equals(log, [msg, 1, msg, 2, msg, 3, msg, 4, msg, 5]); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(2)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(3)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(4)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(5)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js new file mode 100644 index 0000000000..e317b01cc2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js @@ -0,0 +1 @@ +import something from "./instantiation-error-1.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html new file mode 100644 index 0000000000..27ba006fc7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + const test_load = async_test( + "Test that missing exports lead to SyntaxError events on window and " + + "load events on script"); + + window.log = []; + window.addEventListener("error", ev => { + test_load.step(() => assert_equals(ev.error.constructor, SyntaxError)); + log.push(ev.message); + }); + + window.addEventListener("load", test_load.step_func_done(ev => { + const msg = log[0]; + assert_array_equals(log, [msg, 1, msg, 2, msg, 3, msg, 4, msg, 5]); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(2)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(3)"></script> +<script type="module" src="./missing-export-nested.js" + onerror="unreachable()" onload="log.push(4)"></script> +<script type="module" src="./missing-export.js" + onerror="unreachable()" onload="log.push(5)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html new file mode 100644 index 0000000000..32f0a4a243 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 3</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + const test_load = async_test( + "Test that unresolvable cycles lead to SyntaxError events on window " + + "and load events on script"); + + window.log = []; + window.addEventListener("error", ev => { + test_load.step(() => assert_equals(ev.error.constructor, SyntaxError)); + log.push(ev.message); + }); + + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 6, 'Log length'); + assert_equals(log[1], 1); + assert_equals(log[3], 2); + assert_equals(log[5], 3); + assert_not_equals(log[0], log[2], + 'Instantiation error objects for different root scripts'); + assert_equals(log[0], log[4], + 'Instantiation error objects for the same root script'); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./cycle-unresolvable.js" + onerror="unreachable()" onload="log.push(1)" nomodule></script> +<script type="module" src="./cycle-unresolvable-a.js" + onerror="unreachable()" onload="log.push(2)"></script> +<script type="module" src="./cycle-unresolvable.js" + onerror="unreachable()" onload="log.push(3)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html new file mode 100644 index 0000000000..8d3f23819a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 4</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + const test_load = async_test( + "Test that loading a graph in which a module is already " + + "errored results in an error."); + + window.addEventListener("error", ev => { + test_load.step(() => assert_equals(ev.error.constructor, SyntaxError)); + log.push(ev.message); + }); + + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 4, 'Log length'); + assert_equals(log[1], 1); + assert_equals(log[3], 2); + assert_not_equals(log[0], log[2], + 'Instantiation error objects for different root scripts'); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./instantiation-error-4a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./instantiation-error-4d.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js new file mode 100644 index 0000000000..6fed27f1c7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js @@ -0,0 +1,2 @@ +import "./instantiation-error-4b.js"; +log.push("instantiation-error-4a"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js new file mode 100644 index 0000000000..4b702cae67 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js @@ -0,0 +1,3 @@ +import "./instantiation-error-4c.js"; +import "./instantiation-error-4d.js"; +log.push("instantiation-error-4b"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js new file mode 100644 index 0000000000..ef699f6ca3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js @@ -0,0 +1,2 @@ +import {something} from "./instantiation-error-4c.js"; +log.push("instantiation-error-4c"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js new file mode 100644 index 0000000000..ac04ccb9b3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js @@ -0,0 +1,2 @@ +import {something} from "./instantiation-error-4d.js"; +log.push("instantiation-error-4d"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html new file mode 100644 index 0000000000..20df0bb5c9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 5</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + const test_load = async_test( + "Test that loading a graph in which a module is already " + + "errored results an error."); + + window.log = []; + window.addEventListener("error", ev => { + test_load.step(() => assert_equals(ev.error.constructor, SyntaxError)); + log.push(ev.message); + }); + + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 4, 'Log length'); + assert_equals(log[1], 1); + assert_equals(log[3], 2); + assert_not_equals(log[0], log[2], + 'Instantiation error objects for different root scripts'); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./instantiation-error-5a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./instantiation-error-5d.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js new file mode 100644 index 0000000000..b2e6b106b2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js @@ -0,0 +1,2 @@ +import "./instantiation-error-5b.js"; +log.push("instantiation-error-5a"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js new file mode 100644 index 0000000000..2d37ae8fff --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js @@ -0,0 +1,3 @@ +import "./instantiation-error-5c.js"; +import "./instantiation-error-5d.js"; +log.push("instantiation-error-5b"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js new file mode 100644 index 0000000000..ba221b6fc0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js @@ -0,0 +1,2 @@ +import {something} from "./instantiation-error-5c.js"; +log.push("instantiation-error-5c"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js new file mode 100644 index 0000000000..9775e04f82 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js @@ -0,0 +1,3 @@ +import "./instantiation-error-5e.js"; +import "./instantiation-error-5a.js"; +log.push("instantiation-error-5d"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js new file mode 100644 index 0000000000..8bd3b3c3bf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js @@ -0,0 +1,2 @@ +import {something} from "./instantiation-error-5e.js"; +log.push("instantiation-error-5e"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html new file mode 100644 index 0000000000..8d3ce121ee --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 6</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that ambiguous star exports lead to an instantiation error " + + "and that the correct module is blamed."); + // Concretely, instantiation-error-6a.js fails to instantiate because it + // requests a name from instantion-error-6b.js that is ambiguous there. + // instantiation-error-6b.js itself, however, is fine, and it instantiates + // and evaluates successfully. + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[0]; + assert_array_equals(log, [ + exn, 1, + "instantiation-error-6c", + "instantiation-error-6d", + "instantiation-error-6b", 2 + ]); + assert_equals(exn.constructor, SyntaxError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./instantiation-error-6a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./instantiation-error-6b.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js new file mode 100644 index 0000000000..4db49c6c46 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js @@ -0,0 +1,2 @@ +import {foo} from "./instantiation-error-6b.js"; +log.push("instantiation-error-6a"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js new file mode 100644 index 0000000000..35272fe550 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js @@ -0,0 +1,3 @@ +export * from "./instantiation-error-6c.js"; +export * from "./instantiation-error-6d.js"; +log.push("instantiation-error-6b"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js new file mode 100644 index 0000000000..69d616b4ba --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js @@ -0,0 +1,2 @@ +export let foo = "c"; +log.push("instantiation-error-6c"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js new file mode 100644 index 0000000000..d1336a57a2 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js @@ -0,0 +1,2 @@ +export let foo = "d"; +log.push("instantiation-error-6d"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html new file mode 100644 index 0000000000..57f1f87216 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 7</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that ambiguous star exports lead to an instantiation error, " + + "even when discovered through a star export, and that the correct " + + "module is blamed."); + // This is a variation of instantiation-error-6.html (see the explanation + // there). + window.addEventListener("load", test_load.step_func_done(ev => { + const exn = log[0]; + assert_array_equals(log, [ + exn, 1, + "instantiation-error-7d", + "instantiation-error-7e", + "instantiation-error-7c", + "instantiation-error-7f", + "instantiation-error-7b", 2 + ]); + assert_equals(exn.constructor, SyntaxError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./instantiation-error-7a.js" + onerror="unreachable()" onload="log.push(1)"></script> +<script type="module" src="./instantiation-error-7b.js" + onerror="unreachable()" onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js new file mode 100644 index 0000000000..d27a44865c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js @@ -0,0 +1,2 @@ +import {foo} from "./instantiation-error-7b.js"; +log.push("instantiation-error-7a"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js new file mode 100644 index 0000000000..8c05d3b727 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js @@ -0,0 +1,3 @@ +export * from "./instantiation-error-7c.js"; +export * from "./instantiation-error-7f.js"; +log.push("instantiation-error-7b"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js new file mode 100644 index 0000000000..fff1368034 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js @@ -0,0 +1,3 @@ +export * from "./instantiation-error-7d.js"; +export * from "./instantiation-error-7e.js"; +log.push("instantiation-error-7c"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js new file mode 100644 index 0000000000..fa5e7651f4 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js @@ -0,0 +1,2 @@ +export let foo = "d"; +log.push("instantiation-error-7d"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js new file mode 100644 index 0000000000..6547c3fe6a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js @@ -0,0 +1,2 @@ +export let foo = "e"; +log.push("instantiation-error-7e"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js new file mode 100644 index 0000000000..7f9ec5d12e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js @@ -0,0 +1,2 @@ +export let foo = "f"; +log.push("instantiation-error-7f"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html new file mode 100644 index 0000000000..080b170233 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<title>Handling of instantiation errors, 8</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- The below module tree should fail to instantiate, since it references undefined identifier. --> +<script type="module" src="instantiation-error-1.js"></script> +<script> +setup({allow_uncaught_exception: true}); + +promise_test(t => { + return new Promise(resolve => { + window.addEventListener("error", e => { + assert_equals(e.error.constructor, SyntaxError); + resolve(); + }, { once: true }); + }).then(() => new Promise(resolve => { + window.addEventListener("error", e => { + assert_equals(e.error.constructor, SyntaxError); + resolve(); + }, { once: true }); + // Load another module tree w/ previously instantiate-failed tree as its sub-tree. + document.head.appendChild(Object.assign( + document.createElement('script'), + { type: 'module', innerText: 'import "./instantiation-error-1.js"'})); + })); +}, "Instantiate attempt on a tree w/ previously instantiate-failed tree as a sub-tree shouldn't crash."); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js new file mode 100644 index 0000000000..369b3e7827 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js @@ -0,0 +1 @@ +window.matchesLog.push("integrity-matches-inner"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js new file mode 100644 index 0000000000..d8c4219e90 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js @@ -0,0 +1,2 @@ +import "./integrity-matches-inner.js"; +window.matchesLog.push("integrity-matches"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js new file mode 100644 index 0000000000..8182d4de16 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js @@ -0,0 +1 @@ +window.mismatchesLog.push("integrity-mismatches-inner"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js new file mode 100644 index 0000000000..2d47344a5a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js @@ -0,0 +1,2 @@ +import "./integrity-mismatches-inner.js"; +window.mismatchesLog.push("integrity-mismatches"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html new file mode 100644 index 0000000000..c79843624f --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title><script> integrity=""</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +window.inlineRan = false; + +window.matchesLog = []; +window.matchesEvents = []; + +window.mismatchesLog = []; +window.mismatchesEvents = []; +</script> + +<script type="module" integrity="sha384-garbage"> +window.inlineRan = true; +</script> + +<script type="module" src="integrity-matches.js" integrity="sha384-1/XwTy38IAlmvk1O674Efus1/REqfuX6x0V/B2/GX5R3lNbRjhrIwlWyEDPyOwpN" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script> +<script type="module" src="integrity-mismatches.js" integrity="sha384-doesnotmatch" onload="window.mismatchesEvents.push('load');" onerror="window.mismatchesEvents.push('error')"></script> + +<script type="module"> +test(() => { + assert_true(window.inlineRan); +}, "The integrity attribute must have no affect on inline module scripts"); + +test(() => { + assert_array_equals(window.matchesLog, ["integrity-matches-inner", "integrity-matches"], "The module and its dependency must have executed"); + assert_array_equals(window.matchesEvents, ["load"], "The load event must have fired"); +}, "The integrity attribute must be verified on the top-level of a module and allow it to execute when it matches"); + +test(() => { + assert_array_equals(window.mismatchesLog, [], "The module and its dependency must not have executed"); + assert_array_equals(window.mismatchesEvents, ["error"], "The error event must have fired"); +}, "The integrity attribute must be verified on the top-level of a module and not allow it to execute when there's a mismatch"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html new file mode 100644 index 0000000000..00269efdf9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Late namespace request</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test the situation where a module is instantiated without the " + + "need for a namespace object, but later on a different module " + + "requests the namespace."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, + ["export-something", + "import-something-namespace", 42, 43]); + })); +</script> +<script type="module" src="export-something.js"></script> +<script type="module" src="import-something-namespace.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html new file mode 100644 index 0000000000..d40bb0aca7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>Late star-export request</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test the situation where a module is instantiated without a use of " + + "its star-exports, but later on a different module requests them."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [ + "export-something", "export-something-nested", + "import-something-namespace", 42, 43]); + })); +</script> +<script type="module" src="export-something-nested.js"></script> +<script type="module"> + log.push("import-something-namespace"); + log.push(foo); + set_foo(43); + log.push(foo); + import {foo, set_foo} from "./export-something-nested.js"; +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html new file mode 100644 index 0000000000..58397dd07d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<head> +<title>load/error events for inline module scripts</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/load-error-events-helpers.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#execute-the-script-block"> +</head> +<script> +"use strict"; + +var test1_load = event_test('src, 200, parser-inserted, defer, no async', false, false); +var test4_load = event_test('src, 200, parser-inserted, no defer, async', false, false); + +var test3_dynamic_load = event_test('src, 200, not parser-inserted, no defer, no async, no non-blocking', false, false); +var test4_dynamic_load = event_test('src, 200, not parser-inserted, no defer, async', false, false); + +var test1_error = event_test('src, 404, parser-inserted, defer, no async', false, true); +var test4_error = event_test('src, 404, parser-inserted, no defer, async', false, true); + +var test3_dynamic_error = event_test('src, 404, not parser-inserted, no defer, no async, no non-blocking', false, true); +var test4_dynamic_error = event_test('src, 404, not parser-inserted, no defer, async', false, true); + +var script3_dynamic_load = document.createElement('script'); +script3_dynamic_load.setAttribute('type', 'module'); +script3_dynamic_load.onload = () => onLoad(test3_dynamic_load); +script3_dynamic_load.onerror = () => onError(test3_dynamic_load); +script3_dynamic_load.async = false; +script3_dynamic_load.appendChild(document.createTextNode('onExecute(test3_dynamic_load);')); +document.head.appendChild(script3_dynamic_load); + +var script3_dynamic_error = document.createElement('script'); +script3_dynamic_error.setAttribute('type', 'module'); +script3_dynamic_error.onload = () => onLoad(test3_dynamic_error); +script3_dynamic_error.onerror = () => onError(test3_dynamic_error); +script3_dynamic_error.async = false; +script3_dynamic_error.appendChild(document.createTextNode('import "./not_found.js";')); +document.head.appendChild(script3_dynamic_error); + +var script4_dynamic_load = document.createElement('script'); +script4_dynamic_load.setAttribute('type', 'module'); +script4_dynamic_load.onload = () => onLoad(test4_dynamic_load); +script4_dynamic_load.onerror = () => onError(test4_dynamic_load); +script4_dynamic_load.async = true; +script4_dynamic_load.appendChild(document.createTextNode('onExecute(test4_dynamic_load);')); +document.head.appendChild(script4_dynamic_load); + +var script4_dynamic_error = document.createElement('script'); +script4_dynamic_error.setAttribute('type', 'module'); +script4_dynamic_error.onload = () => onLoad(test4_dynamic_error); +script4_dynamic_error.onerror = () => onError(test4_dynamic_error); +script4_dynamic_error.async = true; +script4_dynamic_error.appendChild(document.createTextNode('import "./not_found.js";')); +document.head.appendChild(script4_dynamic_error); +</script> + +<script onload="onLoad(test1_load);" onerror="onError(test1_load);" type="module">"use strict";onExecute(test1_load);</script> +<script onload="onLoad(test4_load);" onerror="onError(test4_load);" type="module" async>"use strict";onExecute(test4_load);</script> +<script onload="onLoad(test1_error);" onerror="onError(test1_error);" type="module">"use strict";import "./not_found.js";</script> +<script onload="onLoad(test4_error);" onerror="onError(test4_error);" type="module" async>"use strict";import "./not_found.js";</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html new file mode 100644 index 0000000000..d9bf05226c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<head> +<title>load/error events for external module scripts</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/load-error-events-helpers.js"></script> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#execute-the-script-block"> +</head> +<script> +"use strict"; + +var test1_load = event_test('src, 200, parser-inserted, defer, no async', true, false); +var test4_load = event_test('src, 200, parser-inserted, no defer, async', true, false); + +var test3_dynamic_load = event_test('src, 200, not parser-inserted, no defer, no async, no non-blocking', true, false); +var test4_dynamic_load = event_test('src, 200, not parser-inserted, no defer, async', true, false); + +var test1_error = event_test('src, 404, parser-inserted, defer, no async', false, true); +var test4_error = event_test('src, 404, parser-inserted, no defer, async', false, true); + +var test3_dynamic_error = event_test('src, 404, not parser-inserted, no defer, no async, no non-blocking', false, true); +var test4_dynamic_error = event_test('src, 404, not parser-inserted, no defer, async', false, true); + +var script3_dynamic_load = document.createElement('script'); +script3_dynamic_load.setAttribute('type', 'module'); +script3_dynamic_load.onload = () => onLoad(test3_dynamic_load); +script3_dynamic_load.onerror = () => onError(test3_dynamic_load); +script3_dynamic_load.async = false; +script3_dynamic_load.src = "../resources/load-error-events.py?test=test3_dynamic_load"; +document.head.appendChild(script3_dynamic_load); + +var script3_dynamic_error = document.createElement('script'); +script3_dynamic_error.setAttribute('type', 'module'); +script3_dynamic_error.onload = () => onLoad(test3_dynamic_error); +script3_dynamic_error.onerror = () => onError(test3_dynamic_error); +script3_dynamic_error.async = false; +script3_dynamic_error.src = "../resources/load-error-events.py?test=test3_dynamic_error"; +document.head.appendChild(script3_dynamic_error); + +var script4_dynamic_load = document.createElement('script'); +script4_dynamic_load.setAttribute('type', 'module'); +script4_dynamic_load.onload = () => onLoad(test4_dynamic_load); +script4_dynamic_load.onerror = () => onError(test4_dynamic_load); +script4_dynamic_load.async = true; +script4_dynamic_load.src = "../resources/load-error-events.py?test=test4_dynamic_load"; +document.head.appendChild(script4_dynamic_load); + +var script4_dynamic_error = document.createElement('script'); +script4_dynamic_error.setAttribute('type', 'module'); +script4_dynamic_error.onload = () => onLoad(test4_dynamic_error); +script4_dynamic_error.onerror = () => onError(test4_dynamic_error); +script4_dynamic_error.async = true; +script4_dynamic_error.src = "../resources/load-error-events.py?test=test4_dynamic_error"; +document.head.appendChild(script4_dynamic_error); +</script> + +<script src="../resources/load-error-events.py?test=test1_load" onload="onLoad(test1_load);" onerror="onError(test1_load);" type="module"></script> +<script src="../resources/load-error-events.py?test=test4_load" onload="onLoad(test4_load);" onerror="onError(test4_load);" type="module" async></script> +<script src="../resources/load-error-events.py?test=test1_error" onload="onLoad(test1_error);" onerror="onError(test1_error);" type="module"></script> +<script src="../resources/load-error-events.py?test=test4_error" onload="onLoad(test4_error);" onerror="onError(test4_error);" type="module" async></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js new file mode 100644 index 0000000000..860d2bf341 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js @@ -0,0 +1,2 @@ +import "./missing-export.js"; +log.push("nested-missing-export"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js new file mode 100644 index 0000000000..e6f5746eb7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js @@ -0,0 +1,2 @@ +import something from "./missing-export.js"; +log.push("missing-export"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml new file mode 100644 index 0000000000..1655e61a7c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml @@ -0,0 +1,20 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" +"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> +window.evaluated_module_script = true; +</script> +<script> + var test = async_test("module script in XHTML documents should be evaluated."); + window.addEventListener("load", () => { + test.step(() => { assert_true(window.evaluated_module_script); }); + test.done(); + }); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html new file mode 100644 index 0000000000..ae82e1348a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>Once as module script, once as classic script</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that evaluating something as classic script does not prevent " + + "it from being evaluated as module script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [window, undefined]); + })); +</script> +<script type="module" src="this.js"></script> +<script src="this.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html new file mode 100644 index 0000000000..fb512b4b30 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<title>Once as classic script, once as module script</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that evaluating something as classic script does not prevent " + + "it from being evaluated as module script."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [window, undefined]); + })); +</script> +<script src="this.js"></script> +<script type="module" src="this.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js new file mode 100644 index 0000000000..a127aeb559 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js @@ -0,0 +1 @@ +import { b } from "./nested-imports-b.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js new file mode 100644 index 0000000000..18a5af40cc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js @@ -0,0 +1,2 @@ +import { c } from "./nested-imports-c.js"; +export const b = "b"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js new file mode 100644 index 0000000000..ec44596aea --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js @@ -0,0 +1,2 @@ +import { d } from "./nested-imports-d.js"; +export const c = "c"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js new file mode 100644 index 0000000000..cee87849c6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js @@ -0,0 +1,3 @@ +import { e } from "./nested-imports-e.js"; +import "./resources/delayed-modulescript.py"; +export const d = "d"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js new file mode 100644 index 0000000000..ec6f0360a6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js @@ -0,0 +1,2 @@ +import { f } from "./nested-imports-f.js"; +export const e = "e"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js new file mode 100644 index 0000000000..0591e0b316 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js @@ -0,0 +1,2 @@ +import { g } from "./nested-imports-g.js"; +export const f = "f"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js new file mode 100644 index 0000000000..86cbe7d3f8 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js @@ -0,0 +1,2 @@ +import { h } from "./nested-imports-h.js"; +export const g = "g"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js new file mode 100644 index 0000000000..a161291259 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js @@ -0,0 +1,2 @@ +import { c } from "./nested-imports-c.js"; +export const h = "h"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html new file mode 100644 index 0000000000..23bb595d0e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>Test imports under more than 3 levels in different modules</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({ allow_uncaught_exception: true }); + + window.log = []; + + const test_load = async_test("should load all modules successfully"); + window.addEventListener( + "load", + test_load.step_func_done((ev) => { + assert_equals(log.length, 2); + + assert_equals(log[0], 1); + assert_equals(log[1], 2); + }) + ); + + function unreachable() { + log.push("unexpected"); + } +</script> +<script type="module" src="./nested-imports-a.js" onerror="unreachable()" + onload="log.push(1)"></script> +<script type="module" src="./nested-imports-e.js" onerror="unreachable()" + onload="log.push(2)"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js new file mode 100644 index 0000000000..3801ae847a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js @@ -0,0 +1,2 @@ +import "./missing-export.js"; +log.push("missing-export-nested"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html new file mode 100644 index 0000000000..656c99b292 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>The 'nomodule' attribute</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that 'nomodule' has the desired effect on classic scripts, but " + + "no effect on module scripts."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [undefined]); + })); + +</script> +<script type="module" src="this.js" nomodule></script> +<script src="this.js" nomodule></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html new file mode 100644 index 0000000000..b8866f9511 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> +<head> +<title>Referrer with the no-referrer policy</title> +<meta name="referrer" content="no-referrer"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> + +// "name" parameter is necessary for bypassing the module map. + +import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same"; + +import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote"; + +import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same"; + +import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote"; + +import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"; + +import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same"; + +test(t => { + assert_equals( + referrerSame, "", + "Referrer should not be sent for the same-origin top-level script."); +}, "Importing a same-origin top-level script with the no-referrer policy."); + +test(t => { + assert_equals( + referrerRemote, "", + "Referrer should not be sent for the remote-origin top-level script."); +}, "Importing a remote-origin top-level script with the no-referrer policy."); + +test(t => { + assert_equals( + referrerSameSame, "", + "Referrer should not be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a same-origin top-level " + + "script with the no-referrer policy."); + +test(t => { + assert_equals( + referrerSameRemote, "", + "Referrer should not be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a same-origin top-level " + + "script with the no-referrer policy."); + +test(t => { + assert_equals( + referrerRemoteRemote, "", + "Referrer should not be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a remote-origin " + + "top-level script with the no-referrer policy."); + +test(t => { + assert_equals( + referrerRemoteSame, "", + "Referrer should not be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a remote-origin " + + "top-level script with the no-referrer policy."); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html new file mode 100644 index 0000000000..fd4c1ea496 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<html> +<head> +<title>Referrer with the origin-when-cross-origin policy</title> +<meta name="referrer" content="origin-when-cross-origin"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> + +// "name" parameter is necessary for bypassing the module map. + +import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same"; + +import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote"; + +import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same"; + +import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote"; + +import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"; + +import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same"; + +const origin = (new URL(location.href)).origin + "/"; +const remoteOrigin = new URL("http://{{domains[www1]}}:{{ports[http][0]}}/").origin + "/"; + +test(t => { + assert_equals( + referrerSame, location.href, + "Full referrer should be sent for the same-origin top-level script."); +}, "Importing a same-origin top-level script with the " + + "origin-when-cross-origin policy."); + +test(t => { + assert_equals( + referrerRemote, origin, + "Referrer should be stripped to the origin when importing " + + "remote-origin top-level script."); +}, "Importing a remote-origin top-level script with the " + + "origin-when-cross-origin policy."); + +test(t => { + const scriptURL = + new URL("resources/import-referrer-checker.sub.js", location.href) + assert_equals( + referrerSameSame, scriptURL + "?name=same_same", + "Full referrer should be sent for same-origin descendant script" + + "imported by same-origin top-level script."); +}, "Importing a same-origin descendant script from a same-origin top-level " + + "script with the origin-when-cross-origin policy."); + +test(t => { + assert_equals( + referrerSameRemote, origin, + "Referrer should be stripped to the origin for the remote-origin " + + "descendant script imported from same-origin top-level script."); +}, "Importing a remote-origin descendant script from a same-origin top-level " + + "script with the origin-when-cross-origin policy."); + +test(t => { + const scriptURL = new URL( + "html/semantics/scripting-1/the-script-element/module/resources/" + + "import-referrer-checker.sub.js", + remoteOrigin); + assert_equals(referrerRemoteRemote, scriptURL + "?name=remote_remote", + "Full referrer should be sent for the remote-origin descendant script " + + "imported from a remote-origin top-level script."); +}, "Importing a remote-origin descendant script from a remote-origin " + + "top-level script with the origin-when-cross-origin policy."); + +test(t => { + assert_equals(referrerRemoteSame, remoteOrigin, + "Referrer should be stripped to the origin for the same-origin " + + "descendant script imported by remote-origin top-level script."); +}, "Importing a same-origin descendant script from a remote-origin " + + "top-level script with the origin-when-cross-origin policy."); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html new file mode 100644 index 0000000000..a554fb4b0c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html> +<head> +<title>Referrer with the origin policy</title> +<meta name="referrer" content="origin"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> + +// "name" parameter is necessary for bypassing the module map. + +import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same"; + +import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote"; + +import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same"; + +import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote"; + +import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"; + +import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same"; + +const origin = (new URL(location.href)).origin + "/"; +const remoteOrigin = "http://{{domains[www1]}}:{{ports[http][0]}}/"; + +test(t => { + assert_equals( + referrerSame, origin, + "Referrer should be sent for the same-origin top-level script."); +}, "Importing a same-origin top-level script with the origin policy."); + +test(t => { + assert_equals( + referrerRemote, origin, + "Referrer should be sent for the remote-origin top-level script."); +}, "Importing a remote-origin top-level script with the origin policy."); + +test(t => { + assert_equals( + referrerSameSame, origin, + "Referrer should be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a same-origin top-level " + + "script with the origin policy."); + +test(t => { + assert_equals( + referrerSameRemote, origin, + "Referrer should be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a same-origin top-level " + + "script with the origin policy."); + +test(t => { + assert_equals( + referrerRemoteRemote, remoteOrigin, + "Referrer should be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a remote-origin " + + "top-level script with the origin policy."); + +test(t => { + assert_equals( + referrerRemoteSame, remoteOrigin, + "Referrer should be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a remote-origin " + + "top-level script with the origin policy."); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html new file mode 100644 index 0000000000..7d6d515a47 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html @@ -0,0 +1,77 @@ +<!DOCTYPE html> +<html> +<head> +<title>Referrer with the same-origin policy</title> +<meta name="referrer" content="same-origin"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> + +// "name" parameter is necessary for bypassing the module map. + +import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same"; + +import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote"; + +import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same"; + +import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote"; + +import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"; + +import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same"; + +const remoteOrigin = "http://{{domains[www1]}}:{{ports[http][0]}}/"; + +test(t => { + assert_equals( + referrerSame, location.href, + "Referrer should be sent for the same-origin top-level script."); +}, "Importing a same-origin top-level script with the same-origin policy."); + +test(t => { + assert_equals( + referrerRemote, "", + "Referrer should not be sent for the remote-origin top-level script."); +}, "Importing a remote-origin top-level script with the same-origin policy."); + +test(t => { + const path = + new URL("resources/import-referrer-checker.sub.js", location.href); + assert_equals( + referrerSameSame, path + `?name=same_same`, + "Referrer should be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a same-origin top-level " + + "script with the same-origin policy."); + +test(t => { + assert_equals( + referrerSameRemote, "", + "Referrer should not be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a same-origin top-level " + + "script with the same-origin policy."); + +test(t => { + const scriptURL = new URL( + "html/semantics/scripting-1/the-script-element/module/resources/" + + "import-referrer-checker.sub.js", remoteOrigin); + assert_equals( + referrerRemoteRemote, scriptURL + "?name=remote_remote", + "Referrer should be sent for the remote-origin descendant script " + + "when it is imported from a top-level script in the same remote-origin."); +}, "Importing a remote-origin descendant script from a remote-origin " + + "top-level script with the same-origin policy."); + +test(t => { + assert_equals( + referrerRemoteSame, "", + "Referrer should not be sent for the same-origin descendant script " + + "when it is imported from a top-level remote-origin script."); +}, "Importing a same-origin descendant script from a remote-origin " + + "top-level script with the same-origin policy."); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html new file mode 100644 index 0000000000..1984d875b3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> +<title>Referrer with the strict-origin referrer policy</title> +<meta name="referrer" content="strict-origin"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> + +// "name" parameter is necessary for bypassing the module map in descendant import. + +import { referrer as insecureImport } from "./resources/import-referrer-checker-insecure.sub.js?name=insecure_import"; +import { referrer as secureImport } from "https://{{domains[www]}}:{{ports[https][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js?name=secure_import"; + +const origin = (new URL(location.href)).origin + "/"; + +test(t => { + assert_equals( + insecureImport, origin, + "A document with the strict-origin referrer policy served over HTTP, " + + "imports an module script over HTTP, that imports a descendant script " + + "over HTTP. The request for the descendant script is sent with a " + + "`Referer` header with the page's origin"); + + assert_equals( + secureImport, "", + "A document with the strict-origin referrer policy served over HTTP, " + + "imports an module script over HTTPS, that imports a descendant script " + + "over HTTP. The request for the descendant script is sent with no " + + "`Referer` header"); +}, "The strict-* referrer policies compare the trustworthiness of a " + + "request's referrer string against its URL"); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html new file mode 100644 index 0000000000..443731c1b8 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html @@ -0,0 +1,81 @@ +<!DOCTYPE html> +<html> +<head> +<title>Referrer with the unsafe-url policy</title> +<meta name="referrer" content="unsafe-url"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script type="module"> + +// "name" parameter is necessary for bypassing the module map. + +import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same"; + +import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote"; + +import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same"; + +import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote"; + +import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote"; + +import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same"; + +test(t => { + assert_equals( + referrerSame, location.href, + "Referrer should be sent for the same-origin top-level script."); +}, "Importing a same-origin top-level script with the unsafe-url policy."); + +test(t => { + assert_equals( + referrerRemote, location.href, + "Referrer should be sent for the remote-origin top-level script."); +}, "Importing a remote-origin top-level script with the unsafe-url policy."); + +test(t => { + const scriptURL = + new URL("resources/import-referrer-checker.sub.js", location.href) + assert_equals( + referrerSameSame, scriptURL + "?name=same_same", + "Referrer should be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a same-origin top-level " + + "script with the unsafe-url policy."); + +test(t => { + const scriptURL = + new URL("resources/import-remote-origin-referrer-checker.sub.js", + location.href) + assert_equals( + referrerSameRemote, scriptURL + "?name=same_remote", + "Referrer should be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a same-origin top-level " + + "script with the unsafe-url policy."); + +test(t => { + const scriptURL = + "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/" + + "scripting-1/the-script-element/module/resources/" + + "import-referrer-checker.sub.js"; + assert_equals( + referrerRemoteRemote, scriptURL + "?name=remote_remote", + "Referrer should be sent for the remote-origin descendant script."); +}, "Importing a remote-origin descendant script from a remote-origin " + + "top-level script with the unsafe-url policy."); + +test(t => { + const scriptURL = + "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/" + + "scripting-1/the-script-element/module/resources/" + + "import-same-origin-referrer-checker-from-remote-origin.sub.js"; + assert_equals( + referrerRemoteSame, scriptURL + "?name=remote_same", + "Referrer should be sent for the same-origin descendant script."); +}, "Importing a same-origin descendant script from a remote-origin " + + "top-level script with the unsafe-url policy."); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis new file mode 100644 index 0000000000..0fe1379e56 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis @@ -0,0 +1,4 @@ +HTTP/1.1 404 Not Found +Content-Type: text/javascript + +window.ran404 = true; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis new file mode 100644 index 0000000000..c81202f7ef --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis @@ -0,0 +1,4 @@ +HTTP/1.1 500 Not Found +Content-Type: text/javascript + +window.ran500 = true; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py new file mode 100644 index 0000000000..90551e92c3 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py @@ -0,0 +1,20 @@ +def main(request, response): + headers = [ + (b"Content-Type", b"text/javascript"), + (b"Access-Control-Allow-Origin", request.GET.first(b"origin")), + (b"Access-Control-Allow-Credentials", b"true") + ] + identifier = request.GET.first(b"id") + cookie_name = request.GET.first(b"cookieName") + cookie = request.cookies.first(cookie_name, None) + if identifier is None or cookie_name is None: + return headers, b"" + + if cookie is None: + result = b"not found" + elif cookie.value == b"1": + result = b"found" + else: + result = b"different value: " + cookie.value + + return headers, b"window." + identifier + b" = '" + result + b"';" diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html new file mode 100644 index 0000000000..dbc14dffec --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<meta charset="utf-8"> + +<script type="module" + src="check-cookie.py?id=sameOriginNone&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}"> +</script> +<script type="module" + src="check-cookie.py?id=sameOriginAnonymous&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}" + crossOrigin="anonymous"> +</script> +<script type="module" + src="check-cookie.py?id=sameOriginUseCredentials&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}" + crossOrigin="use-credentials"> +</script> +<script type="module" + src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginNone&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}"> +</script> +<script type="module" + src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginAnonymous&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}" + crossOrigin="anonymous"> +</script> +<script type="module" + src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginUseCredentials&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}" + crossOrigin="use-credentials"> +</script> + +<script type="module"> +import "./check-cookie.py?id=sameOriginNoneDescendant&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}"; +</script> +<script type="module" crossOrigin="anonymous"> +import "./check-cookie.py?id=sameOriginAnonymousDescendant&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}"; +</script> +<script type="module" crossOrigin="use-credentials"> +import "./check-cookie.py?id=sameOriginUseCredentialsDescendant&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}"; +</script> +<script type="module"> +import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginNoneDescendant&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}"; +</script> +<script type="module" crossOrigin="anonymous"> +import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginAnonymousDescendant&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}"; +</script> +<script type="module" crossOrigin="use-credentials"> +import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginUseCredentialsDescendant&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}"; +</script> + +<script type="text/javascript"> +window.addEventListener('load', event => { + window.parent.postMessage({}, '*'); +}); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py new file mode 100644 index 0000000000..52dbfba445 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py @@ -0,0 +1,7 @@ +import time + +def main(request, response): + delay = float(request.GET.first(b"ms", 500)) + time.sleep(delay / 1E3) + + return [(b"Content-type", b"text/javascript")], u"export let delayedLoaded = true;" diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js new file mode 100644 index 0000000000..7d9b024e75 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js @@ -0,0 +1,67 @@ +// runTestsFromIframe() is used in the top-level HTML to set cookies and then +// start actual tests in iframe. +function runTestsFromIframe(iframe_url) { + const setSameOriginCookiePromise = fetch( + '/cookies/resources/set-cookie.py?name=same&path=/html/semantics/scripting-1/the-script-element/module/', + { + mode: 'no-cors', + credentials: 'include', + }); + const setCrossOriginCookiePromise = fetch( + 'http://{{domains[www2]}}:{{ports[http][0]}}/cookies/resources/set-cookie.py?name=cross&path=/html/semantics/scripting-1/the-script-element/module/', + { + mode: 'no-cors', + credentials: 'include', + }); + const windowLoadPromise = new Promise(resolve => { + window.addEventListener('load', () => { + resolve(); + }); + }); + + const iframe = document.createElement('iframe'); + Promise.all([setSameOriginCookiePromise, + setCrossOriginCookiePromise, + windowLoadPromise]).then(() => { + iframe.src = iframe_url; + document.body.appendChild(iframe); + fetch_tests_from_window(iframe.contentWindow); + }); +} + +// The functions below are used from tests within the iframe. + +let testNumber = 0; + +// importFunc and setTimeoutFunc is used to make the active script at the time +// of import() to be the script elements that call `runTest()`, +// NOT this script defining runTest(). + +function runTest(importFunc, origin, expected, source) { + let url; + let description; + if (origin === 'same') { + url = "./check-cookie.py"; + description = "Same-origin dynamic import from " + source; + } else { + url = "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py"; + description = "Cross-origin dynamic import from " + source; + } + promise_test(() => { + const id = "test" + testNumber; + testNumber += 1; + return importFunc(url + "?id=" + id + "&cookieName=" + origin + "&origin=" + location.origin) + .then(() => { + assert_equals(window[id], expected, "cookie"); + }); + }, description); +} + +function setTimeoutWrapper(setTimeoutFunc) { + return url => { + return new Promise(resolve => { + window.resolve = resolve; + setTimeoutFunc(`import("${url}").then(window.resolve)`); + }); + }; +} diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html new file mode 100644 index 0000000000..88204ef00b --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="dynamic-import-credentials-helper.sub.js"></script> + +<!-- +The active script at the time of import() is the script elements below, and +thus the credentials mode of the fetch options of the script elements below +are used for dynamic import requests. +--> + +<script> +runTest(url => import(url), + "same", "found", "classic script (crossOrigin not specified)"); +runTest(url => import(url), + "cross", "not found", "classic script (crossOrigin not specified)"); +</script> + +<script crossOrigin="anonymous"> +runTest(url => import(url), "same", "found", + "classic script (crossOrigin=anonymous)"); +runTest(url => import(url), "cross", "not found", + "classic script (crossOrigin=anonymous)"); +</script> + +<script crossOrigin="use-credentials"> +runTest(url => import(url), + "same", "found", "classic script (crossOrigin=use-credentials)"); +runTest(url => import(url), + "cross", "found", "classic script (crossOrigin=use-credentials)"); +</script> + +<script type="module"> +runTest(url => import(url), + "same", "found", "module script (crossOrigin not specified)"); +runTest(url => import(url), + "cross", "not found", "module script (crossOrigin not specified)"); +</script> + +<script type="module" crossOrigin="anonymous"> +runTest(url => import(url), "same", "found", + "module script (crossOrigin=anonymous)"); +runTest(url => import(url), "cross", "not found", + "module script (crossOrigin=anonymous)"); +</script> + +<script type="module" crossOrigin="use-credentials"> +runTest(url => import(url), + "same", "found", "module script (crossOrigin=use-credentials)"); +runTest(url => import(url), + "cross", "found", "module script (crossOrigin=use-credentials)"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html new file mode 100644 index 0000000000..ffba141527 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html @@ -0,0 +1,56 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="dynamic-import-credentials-helper.sub.js"></script> + +<!-- +The active script at the time of import() is the classic script created by +https://html.spec.whatwg.org/multipage/C/#timer-initialisation-steps +and the active script at the time of setTimeout() is the script elements below, +thus the credentials mode of the fetch options of the script elements below +are used for dynamic import requests. + +setTimeout() calls below can't be wrapped (e.g. by step_timeout()) +because wrapping setTimeout() would set active scripts differently. +--> + +<script> +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "same", "found", "setTimeout(string) from classic script (crossOrigin not specified)"); +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "cross", "not found", "setTimeout(string) from classic script (crossOrigin not specified)"); +</script> + +<script crossOrigin="anonymous"> +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "same", "found", "setTimeout(string) from classic script (crossOrigin=anonymous)"); +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "cross", "not found", "setTimeout(string) from classic script (crossOrigin=anonymous)"); +</script> + +<script crossOrigin="use-credentials"> +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "same", "found", "setTimeout(string) from classic script (crossOrigin=use-credentials)"); +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "cross", "found", "setTimeout(string) from classic script (crossOrigin=use-credentials)"); +</script> + +<script type="module"> +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "same", "found", "setTimeout(string) from module script (crossOrigin not specified)"); +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "cross", "not found", "setTimeout(string) from module script (crossOrigin not specified)"); +</script> + +<script type="module" crossOrigin="anonymous"> +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "same", "found", "setTimeout(string) from module script (crossOrigin=anonymous)"); +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "cross", "not found", "setTimeout(string) from module script (crossOrigin=anonymous)"); +</script> + +<script type="module" crossOrigin="use-credentials"> +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "same", "found", "setTimeout(string) from module script (crossOrigin=use-credentials)"); +runTest(setTimeoutWrapper(x => setTimeout(x, 0)), + "cross", "found", "setTimeout(string) from module script (crossOrigin=use-credentials)"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js new file mode 100644 index 0000000000..3a76cf71f6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js @@ -0,0 +1 @@ +loaded.push("fast"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js new file mode 100644 index 0000000000..6fc4ad395c --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js @@ -0,0 +1 @@ +import "../../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript%3Bcharset=windows-1250&dummy=6"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js new file mode 100644 index 0000000000..3ae805d78d --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js @@ -0,0 +1 @@ +import "../../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript&dummy=5"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js new file mode 100644 index 0000000000..2d6fd96712 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js @@ -0,0 +1 @@ +export { referrer } from 'http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}'; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js new file mode 100644 index 0000000000..2c7dce9dff --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js @@ -0,0 +1,2 @@ +import { referrer as referrerImport } from './referrer-checker.py?name={{GET[name]}}'; +export const referrer = referrerImport; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js new file mode 100644 index 0000000000..45a2520b68 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js @@ -0,0 +1,2 @@ +import { referrer as referrerImport } from 'http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}'; +export const referrer = referrerImport; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js new file mode 100644 index 0000000000..5a53bcd4d5 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js @@ -0,0 +1,2 @@ +import { referrer as referrerImport } from 'http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}'; +export const referrer = referrerImport; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js new file mode 100644 index 0000000000..c2ccab7c62 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js @@ -0,0 +1 @@ +import "../../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript%3Bcharset=windows-1250&dummy=6"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js new file mode 100644 index 0000000000..5708a26e07 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js @@ -0,0 +1 @@ +import "../../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript&dummy=5"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js new file mode 100644 index 0000000000..d62e4f05be --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js @@ -0,0 +1 @@ +import "./404-but-js.asis"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js new file mode 100644 index 0000000000..d62e4f05be --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js @@ -0,0 +1 @@ +import "./404-but-js.asis"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js new file mode 100644 index 0000000000..6db57b5017 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js @@ -0,0 +1 @@ +import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/imports-b.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py new file mode 100644 index 0000000000..413f48d381 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py @@ -0,0 +1,6 @@ +def main(request, response): + referrer = request.headers.get(b"referer", b"") + response_headers = [(b"Content-Type", b"text/javascript"), + (b"Access-Control-Allow-Origin", b"*")] + return (200, response_headers, + b"export const referrer = '" + referrer + b"';") diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js new file mode 100644 index 0000000000..4623ef7360 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js @@ -0,0 +1,3 @@ +// This module is imported with pipe=trickle(d2) to make it load more slowly +// than fast-module.js +loaded.push("slow"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html new file mode 100644 index 0000000000..e3b8e15b41 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html @@ -0,0 +1,93 @@ +<!DOCTYPE html> +<title>Module scripts with for and event attributes</title> +<link rel="author" title="Matheus Kerschbaum" href="mailto:matjk7@gmail.com"> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var expected = [ + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, +]; +var run = expected.map(function() { return false }); +</script> +<script for="wİndow" event="onload" type="module"> +run[0] = true; +</script> +<script for="window" event="onload x" type="module"> +run[1] = true; +</script> +<script for="window" event="onload(x" type="module"> +run[2] = true; +</script> +<script for="window" event="onload(x)" type="module"> +run[3] = true; +</script> +<script for="window" event="onclick" type="module"> +run[4] = true; +</script> +<script for="" event="onload" type="module"> +run[5] = true; +</script> +<script for="window" event="" type="module"> +run[6] = true; +</script> +<script for="" event="" type="module"> +run[7] = true; +</script> +<script for=" window" event="onload" type="module"> +run[8] = true; +</script> +<script for="window " event="onload" type="module"> +run[9] = true; +</script> +<script for="window" event=" onload" type="module"> +run[10] = true; +</script> +<script for="window" event="onload " type="module"> +run[11] = true; +</script> +<script for=" window " event=" onload " type="module"> +run[12] = true; +</script> +<script for=" window " event=" onload() " type="module"> +run[13] = true; +</script> +<script for="object" event="handler" type="module"> +run[14] = true; +</script> +<script event="handler" type="module"> +run[15] = true; +</script> +<script for="object" type="module"> +run[16] = true; +</script> +<script type="module"> +test(function() { + for (var i = 0; i < run.length; ++i) { + test(function() { + var script = document.querySelectorAll("script[for], script[event]")[i]; + assert_equals(run[i], expected[i], + "script for=" + format_value(script.getAttribute("for")) + + " event=" + format_value(script.getAttribute("event"))); + }, "Script " + i); + } +}); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js new file mode 100644 index 0000000000..6863075bd9 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js @@ -0,0 +1 @@ +window.currentScriptRecorded = document.currentScript; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html new file mode 100644 index 0000000000..cc4e2d69b7 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Single evaluation, 1</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that a module is evaluated only once, and that 'this' is " + + "undefined (because of strict mode)."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [undefined, "this-nested"]); + })); +</script> +<script type="module" src="this.js"></script> +<script type="module" src="this.js"></script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this.js"></script> +<script type="module" src="this-nested.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html new file mode 100644 index 0000000000..790e2fa9c6 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Single evaluation, 2</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + window.log = []; + + const test_load = async_test( + "Test that a module is evaluated only once, and that 'this' is " + + "undefined (because of strict mode)."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_array_equals(log, [undefined, "this-nested"]); + })); +</script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this.js"></script> +<script type="module" src="this-nested.js"></script> +<script type="module" src="this.js"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html new file mode 100644 index 0000000000..3a42cf9e30 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Cyclic graph with slow imports</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="module"> +import { loaded } from "./slow-module-graph-a.js"; + +test(() => { + assert_true(loaded); +}, "module graph with cycles load even if part of the graph loads slow"); +</script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js new file mode 100644 index 0000000000..48701aa1d0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js @@ -0,0 +1,3 @@ +import "./slow-module-graph-b.js"; +import "./resources/delayed-modulescript.py" +export let loaded = true; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js new file mode 100644 index 0000000000..53a8f2026e --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js @@ -0,0 +1 @@ +import "./slow-module-graph-a.js"; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html new file mode 100644 index 0000000000..d07005caaa --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<title>Handling of invalid specifiers</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + setup({allow_uncaught_exception: true}); + + window.log = []; + + window.addEventListener("error", ev => log.push(ev.error)); + + const test_load = async_test( + "Test that invalid module specifier leads to TypeError on window."); + window.addEventListener("load", test_load.step_func_done(ev => { + assert_equals(log.length, 1); + assert_equals(log[0].constructor, TypeError); + })); + + function unreachable() { log.push("unexpected"); } +</script> +<script type="module" src="./bad-module-specifier.js" onerror="unreachable()"></script> diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js new file mode 100644 index 0000000000..de1b053c5a --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js @@ -0,0 +1,2 @@ +import "./syntaxerror.js"; +log.push("nested-syntaxerror"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js new file mode 100644 index 0000000000..31a9e2cbdf --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js @@ -0,0 +1,2 @@ +log.push("syntaxerror"); +%!#$@#$@#$@ diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js new file mode 100644 index 0000000000..f204812fd1 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js @@ -0,0 +1,2 @@ +import "./this.js"; +log.push("this-nested"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js new file mode 100644 index 0000000000..996a439df0 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js @@ -0,0 +1 @@ +log.push(this); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js new file mode 100644 index 0000000000..9769c84b23 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js @@ -0,0 +1,3 @@ +window.before_throwing_error = true; +throw new Error; +window.after_throwing_error = true; diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js new file mode 100644 index 0000000000..f1801ea366 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js @@ -0,0 +1,2 @@ +import "./throw.js"; +log.push("throw-nested"); diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js new file mode 100644 index 0000000000..cef7918216 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js @@ -0,0 +1,2 @@ +log.push("throw"); +throw {foo: true} diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js new file mode 100644 index 0000000000..2931eec500 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js @@ -0,0 +1,2 @@ +log.push("throw2"); +throw {bar: true} diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html new file mode 100644 index 0000000000..5817ae4d43 --- /dev/null +++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<title>Type attribute of module scripts</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +window.t1 = async_test('type="module"'); +window.t2 = async_test('type="MODULE"'); +window.t3 = async_test('type="Module"'); +window.t4 = async_test('type="module "'); +window.t5 = async_test('type=" module"'); +</script> +<script type="module">window.t1.done();</script> +<script type="MODULE">window.t2.done();</script> +<script type="Module">window.t3.done();</script> +<script type="module ">window.t4.unreached_func('Unexpectedly evaluated');</script> +<script type=" module">window.t5.unreached_func('Unexpectedly evaluated');</script> +<script type="module"> +window.t1.unreached_func('Unexpectedly not evaluated')(); +window.t2.unreached_func('Unexpectedly not evaluated')(); +window.t3.unreached_func('Unexpectedly not evaluated')(); +window.t4.done(); +window.t5.done(); +</script> |