diff options
Diffstat (limited to 'tests/wpt/web-platform-tests/html/semantics/scripting-1/the-script-element')
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> |