aboutsummaryrefslogtreecommitdiffstats
path: root/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element
diff options
context:
space:
mode:
Diffstat (limited to 'tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element')
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/css-module-worker-test.html43
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/record-fetch.py20
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js3
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.sub.js3
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js2
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.sub.js2
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/microtasks/resources/checkpoint-after-error-event.js4
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js9
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js9
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js60
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js66
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html19
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html43
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html23
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js9
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js11
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html4
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js4
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py18
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html9
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js74
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html22
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html42
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js58
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html80
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js12
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/promise-reject-and-remove.html10
-rw-r--r--tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/promise-reject-and-remove-iframe.html12
28 files changed, 592 insertions, 79 deletions
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/css-module-worker-test.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/css-module-worker-test.html
index 1618f40eb61..7ff672da6a9 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/css-module-worker-test.html
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/css-module-worker-test.html
@@ -3,34 +3,51 @@
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+ <script src="/common/utils.js"></script>
</head>
<body>
<script>
setup({allow_uncaught_exception: true});
- async_test(function (test) {
- const worker = new Worker("./resources/worker.js", {
+ promise_test(function (test) {
+ const uuid = token();
+ const worker = new Worker(`./resources/worker.sub.js?key=${uuid}`, {
type: "module"
});
- worker.onmessage = test.unreached_func("A CSS Module within a web worker should not load.");
- worker.onerror = test.step_func_done();
- }, "A static import CSS Module within a web worker should not load.");
+ return new Promise((resolve, reject) => {
+ worker.addEventListener("error", resolve);
+ worker.addEventListener("message", reject);
+ }).then(async () => {
+ const fetchResponse = await fetch(`./resources/record-fetch.py?key=${uuid}&action=getCount`);
+ const fetchData = await fetchResponse.json();
+ assert_equals(fetchData.count, 0, "Shouldn't have tried fetching CSS module in worker");
+ });
+ }, "A static import CSS Module within a web worker should not load and should not attempt to fetch the module.");
- async_test(function (test) {
- const worker = new Worker("./resources/worker-dynamic-import.js", {
+ promise_test(function (test) {
+ const uuid = token();
+ const worker = new Worker(`./resources/worker-dynamic-import.sub.js?key=${uuid}`, {
type: "module"
});
- worker.onmessage = test.step_func_done(e => {
- assert_equals(e.data, "NOT LOADED");
+
+ return new Promise(resolve => {
+ worker.addEventListener("message", resolve);
+ }).then(async (event) => {
+ assert_equals(event.data, "NOT LOADED");
+ const fetchResponse = await fetch(`./resources/record-fetch.py?key=${uuid}&action=getCount`);
+ const fetchData = await fetchResponse.json();
+ assert_equals(fetchData.count, 0, "Shouldn't have tried fetching CSS module in worker");
});
- }, "A dynamic import CSS Module within a web worker should not load.");
+ }, "A dynamic import CSS Module within a web worker should not load and should not attempt to fetch the module.");
- async_test(function (test) {
+ promise_test(function (test) {
const worker = new Worker("./resources/basic.css", {
type: "module"
});
- worker.onerror = test.step_func_done();
- }, "A CSS Module within a web worker should not load.");
+ return new Promise(resolve => {
+ worker.onerror = resolve;
+ });
+ }, "An attempt to load a CSS module as a worker should fail.");
</script>
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/record-fetch.py b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/record-fetch.py
new file mode 100644
index 00000000000..4928cb4acb9
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/record-fetch.py
@@ -0,0 +1,20 @@
+def main(request, response):
+ try:
+ stash_key = request.GET.first(b"key")
+ action = request.GET.first(b"action")
+
+ run_count = request.server.stash.take(stash_key)
+ if not run_count:
+ run_count = 0
+
+ if action == b"incCount":
+ request.server.stash.put(stash_key, run_count + 1)
+ response.headers.set(b"Content-Type", b"text/css")
+ response.content = b'#test { background-color: #FF0000; }'
+ elif action == b"getCount":
+ response.headers.set(b"Content-Type", b"text/json")
+ response.content = b'{"count": %d }' % run_count
+ else:
+ response.set_error(400, u"Invalid action")
+ except:
+ response.set_error(400, u"Not enough parameters")
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js
deleted file mode 100644
index 6f6852ce550..00000000000
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import("./basic.css", { assert: { type: "css" } })
- .then(() => postMessage("LOADED"))
- .catch(e => postMessage("NOT LOADED")); \ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.sub.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.sub.js
new file mode 100644
index 00000000000..791bd7d3f94
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker-dynamic-import.sub.js
@@ -0,0 +1,3 @@
+import("./record-fetch.py?key={{GET[key]}}&action=incCount", { assert: { type: "css" } })
+ .then(() => postMessage("LOADED"))
+ .catch(e => postMessage("NOT LOADED")); \ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js
deleted file mode 100644
index c97d9652d35..00000000000
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import "./basic.css" assert { type: "css" };
-postMessage("Unexpectedly loaded"); \ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.sub.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.sub.js
new file mode 100644
index 00000000000..ffee312d21e
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/css-module/resources/worker.sub.js
@@ -0,0 +1,2 @@
+import "./record-fetch.py?key={{GET[key]}}&action=incCount" assert { type: "css" };
+postMessage("Unexpectedly loaded"); \ No newline at end of file
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/microtasks/resources/checkpoint-after-error-event.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/microtasks/resources/checkpoint-after-error-event.js
index f415732aa68..1a2b9404a7e 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/microtasks/resources/checkpoint-after-error-event.js
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/microtasks/resources/checkpoint-after-error-event.js
@@ -14,7 +14,7 @@ self.setup({allow_uncaught_exception: true});
// handlers are evaluated, not after each error event handler.
// Just after each event handler is invoked,
-// https://heycam.github.io/webidl/#call-a-user-objects-operation
+// https://webidl.spec.whatwg.org/#call-a-user-objects-operation
// calls #clean-up-after-running-script, but this doesn't execute new
// microtasks immediately, because:
// - Before https://github.com/whatwg/html/pull/4352:
@@ -57,7 +57,7 @@ async_test(t => {
// around event events other than the `self` error event cases above.
// In this case, microtasks are executed just after each event handler is
// invoked via #clean-up-after-running-script called from
-// https://heycam.github.io/webidl/#call-a-user-objects-operation,
+// https://webidl.spec.whatwg.org/#call-a-user-objects-operation,
// because the event handlers are executed outside the
// #prepare-to-run-script/#clean-up-after-running-script scopes in
// #run-a-classic-script/#run-a-module-script.
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js
new file mode 100644
index 00000000000..8a8530c9b6d
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js
new file mode 100644
index 00000000000..1c2a2b636a4
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js
new file mode 100644
index 00000000000..70cb20fa57a
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js
new file mode 100644
index 00000000000..0719a18bf16
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html
new file mode 100644
index 00000000000..688a6193a58
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html
new file mode 100644
index 00000000000..bd920f8107d
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html
index f000178842b..12738c7b973 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html
@@ -3,7 +3,7 @@
<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)"],
@@ -37,4 +37,25 @@ for (const [label, specifier] of cases) {
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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js
new file mode 100644
index 00000000000..b470bc8ae56
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js
new file mode 100644
index 00000000000..07071e05ced
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html b/tests/wpt/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 00000000000..56f915aac13
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js
new file mode 100644
index 00000000000..e9983fb6cd9
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py
new file mode 100644
index 00000000000..a44d3dd3eb0
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html b/tests/wpt/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 00000000000..c3a870b3f1e
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js
new file mode 100644
index 00000000000..1d3e88a51d4
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
index e0e3ec8a94d..5514049c78d 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
@@ -8,17 +8,35 @@
<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; })`)
+ return Promise.resolve(`import("../../../imports-a.js?1").then(() => { self.ran = true; })`)
.then(eval)
.then(() => {
assert_true(self.ran);
@@ -42,7 +60,7 @@ promise_test(t => {
self.ran = false;
})
- return Promise.resolve(`return import("../imports-a.js?2").then(() => { self.ran = true; })`)
+ return Promise.resolve(`return import("../../../imports-a.js?2").then(() => { self.ran = true; })`)
.then(Function)
.then(Function.prototype.call.bind(Function.prototype.call))
.then(() => {
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html
new file mode 100644
index 00000000000..77de19e74bc
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js
new file mode 100644
index 00000000000..82982b4d93c
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js
@@ -0,0 +1,58 @@
+// 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");
+
+test(() => {
+ assert_equals(typeof importMetaOnRootModule, "object");
+ assert_not_equals(importMetaOnRootModule, null);
+}, "import.meta is an object");
+
+test(() => {
+ importMetaOnRootModule.newProperty = 1;
+ assert_true(Object.isExtensible(importMetaOnRootModule));
+}, "import.meta is extensible");
+
+test(() => {
+ const names = new Set(Reflect.ownKeys(importMetaOnRootModule));
+ for (const name of names) {
+ var desc = Object.getOwnPropertyDescriptor(importMetaOnRootModule, 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");
+
+
+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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
index 79f08ebaee3..284a15f2b23 100644
--- a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
@@ -1,66 +1,34 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
-<script type="module">
-import { importMetaOnRootModule, importMetaOnDependentModule }
- from "./import-meta-root.js";
+<script type="module" src="import-meta-url.any.js"></script>
-var base = location.href.slice(0, location.href.lastIndexOf('/'));
+<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");
-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");
-
-test(() => {
- assert_equals(typeof importMetaOnRootModule, "object");
- assert_not_equals(importMetaOnRootModule, null);
-}, "import.meta is an object");
-
-test(() => {
- importMetaOnRootModule.newProperty = 1;
- assert_true(Object.isExtensible(importMetaOnRootModule));
-}, "import.meta is extensible");
-
-test(() => {
- let names = new Set(Reflect.ownKeys(importMetaOnRootModule));
- for (name of names) {
- var desc = Object.getOwnPropertyDescriptor(importMetaOnRootModule, 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");
-
-
-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");
-
+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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js
new file mode 100644
index 00000000000..3618137aef9
--- /dev/null
+++ b/tests/wpt/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/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/promise-reject-and-remove.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/promise-reject-and-remove.html
new file mode 100644
index 00000000000..a3b2730e569
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/promise-reject-and-remove.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(t => {
+ window.onload = t.step_func_done();
+}, 'Removing iframe in promise reject handler should not crash');
+</script>
+<iframe src="resources/promise-reject-and-remove-iframe.html"></iframe>
diff --git a/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/promise-reject-and-remove-iframe.html b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/promise-reject-and-remove-iframe.html
new file mode 100644
index 00000000000..6da274469f8
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element/resources/promise-reject-and-remove-iframe.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script>
+const promise = Promise.reject();
+
+window.onload = () => {
+ promise.catch(() => parent.document.querySelector('iframe').remove());
+};
+</script>
+
+<!-- Load a slow script to delay window.onload for a while.
+ Without this, crashes are flaky. -->
+<script src="/common/slow.py"></script>