summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module')
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html52
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html26
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html38
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html28
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html28
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html68
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js8
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js8
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html43
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html13
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html31
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html23
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html23
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html7
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html8
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html28
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js9
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js9
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py19
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js60
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js66
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html19
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html43
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html25
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html61
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html53
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html12
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js58
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js9
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html19
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js32
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js14
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js14
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js13
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html10
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html43
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html55
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html55
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js7
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html12
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html12
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html9
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py18
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html9
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js74
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html63
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html64
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html73
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html73
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html54
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html54
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html104
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html103
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html83
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html79
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html42
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html34
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html35
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html35
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js10
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html16
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html24
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js8
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js7
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html60
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html35
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html34
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html106
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html57
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html39
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js77
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js38
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html34
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js12
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html14
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js6
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js6
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html64
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html29
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html35
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html35
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html32
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html32
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html36
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html27
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html40
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html25
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html61
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html61
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html17
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html17
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html29
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html18
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html68
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html82
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html71
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html77
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html38
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html81
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html50
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py7
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js67
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html51
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html56
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py6
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html93
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html20
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html11
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html22
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html24
264 files changed, 5020 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js
new file mode 100644
index 0000000000..a53a3bebe7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/bad-module-specifier.js
@@ -0,0 +1,3 @@
+import "string-without-dot-slash-prefix";
+import "./this.js";
+log.push("bad-module-specifier");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html
new file mode 100644
index 0000000000..7cd4916309
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-01.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Root module scripts should always use UTF-8</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module" src="../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript&dummy=1"></script>
+<script type="module">
+test(function() {
+ assert_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'UTF-8 module script');
+</script>
+
+<script type="module" src="../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript&dummy=2" charset="windows-1250"></script>
+<script type="module">
+test(function() {
+ assert_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'UTF-8 module script with wrong charset in attribute');
+</script>
+
+<script type="module" src="../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript%3Bcharset=windows-1250&dummy=3"></script>
+<script type="module">
+test(function() {
+ assert_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'UTF-8 module script with wrong charset in Content-Type');
+</script>
+
+<script type="module" src="../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript&dummy=1"></script>
+<script type="module">
+test(function() {
+ assert_not_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'Non-UTF-8 module script');
+</script>
+
+<script type="module" src="../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript&dummy=2" charset="windows-1250"></script>
+<script type="module">
+test(function() {
+ assert_not_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'Non-UTF-8 module script with charset in attribute');
+</script>
+
+<script type="module" src="../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript%3Bcharset=windows-1250"></script>
+<script type="module">
+test(function() {
+ assert_not_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'Non-UTF-8 module script with charset in Content-Type');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html
new file mode 100644
index 0000000000..c7c4517ad3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-02.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Module scripts should ignore BOMs and always use UTF-8</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setup({allow_uncaught_exception: true});
+</script>
+<script type="module" src="../serve-with-content-type.py?fn=resources/bom-utf-8.js&ct=text/javascript"></script>
+<script type="module" src="../serve-with-content-type.py?fn=resources/bom-utf-16be.js&ct=text/javascript"></script>
+<script type="module" src="../serve-with-content-type.py?fn=resources/bom-utf-16le.js&ct=text/javascript"></script>
+<script type="module">
+test(function() {
+ assert_equals(window.executed_utf8_bom, '\u4e09\u6751\u304b\u306a\u5b50',
+ 'Should be decoded as UTF-8');
+}, 'UTF-8 module script with UTF-8 BOM');
+
+test(function() {
+ assert_equals(window.executed_utf16be_bom, undefined,
+ 'Should result in compile error because of UTF-16BE BOM');
+}, 'UTF-16 module script with UTF-16BE BOM');
+
+test(function() {
+ assert_equals(window.executed_utf16le_bom, undefined,
+ 'Should result in compile error because of UTF-16LE BOM');
+}, 'UTF-16 module script with UTF-16LE BOM');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html
new file mode 100644
index 0000000000..666cb2e68b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/charset-03.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Imported module scripts should always use UTF-8</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script type="module" src="resources/import-utf8.js"></script>
+<script type="module">
+test(function() {
+ assert_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'UTF-8 imported module script');
+</script>
+
+<script type="module" src="resources/import-utf8-with-charset-header.js"></script>
+<script type="module">
+test(function() {
+ assert_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'UTF-8 imported module script with wrong charset in Content-Type');
+</script>
+
+<script type="module" src="resources/import-non-utf8.js"></script>
+<script type="module">
+test(function() {
+ assert_not_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'Non-UTF-8 imported module script');
+</script>
+
+<script type="module" src="resources/import-non-utf8-with-charset-header.js"></script>
+<script type="module">
+test(function() {
+ assert_not_equals(window.getSomeString(), "śćążź",
+ 'Should be decoded as UTF-8');
+}, 'Non-UTF-8 imported module script with charset in Content-Type');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html
new file mode 100644
index 0000000000..50933da2c1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Choice of parse errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Parse errors in different files should be reported " +
+ "depending on different roots");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 4);
+
+ // Two different parse errors from different module scripts
+ // should be reported for each <script> element.
+ assert_equals(log[0].constructor, SyntaxError);
+ assert_equals(log[1], 1);
+
+ assert_equals(log[2].constructor, SyntaxError);
+ assert_equals(log[3], 2);
+
+ assert_not_equals(log[0], log[2],
+ 'two different parse errors should be reported');
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./choice-of-error-1a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./choice-of-error-1b.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js
new file mode 100644
index 0000000000..f479e5e1fa
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1a.js
@@ -0,0 +1,2 @@
+import './choice-of-error-1b.js';
+import './syntaxerror.js?1c';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js
new file mode 100644
index 0000000000..257f4a4678
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-1b.js
@@ -0,0 +1,2 @@
+import './choice-of-error-1a.js';
+import './syntaxerror.js?1d';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html
new file mode 100644
index 0000000000..51adb09d11
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Choice of instantiation errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Instantiation errors in different files should be reported " +
+ "depending on different roots");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 4);
+
+ // Two different instantiation errors from different module scripts
+ // should be reported for each <script> element.
+ assert_equals(log[0].constructor, SyntaxError);
+ assert_equals(log[1], 1);
+
+ assert_equals(log[2].constructor, SyntaxError);
+ assert_equals(log[3], 2);
+
+ assert_not_equals(log[0], log[2],
+ 'two different instantiation errors should be reported');
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./choice-of-error-2a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./choice-of-error-2b.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js
new file mode 100644
index 0000000000..2dc7aac11a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2a.js
@@ -0,0 +1,2 @@
+import './choice-of-error-2b.js';
+import './instantiation-error-1.js?2c';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js
new file mode 100644
index 0000000000..2adb9eea59
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-2b.js
@@ -0,0 +1,2 @@
+import './choice-of-error-2a.js';
+import './instantiation-error-1.js?2d';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html
new file mode 100644
index 0000000000..bc52119bfe
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>Choice of evaluation errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Evaluation errors are cached in intermediate module scripts");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 5);
+
+ // Evaluation errors, unlike parse/instantiation errors, are remembered
+ // and cached in module scripts between the root and the script that
+ // caused an evaluation error, and thus the same evaluation error
+ // is reported for both <script> elements.
+ assert_equals(log[0], "throw2");
+ assert_true(log[1].bar);
+ assert_equals(log[2], 1);
+
+ assert_true(log[3].bar);
+ assert_equals(log[4], 2);
+
+ assert_equals(log[1], log[3], 'evaluation errors must be the same');
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./choice-of-error-3a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./choice-of-error-3b.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js
new file mode 100644
index 0000000000..71154674a3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3a.js
@@ -0,0 +1,2 @@
+import './choice-of-error-3b.js';
+import './throw.js?3c';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js
new file mode 100644
index 0000000000..2131a35eff
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/choice-of-error-3b.js
@@ -0,0 +1,2 @@
+import './choice-of-error-3a.js';
+import './throw2.js?3d';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html
new file mode 100644
index 0000000000..ff580d4899
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-1.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Handling of compilation errors, 1</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+
+ const test_load = async_test(
+ "Test that syntax errors lead to SyntaxError events on window, " +
+ "and that exceptions are remembered.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 5);
+ assert_equals(log[0].constructor, SyntaxError);
+ assert_true(log.every(exn => exn === log[0]));
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html
new file mode 100644
index 0000000000..131a6e439f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/compilation-error-2.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Handling of compilation errors, 2</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+
+ const test_load = async_test(
+ "Test that syntax errors lead to SyntaxError events on window, " +
+ "and that exceptions are remembered.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 5);
+ assert_equals(log[0].constructor, SyntaxError);
+ assert_true(log.every(exn => exn === log[0]));
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror-nested.js" onerror="unreachable()"></script>
+<script type="module" src="./syntaxerror.js" onerror="unreachable()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html
new file mode 100644
index 0000000000..983961ae44
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/credentials.sub.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+document.cookie = 'same=1';
+
+const setCookiePromise = fetch(
+ 'http://{{domains[www2]}}:{{ports[http][0]}}/cookies/resources/set-cookie.py?name=cross&path=/html/semantics/scripting-1/the-script-element/module/',
+ {
+ mode: 'no-cors',
+ credentials: 'include',
+ });
+
+const windowLoadPromise = new Promise(resolve => {
+ window.addEventListener('load', () => {
+ resolve();
+ });
+});
+
+promise_test(t => {
+ const iframe = document.createElement('iframe');
+
+ return Promise.all([setCookiePromise, windowLoadPromise]).then(() => {
+ const messagePromise = new Promise(resolve => {
+ window.addEventListener('message', event => {
+ resolve();
+ });
+ });
+
+ iframe.src = 'resources/credentials-iframe.sub.html';
+ document.body.appendChild(iframe);
+
+ return messagePromise;
+ }).then(() => {
+ const w = iframe.contentWindow;
+
+ assert_equals(w.sameOriginNone, 'found',
+ 'Modules should be loaded with the credentials when the crossOrigin attribute is not specified and the target is same-origin');
+ assert_equals(w.sameOriginAnonymous, 'found',
+ 'Modules should be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is same-origin');
+ assert_equals(w.sameOriginUseCredentials, 'found',
+ 'Modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is same-origin');
+ assert_equals(w.crossOriginNone, 'not found',
+ 'Modules should not be loaded with the credentials when the crossOrigin attribute is not specified and the target is cross-origin');
+ assert_equals(w.crossOriginAnonymous, 'not found',
+ 'Modules should not be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is cross-origin');
+ assert_equals(w.crossOriginUseCredentials, 'found',
+ 'Modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is cross-origin');
+
+ assert_equals(w.sameOriginNoneDescendant, 'found',
+ 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is not specified and the target is same-origin');
+ assert_equals(w.sameOriginAnonymousDescendant, 'found',
+ 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is same-origin');
+ assert_equals(w.sameOriginUseCredentialsDescendant, 'found',
+ 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is same-origin');
+ assert_equals(w.crossOriginNoneDescendant, 'not found',
+ 'Descendant modules should not be loaded with the credentials when the crossOrigin attribute is not specified and the target is cross-origin');
+ assert_equals(w.crossOriginAnonymousDescendant, 'not found',
+ 'Descendant modules should not be loaded with the credentials when the crossOrigin attribute is specified with "anonymous" as its value and the target is cross-origin');
+ assert_equals(w.crossOriginUseCredentialsDescendant, 'found',
+ 'Descendant modules should be loaded with the credentials when the crossOrigin attribute is specified with "use-credentials" as its value and the target is cross-origin');
+});
+}, 'Modules should be loaded with or without the credentials based on the same-origin-ness and the crossOrigin attribute');
+</script>
+<body>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js
new file mode 100644
index 0000000000..59bf0fd42f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-common.js
@@ -0,0 +1,8 @@
+document._log = [];
+window.addEventListener("error", function (ev) {
+ var errorSerialized = ev.lineno + "-" + ev.colno;
+ document._log.push(errorSerialized);
+});
+window.addEventListener("load", function () {
+ document._log = document._log.join(",");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html
new file mode 100644
index 0000000000..8eb3292e89
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-different.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-import-NoCORS</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-import-NoCORS</h1>
+ <script type="module" onerror="document._log.push('error');">
+
+ import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js";
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html
new file mode 100644
index 0000000000..cccb30f718
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-missingheader.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-BlockedMissingHeader</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-BlockedMissingHeader</h1>
+ <script type="module" onerror="document._log.push('error');" crossorigin>
+
+ import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js";
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html
new file mode 100644
index 0000000000..84f4de1d7e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-same.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-WithCORS</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-WithCORS</h1>
+ <script type="module" crossorigin>
+
+ import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,*)";
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html
new file mode 100644
index 0000000000..5743a9e304
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-import-wrongheader.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-BlockedWrongHeader</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-BlockedWrongHeader</h1>
+ <script type="module" onerror="document._log.push('error');" crossorigin>
+
+ import { foo } from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,http://{{domains[www2]}}:{{ports[http][0]}})";
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html
new file mode 100644
index 0000000000..54d4354c53
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-different.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-NoCORS</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-NoCORS</h1>
+ <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js" onerror="document._log.push('error');"></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html
new file mode 100644
index 0000000000..03943002ba
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-missingheader.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-BlockedMissingHeader</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-BlockedMissingHeader</h1>
+ <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js" onerror="document._log.push('error');" crossorigin></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html
new file mode 100644
index 0000000000..3ec839e9a9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-same.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-WithCORS</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-WithCORS</h1>
+ <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,*)" crossorigin></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html
new file mode 100644
index 0000000000..c45736a896
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-root-wrongheader.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin-root-BlockedWrongHeader</title>
+ <script src="crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin-root-BlockedWrongHeader</h1>
+ <script type="module" src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js?pipe=header(Access-Control-Allow-Origin,http://{{domains[www2]}}:{{ports[http][0]}})" onerror="document._log.push('error');" crossorigin></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js
new file mode 100644
index 0000000000..29d04ec619
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin-scripterror.js
@@ -0,0 +1,8 @@
+export var foo = {};
+
+// Push an event to the log indicating that the script was executed.
+document._log.push("running");
+
+// Deliberately trigger an error to test what details of the error
+// the (possibly) cross-origin parent can listen to.
+nonExistentMethod();
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html
new file mode 100644
index 0000000000..5c8d6667b0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/crossorigin.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<html>
+<head>
+ <title>html-script-module-crossOrigin</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <h1>html-script-module-crossOrigin</h1>
+ <iframe id="root-WithCORS" src="crossorigin-root-same.sub.html"></iframe>
+ <iframe id="root-NoCORS" src="crossorigin-root-different.sub.html"></iframe>
+ <iframe id="root-BlockedMissingHeader" src="crossorigin-root-missingheader.sub.html"></iframe>
+ <iframe id="root-BlockedWrongHeader" src="crossorigin-root-wrongheader.sub.html"></iframe>
+ <iframe id="import-WithCORS" src="crossorigin-import-same.sub.html"></iframe>
+ <iframe id="import-NoCORS" src="crossorigin-import-different.sub.html"></iframe>
+ <iframe id="import-BlockedMissingHeader" src="crossorigin-import-missingheader.sub.html"></iframe>
+ <iframe id="import-BlockedWrongHeader" src="crossorigin-import-wrongheader.sub.html"></iframe>
+ <script>
+
+ var tests = [
+ { "obj": async_test("Root module, Error in CORS-same-origin script"), "id": "root-WithCORS", "expected": "running,8-1" },
+ { "obj": async_test("Root module, Blocked script download, missing CORS ACAO header"), "id": "root-NoCORS", "expected": "error" },
+ { "obj": async_test("Root module, Blocked script download, crossorigin attribute with missing CORS ACAO header"), "id": "root-BlockedMissingHeader", "expected": "error" },
+ { "obj": async_test("Root module, Blocked script download, mismatched CORS ACAO header"), "id": "root-BlockedWrongHeader", "expected": "error" },
+ { "obj": async_test("Imported module, Error in CORS-same-origin script"), "id": "import-WithCORS", "expected": "running,8-1" },
+ { "obj": async_test("Imported module, Blocked script download, missing CORS ACAO header"), "id": "import-NoCORS", "expected": "error" },
+ { "obj": async_test("Imported module, Blocked script download, crossorigin attribute with missing CORS ACAO header"), "id": "import-BlockedMissingHeader", "expected": "error" },
+ { "obj": async_test("Imported module, Blocked script download, mismatched CORS ACAO header"), "id": "import-BlockedWrongHeader", "expected": "error" },
+ ];
+
+ window.addEventListener("load", function () {
+ tests.forEach(function (test) {
+ var target = document.getElementById(test.id);
+ test.obj.step(function () {
+ assert_equals(target.contentDocument._log, test.expected, "Unexpected _log value");
+ });
+ test.obj.done();
+ });
+ });
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html
new file mode 100644
index 0000000000..146a9db60d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentScript-null.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module" src="set-currentScript-on-window.js"></script>
+<script type="module">
+import { currentScriptOnImportedModule } from "./currentscript.js";
+
+test(() => {
+ assert_equals(document.currentScript, null, "document.currentScript on inline scripts should be null");
+ assert_equals(currentScriptOnImportedModule, null, "document.currentScript on imported scripts should be null");
+ assert_equals(window.currentScriptRecorded, null, "document.currentScript on external module scripts should be null");
+}, "currentScript on script type=module should be all null");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js
new file mode 100644
index 0000000000..547359ff96
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/currentscript.js
@@ -0,0 +1 @@
+export let currentScriptOnImportedModule = window.document.currentScript;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html
new file mode 100644
index 0000000000..bd77a8f1bb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/custom-element-exception.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Handling of exceptions in custom element constructors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+ window.addEventListener("error", ev => log.push(ev.error));
+
+ const test_load = async_test(
+ "Test that exceptions from the constructor of a custom element " +
+ "inside a module are propagated as expected.\n");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(1, log.length);
+ const exception = log[0];
+ assert_true(exception instanceof Error);
+ assert_equals(exception.message, "custom element error");
+ }));
+</script>
+<script type="module">
+ class XThrower extends HTMLElement {
+ constructor() {
+ super();
+ throw new Error("custom element error");
+ }
+ }
+ customElements.define("x-thrower", XThrower);
+ document.createElement("x-thrower");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js
new file mode 100644
index 0000000000..1f91f93eb1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access-a.js
@@ -0,0 +1,3 @@
+log.push("cycle-tdz-access-a");
+import { Y } from "./cycle-tdz-access.js";
+export var X = Y;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js
new file mode 100644
index 0000000000..9df68b3b27
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-tdz-access.js
@@ -0,0 +1,3 @@
+log.push("cycle-tdz-access");
+import { X } from "./cycle-tdz-access-a.js";
+export let Y = X;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js
new file mode 100644
index 0000000000..12994f23d0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable-a.js
@@ -0,0 +1,2 @@
+export {x} from "./cycle-unresolvable.js";
+log.push("cycle-unresolvable-a");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js
new file mode 100644
index 0000000000..61c6d8dcb0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/cycle-unresolvable.js
@@ -0,0 +1,2 @@
+export {x} from "./cycle-unresolvable-a.js";
+log.push("cycle-unresolvable");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html
new file mode 100644
index 0000000000..57002a3e07
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Importing a module multiple times with the same specifier</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+window.log = [];
+</script>
+<script type="module">
+import { foo } from './export-something.js';
+import { set_foo } from './export-something.js';
+import default1 from './export-default.js';
+import default2 from './export-default.js';
+
+test(() => {
+ assert_array_equals(log, ['export-something', 'export-default']);
+ assert_equals(foo, 42);
+ set_foo(43);
+ assert_equals(foo, 43);
+ assert_equals(default1, "fox");
+ assert_equals(default2, "fox");
+}, 'Duplicated imports with the same specifier');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html
new file mode 100644
index 0000000000..6a01495c33
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/duplicated-imports-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Importing a module multiple times with the different specifier</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+window.log = [];
+</script>
+<script type="module">
+import { foo } from './export-something.js';
+import { set_foo } from '../module/export-something.js';
+import default1 from './export-default.js';
+import default2 from '../module/export-default.js';
+
+test(() => {
+ assert_array_equals(log, ['export-something', 'export-default']);
+ assert_equals(foo, 42);
+ set_foo(43);
+ assert_equals(foo, 43);
+ assert_equals(default1, "fox");
+ assert_equals(default2, "fox");
+}, 'Duplicated imports with the different specifier');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html
new file mode 100644
index 0000000000..817cf6d5dd
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker-importScripts.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<title>Base URLs used in resolving specifiers in dynamic imports from importScripts()</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker("./worker-importScripts.sub.js"));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html
new file mode 100644
index 0000000000..a12204281c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url-worker.sub.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<title>Base URLs used in resolving specifiers in dynamic imports from workers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+fetch_tests_from_worker(new Worker(
+ "../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"));
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html
new file mode 100644
index 0000000000..f7d4927a10
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/base-url.sub.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Base URLs used in resolving specifiers in dynamic imports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+self.testName = "same origin classic <script>";
+self.baseUrlSanitized = false;
+</script>
+<script src="../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script>
+
+<script>
+self.testName = "cross origin classic <script> without crossorigin attribute";
+self.baseUrlSanitized = true;
+</script>
+<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js"></script>
+
+<script>
+self.testName = "cross origin classic <script> with crossorigin attribute";
+self.baseUrlSanitized = false;
+</script>
+<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" crossorigin></script>
+
+<script>
+self.testName = "cross origin module <script>";
+self.baseUrlSanitized = false;
+</script>
+<script src="../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js%3Fpipe=header(Access-Control-Allow-Origin,*)" type="module"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js
new file mode 100644
index 0000000000..8a8530c9b6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/code-cache.js
@@ -0,0 +1,9 @@
+promise_test(() => {
+ return (new Function('w', 'return import(w)'))("./import.js?Function")
+ .then(module => assert_equals(module.A.from, 'alpha/import.js'));
+}, 'alpha - Function');
+
+promise_test(() => {
+ return eval('import("./import.js?eval")')
+ .then(module => assert_equals(module.A.from, 'alpha/import.js'));
+}, 'alpha - eval');
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js
new file mode 100644
index 0000000000..b2ac52df2a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/import.js
@@ -0,0 +1 @@
+export const A = { "from": "alpha/import.js" };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js
new file mode 100644
index 0000000000..904d32f9bf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/alpha/worker-importScripts.sub.js
@@ -0,0 +1,15 @@
+"use strict";
+
+importScripts("/resources/testharness.js");
+
+// CORS-same-origin
+self.testName = "same-origin importScripts()";
+self.baseUrlSanitized = false;
+importScripts("../beta/redirect.py?location=http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js");
+
+// CORS-cross-origin
+self.testName = "cross-origin importScripts()";
+self.baseUrlSanitized = true;
+importScripts("../beta/redirect.py?location=http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js");
+
+done();
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js
new file mode 100644
index 0000000000..1c2a2b636a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/code-cache.js
@@ -0,0 +1,9 @@
+promise_test(() => {
+ return (new Function('w', 'return import(w)'))("./import.js?Function")
+ .then(module => assert_equals(module.A.from, 'beta/import.js'));
+}, 'beta - Function');
+
+promise_test(() => {
+ return eval('import("./import.js?eval")')
+ .then(module => assert_equals(module.A.from, 'beta/import.js'));
+}, 'beta - eval');
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js
new file mode 100644
index 0000000000..7de1c68182
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/import.js
@@ -0,0 +1 @@
+export const A = { "from": "beta/import.js" };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py
new file mode 100644
index 0000000000..f2fd1ebd51
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/beta/redirect.py
@@ -0,0 +1,19 @@
+def main(request, response):
+ """Simple handler that causes redirection.
+
+ The request should typically have two query parameters:
+ status - The status to use for the redirection. Defaults to 302.
+ location - The resource to redirect to.
+ """
+ status = 302
+ if b"status" in request.GET:
+ try:
+ status = int(request.GET.first(b"status"))
+ except ValueError:
+ pass
+
+ response.status = status
+
+ location = request.GET.first(b"location")
+
+ response.headers.set(b"Location", location)
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js
new file mode 100644
index 0000000000..70cb20fa57
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.js
@@ -0,0 +1,60 @@
+function objectUrlFromModule(module) {
+ const blob = new Blob([module], { type: "text/javascript" });
+ return URL.createObjectURL(blob);
+}
+
+const moduleText = `export const foo = "bar";`;
+
+async_test((t) => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+ t.add_cleanup(() => URL.revokeObjectURL(moduleBlobUrl));
+
+ const worker = new Worker("./resources/blob-url-worker.js");
+ worker.postMessage(moduleBlobUrl);
+
+ worker.addEventListener(
+ "message",
+ t.step_func_done((evt) => {
+ assert_true(evt.data.importSucceeded);
+ assert_equals(evt.data.module.foo, "bar");
+ })
+ );
+}, "A blob URL created in a window agent can be imported from a worker");
+
+async_test((t) => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+ URL.revokeObjectURL(moduleBlobUrl);
+
+ const worker = new Worker("./resources/blob-url-worker.js");
+ worker.postMessage(moduleBlobUrl);
+
+ worker.addEventListener(
+ "message",
+ t.step_func_done((evt) => {
+ assert_false(evt.data.importSucceeded);
+ assert_equals(evt.data.errorName, "TypeError");
+ })
+ );
+}, "A blob URL revoked in a window agent will not resolve in a worker");
+
+promise_test(async (t) => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+
+ await import(moduleBlobUrl);
+
+ URL.revokeObjectURL(moduleBlobUrl);
+
+ const worker = new Worker("./resources/blob-url-worker.js");
+ worker.postMessage(moduleBlobUrl);
+
+ await new Promise((resolve) => {
+ worker.addEventListener(
+ "message",
+ t.step_func((evt) => {
+ assert_false(evt.data.importSucceeded);
+ assert_equals(evt.data.errorName, "TypeError");
+ resolve();
+ })
+ );
+ });
+}, "A revoked blob URL will not resolve in a worker even if it's in the window's module graph");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js
new file mode 100644
index 0000000000..0719a18bf1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.js
@@ -0,0 +1,66 @@
+// META: global=window,dedicatedworker,sharedworker,dedicatedworker-module,sharedworker-module
+
+function objectUrlFromModule(module) {
+ const blob = new Blob([module], { type: "text/javascript" });
+ return URL.createObjectURL(blob);
+}
+
+const moduleText = `export const foo = "bar";`;
+
+promise_test(async (t) => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+ t.add_cleanup(() => URL.revokeObjectURL(moduleBlobUrl));
+
+ const module = await import(moduleBlobUrl);
+ assert_equals(module.foo, "bar");
+}, "Blob URLs are supported in dynamic imports");
+
+promise_test(async (t) => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+ t.add_cleanup(() => URL.revokeObjectURL(moduleBlobUrl));
+
+ const module1 = await import(moduleBlobUrl);
+ const module2 = await import(moduleBlobUrl);
+ assert_equals(module1, module2);
+}, "Identical blob URLs resolve to the same module");
+
+promise_test(async (t) => {
+ const moduleBlob = new Blob([moduleText], { type: "text/javascript" });
+ const moduleBlobUrl1 = URL.createObjectURL(moduleBlob);
+ const moduleBlobUrl2 = URL.createObjectURL(moduleBlob);
+ t.add_cleanup(() => {
+ URL.revokeObjectURL(moduleBlobUrl1);
+ URL.revokeObjectURL(moduleBlobUrl2);
+ });
+
+ const module1 = await import(moduleBlobUrl1);
+ const module2 = await import(moduleBlobUrl2);
+ assert_not_equals(module1, module2);
+}, "Different blob URLs pointing to the same blob resolve to different modules");
+
+promise_test(async (t) => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+ URL.revokeObjectURL(moduleBlobUrl);
+
+ await promise_rejects_js(t, TypeError, import(moduleBlobUrl));
+}, "A revoked blob URL will not resolve");
+
+promise_test(async () => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+ const module1 = await import(moduleBlobUrl);
+
+ URL.revokeObjectURL(moduleBlobUrl);
+
+ const module2 = await import(moduleBlobUrl);
+ assert_equals(module1, module2);
+}, "A revoked blob URL will resolve if it's already in the module graph");
+
+promise_test(async () => {
+ const moduleBlobUrl = objectUrlFromModule(moduleText);
+
+ const importPromise = import(moduleBlobUrl);
+ URL.revokeObjectURL(moduleBlobUrl);
+
+ const module = await importPromise;
+ assert_equals(module.foo, "bar");
+}, "Revoking a blob URL immediately after calling import will not fail");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html
new file mode 100644
index 0000000000..688a6193a5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-base-url.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!--
+Regression test for https://crbug.com/990810:
+Functions with the same source code shouldn't be cached if their referencing
+scripts and host defined options are different.
+
+Each Function in the following three scripts should have different base URLs
+respectively, but in https://crbug.com/990810 the Function in
+`gamma/code-cache.js` reuses the Function in `beta/code-cache.js`, resulting in
+wrong base URL.
+-->
+
+<script src="alpha/code-cache.js"></script>
+<script src="beta/code-cache.js"></script>
+<script src="gamma/code-cache.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html
new file mode 100644
index 0000000000..bd920f8107
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/code-cache-nonce.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+// Regression test for https://crbug.com/979351:
+// This test loads a same script file (`resources/code-cache-nonce.js`)
+// with three different nonces (i.e. different host defined options).
+// Dynamic imports from the script therefore should have different nonces,
+// but when code caching ignores the difference in nonces, the first nonce
+// ('abc') is reused incorrectly for subsequent dynamic imports, causing
+// CSP violation (and thus dynamic import rejection).
+
+function runTest(nonce, description) {
+ // Perform a dynamic import with nonce=`nonce`
+ // from a page (`iframe`) with a matching CSP script-src 'nonce-`nonce`'.
+ // This should be successful.
+ promise_test(t => {
+ return new Promise((resolve, reject) => {
+ const iframe = document.createElement('iframe');
+ iframe.src = 'resources/code-cache-nonce-iframe.sub.html?nonce=' + nonce;
+ iframe.onload = () => {
+ // `globalThis.promise` is set by `resources/code-cache-nonce.js`.
+ // `t.step_timeout()` is workaround for https://crbug.com/1247801.
+ globalThis.promise.then(
+ v => t.step_timeout(() => resolve(v), 0),
+ v => t.step_timeout(() => reject(v), 0)
+ );
+ };
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => iframe.remove());
+ });
+ }, description);
+}
+
+// As `promise_test` are serialized, each iframe is created after previous
+// iframes and scripts are completely loaded.
+runTest('abc', 'First dynamic import should use nonce=abc');
+runTest('def', 'Second dynamic import should use nonce=def');
+runTest('ghi', 'Third dynamic import should use nonce=ghi');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html
new file mode 100644
index 0000000000..5ec6433e65
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/delay-load-event.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Dynamic imports don't delay the load event</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// Dynamic imports don't #delay-the-load-event.
+// Therefore, Window load event would be fired
+// just after the dynamic import() below starts.
+window.loaded = [];
+window.addEventListener('load', () => loaded.push('Window load event'));
+promise_test(t => {
+ loaded.push('import start');
+ // This 'loading' log is added to detect the previous Chromium behavior
+ // where the Window load event is delayed until just before script
+ // element's load event.
+ t.step_timeout(() => loaded.push('loading'), 1000);
+ return import("../resources/slow-module.js?pipe=trickle(d2)")
+ .then(() => {
+ assert_array_equals(
+ loaded,
+ ['import start', 'Window load event', 'loading', 'slow'],
+ "Window load event shouldn't be delayed by dynamic imports");
+ });
+}, "Dynamic imports don't delay the load event.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html
new file mode 100644
index 0000000000..189aa819fa
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials-setTimeout.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/dynamic-import-credentials-helper.sub.js"></script>
+
+<script type="text/javascript">
+runTestsFromIframe('../resources/dynamic-import-credentials-setTimeout-iframe.sub.html');
+</script>
+<body>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html
new file mode 100644
index 0000000000..910644531c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/dynamic-import-credentials-helper.sub.js"></script>
+
+<script type="text/javascript">
+runTestsFromIframe('../resources/dynamic-import-credentials-iframe.sub.html');
+</script>
+<body>
+</body>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html
new file mode 100644
index 0000000000..12738c7b97
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-fetch-error.sub.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>import(): error cases occuring during fetching</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script type="module">
+const cases = [
+ ["wrong MIME type", "../errorhandling-wrongMimetype.js?pipe=header(Content-Type,text/plain)"],
+ ["wrong MIME type of a dependency", "../errorhandling-wrongMimetype-import.js"],
+ ["404", "../resources/404-but-js.asis"],
+ ["404 of a dependency", "../resources/imports-404-but-js.js"],
+ ["500", "../resources/500-but-js.asis"],
+ ["500 of a dependency", "../resources/imports-500-but-js.js"],
+ ["cross-origin module (without CORS)", "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/imports-a.js"],
+ ["cross-origin module dependency (without CORS)", "../resources/imports-b-cross-origin.sub.js"]
+];
+
+for (const [label, specifier] of cases) {
+ promise_test(t => {
+ return promise_rejects_js(t, TypeError, import(specifier));
+ }, "import() must reject when there is a " + label);
+
+ promise_test(async t => {
+ // The use of ?x is used to separate tests so they don't interfere with each other.
+ // (However, it shouldn't matter anyway, in a spec-compliant implementation.)
+ const suffix = (specifier.includes("?") ? "&" : "?") + "x";
+ const promise1 = import(specifier + suffix);
+ const promise2 = import(specifier + suffix);
+
+ await promise_rejects_js(t, TypeError, promise1, "It must reject the first time");
+ await promise_rejects_js(t, TypeError, promise2, "It must reject the second time");
+
+ const error1 = await promise1.catch(e => e);
+ const error2 = await promise2.catch(e => e);
+
+ assert_not_equals(error1, error2, "The error objects must be different");
+ }, "import() must reject with a different error object for each import when there is a " + label);
+}
+
+promise_test(async t => {
+ const id = token();
+ const url = `./resources/status-changing-script.py?id=${id}`;
+
+ // Serve HTTP 404 for the first import().
+ await fetch(url + '&newStatus=404');
+ const promise1 = import(url);
+ await promise_rejects_js(t, TypeError, promise1,
+ "First import() must be rejected due to 404");
+
+ // Serve HTTP 200 after the first import() completes.
+ await fetch(url + '&newStatus=200');
+ const r = await fetch(url, { cache: 'no-cache' });
+ assert_equals(r.status, 200);
+
+ const promise2 = import(url);
+ await promise_rejects_js(t, TypeError, promise2,
+ "Second import() must be rejected, because the result of " +
+ "the first import() is cached in the module map");
+}, "import() fetch errors must be cached");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html
new file mode 100644
index 0000000000..e9b10e3bab
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-script-error.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<title>import(): error cases caused by the imported module script</title>
+<link rel="author" title="Kouhei Ueno" href="mailto:kouhei@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script type="module">
+const cases = [
+ ["parse error", "../syntaxerror.js", SyntaxError],
+ ["bad module specifier", "does-not-start-with-dot.js", TypeError, { differentErrorObjects: true }],
+ ["bad module specifier in a dependency", "../bad-module-specifier.js", TypeError],
+ ["instantiation error", "../instantiation-error-1.js", SyntaxError, { differentErrorObjects: true }],
+ ["evaluation error", "../throw-error.js", Error]
+];
+
+for (const [label, specifier, error, { differentErrorObjects } = {}] of cases) {
+ promise_test(t => {
+ return promise_rejects_js(t, error, import(specifier));
+ }, "import() must reject when there is a " + label);
+
+ const errorObjectsLabel = differentErrorObjects ? "different error objects" : "the same error object";
+ promise_test(async t => {
+ // The use of ?x is used to separate tests so they don't interfere with each other.
+ // (However, it shouldn't matter anyway, in a spec-compliant implementation.)
+ const promise1 = import(specifier + "?x");
+ const promise2 = import(specifier + "?x");
+
+ await promise_rejects_js(t, error, promise1, "It must reject the first time");
+ await promise_rejects_js(t, error, promise2, "It must reject the second time");
+
+ const error1 = await promise1.catch(e => e);
+ const error2 = await promise2.catch(e => e);
+
+ if (differentErrorObjects) {
+ assert_not_equals(error1, error2, "The error objects must be different");
+ } else {
+ assert_equals(error1, error2, "The error objects must be equal");
+ }
+ }, `import() must reject with ${errorObjectsLabel} for each import when there is a ${label}`);
+}
+
+promise_test(t => {
+ delete window.before_throwing_error;
+ delete window.after_throwing_error;
+
+ return promise_rejects_js(t, Error, import("../throw-error.js?y")).then(() => {
+ assert_true(window.before_throwing_error,
+ "the module script should run to a point where it throws exception");
+ assert_equals(window.after_throwing_error, undefined,
+ "the module script should not run after it throws exception");
+ });
+}, "import()ing a module with an evaluation error must stop evaluation");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html
new file mode 100644
index 0000000000..9807e21b0d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>Basic dynamic imports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module">
+promise_test(t => {
+ return import("./../imports-a.js").then(module => {
+ assert_true(window.evaluated_imports_a);
+ assert_equals(module.A["from"], "imports-a.js");
+ });
+}, "Dynamic imports should resolve module.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js
new file mode 100644
index 0000000000..ec7784983d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/base-url.sub.js
@@ -0,0 +1,58 @@
+"use strict";
+
+// This script triggers import(), and thus the base URL of this script
+// (either loaded by `<script>` or `importScripts()`) is used as the base URL
+// of resolving relative URL-like specifiers in `import()`.
+
+// The following fields should be set by the callers of this script
+// (unless loaded as the worker top-level script):
+// - self.testName (string)
+// - self.baseUrlSanitized (boolean)
+
+// When this script is loaded as the worker top-level script:
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope &&
+ !self.testName) {
+ importScripts("/resources/testharness.js");
+ self.testName = 'worker top-level script';
+ // Worker top-level scripts are always same-origin.
+ self.baseUrlSanitized = false;
+}
+
+{
+ // This could change by the time the test is executed, so we save it now.
+ // As this script is loaded multiple times, savedBaseUrlSanitized is scoped.
+ const savedBaseUrlSanitized = self.baseUrlSanitized;
+
+ promise_test(() => {
+ const promise = import("./import.js?pipe=header(Access-Control-Allow-Origin,*)&label=relative-" + self.testName);
+ if (savedBaseUrlSanitized) {
+ // The base URL is "about:blank" and thus import() here should fail.
+ return promise.then(module => {
+ // This code should be unreached, but assert_equals() is used here
+ // to log `module.A["from"]` in case of unexpected resolution.
+ assert_equals(module.A["from"], "(unreached)",
+ "Relative URL-like specifier resolution should fail");
+ assert_unreached();
+ },
+ () => {});
+ } else {
+ // The base URL is the response URL of this script, i.e.
+ // `.../gamma/base-url.sub.js`.
+ return promise.then(module => {
+ assert_equals(module.A["from"], "gamma/import.js");
+ });
+ }
+ },
+ "Relative URL-like from " + self.testName);
+}
+
+promise_test(() => {
+ return import("http://{{hosts[alt][]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js?pipe=header(Access-Control-Allow-Origin,*)&label=absolute-" + self.testName)
+ .then(module => {
+ assert_equals(module.A["from"], "gamma/import.js");
+ })
+ },
+ "Absolute URL-like from " + self.testName);
+
+done();
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js
new file mode 100644
index 0000000000..b470bc8ae5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/code-cache.js
@@ -0,0 +1,9 @@
+promise_test(() => {
+ return (new Function('w', 'return import(w)'))("./import.js?Function")
+ .then(module => assert_equals(module.A.from, 'gamma/import.js'));
+}, 'gamma - Function');
+
+promise_test(() => {
+ return eval('import("./import.js?eval")')
+ .then(module => assert_equals(module.A.from, 'gamma/import.js'));
+}, 'gamma - eval');
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js
new file mode 100644
index 0000000000..435c1369be
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/gamma/import.js
@@ -0,0 +1 @@
+export const A = { "from": "gamma/import.js" };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html
new file mode 100644
index 0000000000..13cc8b6624
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/inline-event-handler.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id='div' onmousedown='import("./../imports-a.js").then(window.continueTest);'></div>
+<script>
+const div = document.getElementById('div');
+
+promise_test(t => {
+ const promise = new Promise(resolve => window.continueTest = resolve);
+
+ const event = new MouseEvent('mousedown', {'button': 1});
+ div.dispatchEvent(event);
+
+ return promise.then(() => {
+ assert_true(window.evaluated_imports_a);
+ div.parentNode.removeChild(div);
+ });
+}, "dynamic import should work when triggered from inline event handlers");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js
new file mode 100644
index 0000000000..82cb3b215d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/basic.any.js
@@ -0,0 +1,32 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: script=ticker.js
+
+promise_test(async t => {
+ const getCount = ticker(1000);
+
+ const importP = import("<invalid>");
+ await promise_rejects_js(t, TypeError, importP, 'import() should reject');
+
+ assert_less_than(getCount(), 1000);
+}, "import() should not drain the microtask queue if it fails during specifier resolution");
+
+promise_test(async t => {
+ // Use Date.now() to ensure that the module is not in the module map
+ const specifier = "./empty-module.js?" + Date.now();
+
+ await import(specifier);
+
+ const getCount = ticker(1000);
+ await import(specifier);
+ assert_less_than(getCount(), 1000);
+}, "import() should not drain the microtask queue when loading an already loaded module");
+
+promise_test(async t => {
+ // Use Date.now() to ensure that the module is not in the module map
+ const specifier = "./empty-module.js?" + Date.now();
+
+ const getCount = ticker(1e7);
+ await import(specifier);
+ assert_equals(getCount(), 1e7);
+}, "import() should drain the microtask queue when fetching a new module");
+
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js
new file mode 100644
index 0000000000..bd6f5d092f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/css-import-in-worker.any.js
@@ -0,0 +1,14 @@
+// META: global=dedicatedworker,sharedworker
+// META: script=ticker.js
+
+promise_test(async t => {
+ // Use Date.now() to ensure that the module is not in the module map
+ const specifier = "./empty-module.css?" + Date.now();
+
+ const getCount = ticker(1000);
+
+ const importP = import(specifier, { assert: { type: "css" } });
+ await promise_rejects_js(t, TypeError, importP, 'import() should reject');
+
+ assert_less_than(getCount(), 1000);
+}, "import() should not drain the microtask queue if it fails because of the 'type: css' assertion in a worker");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css
new file mode 100644
index 0000000000..108e7649bd
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.css
@@ -0,0 +1,4 @@
+/*
+This file is empty, because all it matters is if the
+dynamic import that loads it fails or succedes.
+*/
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js
new file mode 100644
index 0000000000..108e7649bd
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/empty-module.js
@@ -0,0 +1,4 @@
+/*
+This file is empty, because all it matters is if the
+dynamic import that loads it fails or succedes.
+*/
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js
new file mode 100644
index 0000000000..4c75cab1b6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/serviceworker.any.js
@@ -0,0 +1,14 @@
+// META: global=serviceworker
+// META: script=ticker.js
+
+promise_test(async t => {
+ // Use Date.now() to ensure that the module is not in the module map
+ const specifier = "./empty-module.js?" + Date.now();
+
+ const getCount = ticker(1000);
+
+ const importP = import(specifier);
+ await promise_rejects_js(t, TypeError, importP, 'import() should reject');
+
+ assert_less_than(getCount(), 1000);
+}, "import() should not drain the microtask queue if it fails because it's used in a ServiceWorker");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js
new file mode 100644
index 0000000000..42619b6e70
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/ticker.js
@@ -0,0 +1,13 @@
+globalThis.ticker = function ticker(max) {
+ let i = 0;
+ let stop = false;
+ Promise.resolve().then(function loop() {
+ if (stop || i >= max) return;
+ i++;
+ Promise.resolve().then(loop);
+ });
+ return () => {
+ stop = true;
+ return i;
+ };
+};
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js
new file mode 100644
index 0000000000..f67ba9a1ae
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/with-import-assertions.any.js
@@ -0,0 +1,15 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: script=ticker.js
+
+promise_test(async t => {
+ // Use Date.now() to ensure that the module is not in the module map
+ const specifier = "./empty-module.js?" + Date.now();
+
+ const getCount = ticker(1000);
+
+ const importP = import(specifier, { assert: { type: "<invalid>" } });
+ await promise_rejects_js(t, TypeError, importP, 'import() should reject');
+
+ assert_less_than(getCount(), 1000);
+}, "import() should not drain the microtask queue if it fails while validating the 'type' assertion");
+
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html
new file mode 100644
index 0000000000..6c598aee39
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet-ref.https.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<canvas id ="output" width="100" height="100" style="background: blue;"></canvas>
+<script>
+"use strict";
+const canvas = document.getElementById('output');
+const ctx = canvas.getContext('2d');
+
+ctx.fillStyle = 'green';
+ctx.fillRect(0, 0, 100, 100);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html
new file mode 100644
index 0000000000..5cd59f86dc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/microtasks/worklet.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://html.spec.whatwg.org/#hostimportmoduledynamically(referencingscriptormodule,-specifier,-promisecapability)">
+<link rel="match" href="worklet-ref.https.html">
+<style>
+#output {
+ width: 100px;
+ height: 100px;
+ background-image: paint(rects);
+ background-color: blue;
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/worklet-reftest.js"></script>
+<body>
+<div id="output"></div>
+
+<script id="code" type="text/worklet">
+registerPaint('rects', class {
+ async paint(ctx, geom) {
+ ctx.fillStyle = 'red';
+
+ const getCount = ticker(1000);
+
+ try {
+ // Use Date.now() to ensure that the module is not in the module map
+ await import("./empty-module.js?" + Date.now());
+ } catch (e) {
+ if (getCount() < 1000) {
+ ctx.fillStyle = 'green';
+ }
+ }
+ ctx.fillRect(0, 0, geom.width, geom.height);
+ }
+});
+</script>
+
+<script>
+"use strict";
+CSS.paintWorklet.addModule("./ticker.js").then(() =>
+ importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent)
+);
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html
new file mode 100644
index 0000000000..b01f595c03
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-classic-manual.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic import when there is no active script</title>
+<link rel="help" href="https://github.com/whatwg/html/pull/4181">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<p>Click these buttons in sequence:</p>
+
+<button id="button1">Click me 1</button>
+
+<button id="button2">Click me 2</button>
+
+<p>The result will be pass/fail per the testharness.js results</p>
+
+<!-- We set the attributes from a separate script to specifically make
+ sure that it's not that script's base URL that gets used, but instead this page's. -->
+<script src="scripts/no-active-script.js"></script>
+
+<script>
+"use strict";
+setup({ explicit_timeout: true });
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = new Promise((resolve, reject) => {
+ window.continueTest1 = resolve;
+ window.errorTest1 = reject;
+ });
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+}, "onclick that directly imports should successfully import, using page's base URL");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = new Promise((resolve, reject) => {
+ window.continueTest2 = resolve;
+ window.errorTest2 = reject;
+ });
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+}, "onclick that indirectly imports after a task should successfully import, using page's base URL");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html
new file mode 100644
index 0000000000..359b71d821
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-module-manual.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic import when there is no active script</title>
+<link rel="help" href="https://github.com/whatwg/html/pull/4181">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<p>Click these buttons in sequence:</p>
+
+<button id="button1">Click me 1</button>
+
+<button id="button2">Click me 2</button>
+
+<p>The result will be pass/fail per the testharness.js results</p>
+
+<!-- We set the attributes from a separate script to specifically make
+ sure that it's not that script's base URL that gets used, but instead this page's. -->
+<script src="scripts/no-active-script.js" type="module"></script>
+
+<script type="module">
+"use strict";
+setup({ explicit_timeout: true });
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = new Promise((resolve, reject) => {
+ window.continueTest1 = resolve;
+ window.errorTest1 = reject;
+ });
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+}, "onclick that directly imports should successfully import, using page's base URL");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = new Promise((resolve, reject) => {
+ window.continueTest2 = resolve;
+ window.errorTest2 = reject;
+ });
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+}, "onclick that indirectly imports after a task should successfully import, using page's base URL");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html
new file mode 100644
index 0000000000..0958cfbeba
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-classic.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'">
+<script nonce="correct" src="/resources/testharness.js"></script>
+<script nonce="correct" src="/resources/testharnessreport.js"></script>
+<script nonce="correct" src="./propagate-nonce-external.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html
new file mode 100644
index 0000000000..47c422e59c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external-module.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'">
+<script nonce="correct" src="/resources/testharness.js"></script>
+<script nonce="correct" src="/resources/testharnessreport.js"></script>
+<script type="module" nonce="correct" src="./propagate-nonce-external.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js
new file mode 100644
index 0000000000..3b97d2f40e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-external.js
@@ -0,0 +1,7 @@
+// This file is loaded both as a module and as a classic script.
+promise_test(t => {
+ return import("../imports-a.js").then(module => {
+ assert_true(window.evaluated_imports_a);
+ assert_equals(module.A["from"], "imports-a.js");
+ });
+}, "Dynamically imported module should eval when imported from script w/ a valid nonce.");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html
new file mode 100644
index 0000000000..754110cb5e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-classic.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'">
+<script nonce="correct" src="/resources/testharness.js"></script>
+<script nonce="correct" src="/resources/testharnessreport.js"></script>
+<script nonce="correct">
+promise_test(t => {
+ return import("./../imports-a.js").then(module => {
+ assert_true(window.evaluated_imports_a);
+ assert_equals(module.A["from"], "imports-a.js");
+ });
+}, "Dynamically imported module should eval when imported from script w/ a valid nonce.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html
new file mode 100644
index 0000000000..f3322773a4
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/propagate-nonce-inline-module.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<meta http-equiv="content-security-policy" content="script-src 'nonce-correct'">
+<script nonce="correct" src="/resources/testharness.js"></script>
+<script nonce="correct" src="/resources/testharnessreport.js"></script>
+<script type="module" nonce="correct">
+promise_test(t => {
+ return import("./../imports-a.js").then(module => {
+ assert_true(window.evaluated_imports_a);
+ assert_equals(module.A["from"], "imports-a.js");
+ });
+}, "Dynamically imported module should eval when imported from script w/ a valid nonce.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js
new file mode 100644
index 0000000000..07071e05ce
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/blob-url-worker.js
@@ -0,0 +1,11 @@
+self.addEventListener("message", (evt) => {
+ const importModule = import(evt.data);
+ importModule.then(
+ (module) => {
+ self.postMessage({ importSucceeded: true, module: { ...module } });
+ },
+ (error) => {
+ self.postMessage({ importSucceeded: false, errorName: error.name });
+ }
+ );
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html
new file mode 100644
index 0000000000..56f915aac1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce-iframe.sub.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<meta http-equiv="content-security-policy"
+ content="script-src 'unsafe-eval' 'nonce-{{GET[nonce]}}'">
+<script src="code-cache-nonce.js" nonce="{{GET[nonce]}}"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js
new file mode 100644
index 0000000000..e9983fb6cd
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/code-cache-nonce.js
@@ -0,0 +1,4 @@
+// Note that the function source text is intentionally different from e.g.
+// ../alpha/code-cache.js to avoid caching Functions between different sets
+// of tests.
+parent.promise = (new Function('x', 'return import(x)'))('../../imports-a.js');
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html
new file mode 100644
index 0000000000..ad5ab30eda
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/empty-iframe.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ </head>
+ <body>
+ <div id="dummy"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py
new file mode 100644
index 0000000000..a44d3dd3eb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/status-changing-script.py
@@ -0,0 +1,18 @@
+def main(request, response):
+ headers = [(b"Content-Type", b"text/javascript"),
+ (b"Cache-Control", b"private, no-store")]
+
+ id = request.GET.first(b"id")
+
+ with request.server.stash.lock:
+ status = request.server.stash.take(id)
+ if status is None:
+ status = 200
+
+ new_status = request.GET.first(b"newStatus", None)
+ if new_status is not None:
+ status = int(new_status)
+
+ request.server.stash.put(id, status)
+
+ return status, headers, b""
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html
new file mode 100644
index 0000000000..c3a870b3f1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache-iframe.sub.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta http-equiv="content-security-policy"
+ content="script-src 'nonce-{{GET[nonce]}}'">
+<!--
+base element to make the base URLs of the Document and the script different
+-->
+<base href="../">
+<script src="resources/v8-code-cache.js?pipe=header(Cache-Control,max-age=1000)"
+ nonce="{{GET[nonce]}}" type="{{GET[type]}}"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js
new file mode 100644
index 0000000000..1d3e88a51d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/resources/v8-code-cache.js
@@ -0,0 +1,74 @@
+parent.promise = import('../../imports-a.js');
+
+// Padding for triggering V8 Code Cache on Chromium.
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
+// ============================================================================
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js
new file mode 100644
index 0000000000..447e5060b1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/Function.js
@@ -0,0 +1,2 @@
+// import()s in a dynamically created function are resolved relative to the script.
+Function(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`)();
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js
new file mode 100644
index 0000000000..100602733a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/eval.js
@@ -0,0 +1,2 @@
+// import()s in eval are resolved relative to the script.
+eval(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`);
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js
new file mode 100644
index 0000000000..3202ce47b9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/inline-event-handlers-UA-code.js
@@ -0,0 +1,3 @@
+// import()s in an event handler are resolved relative to the document base.
+window.dummyDiv.setAttribute("onclick", `import('./imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`);
+window.dummyDiv.click(); // different from **on**click()
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js
new file mode 100644
index 0000000000..85d8ac29ec
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/no-active-script.js
@@ -0,0 +1,5 @@
+"use strict";
+
+document.querySelector("#button1").setAttribute("onclick", "import('../imports-a.js?label=button1').then(window.continueTest1, window.errorTest1)");
+
+document.querySelector("#button2").setAttribute("onclick", "Promise.resolve(`import('../imports-a.js?label=button2')`).then(eval).then(window.continueTest2, window.errorTest2);");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js
new file mode 100644
index 0000000000..923eb7d8b6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/reflected-inline-event-handlers.js
@@ -0,0 +1,3 @@
+// import()s in an event handler are resolved relative to the document base.
+window.dummyDiv.setAttribute("onclick", `import('./imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`);
+window.dummyDiv.onclick();
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js
new file mode 100644
index 0000000000..342b342e8e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/scripts/setTimeout.js
@@ -0,0 +1,2 @@
+// import()s in a timeout handler are resolved relative to the script.
+setTimeout(`import('../../imports-a.js?label=' + window.label).then(window.continueTest, window.errorTest)`, 0);
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html
new file mode 100644
index 0000000000..855705e585
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-classic.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings uses the script base URL inside a classic script that is loaded from a file</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="dummy"></div>
+
+<base href="scripts/foo/">
+<script>
+// Tweak the base URL of the document here to distinguish:
+// - document URL
+// - document base URL = ../
+// - External scripts' base URL = ./scripts/eval.js etc.
+// - This inline script's base URL = ./scripts/foo/
+document.querySelector("base").remove();
+const base = document.createElement("base");
+base.setAttribute("href", "../");
+document.body.appendChild(base);
+
+function load(scriptSrc) {
+ const el = document.createElement("script");
+ el.src = scriptSrc;
+ document.body.appendChild(el);
+}
+
+function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ window.dummyDiv.removeAttribute("onclick");
+ delete window.evaluated_imports_a;
+ delete window.label;
+
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+window.dummyDiv = document.querySelector("#dummy");
+
+const evaluators = [
+ "setTimeout",
+ "eval",
+ "Function",
+ "reflected-inline-event-handlers",
+ "inline-event-handlers-UA-code"
+];
+
+for (const label of evaluators) {
+ promise_test(() => {
+ const promise = createTestPromise();
+
+ window.label = label;
+ load(`dynamic-import/scripts/${label}.js`);
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+};
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html
new file mode 100644
index 0000000000..d90af9c96a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-external-module.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings uses the script base URL inside a module script that is loaded from a file</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="dummy"></div>
+
+<base href="scripts/foo/">
+<script type="module">
+// Tweak the base URL of the document here to distinguish:
+// - document URL
+// - document base URL = ../
+// - External scripts' base URL = ./scripts/eval.js etc.
+// - This inline script's base URL = ./scripts/foo/
+document.querySelector("base").remove();
+const base = document.createElement("base");
+base.setAttribute("href", "../");
+document.body.appendChild(base);
+
+function load(scriptSrc) {
+ const el = document.createElement("script");
+ el.type = "module";
+ el.src = scriptSrc;
+ document.body.appendChild(el);
+}
+
+function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ window.dummyDiv.removeAttribute("onclick");
+ delete window.evaluated_imports_a;
+ delete window.label;
+
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+window.dummyDiv = document.querySelector("#dummy");
+
+const evaluators = [
+ "setTimeout",
+ "eval",
+ "Function",
+ "reflected-inline-event-handlers",
+ "inline-event-handlers-UA-code"
+];
+
+for (const label of evaluators) {
+ promise_test(() => {
+ const promise = createTestPromise();
+
+ window.label = label;
+ load(`dynamic-import/scripts/${label}.js`);
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+};
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html
new file mode 100644
index 0000000000..2fe1f75535
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-classic.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings uses the script base URL (= document base URL) inside an inline classic script</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<div id="dummy"></div>
+
+<base href="scripts/foo/">
+<script>
+// Tweak the base URL of the document here to distinguish:
+// - document URL
+// - document base URL = ../
+// - This inline script's base URL = ./scripts/foo/
+document.querySelector("base").remove();
+const base = document.createElement("base");
+base.setAttribute("href", "../");
+document.body.appendChild(base);
+
+function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+const dummyDiv = document.querySelector("#dummy");
+
+function doTest(label, evaluator, path) {
+ promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = createTestPromise();
+
+ evaluator(`import('${path}/imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+}
+
+// Inline script's base URL should be used.
+doTest("setTimeout", setTimeout, "../../..");
+doTest("eval", eval, "../../..");
+doTest("the Function constructor",
+ (x) => {
+ Function(x)();
+ },
+ "../../..");
+
+// Document's base URL should be used, as there are no active scripts.
+doTest("reflected inline event handlers",
+ (x) => {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.onclick();
+ },
+ ".");
+
+doTest("inline event handlers triggered via UA code",
+ (x) => {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.click(); // different from .**on**click()
+ },
+ ".");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html
new file mode 100644
index 0000000000..1691550ecb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-base-url-inline-module.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings uses the script base URL (= document base URL) inside an inline module script</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<div id="dummy"></div>
+
+<base href="scripts/foo/">
+<script type="module">
+// Tweak the base URL of the document here to distinguish:
+// - document URL
+// - document base URL = ../
+// - This inline script's base URL = ./scripts/foo/
+document.querySelector("base").remove();
+const base = document.createElement("base");
+base.setAttribute("href", "../");
+document.body.appendChild(base);
+
+function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+const dummyDiv = document.querySelector("#dummy");
+
+function doTest(label, evaluator, path) {
+ promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = createTestPromise();
+
+ evaluator(`import('${path}/imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+}
+
+// Inline script's base URL should be used.
+doTest("setTimeout", setTimeout, "../../..");
+doTest("eval", eval, "../../..");
+doTest("the Function constructor",
+ (x) => {
+ Function(x)();
+ },
+ "../../..");
+
+// Document's base URL should be used, as there are no active scripts.
+doTest("reflected inline event handlers",
+ (x) => {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.onclick();
+ },
+ ".");
+
+doTest("inline event handlers triggered via UA code",
+ (x) => {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.click(); // different from .**on**click()
+ },
+ ".");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html
new file mode 100644
index 0000000000..34ea00abc8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-classic.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings inside a classic script</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="dummy"></div>
+
+<script>
+function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+const dummyDiv = document.querySelector("#dummy");
+
+const evaluators = {
+ eval,
+ setTimeout,
+ "the Function constructor"(x) {
+ Function(x)();
+ },
+ "reflected inline event handlers"(x) {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.onclick();
+ },
+ "inline event handlers triggered via UA code"(x) {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.click(); // different from .**on**click()
+ }
+};
+
+for (const [label, evaluator] of Object.entries(evaluators)) {
+ promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = createTestPromise();
+
+ evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+};
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html
new file mode 100644
index 0000000000..b85d446d8d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-module.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings inside a module script</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="dummy"></div>
+
+<script type="module">
+function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+const dummyDiv = document.querySelector("#dummy");
+
+const evaluators = {
+ eval,
+ setTimeout,
+ "the Function constructor"(x) {
+ Function(x)();
+ },
+ "reflected inline event handlers"(x) {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.onclick();
+ },
+ "inline event handlers triggered via UA code"(x) {
+ dummyDiv.setAttribute("onclick", x);
+ dummyDiv.click(); // different from .**on**click()
+ }
+};
+
+for (const [label, evaluator] of Object.entries(evaluators)) {
+ promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ delete window.evaluated_imports_a;
+ });
+
+ const promise = createTestPromise();
+
+ evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
+
+ return promise.then(module => {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+};
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html
new file mode 100644
index 0000000000..b582eba8b0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-classic.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings uses the appropriate nonce inside a classic script</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<meta http-equiv="content-security-policy" content="script-src 'nonce-correct' 'unsafe-eval' 'unsafe-hashes' 'sha256-cAMzxBL19bKt4KwKGbxy/ZOFIIjH5AmRjlVbsD5pvNw=' 'sha256-3VjoJYNK/9HJMS8rrZHlqSZgUssDY+GPyc7AU8lNM3k='">
+
+<script nonce="correct" src="/resources/testharness.js"></script>
+<script nonce="correct" src="/resources/testharnessreport.js"></script>
+
+<div id="dummy"></div>
+
+<script nonce="correct">
+"use strict";
+const dummyDiv = document.querySelector("#dummy");
+
+function createTestPromise(t) {
+ t.add_cleanup(() => {
+ delete window.evaluated_imports_a;
+ delete window.unreached;
+ delete window.continueTest;
+ delete window.errorTest;
+ });
+
+ return new Promise((resolve, reject) => {
+ window.unreached = t.unreached_func("Must not reach this");
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+function assertSuccessful(module) {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+}
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ setTimeout(`import('../imports-a.js?label=setTimeout').then(window.continueTest, window.errorTest)`, 0);
+
+ return promise.then(assertSuccessful);
+}, "setTimeout must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ eval(`import('../imports-a.js?label=direct eval').then(window.continueTest, window.errorTest)`);
+
+ return promise.then(assertSuccessful);
+}, "direct eval must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ const evalAlias = eval;
+ evalAlias(`import('../imports-a.js?label=indirect eval').then(window.continueTest, window.errorTest)`);
+
+ return promise.then(assertSuccessful);
+}, "indirect eval must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ Function(`import('../imports-a.js?label=the Function constructor').then(window.continueTest, window.errorTest)`)();
+
+ return promise.then(assertSuccessful);
+}, "the Function constructor must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ });
+
+ const promise = createTestPromise(t);
+
+ // This only works because of the 'unsafe-hashes' and the hash in the CSP policy
+ dummyDiv.setAttribute(
+ "onclick",
+ `import('../imports-a.js?label=reflected inline event handlers').then(window.continueTest, window.errorTest)`
+ );
+ dummyDiv.onclick();
+
+ return promise_rejects_js(t, TypeError, promise);
+}, "reflected inline event handlers must not inherit the nonce from the triggering script, thus fail");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ });
+
+ const promise = createTestPromise(t);
+
+ // This only works because of the 'unsafe-hashes' and the hash in the CSP policy
+ dummyDiv.setAttribute(
+ "onclick",
+ `import('../imports-a.js?label=inline event handlers triggered via UA code').then(window.continueTest, window.errorTest)`
+ );
+ assert_equals(typeof dummyDiv.onclick, "function", "the browser must be able to parse a string containing the import() syntax into a function");
+ dummyDiv.click(); // different from **on**click()
+
+ return promise_rejects_js(t, TypeError, promise);
+}, "inline event handlers triggered via UA code must not inherit the nonce from the triggering script, thus fail");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html
new file mode 100644
index 0000000000..4fa1cc5877
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-nonce-module.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings uses the appropriate nonce inside a module script</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<meta http-equiv="content-security-policy" content="script-src 'nonce-correct' 'unsafe-eval' 'unsafe-hashes' 'sha256-cAMzxBL19bKt4KwKGbxy/ZOFIIjH5AmRjlVbsD5pvNw=' 'sha256-3VjoJYNK/9HJMS8rrZHlqSZgUssDY+GPyc7AU8lNM3k='">
+
+<script nonce="correct" src="/resources/testharness.js"></script>
+<script nonce="correct" src="/resources/testharnessreport.js"></script>
+
+<div id="dummy"></div>
+
+<script type="module" nonce="correct">
+const dummyDiv = document.querySelector("#dummy");
+
+function createTestPromise(t) {
+ t.add_cleanup(() => {
+ delete window.evaluated_imports_a;
+ delete window.unreached;
+ delete window.continueTest;
+ delete window.errorTest;
+ });
+
+ return new Promise((resolve, reject) => {
+ window.unreached = t.unreached_func("Must not reach this");
+ window.continueTest = resolve;
+ window.errorTest = reject;
+ });
+}
+
+function assertSuccessful(module) {
+ assert_true(window.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+}
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ setTimeout(`import('../imports-a.js?label=setTimeout').then(window.continueTest, window.errorTest)`, 0);
+
+ return promise.then(assertSuccessful);
+}, "setTimeout must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ eval(`import('../imports-a.js?label=direct eval').then(window.continueTest, window.errorTest)`);
+
+ return promise.then(assertSuccessful);
+}, "direct eval must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ const evalAlias = eval;
+ evalAlias(`import('../imports-a.js?label=indirect eval').then(window.continueTest, window.errorTest)`);
+
+ return promise.then(assertSuccessful);
+}, "indirect eval must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ const promise = createTestPromise(t);
+
+ Function(`import('../imports-a.js?label=the Function constructor').then(window.continueTest, window.errorTest)`)();
+
+ return promise.then(assertSuccessful);
+}, "the Function constructor must inherit the nonce from the triggering script, thus execute");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ });
+
+ const promise = createTestPromise(t);
+
+ // This only works because of the 'unsafe-hashes' and the hash in the CSP policy
+ dummyDiv.setAttribute(
+ "onclick",
+ `import('../imports-a.js?label=reflected inline event handlers').then(window.continueTest, window.errorTest)`
+ );
+ dummyDiv.onclick();
+
+ return promise_rejects_js(t, TypeError, promise);
+}, "reflected inline event handlers must not inherit the nonce from the triggering script, thus fail");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ dummyDiv.removeAttribute("onclick");
+ });
+
+ const promise = createTestPromise(t);
+
+ // This only works because of the 'unsafe-hashes' and the hash in the CSP policy
+ dummyDiv.setAttribute(
+ "onclick",
+ `import('../imports-a.js?label=inline event handlers triggered via UA code').then(window.continueTest, window.errorTest)`
+ );
+ assert_equals(typeof dummyDiv.onclick, 'function', "the browser must be able to parse a string containing the import() syntax into a function");
+ dummyDiv.click(); // different from **on**click()
+
+ return promise_rejects_js(t, TypeError, promise);
+}, "inline event handlers triggered via UA code must not inherit the nonce from the triggering script, thus fail");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
new file mode 100644
index 0000000000..5514049c78
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-of-promise-result.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>import() inside compiled strings inside a classic script</title>
+<link rel="help" href="https://github.com/whatwg/html/pull/3163">
+<link rel="help" href="https://github.com/tc39/ecma262/issues/871#issuecomment-292493142">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<base href="scripts/foo/">
+<script>
+"use strict";
+
+// This test is based on the current specification, but all browser
+// implementations aren't conformant. See
+// https://bugs.chromium.org/p/chromium/issues/detail?id=1245063
+// https://github.com/heycam/webidl/pull/902
+
+// Tweak the base URL of the document here to distinguish:
+// - document URL
+// - document base URL = ../
+// - This inline script's base URL = ./scripts/foo/
+document.querySelector("base").remove();
+const base = document.createElement("base");
+base.setAttribute("href", "../");
+document.body.appendChild(base);
+
+self.ran = false;
+
+// The active script for the dynamic import is this inline script
+// (see https://html.spec.whatwg.org/C/#hostmakejobcallback).
+promise_test(t => {
+ t.add_cleanup(() => {
+ self.ran = false;
+ })
+
+ return Promise.resolve(`import("../../../imports-a.js?1").then(() => { self.ran = true; })`)
+ .then(eval)
+ .then(() => {
+ assert_true(self.ran);
+ });
+}, "Evaled the script via eval, successful import");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ self.ran = false;
+ })
+
+ return Promise.resolve(`import("bad-specifier?1").catch(() => { self.ran = true; })`)
+ .then(eval)
+ .then(() => {
+ assert_true(self.ran);
+ });
+}, "Evaled the script via eval, failed import");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ self.ran = false;
+ })
+
+ return Promise.resolve(`return import("../../../imports-a.js?2").then(() => { self.ran = true; })`)
+ .then(Function)
+ .then(Function.prototype.call.bind(Function.prototype.call))
+ .then(() => {
+ assert_true(self.ran);
+ });
+}, "Evaled the script via Function, successful import");
+
+promise_test(t => {
+ t.add_cleanup(() => {
+ self.ran = false;
+ })
+
+ return Promise.resolve(`return import("bad-specifier?2").catch(() => { self.ran = true; })`)
+ .then(Function)
+ .then(Function.prototype.call.bind(Function.prototype.call))
+ .then(() => {
+ assert_true(self.ran);
+ });
+}, "Evaled the script via Function, failed import");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html
new file mode 100644
index 0000000000..3b1d98f6b1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/string-compilation-other-document.html
@@ -0,0 +1,79 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Check import() works when active script is in another document</title>
+<link rel="author" title="Jon Coppeard" href="mailto:jcoppeard@mozilla.com">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<iframe id="frame" src="resources/empty-iframe.html"></iframe>
+
+<script>
+
+function startTest() {
+ const otherWindow = document.getElementById("frame").contentWindow;
+ const otherDiv = otherWindow.document.getElementById("dummy");
+
+ function createTestPromise() {
+ return new Promise((resolve, reject) => {
+ otherWindow.continueTest = resolve;
+ otherWindow.errorTest = reject;
+ });
+ }
+
+ const evaluators = {
+ eval: otherWindow.eval,
+ setTimeout: otherWindow.setTimeout,
+ "the Function constructor"(x) {
+ otherWindow.Function(x)();
+ },
+ };
+
+ for (const [label, evaluator] of Object.entries(evaluators)) {
+ promise_test(t => {
+ t.add_cleanup(() => {
+ otherDiv.removeAttribute("onclick");
+ delete otherWindow.evaluated_imports_a;
+ });
+
+ const promise = createTestPromise();
+
+ evaluator(`import('../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
+
+ return promise.then(module => {
+ assert_true(otherWindow.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+ };
+
+ const eventHandlerEvaluators = {
+ "reflected inline event handlers"(x) {
+ otherDiv.setAttribute("onclick", x);
+ otherDiv.onclick();
+ },
+ "inline event handlers triggered by JS"(x) {
+ otherDiv.setAttribute("onclick", x);
+ otherDiv.click(); // different from .**on**click()
+ }
+ };
+
+ for (const [label, evaluator] of Object.entries(eventHandlerEvaluators)) {
+ promise_test(t => {
+ t.add_cleanup(() => {
+ otherDiv.removeAttribute("onclick");
+ delete otherWindow.evaluated_imports_a;
+ });
+
+ const promise = createTestPromise();
+
+ evaluator(`import('../../imports-a.js?label=${label}').then(window.continueTest, window.errorTest);`);
+
+ return promise.then(module => {
+ assert_true(otherWindow.evaluated_imports_a, "The module must have been evaluated");
+ assert_equals(module.A.from, "imports-a.js", "The module namespace object must be correct");
+ });
+ }, label + " should successfully import");
+ };
+}
+</script>
+<body onLoad="startTest()"></body>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html
new file mode 100644
index 0000000000..77de19e74b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/dynamic-import/v8-code-cache.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+// Regression test for https://crbug.com/1244145:
+// This test loads a same script file (`resources/v8-code-cache.js`)
+// multiple times to trigger V8 Code Cache.
+// Host defined options (including base URLs and nonces) are lost when the
+// script is compiled using the cached metadata, and thus causing
+// dynamic import failures due to wrong base URLs and wrong nonces.
+
+function runTest(type, nonce, description) {
+ promise_test(t => {
+ return new Promise((resolve, reject) => {
+ const iframe = document.createElement('iframe');
+ iframe.src = 'resources/v8-code-cache-iframe.sub.html?nonce=' + nonce + '&type=' + type;
+ iframe.onload = () => {
+ // `window.promise` is set by `resources/v8-code-cache.js`.
+ window.promise.then(resolve, reject);
+ };
+ document.body.appendChild(iframe);
+ t.add_cleanup(() => iframe.remove());
+ });
+ }, type + ': ' + description);
+}
+
+// As `promise_test` are serialized, each iframe is created after previous
+// iframes and scripts are completely loaded.
+for (const type of ['text/javascript', 'module']) {
+ // Cache the script in V8 Code Cache by running multiple times.
+ runTest(type, 'abc', 'Run #1');
+ runTest(type, 'abc', 'Run #2');
+ runTest(type, 'abc', 'Run #3');
+ runTest(type, 'abc', 'Run #4');
+ // Changing the nonce seems to disable compilation cache, trigger compilation
+ // using V8 Code Cache and thus expose the bug.
+ runTest(type, 'def', 'Run #5');
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html
new file mode 100644
index 0000000000..f336276f3f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-and-slow-dependency.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Module importing syntax error script and slow script should not crash UA</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module">
+setup({allow_uncaught_exception: true});
+window.log = [];
+window.loaded = false;
+</script>
+<script type="module">
+import "./syntaxerror.js";
+import "./resources/delayed-modulescript.py";
+
+window.loaded = true;
+</script>
+<script type="module">
+test(() => {
+ assert_false(loaded);
+ }, "module graph with a syntax error should not evaulate but should not crash UA.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html
new file mode 100644
index 0000000000..2480a60d6d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Handling of different types of errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "network error has higher priority than parse error");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 3);
+
+ // A parse error is reported for the first top-level
+ // <script> element for syntaxerror.js.
+ assert_equals(log[0].constructor, SyntaxError);
+ assert_equals(log[1], 1);
+
+ // onerror is called (with no errors reported) due to a network error
+ // for the second top-level <script>.
+ assert_equals(log[2], 2);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./syntaxerror.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./error-type-1.js"
+ onerror="log.push(2)" onload="unreachable()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js
new file mode 100644
index 0000000000..4882d3f2a5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-1.js
@@ -0,0 +1,2 @@
+import './syntaxerror.js';
+import './404.js';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html
new file mode 100644
index 0000000000..673bf28ca2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Handling of different types of errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "parse error has higher priority than instantiation error");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 4);
+
+ // An instantiation error is reported for the first top-level
+ // <script> element for instantiation-error-1.js.
+ assert_equals(log[0].constructor, SyntaxError);
+ assert_equals(log[1], 1);
+
+ // A parse error is reported for the second top-level <script>.
+ assert_equals(log[2].constructor, SyntaxError);
+ assert_equals(log[3], 2);
+ assert_not_equals(log[0], log[2]);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./instantiation-error-1.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./error-type-2.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js
new file mode 100644
index 0000000000..6b11397300
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-2.js
@@ -0,0 +1,2 @@
+import './instantiation-error-1.js';
+import './syntaxerror.js';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html
new file mode 100644
index 0000000000..8a16266f4c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Handling of different types of errors</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "instantiation error has higher priority than evaluation error");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 5);
+
+ // An evaluation error is reported for the first top-level
+ // <script> element for throw.js.
+ assert_equals(log[0], 'throw');
+ assert_true(log[1].foo);
+ assert_equals(log[2], 1);
+
+ // An instantiation error is reported for the second top-level <script>.
+ assert_equals(log[3].constructor, SyntaxError);
+ assert_equals(log[4], 2);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./throw.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./error-type-3.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js
new file mode 100644
index 0000000000..542be52846
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/error-type-3.js
@@ -0,0 +1,2 @@
+import './throw.js';
+import './instantiation-error-1.js';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js
new file mode 100644
index 0000000000..4eb5597a58
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-common.js
@@ -0,0 +1,10 @@
+function errorHandler(ev)
+{
+ document._errorReported.push("error");
+}
+
+document._errorReported = [];
+window.addEventListener("error", errorHandler);
+window.addEventListener("load", function () {
+ document._errorReported = document._errorReported.join(",");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html
new file mode 100644
index 0000000000..3a00f62f00
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html>
+<head>
+ <title>html-script-module-errorHandling-parseError-Dependent</title>
+ <script src="errorhandling-parseerror-common.js"></script>
+</head>
+<body>
+ <script type="module" onerror="errorHandler(event);">
+
+ // No parse errors in the root module, just in the dependent module
+ import test from "./errorhandling-parseerror-dependent.js";
+ document._errorReported = "shouldn't have run dependent module";
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js
new file mode 100644
index 0000000000..71872c47cf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependent.js
@@ -0,0 +1,2 @@
+// Parse error in a dependent module
+1A
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html
new file mode 100644
index 0000000000..7775aeabb4
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+<head>
+ <title>html-script-module-errorHandling-parseError-DependentMultiple</title>
+ <script src="errorhandling-parseerror-common.js"></script>
+</head>
+<body>
+ <script type="module" onerror="errorHandler(event)">
+
+ // No parse errors in the root module, just in the dependent module
+ import test from "./errorhandling-parseerror-dependentmultiple.js";
+ document._errorReported = "shouldn't have run dependent module";
+
+ </script>
+ <script type="module" onerror="errorHandler(event)">
+
+ // With the broken dependent module already acquired, try to import it
+ // again from another root. This root should be unwound appropriately.
+ import test from "./errorhandling-parseerror-dependentmultiple.js";
+ document._errorReported = "really shouldn't have run dependent module";
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js
new file mode 100644
index 0000000000..71872c47cf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-dependentmultiple.js
@@ -0,0 +1,2 @@
+// Parse error in a dependent module
+1A
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html
new file mode 100644
index 0000000000..012f3e9b8c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-parseerror-root.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html>
+<head>
+ <title>html-script-module-errorHandling-parseError-Root</title>
+ <script src="errorhandling-parseerror-common.js"></script>
+</head>
+<body>
+ <script type="module">
+
+ // Parse error in a root module
+ 1A
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js
new file mode 100644
index 0000000000..286e1a4229
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype-import.js
@@ -0,0 +1,8 @@
+import foo from "./errorhandling-wrongMimetype.js?pipe=header(Content-Type,text/plain)";
+
+// We don't expect this code to run, the import above should fail!
+// If we do run though, don't trigger an error that the testharness
+// might misinterpret as the import itself failing to load.
+
+var A = null;
+export { A };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js
new file mode 100644
index 0000000000..373a532445
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling-wrongMimetype.js
@@ -0,0 +1,7 @@
+// This is a plain JavaScript file, but since it will only be accessed with
+// a Content-Type of text/plain and nosniff, it will be seen as invalid.
+// The file itself will have no errors/effects, so if it does actually run,
+// no error will be detected, and the test will fail.
+
+var foo = null;
+export foo; \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html
new file mode 100644
index 0000000000..cf47465b49
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/errorhandling.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<html>
+<head>
+ <title>html-script-module-errorHandling</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+
+ iframe
+ { display: none; }
+
+ </style>
+</head>
+<body>
+ <h1>html-script-module-errorHandling</h1>
+ <iframe id="iframe_parseError_Root" src="errorhandling-parseerror-root.html"></iframe>
+ <iframe id="iframe_parseError_Dependent" src="errorhandling-parseerror-dependent.html"></iframe>
+ <iframe id="iframe_parseError_DependentMultiple" src="errorhandling-parseerror-dependentmultiple.html"></iframe>
+ <script>
+
+ var tests = [
+ { "id": "iframe_parseError_Root", "expected": "error" },
+ { "id": "iframe_parseError_Dependent", "expected": "error" },
+ { "id": "iframe_parseError_DependentMultiple", "expected": "error,error" },
+ ];
+ tests.forEach(function (testObj) {
+ var testHandle = async_test("IFrame test: '" + testObj.id + "'");
+ var testTarget = document.getElementById(testObj.id);
+ testTarget.addEventListener("load", testHandle.step_func(function () {
+ assert_equals(testTarget.contentDocument._errorReported, testObj.expected, "Unexpected _errorReported value");
+ testHandle.done();
+ }));
+ });
+
+ var test_wrongMimetype_root = async_test("External root module with non-script mimetype");
+ var script_wrongMimetype_root = document.createElement("script");
+ script_wrongMimetype_root.type = "module";
+ script_wrongMimetype_root.src = "errorhandling-wrongMimetype.js?pipe=header(Content-Type,text/plain)";
+ script_wrongMimetype_root.addEventListener("error", test_wrongMimetype_root.step_func(function () {
+ test_wrongMimetype_root.done();
+ }));
+ script_wrongMimetype_root.addEventListener("load", test_wrongMimetype_root.step_func(function () {
+ assert_unreached("This script should not have loaded!");
+ }));
+ document.body.appendChild(script_wrongMimetype_root);
+
+ var test_wrongMimetype_import = async_test("Module with imported non-script mimetype");
+ var script_wrongMimetype_import = document.createElement("script");
+ script_wrongMimetype_import.type = "module";
+ script_wrongMimetype_import.src = "errorhandling-wrongMimetype-import.js";
+ script_wrongMimetype_import.addEventListener("error", test_wrongMimetype_import.step_func(function () {
+ test_wrongMimetype_import.done();
+ }));
+ script_wrongMimetype_import.addEventListener("load", test_wrongMimetype_import.step_func(function () {
+ assert_unreached("This script should not have loaded!");
+ }));
+ document.body.appendChild(script_wrongMimetype_import);
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html
new file mode 100644
index 0000000000..3f2bb35f4e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-1.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Handling of evaluation errors, 1</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Test that exceptions during evaluation lead to error events on " +
+ "window, and that exceptions are remembered.\n");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const exn = log[1];
+ assert_array_equals(log,
+ ["throw", exn, "load", exn, "load", exn, "load", exn, "load"]);
+ assert_true(exn.foo);
+ }));
+
+ function logLoad() { log.push("load") }
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="throw.js" async onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="throw.js" nomodule onerror="unreachable()"
+ onload="logLoad()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html
new file mode 100644
index 0000000000..4f2b3c5a74
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-2.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Handling of evaluation errors, 2</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Test that ill-founded cyclic dependencies cause ReferenceError " +
+ "during evaluation, which leads to error events on window, and that " +
+ "exceptions are remembered.\n");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const exn = log[1];
+ assert_array_equals(log,
+ ["cycle-tdz-access-a", exn, "load", exn, "load", exn, "load"]);
+ assert_equals(exn.constructor, ReferenceError);
+ }));
+
+ function logLoad() { log.push("load"); }
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="cycle-tdz-access.js" async onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="cycle-tdz-access.js" nomodule onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="cycle-tdz-access.js" onerror="unreachable()"
+ onload="logLoad()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html
new file mode 100644
index 0000000000..9bfb5df2cf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-3.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Handling of evaluation errors, 3</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Test that exceptions during evaluation lead to error events on " +
+ "window, and that exceptions are remembered.\n");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const exn = log[1];
+ assert_array_equals(log,
+ ["throw", exn, "load", exn, "load", exn, "load", exn, "load",
+ exn, "load"]);
+ assert_true(exn.foo);
+ }));
+
+ function logLoad() { log.push("load"); }
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw-nested.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw-nested.js" onerror="unreachable()"
+ onload="logLoad()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html
new file mode 100644
index 0000000000..0b4b7d1662
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/evaluation-error-4.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Handling of evaluation errors, 4</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+ window.addEventListener("onunhandledrejection", unreachable);
+
+ const test_load = async_test(
+ "Test that exceptions during evaluation lead to error events on " +
+ "window, and that exceptions are remembered.\n");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const exn = log[1];
+ assert_array_equals(log,
+ ["throw", exn, "load", exn, "load", exn, "load", exn, "load",
+ exn, "load"]);
+ assert_true(exn.foo);
+ }));
+
+ function logLoad() { log.push("load"); }
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./throw-nested.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw-nested.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw-nested.js" onerror="unreachable()"
+ onload="logLoad()"></script>
+<script type="module" src="./throw.js" onerror="unreachable()"
+ onload="logLoad()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js
new file mode 100644
index 0000000000..d7115a2ac6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered2.js
@@ -0,0 +1,3 @@
+test_dynamicOrdered.step(function() {
+ assert_execCount(1, 2, "External script element (#1) should have fired second");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js
new file mode 100644
index 0000000000..c04e101bb8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered3.js
@@ -0,0 +1,3 @@
+test_dynamicOrdered.step(function() {
+ assert_execCount(1, 3, "External script element (#2) should have fired third");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js
new file mode 100644
index 0000000000..958736a3d8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicordered4.js
@@ -0,0 +1,3 @@
+test_dynamicOrdered.step(function() {
+ assert_execCount(1, 4, "External script element (#3) should have fired fourth");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js
new file mode 100644
index 0000000000..a54cb7a303
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered1.js
@@ -0,0 +1,3 @@
+test_dynamicUnordered1.step(function() {
+ test_dynamicUnordered1.done();
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js
new file mode 100644
index 0000000000..df0cd85421
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-dynamicunordered2.js
@@ -0,0 +1,3 @@
+test_dynamicUnordered2.step(function() {
+ test_dynamicUnordered2.done();
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js
new file mode 100644
index 0000000000..fca73bd9db
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered2.js
@@ -0,0 +1,3 @@
+test_parsedOrdered.step(function() {
+ assert_execCount(0, 2, "External deferred (#1) script element should have fired second");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js
new file mode 100644
index 0000000000..6435333bb9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedordered4.js
@@ -0,0 +1,3 @@
+test_parsedOrdered.step(function() {
+ assert_execCount(0, 4, "External deferred (#2) script element should have fired fourth");
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js
new file mode 100644
index 0000000000..ea0bb1b486
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered1.js
@@ -0,0 +1,3 @@
+test_parsedUnordered1.step(function() {
+ test_parsedUnordered1.done();
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js
new file mode 100644
index 0000000000..ce219ee0ea
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder-parsedunordered2.js
@@ -0,0 +1,3 @@
+test_parsedUnordered2.step(function() {
+ test_parsedUnordered2.done();
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html
new file mode 100644
index 0000000000..6a7513dc13
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/execorder.html
@@ -0,0 +1,106 @@
+<!doctype html>
+<html>
+<head>
+ <title>html-script-module-execOrder</title>
+ <meta name=timeout content=long>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script>
+
+ var execCounts = [
+ 0, // test_parsedOrdered
+ 0, // test_dynamicOrdered
+ ];
+ function assert_execCount(set, expected, description)
+ {
+ if (!execCounts[set])
+ {
+ execCounts[set] = 0;
+ }
+ assert_equals(++execCounts[set], expected, description);
+ }
+
+ function create_script(src, opts)
+ {
+ var element = document.createElement("script");
+ element.src = src;
+ element.async = (opts.asyncOrdered ? false : true);
+ element.type = (opts.module ? "module" : "text/javascript");
+ document.body.appendChild(element);
+ }
+
+ </script>
+</head>
+<body>
+ <h1>html-script-module-execOrder</h1>
+ <script>
+
+ /////
+ // Start test_parsedUnordered*
+ /////
+ var test_parsedUnordered1 = async_test("Unordered module script execution (parsed, unordered #1)");
+ var test_parsedUnordered2 = async_test("Unordered module script execution (parsed, unordered #2)");
+ </script>
+ <script type="module" src="execorder-parsedunordered1.js"></script>
+ <script type="module" src="execorder-parsedunordered2.js"></script>
+ <script>
+ /////
+ // End test_parsedUnordered*
+ /////
+
+ /////
+ // Start test_dynamicUnordered*
+ /////
+ var test_dynamicUnordered1 = async_test("Unordered module script execution (dynamic, unordered #1)");
+ var test_dynamicUnordered2 = async_test("Unordered module script execution (dynamic, unordered #2)");
+ create_script("execorder-dynamicunordered1.js", { module: true });
+ create_script("execorder-dynamicunordered2.js", { module: true });
+ /////
+ // End test_dynamicUnordered*
+ /////
+
+ /////
+ // Begin test_parsedOrdered
+ /////
+ var test_parsedOrdered = async_test("Interlaced module/non-module script execution (parsed, async-ordered)");
+ window.addEventListener("load", test_parsedOrdered.step_func(function() {
+ assert_execCount(0, 5, "onload should have fired fifth");
+ test_parsedOrdered.done();
+ }));
+ </script>
+ <script src="execorder-parsedordered2.js" defer></script>
+ <script type="module">
+ test_parsedOrdered.step(function() {
+ assert_execCount(0, 3, "Inline module-typed script element should have fired third");
+ });
+ </script>
+ <script src="execorder-parsedordered4.js" defer></script>
+ <script>
+ test_parsedOrdered.step(function() {
+ assert_execCount(0, 1, "Inline untyped script element should have fired first");
+ });
+ /////
+ // End test_parsedOrdered
+ /////
+
+ /////
+ // Start test_dynamicOrdered
+ /////
+ var test_dynamicOrdered = async_test("Interlaced module/non-module script execution (dynamic, async-ordered)");
+ window.addEventListener("load", test_dynamicOrdered.step_func(function() {
+ assert_execCount(1, 5, "onload should have fired fifth (last)");
+ test_dynamicOrdered.done();
+ }));
+ create_script("execorder-dynamicordered2.js", { asyncOrdered: true, module: false });
+ create_script("execorder-dynamicordered3.js", { asyncOrdered: true, module: true });
+ create_script("execorder-dynamicordered4.js", { asyncOrdered: true, module: false });
+ test_dynamicOrdered.step(function() {
+ assert_execCount(1, 1, "Inline untyped script element should have fired first");
+ });
+ /////
+ // End test_dynamicOrdered
+ /////
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js
new file mode 100644
index 0000000000..283830ab28
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-default.js
@@ -0,0 +1,2 @@
+log.push("export-default");
+export default "fox";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js
new file mode 100644
index 0000000000..ca806eb8b1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something-nested.js
@@ -0,0 +1,2 @@
+log.push("export-something-nested");
+export * from "./export-something.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js
new file mode 100644
index 0000000000..cf2c3a99fe
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/export-something.js
@@ -0,0 +1,3 @@
+log.push("export-something");
+export let foo = 42;
+export function set_foo(x) { foo = x };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html
new file mode 100644
index 0000000000..170bb665ff
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Handling of fetch errors, 1</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that failure to fetch root leads to error event on script.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, ["script"]);
+ }));
+</script>
+<script type="module" src="./no-such-file.js" onerror="log.push('script')"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html
new file mode 100644
index 0000000000..9386ce603a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Handling of fetch errors, 2</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that failure to fetch dependency leads to error event on script.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, ["script"]);
+ }));
+</script>
+<script type="module" src="./fetch-error-2.js" onerror="log.push('script')"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js
new file mode 100644
index 0000000000..20c0ea6402
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/fetch-error-2.js
@@ -0,0 +1,2 @@
+import "./no-such-file.js"
+import "./this.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js
new file mode 100644
index 0000000000..cfaeabc47e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-dependent.js
@@ -0,0 +1 @@
+export let importMetaOnDependentModule = import.meta;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js
new file mode 100644
index 0000000000..494e168102
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-object.any.js
@@ -0,0 +1,20 @@
+// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module
+
+test(() => {
+ assert_equals(typeof import.meta, "object");
+ assert_not_equals(import.meta, null);
+}, "import.meta is an object");
+
+test(() => {
+ import.meta.newProperty = 1;
+ assert_true(Object.isExtensible(import.meta));
+}, "import.meta is extensible");
+
+test(() => {
+ for (const name of Reflect.ownKeys(import.meta)) {
+ const desc = Object.getOwnPropertyDescriptor(import.meta, name);
+ assert_equals(desc.writable, true);
+ assert_equals(desc.enumerable, true);
+ assert_equals(desc.configurable, true);
+ }
+}, "import.meta's properties are writable, configurable, and enumerable");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html
new file mode 100644
index 0000000000..214b9bb59c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!--
+ More extensive tests of import maps and import.meta.resolve() will be
+ located in the import maps test suite. This contains some basic tests plus
+ tests some tricky parts of the import.meta.resolve() algorithm around string
+ conversion which are only testable with import maps.
+-->
+
+<script type="importmap">
+{
+ "imports": {
+ "bare": "https://example.com/",
+ "https://example.com/rewrite": "https://example.com/rewritten",
+
+ "1": "https://example.com/PASS-1",
+ "null": "https://example.com/PASS-null",
+ "undefined": "https://example.com/PASS-undefined",
+ "[object Object]": "https://example.com/PASS-object",
+
+ "./start": "./resources/export-1.mjs",
+ "./resources/export-1.mjs": "./resources/export-2.mjs"
+ }
+}
+</script>
+
+<script type="module">
+test(() => {
+ assert_equals(import.meta.resolve("bare"), "https://example.com/");
+}, "import.meta.resolve() given an import mapped bare specifier");
+
+test(() => {
+ assert_equals(import.meta.resolve("https://example.com/rewrite"), "https://example.com/rewritten");
+}, "import.meta.resolve() given an import mapped URL-like specifier");
+
+test(() => {
+ assert_equals(import.meta.resolve(), "https://example.com/PASS-undefined", "no-arg case");
+
+ assert_equals(import.meta.resolve(1), "https://example.com/PASS-1");
+ assert_equals(import.meta.resolve(null), "https://example.com/PASS-null");
+ assert_equals(import.meta.resolve(undefined), "https://example.com/PASS-undefined");
+
+ // Only toString() methods are consulted by ToString, not valueOf() ones.
+ // So this becomes "[object Object]".
+ assert_equals(import.meta.resolve({ valueOf() { return "./x"; } }), "https://example.com/PASS-object");
+}, "Testing the ToString() step of import.meta.resolve() via import maps");
+
+promise_test(async () => {
+ const one = (await import("./start")).default;
+ assert_equals(one, 1);
+
+ const two = (await import(import.meta.resolve("./start"))).default;
+ assert_equals(two, 2);
+}, "import(import.meta.resolve(x)) can be different from import(x)");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html
new file mode 100644
index 0000000000..d2e0f185e0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-multiple-scripts.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe src="resources/store-import-meta.html"></iframe>
+
+<script type="module">
+import * as otherImportMeta from "./resources/export-import-meta.mjs";
+setup({ explicit_done: true });
+
+window.onload = () => {
+ test(() => {
+ assert_not_equals(frames[0].importMetaURL, import.meta.url,
+ "Precondition check: we've set things up so that the other script has a different import.meta.url");
+
+ const expected = (new URL("resources/x", location.href)).href;
+ assert_equals(frames[0].importMetaResolve("./x"), expected);
+ }, "import.meta.resolve resolves URLs relative to the import.meta.url, not relative to the active script when it is called: another global's inline script");
+
+ test(() => {
+ const otherFrameImportMetaResolve = frames[0].importMetaResolve;
+
+ document.querySelector("iframe").remove();
+
+ const expected = (new URL("resources/x", location.href)).href;
+ assert_equals(otherFrameImportMetaResolve("./x"), expected);
+ }, "import.meta.resolve still works if its global has been destroyed (by detaching the iframe)");
+
+ test(() => {
+ assert_not_equals(otherImportMeta.url, import.meta.url,
+ "Precondition check: we've set things up so that the other script has a different import.meta.url");
+
+ const expected = (new URL("resources/x", location.href)).href;
+ assert_equals(otherImportMeta.resolve("./x"), expected);
+ }, "import.meta.resolve resolves URLs relative to the import.meta.url, not relative to the active script when it is called: another module script");
+
+ done();
+};
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js
new file mode 100644
index 0000000000..5b8a84efaf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve.any.js
@@ -0,0 +1,77 @@
+// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module
+
+import { importMetaOnRootModule, importMetaOnDependentModule }
+ from "./import-meta-root.js";
+
+test(() => {
+ assert_equals(typeof import.meta.resolve, "function");
+ assert_equals(import.meta.resolve.name, "resolve");
+ assert_equals(import.meta.resolve.length, 1);
+ assert_equals(Object.getPrototypeOf(import.meta.resolve), Function.prototype);
+}, "import.meta.resolve is a function with the right properties");
+
+test(() => {
+ assert_false(isConstructor(import.meta.resolve));
+
+ assert_throws_js(TypeError, () => new import.meta.resolve("./x"));
+}, "import.meta.resolve is not a constructor");
+
+test(() => {
+ // See also tests in ./import-meta-resolve-importmap.html.
+
+ assert_equals(import.meta.resolve({ toString() { return "./x"; } }), resolveURL("x"));
+ assert_throws_js(TypeError, () => import.meta.resolve(Symbol("./x")),
+ "symbol");
+ assert_throws_js(TypeError, () => import.meta.resolve(),
+ "no argument (which is treated like \"undefined\")");
+}, "import.meta.resolve ToString()s its argument");
+
+test(() => {
+ assert_equals(import.meta.resolve("./x"), resolveURL("x"),
+ "current module import.meta");
+ assert_equals(importMetaOnRootModule.resolve("./x"), resolveURL("x"),
+ "sibling module import.meta");
+ assert_equals(importMetaOnDependentModule.resolve("./x"), resolveURL("x"),
+ "dependency module import.meta");
+}, "Relative URL-like specifier resolution");
+
+test(() => {
+ assert_equals(import.meta.resolve("https://example.com/"), "https://example.com/",
+ "current module import.meta");
+ assert_equals(importMetaOnRootModule.resolve("https://example.com/"), "https://example.com/",
+ "sibling module import.meta");
+ assert_equals(importMetaOnDependentModule.resolve("https://example.com/"), "https://example.com/",
+ "dependency module import.meta");
+}, "Absolute URL-like specifier resolution");
+
+test(() => {
+ const invalidSpecifiers = [
+ "https://eggplant:b/c",
+ "pumpkins.js",
+ ".tomato",
+ "..zuccini.mjs",
+ ".\\yam.es"
+ ];
+
+ for (const specifier of invalidSpecifiers) {
+ assert_throws_js(TypeError, () => import.meta.resolve(specifier), specifier);
+ }
+}, "Invalid module specifiers");
+
+test(() => {
+ const { resolve } = import.meta;
+ assert_equals(resolve("https://example.com/"), "https://example.com/", "current module import.meta");
+}, "Works fine with no this value");
+
+function resolveURL(urlRelativeToThisTest) {
+ return (new URL(urlRelativeToThisTest, location.href)).href;
+}
+
+function isConstructor(o) {
+ try {
+ new (new Proxy(o, { construct: () => ({}) }));
+ return true;
+ } catch {
+ return false;
+ }
+}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js
new file mode 100644
index 0000000000..62ec082a8e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-root.js
@@ -0,0 +1,2 @@
+export let importMetaOnRootModule = import.meta;
+export { importMetaOnDependentModule } from "./import-meta-dependent.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js
new file mode 100644
index 0000000000..61d96f35af
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.any.js
@@ -0,0 +1,38 @@
+// META: global=dedicatedworker-module,sharedworker-module,serviceworker-module
+
+import { importMetaOnRootModule, importMetaOnDependentModule }
+ from "./import-meta-root.js";
+
+const base = location.href.slice(0, location.href.lastIndexOf('/'));
+
+test(() => {
+ assert_equals(importMetaOnRootModule.url,
+ base + "/import-meta-root.js");
+}, "import.meta.url in a root external script");
+
+test(() => {
+ assert_equals(importMetaOnDependentModule.url,
+ base + "/import-meta-dependent.js");
+}, "import.meta.url in a dependent external script");
+
+
+import { importMetaOnRootModule as hashedImportMetaOnRootModule1,
+ importMetaOnDependentModule as hashedImportMetaOnDependentModule1 }
+ from "./import-meta-root.js#1";
+
+import { importMetaOnRootModule as hashedImportMetaOnRootModule2,
+ importMetaOnDependentModule as hashedImportMetaOnDependentModule2 }
+ from "./import-meta-root.js#2";
+
+test(() => {
+ assert_equals(hashedImportMetaOnRootModule1.url,
+ base + "/import-meta-root.js#1");
+ assert_equals(hashedImportMetaOnRootModule2.url,
+ base + "/import-meta-root.js#2");
+
+ // Must not be affected
+ assert_equals(hashedImportMetaOnDependentModule1.url,
+ base + "/import-meta-dependent.js");
+ assert_equals(hashedImportMetaOnDependentModule2.url,
+ base + "/import-meta-dependent.js");
+}, "import.meta.url when importing the module with different fragments");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
new file mode 100644
index 0000000000..284a15f2b2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-url.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module" src="import-meta-url.any.js"></script>
+
+<script type="module">
+const base = location.href.slice(0, location.href.lastIndexOf('/'));
+
+test(() => {
+ assert_equals(import.meta.url, location.href);
+}, "import.meta.url in a root inline script");
+
+for (const workerType of ['DedicatedWorker', 'SharedWorker']) {
+ promise_test(async t => {
+ const worker_request_url =
+ new URL(`postmessage-worker.js?${workerType}`, location);
+ let w;
+ let port;
+ if (workerType === 'DedicatedWorker') {
+ w = new Worker(worker_request_url.href, {type: 'module'});
+ port = w;
+ } else {
+ w = new SharedWorker(worker_request_url.href, {type: 'module'});
+ port = w.port;
+ w.port.start();
+ }
+ w.onerror = t.unreached_func('Worker error');
+ const url = await new Promise(resolve => {
+ port.onmessage = evt => resolve(evt.data);
+ });
+ assert_equals(url, worker_request_url.href);
+ }, `import.meta.url at top-level module ${workerType}`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js
new file mode 100644
index 0000000000..3618137aef
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/postmessage-worker.js
@@ -0,0 +1,12 @@
+if ('DedicatedWorkerGlobalScope' in self &&
+ self instanceof DedicatedWorkerGlobalScope) {
+ postMessage(import.meta.url);
+} else if (
+ 'SharedWorkerGlobalScope' in self &&
+ self instanceof SharedWorkerGlobalScope) {
+ self.onconnect = function(e) {
+ const port = e.ports[0];
+ port.start();
+ port.postMessage(import.meta.url);
+ };
+}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs
new file mode 100644
index 0000000000..aef22247d7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-1.mjs
@@ -0,0 +1 @@
+export default 1;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs
new file mode 100644
index 0000000000..842e368a0a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-2.mjs
@@ -0,0 +1 @@
+export default 2;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs
new file mode 100644
index 0000000000..488ca74c93
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/export-import-meta.mjs
@@ -0,0 +1,2 @@
+export const url = import.meta.url;
+export const resolve = import.meta.resolve;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html
new file mode 100644
index 0000000000..c9751da408
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-meta/resources/store-import-meta.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<script type="module">
+window.importMetaURL = import.meta.url;
+window.importMetaResolve = import.meta.resolve;
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js
new file mode 100644
index 0000000000..32d90287d7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-something-namespace.js
@@ -0,0 +1,5 @@
+log.push("import-something-namespace");
+log.push(m.foo);
+m.set_foo(43);
+log.push(m.foo);
+import * as m from "./export-something.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html
new file mode 100644
index 0000000000..4911a071a0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/import-subgraph-404.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module">
+import { delayedLoaded } from "./resources/delayed-modulescript.py";
+import { A } from "./404.js";
+window.loadSuccess = delayedLoaded;
+</script>
+<script type="module">
+test(function () {
+ assert_equals(window.loadSuccess, undefined,
+ "module tree w/ its sub graph 404 should fail to load without crashing");
+}, "Import a module graph w/ sub-graph 404.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js
new file mode 100644
index 0000000000..44d1ac96c2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-a.js
@@ -0,0 +1,3 @@
+var A = { "from": "imports-a.js" };
+window.evaluated_imports_a = true;
+export { A };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js
new file mode 100644
index 0000000000..ae194e4d8a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-b.js
@@ -0,0 +1 @@
+export var B = { "from": "imports-b.js" };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js
new file mode 100644
index 0000000000..8bd8526f76
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-a.js
@@ -0,0 +1,2 @@
+import { CycleB } from "./imports-cycle-b.js";
+export var CycleA = "CycleA";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js
new file mode 100644
index 0000000000..218f350c39
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle-b.js
@@ -0,0 +1,2 @@
+import { CycleA } from "./imports-cycle-a.js";
+export var CycleB = "CycleB";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js
new file mode 100644
index 0000000000..88a77a4d67
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-cycle.js
@@ -0,0 +1,6 @@
+import { CycleA } from "./imports-cycle-a.js";
+
+test_importCycle.step(function () {
+ assert_equals(CycleA, "CycleA");
+ test_importCycle.done();
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js
new file mode 100644
index 0000000000..8cb2298e8a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-a.js
@@ -0,0 +1,2 @@
+import { A } from "./imports-a.js";
+export { A as INC_A };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js
new file mode 100644
index 0000000000..b7d84005c5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-ab.js
@@ -0,0 +1,5 @@
+import { A } from "./imports-a.js";
+export { A as INC_AB_A };
+
+import { B } from "./imports-b.js";
+export { B as INC_AB_B };
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js
new file mode 100644
index 0000000000..243b84fdd0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-inc-b.js
@@ -0,0 +1,2 @@
+import { B } from "./imports-b.js";
+export { B as INC_B }; \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js
new file mode 100644
index 0000000000..40eca1c8df
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self-inner.js
@@ -0,0 +1,2 @@
+import { SelfInner as SelfInnerA } from "./imports-self-inner.js";
+export var SelfInner = "SelfInner";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js
new file mode 100644
index 0000000000..05fa60e2dc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports-self.js
@@ -0,0 +1,6 @@
+import { SelfInner } from "./imports-self-inner.js";
+
+test_importSelf.step(function () {
+ assert_equals(SelfInner, "SelfInner");
+ test_importSelf.done();
+});
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html
new file mode 100644
index 0000000000..ca6900744d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/imports.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>html-script-module-imports</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <h1>html-script-module-imports</h1>
+
+ <script type="module">
+
+ import { A } from "./imports-a.js";
+
+ test(function () {
+ assert_equals(A.from, "imports-a.js", "Unexpected A");
+ }, "Import a simple module");
+
+ </script>
+ <script type="module">
+
+ import { B as B_RENAMED } from "./imports-b.js";
+
+ test(function () {
+ assert_equals(B_RENAMED.from, "imports-b.js", "Unexpected B_RENAMED");
+
+ try
+ {
+ B;
+ assert_unreached("Unexpectedly defined B");
+ }
+ catch (ex)
+ {}
+ }, "Import a simple module, renamed");
+
+ </script>
+ <script type="module">
+
+ import { INC_A } from "./imports-inc-a.js";
+ import { INC_B } from "./imports-inc-b.js";
+ import { INC_AB_A, INC_AB_B } from "./imports-inc-ab.js";
+
+ test(function () {
+ assert_equals(INC_A.from, "imports-a.js", "Unexpected INC_A");
+ assert_equals(INC_B.from, "imports-b.js", "Unexpected INC_A");
+ assert_equals(INC_AB_A.from, "imports-a.js", "Unexpected INC_A");
+ assert_equals(INC_AB_B.from, "imports-b.js", "Unexpected INC_A");
+ assert_equals(INC_A, INC_AB_A, "INC_A and INC_AB_A should be the same");
+ assert_equals(INC_B, INC_AB_B, "INC_B and INC_AB_B should be the same");
+ }, "Import the same module multiple times");
+
+ </script>
+
+ <script>
+ var test_importSelf = async_test("Import a module that validly imports itself");
+ </script>
+ <script type="module" src="imports-self.js"></script>
+
+ <script>
+ var test_importCycle = async_test("Import a module with a valid cyclical module dependency");
+ </script>
+ <script type="module" src="imports-cycle.js"></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html
new file mode 100644
index 0000000000..ce88c0a152
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inactive-context-import.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Dynamic import triggered from inactive context should not crash</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="container">
+<iframe></iframe>
+</div>
+
+<script>
+test(() => {
+ const iframe = document.querySelector('iframe');
+ const otherWindow = iframe.contentWindow;
+ iframe.remove();
+
+ // Below should not crash
+ otherWindow.eval(`import('foobar');`);
+}, 'dynamic import from inactive context should not crash');
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html
new file mode 100644
index 0000000000..db03612e82
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/inline-async-execorder.html
@@ -0,0 +1,29 @@
+<html>
+ <head>
+ <title>Inline async module script execution order</title>
+ <meta name=timeout content=long>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ let loaded = [];
+ let test = async_test("Inline async module script execution order");
+ window.addEventListener("load", test.step_func(function() {
+ assert_array_equals(loaded,
+ ["fast", "fast", "fast", "slow", "slow", "slow"]);
+ test.done();
+ }));
+ </script>
+ <script type="module" async src="resources/slow-module.js?pipe=trickle(d2)&unique=1"></script>
+ <script type="module" async>
+ import "./resources/slow-module.js?pipe=trickle(d2)&unique=2";
+ loaded.push("slow");
+ </script>
+ <script type="module" async src="resources/fast-module.js?unique=1"></script>
+ <script type="module" async>
+ import "./resources/fast-module.js?unique=2";
+ loaded.push("fast");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
new file mode 100644
index 0000000000..57b40f5baa
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 1</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ const test_load = async_test(
+ "Test that missing exports lead to SyntaxError events on window and " +
+ "load events on script");
+
+ window.log = [];
+ window.addEventListener("error", ev => {
+ test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+ log.push(ev.message);
+ });
+
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const msg = log[0];
+ assert_array_equals(log, [msg, 1, msg, 2, msg, 3, msg, 4, msg, 5]);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./missing-export.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./missing-export.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
+<script type="module" src="./missing-export-nested.js"
+ onerror="unreachable()" onload="log.push(3)"></script>
+<script type="module" src="./missing-export.js"
+ onerror="unreachable()" onload="log.push(4)"></script>
+<script type="module" src="./missing-export-nested.js"
+ onerror="unreachable()" onload="log.push(5)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js
new file mode 100644
index 0000000000..e317b01cc2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-1.js
@@ -0,0 +1 @@
+import something from "./instantiation-error-1.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
new file mode 100644
index 0000000000..27ba006fc7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-2.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 2</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ const test_load = async_test(
+ "Test that missing exports lead to SyntaxError events on window and " +
+ "load events on script");
+
+ window.log = [];
+ window.addEventListener("error", ev => {
+ test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+ log.push(ev.message);
+ });
+
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const msg = log[0];
+ assert_array_equals(log, [msg, 1, msg, 2, msg, 3, msg, 4, msg, 5]);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./missing-export-nested.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./missing-export-nested.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
+<script type="module" src="./missing-export.js"
+ onerror="unreachable()" onload="log.push(3)"></script>
+<script type="module" src="./missing-export-nested.js"
+ onerror="unreachable()" onload="log.push(4)"></script>
+<script type="module" src="./missing-export.js"
+ onerror="unreachable()" onload="log.push(5)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
new file mode 100644
index 0000000000..32f0a4a243
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-3.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 3</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ const test_load = async_test(
+ "Test that unresolvable cycles lead to SyntaxError events on window " +
+ "and load events on script");
+
+ window.log = [];
+ window.addEventListener("error", ev => {
+ test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+ log.push(ev.message);
+ });
+
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 6, 'Log length');
+ assert_equals(log[1], 1);
+ assert_equals(log[3], 2);
+ assert_equals(log[5], 3);
+ assert_not_equals(log[0], log[2],
+ 'Instantiation error objects for different root scripts');
+ assert_equals(log[0], log[4],
+ 'Instantiation error objects for the same root script');
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./cycle-unresolvable.js"
+ onerror="unreachable()" onload="log.push(1)" nomodule></script>
+<script type="module" src="./cycle-unresolvable-a.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
+<script type="module" src="./cycle-unresolvable.js"
+ onerror="unreachable()" onload="log.push(3)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
new file mode 100644
index 0000000000..8d3f23819a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 4</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+ const test_load = async_test(
+ "Test that loading a graph in which a module is already " +
+ "errored results in an error.");
+
+ window.addEventListener("error", ev => {
+ test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+ log.push(ev.message);
+ });
+
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 4, 'Log length');
+ assert_equals(log[1], 1);
+ assert_equals(log[3], 2);
+ assert_not_equals(log[0], log[2],
+ 'Instantiation error objects for different root scripts');
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./instantiation-error-4a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./instantiation-error-4d.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js
new file mode 100644
index 0000000000..6fed27f1c7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4a.js
@@ -0,0 +1,2 @@
+import "./instantiation-error-4b.js";
+log.push("instantiation-error-4a");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js
new file mode 100644
index 0000000000..4b702cae67
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4b.js
@@ -0,0 +1,3 @@
+import "./instantiation-error-4c.js";
+import "./instantiation-error-4d.js";
+log.push("instantiation-error-4b");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js
new file mode 100644
index 0000000000..ef699f6ca3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4c.js
@@ -0,0 +1,2 @@
+import {something} from "./instantiation-error-4c.js";
+log.push("instantiation-error-4c");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js
new file mode 100644
index 0000000000..ac04ccb9b3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-4d.js
@@ -0,0 +1,2 @@
+import {something} from "./instantiation-error-4d.js";
+log.push("instantiation-error-4d");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
new file mode 100644
index 0000000000..20df0bb5c9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 5</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ const test_load = async_test(
+ "Test that loading a graph in which a module is already " +
+ "errored results an error.");
+
+ window.log = [];
+ window.addEventListener("error", ev => {
+ test_load.step(() => assert_equals(ev.error.constructor, SyntaxError));
+ log.push(ev.message);
+ });
+
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 4, 'Log length');
+ assert_equals(log[1], 1);
+ assert_equals(log[3], 2);
+ assert_not_equals(log[0], log[2],
+ 'Instantiation error objects for different root scripts');
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./instantiation-error-5a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./instantiation-error-5d.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js
new file mode 100644
index 0000000000..b2e6b106b2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5a.js
@@ -0,0 +1,2 @@
+import "./instantiation-error-5b.js";
+log.push("instantiation-error-5a");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js
new file mode 100644
index 0000000000..2d37ae8fff
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5b.js
@@ -0,0 +1,3 @@
+import "./instantiation-error-5c.js";
+import "./instantiation-error-5d.js";
+log.push("instantiation-error-5b");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js
new file mode 100644
index 0000000000..ba221b6fc0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5c.js
@@ -0,0 +1,2 @@
+import {something} from "./instantiation-error-5c.js";
+log.push("instantiation-error-5c");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js
new file mode 100644
index 0000000000..9775e04f82
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5d.js
@@ -0,0 +1,3 @@
+import "./instantiation-error-5e.js";
+import "./instantiation-error-5a.js";
+log.push("instantiation-error-5d");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js
new file mode 100644
index 0000000000..8bd3b3c3bf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-5e.js
@@ -0,0 +1,2 @@
+import {something} from "./instantiation-error-5e.js";
+log.push("instantiation-error-5e");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html
new file mode 100644
index 0000000000..8d3ce121ee
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 6</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+
+ const test_load = async_test(
+ "Test that ambiguous star exports lead to an instantiation error " +
+ "and that the correct module is blamed.");
+ // Concretely, instantiation-error-6a.js fails to instantiate because it
+ // requests a name from instantion-error-6b.js that is ambiguous there.
+ // instantiation-error-6b.js itself, however, is fine, and it instantiates
+ // and evaluates successfully.
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const exn = log[0];
+ assert_array_equals(log, [
+ exn, 1,
+ "instantiation-error-6c",
+ "instantiation-error-6d",
+ "instantiation-error-6b", 2
+ ]);
+ assert_equals(exn.constructor, SyntaxError);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./instantiation-error-6a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./instantiation-error-6b.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js
new file mode 100644
index 0000000000..4db49c6c46
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6a.js
@@ -0,0 +1,2 @@
+import {foo} from "./instantiation-error-6b.js";
+log.push("instantiation-error-6a");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js
new file mode 100644
index 0000000000..35272fe550
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6b.js
@@ -0,0 +1,3 @@
+export * from "./instantiation-error-6c.js";
+export * from "./instantiation-error-6d.js";
+log.push("instantiation-error-6b");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js
new file mode 100644
index 0000000000..69d616b4ba
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6c.js
@@ -0,0 +1,2 @@
+export let foo = "c";
+log.push("instantiation-error-6c");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js
new file mode 100644
index 0000000000..d1336a57a2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-6d.js
@@ -0,0 +1,2 @@
+export let foo = "d";
+log.push("instantiation-error-6d");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html
new file mode 100644
index 0000000000..57f1f87216
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 7</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+
+ const test_load = async_test(
+ "Test that ambiguous star exports lead to an instantiation error, " +
+ "even when discovered through a star export, and that the correct " +
+ "module is blamed.");
+ // This is a variation of instantiation-error-6.html (see the explanation
+ // there).
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ const exn = log[0];
+ assert_array_equals(log, [
+ exn, 1,
+ "instantiation-error-7d",
+ "instantiation-error-7e",
+ "instantiation-error-7c",
+ "instantiation-error-7f",
+ "instantiation-error-7b", 2
+ ]);
+ assert_equals(exn.constructor, SyntaxError);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./instantiation-error-7a.js"
+ onerror="unreachable()" onload="log.push(1)"></script>
+<script type="module" src="./instantiation-error-7b.js"
+ onerror="unreachable()" onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js
new file mode 100644
index 0000000000..d27a44865c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7a.js
@@ -0,0 +1,2 @@
+import {foo} from "./instantiation-error-7b.js";
+log.push("instantiation-error-7a");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js
new file mode 100644
index 0000000000..8c05d3b727
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7b.js
@@ -0,0 +1,3 @@
+export * from "./instantiation-error-7c.js";
+export * from "./instantiation-error-7f.js";
+log.push("instantiation-error-7b");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js
new file mode 100644
index 0000000000..fff1368034
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7c.js
@@ -0,0 +1,3 @@
+export * from "./instantiation-error-7d.js";
+export * from "./instantiation-error-7e.js";
+log.push("instantiation-error-7c");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js
new file mode 100644
index 0000000000..fa5e7651f4
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7d.js
@@ -0,0 +1,2 @@
+export let foo = "d";
+log.push("instantiation-error-7d");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js
new file mode 100644
index 0000000000..6547c3fe6a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7e.js
@@ -0,0 +1,2 @@
+export let foo = "e";
+log.push("instantiation-error-7e");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js
new file mode 100644
index 0000000000..7f9ec5d12e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-7f.js
@@ -0,0 +1,2 @@
+export let foo = "f";
+log.push("instantiation-error-7f");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html
new file mode 100644
index 0000000000..080b170233
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/instantiation-error-8.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Handling of instantiation errors, 8</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<!-- The below module tree should fail to instantiate, since it references undefined identifier. -->
+<script type="module" src="instantiation-error-1.js"></script>
+<script>
+setup({allow_uncaught_exception: true});
+
+promise_test(t => {
+ return new Promise(resolve => {
+ window.addEventListener("error", e => {
+ assert_equals(e.error.constructor, SyntaxError);
+ resolve();
+ }, { once: true });
+ }).then(() => new Promise(resolve => {
+ window.addEventListener("error", e => {
+ assert_equals(e.error.constructor, SyntaxError);
+ resolve();
+ }, { once: true });
+ // Load another module tree w/ previously instantiate-failed tree as its sub-tree.
+ document.head.appendChild(Object.assign(
+ document.createElement('script'),
+ { type: 'module', innerText: 'import "./instantiation-error-1.js"'}));
+ }));
+}, "Instantiate attempt on a tree w/ previously instantiate-failed tree as a sub-tree shouldn't crash.");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js
new file mode 100644
index 0000000000..369b3e7827
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches-inner.js
@@ -0,0 +1 @@
+window.matchesLog.push("integrity-matches-inner");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js
new file mode 100644
index 0000000000..d8c4219e90
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-matches.js
@@ -0,0 +1,2 @@
+import "./integrity-matches-inner.js";
+window.matchesLog.push("integrity-matches");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js
new file mode 100644
index 0000000000..8182d4de16
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches-inner.js
@@ -0,0 +1 @@
+window.mismatchesLog.push("integrity-mismatches-inner");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js
new file mode 100644
index 0000000000..2d47344a5a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity-mismatches.js
@@ -0,0 +1,2 @@
+import "./integrity-mismatches-inner.js";
+window.mismatchesLog.push("integrity-mismatches");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html
new file mode 100644
index 0000000000..c79843624f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/integrity.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>&lt;script> integrity=""</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+window.inlineRan = false;
+
+window.matchesLog = [];
+window.matchesEvents = [];
+
+window.mismatchesLog = [];
+window.mismatchesEvents = [];
+</script>
+
+<script type="module" integrity="sha384-garbage">
+window.inlineRan = true;
+</script>
+
+<script type="module" src="integrity-matches.js" integrity="sha384-1/XwTy38IAlmvk1O674Efus1/REqfuX6x0V/B2/GX5R3lNbRjhrIwlWyEDPyOwpN" onload="window.matchesEvents.push('load');" onerror="window.matchesEvents.push('error')"></script>
+<script type="module" src="integrity-mismatches.js" integrity="sha384-doesnotmatch" onload="window.mismatchesEvents.push('load');" onerror="window.mismatchesEvents.push('error')"></script>
+
+<script type="module">
+test(() => {
+ assert_true(window.inlineRan);
+}, "The integrity attribute must have no affect on inline module scripts");
+
+test(() => {
+ assert_array_equals(window.matchesLog, ["integrity-matches-inner", "integrity-matches"], "The module and its dependency must have executed");
+ assert_array_equals(window.matchesEvents, ["load"], "The load event must have fired");
+}, "The integrity attribute must be verified on the top-level of a module and allow it to execute when it matches");
+
+test(() => {
+ assert_array_equals(window.mismatchesLog, [], "The module and its dependency must not have executed");
+ assert_array_equals(window.mismatchesEvents, ["error"], "The error event must have fired");
+}, "The integrity attribute must be verified on the top-level of a module and not allow it to execute when there's a mismatch");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html
new file mode 100644
index 0000000000..00269efdf9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-namespace-request.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Late namespace request</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test the situation where a module is instantiated without the " +
+ "need for a namespace object, but later on a different module " +
+ "requests the namespace.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log,
+ ["export-something",
+ "import-something-namespace", 42, 43]);
+ }));
+</script>
+<script type="module" src="export-something.js"></script>
+<script type="module" src="import-something-namespace.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html
new file mode 100644
index 0000000000..d40bb0aca7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/late-star-export-request.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Late star-export request</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test the situation where a module is instantiated without a use of " +
+ "its star-exports, but later on a different module requests them.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, [
+ "export-something", "export-something-nested",
+ "import-something-namespace", 42, 43]);
+ }));
+</script>
+<script type="module" src="export-something-nested.js"></script>
+<script type="module">
+ log.push("import-something-namespace");
+ log.push(foo);
+ set_foo(43);
+ log.push(foo);
+ import {foo, set_foo} from "./export-something-nested.js";
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html
new file mode 100644
index 0000000000..58397dd07d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events-inline.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<head>
+<title>load/error events for inline module scripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/load-error-events-helpers.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#execute-the-script-block">
+</head>
+<script>
+"use strict";
+
+var test1_load = event_test('src, 200, parser-inserted, defer, no async', false, false);
+var test4_load = event_test('src, 200, parser-inserted, no defer, async', false, false);
+
+var test3_dynamic_load = event_test('src, 200, not parser-inserted, no defer, no async, no non-blocking', false, false);
+var test4_dynamic_load = event_test('src, 200, not parser-inserted, no defer, async', false, false);
+
+var test1_error = event_test('src, 404, parser-inserted, defer, no async', false, true);
+var test4_error = event_test('src, 404, parser-inserted, no defer, async', false, true);
+
+var test3_dynamic_error = event_test('src, 404, not parser-inserted, no defer, no async, no non-blocking', false, true);
+var test4_dynamic_error = event_test('src, 404, not parser-inserted, no defer, async', false, true);
+
+var script3_dynamic_load = document.createElement('script');
+script3_dynamic_load.setAttribute('type', 'module');
+script3_dynamic_load.onload = () => onLoad(test3_dynamic_load);
+script3_dynamic_load.onerror = () => onError(test3_dynamic_load);
+script3_dynamic_load.async = false;
+script3_dynamic_load.appendChild(document.createTextNode('onExecute(test3_dynamic_load);'));
+document.head.appendChild(script3_dynamic_load);
+
+var script3_dynamic_error = document.createElement('script');
+script3_dynamic_error.setAttribute('type', 'module');
+script3_dynamic_error.onload = () => onLoad(test3_dynamic_error);
+script3_dynamic_error.onerror = () => onError(test3_dynamic_error);
+script3_dynamic_error.async = false;
+script3_dynamic_error.appendChild(document.createTextNode('import "./not_found.js";'));
+document.head.appendChild(script3_dynamic_error);
+
+var script4_dynamic_load = document.createElement('script');
+script4_dynamic_load.setAttribute('type', 'module');
+script4_dynamic_load.onload = () => onLoad(test4_dynamic_load);
+script4_dynamic_load.onerror = () => onError(test4_dynamic_load);
+script4_dynamic_load.async = true;
+script4_dynamic_load.appendChild(document.createTextNode('onExecute(test4_dynamic_load);'));
+document.head.appendChild(script4_dynamic_load);
+
+var script4_dynamic_error = document.createElement('script');
+script4_dynamic_error.setAttribute('type', 'module');
+script4_dynamic_error.onload = () => onLoad(test4_dynamic_error);
+script4_dynamic_error.onerror = () => onError(test4_dynamic_error);
+script4_dynamic_error.async = true;
+script4_dynamic_error.appendChild(document.createTextNode('import "./not_found.js";'));
+document.head.appendChild(script4_dynamic_error);
+</script>
+
+<script onload="onLoad(test1_load);" onerror="onError(test1_load);" type="module">"use strict";onExecute(test1_load);</script>
+<script onload="onLoad(test4_load);" onerror="onError(test4_load);" type="module" async>"use strict";onExecute(test4_load);</script>
+<script onload="onLoad(test1_error);" onerror="onError(test1_error);" type="module">"use strict";import "./not_found.js";</script>
+<script onload="onLoad(test4_error);" onerror="onError(test4_error);" type="module" async>"use strict";import "./not_found.js";</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html
new file mode 100644
index 0000000000..d9bf05226c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/load-error-events.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<head>
+<title>load/error events for external module scripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/load-error-events-helpers.js"></script>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#execute-the-script-block">
+</head>
+<script>
+"use strict";
+
+var test1_load = event_test('src, 200, parser-inserted, defer, no async', true, false);
+var test4_load = event_test('src, 200, parser-inserted, no defer, async', true, false);
+
+var test3_dynamic_load = event_test('src, 200, not parser-inserted, no defer, no async, no non-blocking', true, false);
+var test4_dynamic_load = event_test('src, 200, not parser-inserted, no defer, async', true, false);
+
+var test1_error = event_test('src, 404, parser-inserted, defer, no async', false, true);
+var test4_error = event_test('src, 404, parser-inserted, no defer, async', false, true);
+
+var test3_dynamic_error = event_test('src, 404, not parser-inserted, no defer, no async, no non-blocking', false, true);
+var test4_dynamic_error = event_test('src, 404, not parser-inserted, no defer, async', false, true);
+
+var script3_dynamic_load = document.createElement('script');
+script3_dynamic_load.setAttribute('type', 'module');
+script3_dynamic_load.onload = () => onLoad(test3_dynamic_load);
+script3_dynamic_load.onerror = () => onError(test3_dynamic_load);
+script3_dynamic_load.async = false;
+script3_dynamic_load.src = "../resources/load-error-events.py?test=test3_dynamic_load";
+document.head.appendChild(script3_dynamic_load);
+
+var script3_dynamic_error = document.createElement('script');
+script3_dynamic_error.setAttribute('type', 'module');
+script3_dynamic_error.onload = () => onLoad(test3_dynamic_error);
+script3_dynamic_error.onerror = () => onError(test3_dynamic_error);
+script3_dynamic_error.async = false;
+script3_dynamic_error.src = "../resources/load-error-events.py?test=test3_dynamic_error";
+document.head.appendChild(script3_dynamic_error);
+
+var script4_dynamic_load = document.createElement('script');
+script4_dynamic_load.setAttribute('type', 'module');
+script4_dynamic_load.onload = () => onLoad(test4_dynamic_load);
+script4_dynamic_load.onerror = () => onError(test4_dynamic_load);
+script4_dynamic_load.async = true;
+script4_dynamic_load.src = "../resources/load-error-events.py?test=test4_dynamic_load";
+document.head.appendChild(script4_dynamic_load);
+
+var script4_dynamic_error = document.createElement('script');
+script4_dynamic_error.setAttribute('type', 'module');
+script4_dynamic_error.onload = () => onLoad(test4_dynamic_error);
+script4_dynamic_error.onerror = () => onError(test4_dynamic_error);
+script4_dynamic_error.async = true;
+script4_dynamic_error.src = "../resources/load-error-events.py?test=test4_dynamic_error";
+document.head.appendChild(script4_dynamic_error);
+</script>
+
+<script src="../resources/load-error-events.py?test=test1_load" onload="onLoad(test1_load);" onerror="onError(test1_load);" type="module"></script>
+<script src="../resources/load-error-events.py?test=test4_load" onload="onLoad(test4_load);" onerror="onError(test4_load);" type="module" async></script>
+<script src="../resources/load-error-events.py?test=test1_error" onload="onLoad(test1_error);" onerror="onError(test1_error);" type="module"></script>
+<script src="../resources/load-error-events.py?test=test4_error" onload="onLoad(test4_error);" onerror="onError(test4_error);" type="module" async></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js
new file mode 100644
index 0000000000..860d2bf341
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export-nested.js
@@ -0,0 +1,2 @@
+import "./missing-export.js";
+log.push("nested-missing-export");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js
new file mode 100644
index 0000000000..e6f5746eb7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/missing-export.js
@@ -0,0 +1,2 @@
+import something from "./missing-export.js";
+log.push("missing-export");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml
new file mode 100644
index 0000000000..1655e61a7c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-in-xhtml.xhtml
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+window.evaluated_module_script = true;
+</script>
+<script>
+ var test = async_test("module script in XHTML documents should be evaluated.");
+ window.addEventListener("load", () => {
+ test.step(() => { assert_true(window.evaluated_module_script); });
+ test.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html
new file mode 100644
index 0000000000..ae82e1348a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-1.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Once as module script, once as classic script</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that evaluating something as classic script does not prevent " +
+ "it from being evaluated as module script.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, [window, undefined]);
+ }));
+</script>
+<script type="module" src="this.js"></script>
+<script src="this.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html
new file mode 100644
index 0000000000..fb512b4b30
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/module-vs-script-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Once as classic script, once as module script</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that evaluating something as classic script does not prevent " +
+ "it from being evaluated as module script.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, [window, undefined]);
+ }));
+</script>
+<script src="this.js"></script>
+<script type="module" src="this.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js
new file mode 100644
index 0000000000..a127aeb559
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-a.js
@@ -0,0 +1 @@
+import { b } from "./nested-imports-b.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js
new file mode 100644
index 0000000000..18a5af40cc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-b.js
@@ -0,0 +1,2 @@
+import { c } from "./nested-imports-c.js";
+export const b = "b";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js
new file mode 100644
index 0000000000..ec44596aea
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-c.js
@@ -0,0 +1,2 @@
+import { d } from "./nested-imports-d.js";
+export const c = "c";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js
new file mode 100644
index 0000000000..cee87849c6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-d.js
@@ -0,0 +1,3 @@
+import { e } from "./nested-imports-e.js";
+import "./resources/delayed-modulescript.py";
+export const d = "d";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js
new file mode 100644
index 0000000000..ec6f0360a6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-e.js
@@ -0,0 +1,2 @@
+import { f } from "./nested-imports-f.js";
+export const e = "e";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js
new file mode 100644
index 0000000000..0591e0b316
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-f.js
@@ -0,0 +1,2 @@
+import { g } from "./nested-imports-g.js";
+export const f = "f";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js
new file mode 100644
index 0000000000..86cbe7d3f8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-g.js
@@ -0,0 +1,2 @@
+import { h } from "./nested-imports-h.js";
+export const g = "g";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js
new file mode 100644
index 0000000000..a161291259
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports-h.js
@@ -0,0 +1,2 @@
+import { c } from "./nested-imports-c.js";
+export const h = "h";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html
new file mode 100644
index 0000000000..23bb595d0e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-imports.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Test imports under more than 3 levels in different modules</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({ allow_uncaught_exception: true });
+
+ window.log = [];
+
+ const test_load = async_test("should load all modules successfully");
+ window.addEventListener(
+ "load",
+ test_load.step_func_done((ev) => {
+ assert_equals(log.length, 2);
+
+ assert_equals(log[0], 1);
+ assert_equals(log[1], 2);
+ })
+ );
+
+ function unreachable() {
+ log.push("unexpected");
+ }
+</script>
+<script type="module" src="./nested-imports-a.js" onerror="unreachable()"
+ onload="log.push(1)"></script>
+<script type="module" src="./nested-imports-e.js" onerror="unreachable()"
+ onload="log.push(2)"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js
new file mode 100644
index 0000000000..3801ae847a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nested-missing-export.js
@@ -0,0 +1,2 @@
+import "./missing-export.js";
+log.push("missing-export-nested");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html
new file mode 100644
index 0000000000..656c99b292
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/nomodule-attribute.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>The 'nomodule' attribute</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that 'nomodule' has the desired effect on classic scripts, but " +
+ "no effect on module scripts.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, [undefined]);
+ }));
+
+</script>
+<script type="module" src="this.js" nomodule></script>
+<script src="this.js" nomodule></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html
new file mode 100644
index 0000000000..b8866f9511
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-no-referrer.sub.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the no-referrer policy</title>
+<meta name="referrer" content="no-referrer">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same";
+
+test(t => {
+ assert_equals(
+ referrerSame, "",
+ "Referrer should not be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the no-referrer policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemote, "",
+ "Referrer should not be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the no-referrer policy.");
+
+test(t => {
+ assert_equals(
+ referrerSameSame, "",
+ "Referrer should not be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+ "script with the no-referrer policy.");
+
+test(t => {
+ assert_equals(
+ referrerSameRemote, "",
+ "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+ "script with the no-referrer policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemoteRemote, "",
+ "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+ "top-level script with the no-referrer policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemoteSame, "",
+ "Referrer should not be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a remote-origin " +
+ "top-level script with the no-referrer policy.");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html
new file mode 100644
index 0000000000..fd4c1ea496
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin-when-cross-origin.sub.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the origin-when-cross-origin policy</title>
+<meta name="referrer" content="origin-when-cross-origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same";
+
+const origin = (new URL(location.href)).origin + "/";
+const remoteOrigin = new URL("http://{{domains[www1]}}:{{ports[http][0]}}/").origin + "/";
+
+test(t => {
+ assert_equals(
+ referrerSame, location.href,
+ "Full referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the " +
+ "origin-when-cross-origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemote, origin,
+ "Referrer should be stripped to the origin when importing " +
+ "remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the " +
+ "origin-when-cross-origin policy.");
+
+test(t => {
+ const scriptURL =
+ new URL("resources/import-referrer-checker.sub.js", location.href)
+ assert_equals(
+ referrerSameSame, scriptURL + "?name=same_same",
+ "Full referrer should be sent for same-origin descendant script" +
+ "imported by same-origin top-level script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+ "script with the origin-when-cross-origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerSameRemote, origin,
+ "Referrer should be stripped to the origin for the remote-origin " +
+ "descendant script imported from same-origin top-level script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+ "script with the origin-when-cross-origin policy.");
+
+test(t => {
+ const scriptURL = new URL(
+ "html/semantics/scripting-1/the-script-element/module/resources/" +
+ "import-referrer-checker.sub.js",
+ remoteOrigin);
+ assert_equals(referrerRemoteRemote, scriptURL + "?name=remote_remote",
+ "Full referrer should be sent for the remote-origin descendant script " +
+ "imported from a remote-origin top-level script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+ "top-level script with the origin-when-cross-origin policy.");
+
+test(t => {
+ assert_equals(referrerRemoteSame, remoteOrigin,
+ "Referrer should be stripped to the origin for the same-origin " +
+ "descendant script imported by remote-origin top-level script.");
+}, "Importing a same-origin descendant script from a remote-origin " +
+ "top-level script with the origin-when-cross-origin policy.");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html
new file mode 100644
index 0000000000..a554fb4b0c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-origin.sub.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the origin policy</title>
+<meta name="referrer" content="origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same";
+
+const origin = (new URL(location.href)).origin + "/";
+const remoteOrigin = "http://{{domains[www1]}}:{{ports[http][0]}}/";
+
+test(t => {
+ assert_equals(
+ referrerSame, origin,
+ "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemote, origin,
+ "Referrer should be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerSameSame, origin,
+ "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+ "script with the origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerSameRemote, origin,
+ "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+ "script with the origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemoteRemote, remoteOrigin,
+ "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+ "top-level script with the origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemoteSame, remoteOrigin,
+ "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a remote-origin " +
+ "top-level script with the origin policy.");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html
new file mode 100644
index 0000000000..7d6d515a47
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-same-origin.sub.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the same-origin policy</title>
+<meta name="referrer" content="same-origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same";
+
+const remoteOrigin = "http://{{domains[www1]}}:{{ports[http][0]}}/";
+
+test(t => {
+ assert_equals(
+ referrerSame, location.href,
+ "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the same-origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemote, "",
+ "Referrer should not be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the same-origin policy.");
+
+test(t => {
+ const path =
+ new URL("resources/import-referrer-checker.sub.js", location.href);
+ assert_equals(
+ referrerSameSame, path + `?name=same_same`,
+ "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+ "script with the same-origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerSameRemote, "",
+ "Referrer should not be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+ "script with the same-origin policy.");
+
+test(t => {
+ const scriptURL = new URL(
+ "html/semantics/scripting-1/the-script-element/module/resources/" +
+ "import-referrer-checker.sub.js", remoteOrigin);
+ assert_equals(
+ referrerRemoteRemote, scriptURL + "?name=remote_remote",
+ "Referrer should be sent for the remote-origin descendant script " +
+ "when it is imported from a top-level script in the same remote-origin.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+ "top-level script with the same-origin policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemoteSame, "",
+ "Referrer should not be sent for the same-origin descendant script " +
+ "when it is imported from a top-level remote-origin script.");
+}, "Importing a same-origin descendant script from a remote-origin " +
+ "top-level script with the same-origin policy.");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html
new file mode 100644
index 0000000000..1984d875b3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-strict-policies.sub.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the strict-origin referrer policy</title>
+<meta name="referrer" content="strict-origin">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map in descendant import.
+
+import { referrer as insecureImport } from "./resources/import-referrer-checker-insecure.sub.js?name=insecure_import";
+import { referrer as secureImport } from "https://{{domains[www]}}:{{ports[https][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js?name=secure_import";
+
+const origin = (new URL(location.href)).origin + "/";
+
+test(t => {
+ assert_equals(
+ insecureImport, origin,
+ "A document with the strict-origin referrer policy served over HTTP, " +
+ "imports an module script over HTTP, that imports a descendant script " +
+ "over HTTP. The request for the descendant script is sent with a " +
+ "`Referer` header with the page's origin");
+
+ assert_equals(
+ secureImport, "",
+ "A document with the strict-origin referrer policy served over HTTP, " +
+ "imports an module script over HTTPS, that imports a descendant script " +
+ "over HTTP. The request for the descendant script is sent with no " +
+ "`Referer` header");
+}, "The strict-* referrer policies compare the trustworthiness of a " +
+ "request's referrer string against its URL");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html
new file mode 100644
index 0000000000..443731c1b8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/referrer-unsafe-url.sub.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrer with the unsafe-url policy</title>
+<meta name="referrer" content="unsafe-url">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script type="module">
+
+// "name" parameter is necessary for bypassing the module map.
+
+import { referrer as referrerSame } from "./resources/referrer-checker.py?name=same";
+
+import { referrer as referrerRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name=remote";
+
+import { referrer as referrerSameSame } from "./resources/import-referrer-checker.sub.js?name=same_same";
+
+import { referrer as referrerSameRemote } from "./resources/import-remote-origin-referrer-checker.sub.js?name=same_remote";
+
+import { referrer as referrerRemoteRemote } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js?name=remote_remote";
+
+import { referrer as referrerRemoteSame } from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js?name=remote_same";
+
+test(t => {
+ assert_equals(
+ referrerSame, location.href,
+ "Referrer should be sent for the same-origin top-level script.");
+}, "Importing a same-origin top-level script with the unsafe-url policy.");
+
+test(t => {
+ assert_equals(
+ referrerRemote, location.href,
+ "Referrer should be sent for the remote-origin top-level script.");
+}, "Importing a remote-origin top-level script with the unsafe-url policy.");
+
+test(t => {
+ const scriptURL =
+ new URL("resources/import-referrer-checker.sub.js", location.href)
+ assert_equals(
+ referrerSameSame, scriptURL + "?name=same_same",
+ "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a same-origin top-level " +
+ "script with the unsafe-url policy.");
+
+test(t => {
+ const scriptURL =
+ new URL("resources/import-remote-origin-referrer-checker.sub.js",
+ location.href)
+ assert_equals(
+ referrerSameRemote, scriptURL + "?name=same_remote",
+ "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a same-origin top-level " +
+ "script with the unsafe-url policy.");
+
+test(t => {
+ const scriptURL =
+ "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/" +
+ "scripting-1/the-script-element/module/resources/" +
+ "import-referrer-checker.sub.js";
+ assert_equals(
+ referrerRemoteRemote, scriptURL + "?name=remote_remote",
+ "Referrer should be sent for the remote-origin descendant script.");
+}, "Importing a remote-origin descendant script from a remote-origin " +
+ "top-level script with the unsafe-url policy.");
+
+test(t => {
+ const scriptURL =
+ "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/" +
+ "scripting-1/the-script-element/module/resources/" +
+ "import-same-origin-referrer-checker-from-remote-origin.sub.js";
+ assert_equals(
+ referrerRemoteSame, scriptURL + "?name=remote_same",
+ "Referrer should be sent for the same-origin descendant script.");
+}, "Importing a same-origin descendant script from a remote-origin " +
+ "top-level script with the unsafe-url policy.");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis
new file mode 100644
index 0000000000..0fe1379e56
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/404-but-js.asis
@@ -0,0 +1,4 @@
+HTTP/1.1 404 Not Found
+Content-Type: text/javascript
+
+window.ran404 = true;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis
new file mode 100644
index 0000000000..c81202f7ef
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/500-but-js.asis
@@ -0,0 +1,4 @@
+HTTP/1.1 500 Not Found
+Content-Type: text/javascript
+
+window.ran500 = true;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py
new file mode 100644
index 0000000000..90551e92c3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py
@@ -0,0 +1,20 @@
+def main(request, response):
+ headers = [
+ (b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", request.GET.first(b"origin")),
+ (b"Access-Control-Allow-Credentials", b"true")
+ ]
+ identifier = request.GET.first(b"id")
+ cookie_name = request.GET.first(b"cookieName")
+ cookie = request.cookies.first(cookie_name, None)
+ if identifier is None or cookie_name is None:
+ return headers, b""
+
+ if cookie is None:
+ result = b"not found"
+ elif cookie.value == b"1":
+ result = b"found"
+ else:
+ result = b"different value: " + cookie.value
+
+ return headers, b"window." + identifier + b" = '" + result + b"';"
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html
new file mode 100644
index 0000000000..dbc14dffec
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/credentials-iframe.sub.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+
+<script type="module"
+ src="check-cookie.py?id=sameOriginNone&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}">
+</script>
+<script type="module"
+ src="check-cookie.py?id=sameOriginAnonymous&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}"
+ crossOrigin="anonymous">
+</script>
+<script type="module"
+ src="check-cookie.py?id=sameOriginUseCredentials&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}"
+ crossOrigin="use-credentials">
+</script>
+<script type="module"
+ src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginNone&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}">
+</script>
+<script type="module"
+ src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginAnonymous&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}"
+ crossOrigin="anonymous">
+</script>
+<script type="module"
+ src="http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginUseCredentials&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}"
+ crossOrigin="use-credentials">
+</script>
+
+<script type="module">
+import "./check-cookie.py?id=sameOriginNoneDescendant&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}";
+</script>
+<script type="module" crossOrigin="anonymous">
+import "./check-cookie.py?id=sameOriginAnonymousDescendant&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}";
+</script>
+<script type="module" crossOrigin="use-credentials">
+import "./check-cookie.py?id=sameOriginUseCredentialsDescendant&cookieName=same&origin=http://{{host}}:{{ports[http][0]}}";
+</script>
+<script type="module">
+import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginNoneDescendant&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}";
+</script>
+<script type="module" crossOrigin="anonymous">
+import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginAnonymousDescendant&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}";
+</script>
+<script type="module" crossOrigin="use-credentials">
+import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py?id=crossOriginUseCredentialsDescendant&cookieName=cross&origin=http://{{host}}:{{ports[http][0]}}";
+</script>
+
+<script type="text/javascript">
+window.addEventListener('load', event => {
+ window.parent.postMessage({}, '*');
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py
new file mode 100644
index 0000000000..52dbfba445
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/delayed-modulescript.py
@@ -0,0 +1,7 @@
+import time
+
+def main(request, response):
+ delay = float(request.GET.first(b"ms", 500))
+ time.sleep(delay / 1E3)
+
+ return [(b"Content-type", b"text/javascript")], u"export let delayedLoaded = true;"
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js
new file mode 100644
index 0000000000..7d9b024e75
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-helper.sub.js
@@ -0,0 +1,67 @@
+// runTestsFromIframe() is used in the top-level HTML to set cookies and then
+// start actual tests in iframe.
+function runTestsFromIframe(iframe_url) {
+ const setSameOriginCookiePromise = fetch(
+ '/cookies/resources/set-cookie.py?name=same&path=/html/semantics/scripting-1/the-script-element/module/',
+ {
+ mode: 'no-cors',
+ credentials: 'include',
+ });
+ const setCrossOriginCookiePromise = fetch(
+ 'http://{{domains[www2]}}:{{ports[http][0]}}/cookies/resources/set-cookie.py?name=cross&path=/html/semantics/scripting-1/the-script-element/module/',
+ {
+ mode: 'no-cors',
+ credentials: 'include',
+ });
+ const windowLoadPromise = new Promise(resolve => {
+ window.addEventListener('load', () => {
+ resolve();
+ });
+ });
+
+ const iframe = document.createElement('iframe');
+ Promise.all([setSameOriginCookiePromise,
+ setCrossOriginCookiePromise,
+ windowLoadPromise]).then(() => {
+ iframe.src = iframe_url;
+ document.body.appendChild(iframe);
+ fetch_tests_from_window(iframe.contentWindow);
+ });
+}
+
+// The functions below are used from tests within the iframe.
+
+let testNumber = 0;
+
+// importFunc and setTimeoutFunc is used to make the active script at the time
+// of import() to be the script elements that call `runTest()`,
+// NOT this script defining runTest().
+
+function runTest(importFunc, origin, expected, source) {
+ let url;
+ let description;
+ if (origin === 'same') {
+ url = "./check-cookie.py";
+ description = "Same-origin dynamic import from " + source;
+ } else {
+ url = "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/check-cookie.py";
+ description = "Cross-origin dynamic import from " + source;
+ }
+ promise_test(() => {
+ const id = "test" + testNumber;
+ testNumber += 1;
+ return importFunc(url + "?id=" + id + "&cookieName=" + origin + "&origin=" + location.origin)
+ .then(() => {
+ assert_equals(window[id], expected, "cookie");
+ });
+ }, description);
+}
+
+function setTimeoutWrapper(setTimeoutFunc) {
+ return url => {
+ return new Promise(resolve => {
+ window.resolve = resolve;
+ setTimeoutFunc(`import("${url}").then(window.resolve)`);
+ });
+ };
+}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html
new file mode 100644
index 0000000000..88204ef00b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-iframe.sub.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="dynamic-import-credentials-helper.sub.js"></script>
+
+<!--
+The active script at the time of import() is the script elements below, and
+thus the credentials mode of the fetch options of the script elements below
+are used for dynamic import requests.
+-->
+
+<script>
+runTest(url => import(url),
+ "same", "found", "classic script (crossOrigin not specified)");
+runTest(url => import(url),
+ "cross", "not found", "classic script (crossOrigin not specified)");
+</script>
+
+<script crossOrigin="anonymous">
+runTest(url => import(url), "same", "found",
+ "classic script (crossOrigin=anonymous)");
+runTest(url => import(url), "cross", "not found",
+ "classic script (crossOrigin=anonymous)");
+</script>
+
+<script crossOrigin="use-credentials">
+runTest(url => import(url),
+ "same", "found", "classic script (crossOrigin=use-credentials)");
+runTest(url => import(url),
+ "cross", "found", "classic script (crossOrigin=use-credentials)");
+</script>
+
+<script type="module">
+runTest(url => import(url),
+ "same", "found", "module script (crossOrigin not specified)");
+runTest(url => import(url),
+ "cross", "not found", "module script (crossOrigin not specified)");
+</script>
+
+<script type="module" crossOrigin="anonymous">
+runTest(url => import(url), "same", "found",
+ "module script (crossOrigin=anonymous)");
+runTest(url => import(url), "cross", "not found",
+ "module script (crossOrigin=anonymous)");
+</script>
+
+<script type="module" crossOrigin="use-credentials">
+runTest(url => import(url),
+ "same", "found", "module script (crossOrigin=use-credentials)");
+runTest(url => import(url),
+ "cross", "found", "module script (crossOrigin=use-credentials)");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html
new file mode 100644
index 0000000000..ffba141527
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/dynamic-import-credentials-setTimeout-iframe.sub.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="dynamic-import-credentials-helper.sub.js"></script>
+
+<!--
+The active script at the time of import() is the classic script created by
+https://html.spec.whatwg.org/multipage/C/#timer-initialisation-steps
+and the active script at the time of setTimeout() is the script elements below,
+thus the credentials mode of the fetch options of the script elements below
+are used for dynamic import requests.
+
+setTimeout() calls below can't be wrapped (e.g. by step_timeout())
+because wrapping setTimeout() would set active scripts differently.
+-->
+
+<script>
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "same", "found", "setTimeout(string) from classic script (crossOrigin not specified)");
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "cross", "not found", "setTimeout(string) from classic script (crossOrigin not specified)");
+</script>
+
+<script crossOrigin="anonymous">
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "same", "found", "setTimeout(string) from classic script (crossOrigin=anonymous)");
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "cross", "not found", "setTimeout(string) from classic script (crossOrigin=anonymous)");
+</script>
+
+<script crossOrigin="use-credentials">
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "same", "found", "setTimeout(string) from classic script (crossOrigin=use-credentials)");
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "cross", "found", "setTimeout(string) from classic script (crossOrigin=use-credentials)");
+</script>
+
+<script type="module">
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "same", "found", "setTimeout(string) from module script (crossOrigin not specified)");
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "cross", "not found", "setTimeout(string) from module script (crossOrigin not specified)");
+</script>
+
+<script type="module" crossOrigin="anonymous">
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "same", "found", "setTimeout(string) from module script (crossOrigin=anonymous)");
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "cross", "not found", "setTimeout(string) from module script (crossOrigin=anonymous)");
+</script>
+
+<script type="module" crossOrigin="use-credentials">
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "same", "found", "setTimeout(string) from module script (crossOrigin=use-credentials)");
+runTest(setTimeoutWrapper(x => setTimeout(x, 0)),
+ "cross", "found", "setTimeout(string) from module script (crossOrigin=use-credentials)");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js
new file mode 100644
index 0000000000..3a76cf71f6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/fast-module.js
@@ -0,0 +1 @@
+loaded.push("fast");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js
new file mode 100644
index 0000000000..6fc4ad395c
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8-with-charset-header.js
@@ -0,0 +1 @@
+import "../../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript%3Bcharset=windows-1250&dummy=6";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js
new file mode 100644
index 0000000000..3ae805d78d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-non-utf8.js
@@ -0,0 +1 @@
+import "../../serve-with-content-type.py?fn=external-script-windows1250.js&ct=text/javascript&dummy=5";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js
new file mode 100644
index 0000000000..2d6fd96712
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js
@@ -0,0 +1 @@
+export { referrer } from 'http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}';
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker-insecure.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js
new file mode 100644
index 0000000000..2c7dce9dff
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js
@@ -0,0 +1,2 @@
+import { referrer as referrerImport } from './referrer-checker.py?name={{GET[name]}}';
+export const referrer = referrerImport;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-referrer-checker.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js
new file mode 100644
index 0000000000..45a2520b68
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-remote-origin-referrer-checker.sub.js
@@ -0,0 +1,2 @@
+import { referrer as referrerImport } from 'http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}';
+export const referrer = referrerImport;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js
new file mode 100644
index 0000000000..5a53bcd4d5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js
@@ -0,0 +1,2 @@
+import { referrer as referrerImport } from 'http://{{host}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py?name={{GET[name]}}';
+export const referrer = referrerImport;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-same-origin-referrer-checker-from-remote-origin.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js
new file mode 100644
index 0000000000..c2ccab7c62
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8-with-charset-header.js
@@ -0,0 +1 @@
+import "../../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript%3Bcharset=windows-1250&dummy=6";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js
new file mode 100644
index 0000000000..5708a26e07
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/import-utf8.js
@@ -0,0 +1 @@
+import "../../serve-with-content-type.py?fn=external-script-utf8.js&ct=text/javascript&dummy=5";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js
new file mode 100644
index 0000000000..d62e4f05be
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-404-but-js.js
@@ -0,0 +1 @@
+import "./404-but-js.asis";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js
new file mode 100644
index 0000000000..d62e4f05be
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-500-but-js.js
@@ -0,0 +1 @@
+import "./404-but-js.asis";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js
new file mode 100644
index 0000000000..6db57b5017
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/imports-b-cross-origin.sub.js
@@ -0,0 +1 @@
+import "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/module/imports-b.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py
new file mode 100644
index 0000000000..413f48d381
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/referrer-checker.py
@@ -0,0 +1,6 @@
+def main(request, response):
+ referrer = request.headers.get(b"referer", b"")
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", b"*")]
+ return (200, response_headers,
+ b"export const referrer = '" + referrer + b"';")
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js
new file mode 100644
index 0000000000..4623ef7360
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/resources/slow-module.js
@@ -0,0 +1,3 @@
+// This module is imported with pipe=trickle(d2) to make it load more slowly
+// than fast-module.js
+loaded.push("slow");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html
new file mode 100644
index 0000000000..e3b8e15b41
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/script-for-event.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<title>Module scripts with for and event attributes</title>
+<link rel="author" title="Matheus Kerschbaum" href="mailto:matjk7@gmail.com">
+<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var expected = [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+];
+var run = expected.map(function() { return false });
+</script>
+<script for="w&#x130;ndow" event="onload" type="module">
+run[0] = true;
+</script>
+<script for="window" event="onload x" type="module">
+run[1] = true;
+</script>
+<script for="window" event="onload(x" type="module">
+run[2] = true;
+</script>
+<script for="window" event="onload(x)" type="module">
+run[3] = true;
+</script>
+<script for="window" event="onclick" type="module">
+run[4] = true;
+</script>
+<script for="" event="onload" type="module">
+run[5] = true;
+</script>
+<script for="window" event="" type="module">
+run[6] = true;
+</script>
+<script for="" event="" type="module">
+run[7] = true;
+</script>
+<script for="&#xa0;window" event="onload" type="module">
+run[8] = true;
+</script>
+<script for="window&#xa0;" event="onload" type="module">
+run[9] = true;
+</script>
+<script for="window" event="&#xa0;onload" type="module">
+run[10] = true;
+</script>
+<script for="window" event="onload&#xa0;" type="module">
+run[11] = true;
+</script>
+<script for=" window " event=" onload " type="module">
+run[12] = true;
+</script>
+<script for=" window " event=" onload() " type="module">
+run[13] = true;
+</script>
+<script for="object" event="handler" type="module">
+run[14] = true;
+</script>
+<script event="handler" type="module">
+run[15] = true;
+</script>
+<script for="object" type="module">
+run[16] = true;
+</script>
+<script type="module">
+test(function() {
+ for (var i = 0; i < run.length; ++i) {
+ test(function() {
+ var script = document.querySelectorAll("script[for], script[event]")[i];
+ assert_equals(run[i], expected[i],
+ "script for=" + format_value(script.getAttribute("for")) +
+ " event=" + format_value(script.getAttribute("event")));
+ }, "Script " + i);
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js
new file mode 100644
index 0000000000..6863075bd9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/set-currentScript-on-window.js
@@ -0,0 +1 @@
+window.currentScriptRecorded = document.currentScript;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html
new file mode 100644
index 0000000000..cc4e2d69b7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-1.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Single evaluation, 1</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that a module is evaluated only once, and that 'this' is " +
+ "undefined (because of strict mode).");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, [undefined, "this-nested"]);
+ }));
+</script>
+<script type="module" src="this.js"></script>
+<script type="module" src="this.js"></script>
+<script type="module" src="this-nested.js"></script>
+<script type="module" src="this.js"></script>
+<script type="module" src="this-nested.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html
new file mode 100644
index 0000000000..790e2fa9c6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/single-evaluation-2.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Single evaluation, 2</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that a module is evaluated only once, and that 'this' is " +
+ "undefined (because of strict mode).");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, [undefined, "this-nested"]);
+ }));
+</script>
+<script type="module" src="this-nested.js"></script>
+<script type="module" src="this-nested.js"></script>
+<script type="module" src="this.js"></script>
+<script type="module" src="this-nested.js"></script>
+<script type="module" src="this.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html
new file mode 100644
index 0000000000..3a42cf9e30
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-cycle.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Cyclic graph with slow imports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="module">
+import { loaded } from "./slow-module-graph-a.js";
+
+test(() => {
+ assert_true(loaded);
+}, "module graph with cycles load even if part of the graph loads slow");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js
new file mode 100644
index 0000000000..48701aa1d0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-a.js
@@ -0,0 +1,3 @@
+import "./slow-module-graph-b.js";
+import "./resources/delayed-modulescript.py"
+export let loaded = true;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js
new file mode 100644
index 0000000000..53a8f2026e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/slow-module-graph-b.js
@@ -0,0 +1 @@
+import "./slow-module-graph-a.js";
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html
new file mode 100644
index 0000000000..d07005caaa
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/specifier-error.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Handling of invalid specifiers</title>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({allow_uncaught_exception: true});
+
+ window.log = [];
+
+ window.addEventListener("error", ev => log.push(ev.error));
+
+ const test_load = async_test(
+ "Test that invalid module specifier leads to TypeError on window.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_equals(log.length, 1);
+ assert_equals(log[0].constructor, TypeError);
+ }));
+
+ function unreachable() { log.push("unexpected"); }
+</script>
+<script type="module" src="./bad-module-specifier.js" onerror="unreachable()"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js
new file mode 100644
index 0000000000..de1b053c5a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror-nested.js
@@ -0,0 +1,2 @@
+import "./syntaxerror.js";
+log.push("nested-syntaxerror");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js
new file mode 100644
index 0000000000..31a9e2cbdf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/syntaxerror.js
@@ -0,0 +1,2 @@
+log.push("syntaxerror");
+%!#$@#$@#$@
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js
new file mode 100644
index 0000000000..f204812fd1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this-nested.js
@@ -0,0 +1,2 @@
+import "./this.js";
+log.push("this-nested");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js
new file mode 100644
index 0000000000..996a439df0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/this.js
@@ -0,0 +1 @@
+log.push(this);
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js
new file mode 100644
index 0000000000..9769c84b23
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-error.js
@@ -0,0 +1,3 @@
+window.before_throwing_error = true;
+throw new Error;
+window.after_throwing_error = true;
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js
new file mode 100644
index 0000000000..f1801ea366
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw-nested.js
@@ -0,0 +1,2 @@
+import "./throw.js";
+log.push("throw-nested");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js
new file mode 100644
index 0000000000..cef7918216
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw.js
@@ -0,0 +1,2 @@
+log.push("throw");
+throw {foo: true}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js
new file mode 100644
index 0000000000..2931eec500
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/throw2.js
@@ -0,0 +1,2 @@
+log.push("throw2");
+throw {bar: true}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html
new file mode 100644
index 0000000000..5817ae4d43
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/module/type.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Type attribute of module scripts</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#prepare-a-script">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+window.t1 = async_test('type="module"');
+window.t2 = async_test('type="MODULE"');
+window.t3 = async_test('type="Module"');
+window.t4 = async_test('type="module "');
+window.t5 = async_test('type=" module"');
+</script>
+<script type="module">window.t1.done();</script>
+<script type="MODULE">window.t2.done();</script>
+<script type="Module">window.t3.done();</script>
+<script type="module ">window.t4.unreached_func('Unexpectedly evaluated');</script>
+<script type=" module">window.t5.unreached_func('Unexpectedly evaluated');</script>
+<script type="module">
+window.t1.unreached_func('Unexpectedly not evaluated')();
+window.t2.unreached_func('Unexpectedly not evaluated')();
+window.t3.unreached_func('Unexpectedly not evaluated')();
+window.t4.done();
+window.t5.done();
+</script>