summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module')
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/array.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16be.jsonbin0 -> 40 bytes
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16le.jsonbin0 -> 40 bytes
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-8.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-2.html19
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-bom.any.js17
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset.html37
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cors-crossorigin-requests.html33
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/credentials-iframe.sub.html33
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/credentials.sub.html55
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cross-origin.py16
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-parse-error-with-cors.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-with-cors.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-without-cors.sub.html15
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/data.json3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/false.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-matches.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-mismatches.js2
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html28
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js17
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.html29
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.html67
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.py14
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.html18
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.json3
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/non-object.any.js14
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/null.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.html21
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py6
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-policies.sub.html84
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/repeated-imports.any.js65
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/script-element-json-src.html14
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js5
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/string.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/true.json1
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/utf-8.json4
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html46
-rw-r--r--testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/windows-1250.json4
40 files changed, 709 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/array.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/array.json
new file mode 100644
index 0000000000..e77e32d338
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/array.json
@@ -0,0 +1 @@
+["en", "try"]
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16be.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16be.json
new file mode 100644
index 0000000000..d22a45a591
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16be.json
Binary files differ
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16le.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16le.json
new file mode 100644
index 0000000000..4d1aa264a6
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-16le.json
Binary files differ
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-8.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-8.json
new file mode 100644
index 0000000000..07ba933e86
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/bom-utf-8.json
@@ -0,0 +1 @@
+{ "data": "hello" } \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-2.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-2.html
new file mode 100644
index 0000000000..dfadaba4d1
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-2.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="windows-1250">
+<title>JSON modules: UTF-8 decoding</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script type="module">
+ import json from "../serve-with-content-type.py?fn=json-module/utf-8.json" with { type: "json"};
+ test(() => {
+ assert_equals(json.data, "śćążź");
+ }, "JSON module should be loaded as utf-8 even though document's encoding is windows-1250");
+</script>
+<script type="module">
+ import json from "../serve-with-content-type.py?fn=json-module/windows-1250.json&ct=text/json%3Bcharset=windows-1250" with { type: "json"};
+ test(() => {
+ assert_not_equals(json.data, "śćążź",
+ 'Should be decoded as UTF-8');
+ }, "JSON module should be loaded as utf-8 even if it is encoded in windows-1250 and served with a windows-1250 charset response header, and this document's encoding is windows-1250");
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-bom.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-bom.any.js
new file mode 100644
index 0000000000..483936a4f7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset-bom.any.js
@@ -0,0 +1,17 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: script=/common/utils.js
+
+promise_test(async () => {
+ const jsonModule = await import('./bom-utf-8.json', { with: { type: 'json' } });
+ assert_equals(jsonModule.default.data, 'hello');
+}, 'UTF-8 BOM should be stripped when decoding JSON module script');
+
+promise_test(async test => {
+ await promise_rejects_js(test, SyntaxError,
+ import('./bom-utf-16be.json', { with: { type: 'json' } }), 'Expected parse error from UTF-16BE BOM');
+}, 'UTF-16BE BOM should result in parse error in JSON module script');
+
+promise_test(async test => {
+ await promise_rejects_js(test, SyntaxError,
+ import('./bom-utf-16le.json', { with: { type: 'json' } }), 'Expected parse error from UTF-16LE BOM');
+}, 'UTF-16LE BOM should result in parse error in JSON module script');
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset.html
new file mode 100644
index 0000000000..ce72f0ef1b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/charset.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>JSON modules: UTF-8 decoding</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script type="module" onerror="unreachable()">
+ import json from "../serve-with-content-type.py?fn=json-module/utf-8.json&ct=text/json%3Bcharset=utf-8" with { type: "json"};
+ test(() => {
+ assert_equals(json.data, "śćążź");
+ }, "JSON module should be loaded as utf-8 when charset=utf8 is specified");
+</script>
+<script type="module" onerror="unreachable()">
+ import json from "../serve-with-content-type.py?fn=json-module/utf-8.json&ct=text/json%3Bcharset=shift-jis" with { type: "json"};
+ test(() => {
+ assert_equals(json.data, "śćążź");
+ }, "JSON module should be loaded as utf-8 when charset=shift-jis is specified");
+</script>
+<script type="module" onerror="unreachable()">
+ import json from "../serve-with-content-type.py?fn=json-module/utf-8.json&ct=text/json%3Bcharset=windows-1252" with { type: "json"};
+ test(() => {
+ assert_equals(json.data, "śćążź");
+ }, "JSON module should be loaded as utf-8 when charset=windows-1252 is specified");
+</script>
+<script type="module" onerror="unreachable()">
+ import json from "../serve-with-content-type.py?fn=json-module/utf-8.json&ct=text/json%3Bcharset=utf-7" with { type: "json"};;
+ test(() => {
+ assert_equals(json.data, "śćążź");
+ }, "JSON module should be loaded as utf-8 when charset=utf-7 is specified");
+</script>
+<script type="module" onerror="unreachable()">
+ import json from "../serve-with-content-type.py?fn=json-module/windows-1250.json&ct=text/json%3Bcharset=windows-1250" with { type: "json"};
+ test(() => {
+ assert_not_equals(json.data, "śćążź",
+ 'Should be decoded as UTF-8');
+ }, "JSON module should be loaded as utf-8 even if it is encoded in windows-1250 and served with a windows-1250 charset response header");
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cors-crossorigin-requests.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cors-crossorigin-requests.html
new file mode 100644
index 0000000000..99ff2f67e8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cors-crossorigin-requests.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<html>
+<head>
+ <title>json-module-crossorigin</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <h1>json-module-crossorigin</h1>
+ <iframe id="import-WithCORS" src="crossorigin-import-with-cors.sub.html"></iframe>
+ <iframe id="import-NoCORS" src="crossorigin-import-without-cors.sub.html"></iframe>
+ <iframe id="import-parseerror-WithCors" src="crossorigin-import-parse-error-with-cors.sub.html"></iframe>
+ <script>
+
+ var tests = [
+ { "obj": async_test("Imported JSON module, cross-origin with CORS"), "id": "import-WithCORS", "expected": "imported JSON: 42" },
+ { "obj": async_test("Imported JSON module, cross-origin, missing CORS ACAO header"), "id": "import-NoCORS", "expected": "error" },
+ { "obj": async_test("Imported JSON module with parse error, cross-origin, with CORS"), "id": "import-parseerror-WithCors", "expected": "0-0" },
+ ];
+
+ 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/json-module/credentials-iframe.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/credentials-iframe.sub.html
new file mode 100644
index 0000000000..b89edf8d31
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/credentials-iframe.sub.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+
+<script type="module">
+ import json from "./cross-origin.py?id=sameOriginNoneDescendant&origin=http://{{host}}:{{ports[http][0]}}" with { type: "json" };
+ window.sameOriginNoneDescendant = json.requestHadCookies;
+</script>
+<script type="module" crossOrigin="anonymous">
+ import json from "./cross-origin.py?id=sameOriginAnonymousDescendant&origin=http://{{host}}:{{ports[http][0]}}" with { type: "json" };
+ window.sameOriginAnonymousDescendant = json.requestHadCookies;
+</script>
+<script type="module" crossOrigin="use-credentials">
+ import json from "./cross-origin.py?id=sameOriginUseCredentialsDescendant&origin=http://{{host}}:{{ports[http][0]}}" with { type: "json" };
+ window.sameOriginUseCredentialsDescendant = json.requestHadCookies;
+</script>
+<script type="module">
+ import json from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/cross-origin.py?id=crossOriginNoneDescendant&origin=http://{{host}}:{{ports[http][0]}}" with { type: "json" };
+ window.crossOriginNoneDescendant = json.requestHadCookies;
+</script>
+<script type="module" crossOrigin="anonymous">
+ import json from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/cross-origin.py?id=crossOriginAnonymousDescendant&origin=http://{{host}}:{{ports[http][0]}}" with { type: "json" };
+ window.crossOriginAnonymousDescendant = json.requestHadCookies;
+</script>
+<script type="module" crossOrigin="use-credentials">
+import json from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/cross-origin.py?id=crossOriginUseCredentialsDescendant&origin=http://{{host}}:{{ports[http][0]}}" with { type: "json" };
+window.crossOriginUseCredentialsDescendant = json.requestHadCookies;
+</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/json-module/credentials.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/credentials.sub.html
new file mode 100644
index 0000000000..a6df506e21
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/credentials.sub.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+document.cookie = 'milk=1';
+
+const setCookiePromise = fetch(
+ 'http://{{domains[www2]}}:{{ports[http][0]}}/cookies/resources/set-cookie.py?name=milk&path=/html/semantics/scripting-1/the-script-element/json-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 = 'credentials-iframe.sub.html';
+ document.body.appendChild(iframe);
+
+ return messagePromise;
+ }).then(() => {
+ const w = iframe.contentWindow;
+
+ assert_equals(w.sameOriginNoneDescendant, true,
+ 'Descendant JSON modules should be loaded with the credentials when the crossOrigin attribute is not specified and the target is same-origin');
+ assert_equals(w.sameOriginAnonymousDescendant, true,
+ 'Descendant JSON 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, true,
+ 'Descendant JSON 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, false,
+ 'Descendant JSON 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, false,
+ 'Descendant JSON 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, true,
+ 'Descendant JSON 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');
+});
+}, 'JSON 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/json-module/cross-origin.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cross-origin.py
new file mode 100644
index 0000000000..cd56c3628a
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/cross-origin.py
@@ -0,0 +1,16 @@
+def main(request, response):
+
+ headers = [
+ (b"Content-Type", b"application/json"),
+ (b"Access-Control-Allow-Origin", request.GET.first(b"origin")),
+ (b"Access-Control-Allow-Credentials", b"true")
+ ]
+
+ milk = request.cookies.first(b"milk", None)
+
+ if milk is None:
+ return headers, u'{"requestHadCookies": false}'
+ elif milk.value == b"1":
+ return headers, u'{"requestHadCookies": true}'
+
+ return headers, u'{"requestHadCookies": false}'
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-parse-error-with-cors.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-parse-error-with-cors.sub.html
new file mode 100644
index 0000000000..9972c53d1b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-parse-error-with-cors.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>json-module-import-cross-domain-parse-error-WithCORS</title>
+ <script src="../module/crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>json-module-import-cross-domain-parse-error-WithCORS</h1>
+ <script type="module" crossorigin>
+ import json from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/parse-error.json?pipe=header(Access-Control-Allow-Origin,*)" with { type: "json" };
+ // Push an event to the log indicating that the script was executed.
+ document._log.push(`imported JSON: ${json.answer}`);
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-with-cors.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-with-cors.sub.html
new file mode 100644
index 0000000000..95fd156df2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-with-cors.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>json-module-import-cross-domain-WithCORS</title>
+ <script src="../module/crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>json-module-import-cross-domain-WithCORS</h1>
+ <script type="module" crossorigin>
+ import json from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/data.json?pipe=header(Access-Control-Allow-Origin,*)" with { type: "json" };
+ // Push an event to the log indicating that the script was executed.
+ document._log.push(`imported JSON: ${json.answer}`);
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-without-cors.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-without-cors.sub.html
new file mode 100644
index 0000000000..b9318c8b20
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/crossorigin-import-without-cors.sub.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>json-module-import-cross-domain-NoCORS</title>
+ <script src="../module/crossorigin-common.js"></script>
+</head>
+<body>
+ <h1>json-module-import-cross-domain-NoCORS</h1>
+ <script type="module" onerror="document._log.push('error');">
+ import json from "http://{{domains[www2]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/data.json" with { type: "json" };
+ // Push an event to the log indicating that the script was executed.
+ document._log.push(`imported JSON: ${json.answer}`);
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/data.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/data.json
new file mode 100644
index 0000000000..14a0526ebb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/data.json
@@ -0,0 +1,3 @@
+{
+ "answer": 42
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/false.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/false.json
new file mode 100644
index 0000000000..c508d5366f
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/false.json
@@ -0,0 +1 @@
+false
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-matches.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-matches.js
new file mode 100644
index 0000000000..20459c17e3
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-matches.js
@@ -0,0 +1,2 @@
+import json from "./data.json" with { type: "json" };
+window.matchesLog.push(`integrity-matches,json:${json.answer}`);
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-mismatches.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-mismatches.js
new file mode 100644
index 0000000000..0406dbcca5
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity-mismatches.js
@@ -0,0 +1,2 @@
+import json "./data.json" with { type: "json" };
+window.mismatchesLog.push(`integrity-mismatches,json:${json.answer}`);
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html
new file mode 100644
index 0000000000..68a794b973
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/integrity.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>&lt;script> integrity=""</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.matchesLog = [];
+window.matchesEvents = [];
+
+window.mismatchesLog = [];
+window.mismatchesEvents = [];
+</script>
+<script type="module" src="integrity-matches.js" integrity="sha384-VmQQfGzBiLKdyzw4FA4kL4ohu4tyujV68ddgW1aN/1v3cBZNNBn2gDFdVQxfL7+a" 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_array_equals(window.matchesLog, ["integrity-matches,json:42"], "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 loading a JSON 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 loading a JSON 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/json-module/invalid-content-type.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js
new file mode 100644
index 0000000000..4226c3dc03
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/invalid-content-type.any.js
@@ -0,0 +1,17 @@
+// META: global=window,dedicatedworker,sharedworker
+
+const content_types = [
+ "application/json+protobuf",
+ "application/json+blah",
+ "text/x-json",
+ "text/json+blah",
+ "application/blahjson",
+ "image/json",
+];
+for (const content_type of content_types) {
+ promise_test(async test => {
+ await promise_rejects_js(test, TypeError,
+ import(`./module.json?pipe=header(Content-Type,${content_type})`, { with: { type: "json"} }),
+ `Import of a JSON module with MIME type ${content_type} should fail`);
+ }, `Try importing JSON module with MIME type ${content_type}`);
+}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.html
new file mode 100644
index 0000000000..cc47da1499
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/json-module-service-worker-test.https.html
@@ -0,0 +1,29 @@
+<!doctype html>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+ promise_test(async (test) => {
+ const reg = await navigator.serviceWorker.register('./serviceworker.js', { type: 'module' });
+ test.add_cleanup(() => reg.unregister());
+ assert_not_equals(reg.installing, undefined);
+ }, "Javascript importing JSON Module should load within the context of a service worker");
+
+ promise_test(test => {
+ return promise_rejects_dom(test, "SecurityError",
+ navigator.serviceWorker.register('./module.json', { type: 'module' }),
+ "Attempting to load JSON as a service worker should fail");
+ }, "Trying to register a service worker with a top-level JSON Module should fail");
+
+ promise_test(async (test) => {
+ const reg = await navigator.serviceWorker.register('./serviceworker-dynamic-import.js', { type: 'module' });
+ test.add_cleanup(() => reg.unregister());
+ assert_not_equals(reg.installing, undefined);
+ reg.installing.postMessage("PING");
+ const msgEvent = await new Promise(resolve => {
+ navigator.serviceWorker.onmessage = resolve;
+ });
+ assert_equals(msgEvent.data, "FAILED");
+ }, "JSON Module dynamic import should not load within the context of a service worker");
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.html
new file mode 100644
index 0000000000..54c1892540
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<head>
+<title>load/error events for JSON modules</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('inline, 200, parser-inserted', false, false);
+ var test1_error = event_test('inline, 404, parser-inserted', false, true);
+
+ var test2_load = event_test('src, 200, parser-inserted', true, false);
+ var test2_error = event_test('src, 404, parser-inserted', false, true);
+
+ var test3_dynamic_load = event_test('src, 200, not parser-inserted', true, false);
+ var test3_dynamic_error = event_test('src, 404, not parser-inserted', false, true);
+
+ var test4_dynamic_load = event_test('inline, 200, not parser-inserted', false, false);
+ var test4_dynamic_error = event_test('inline, 404, not parser-inserted', 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.src = "./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.src = "./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.appendChild(document.createTextNode(`
+ import "./module.json" with { type: "json" };
+ 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.json" with { type: "json" };`));
+ document.head.appendChild(script4_dynamic_error);
+</script>
+<script onload="onLoad(test1_load);" onerror="onError(test1_load);" type="module">
+ import "./module.json" with { type: "json"};
+ onExecute(test1_load);
+</script>
+<script onload="onLoad(test1_error);" onerror="onError(test1_error);" type="module">
+ import "./not_found.json" with { type: "json"};
+ onExecute(test1_error);
+</script>
+<script src="./load-error-events.py?test=test2_load" onload="onLoad(test2_load);" onerror="onError(test2_load);" type="module"></script>
+<script src="./load-error-events.py?test=test2_error" onload="onLoad(test2_error);" onerror="onError(test2_error);" type="module"></script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.py
new file mode 100644
index 0000000000..244552a693
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/load-error-events.py
@@ -0,0 +1,14 @@
+import re
+
+def main(request, response):
+ headers = [(b"Content-Type", b"text/javascript")]
+ test = request.GET.first(b'test')
+ assert(re.match(b'^[a-zA-Z0-9_]+$', test))
+
+ status = 200
+ if test.find(b'_load') >= 0:
+ content = b'import "./module.json" with { type: "json"}; %s.executed = true;' % test
+ else:
+ content = b'import "./not_found.json" with { type: "json"}; %s.test.step(function() { assert_unreached("404 script should not be executed"); });' % test
+
+ return status, headers, content
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.html
new file mode 100644
index 0000000000..05fc264f36
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>JSON modules</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+const t = async_test();
+</script>
+<script type="module" onerror="t.step(() => assert_unreached(event))">
+import v from "./module.json" with { type: "json" };
+t.step(() => {
+ assert_equals(typeof v, "object");
+ assert_array_equals(Object.keys(v), ["test"]);
+ assert_equals(v.test, true);
+ t.done();
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.json
new file mode 100644
index 0000000000..f834b2a4e8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/module.json
@@ -0,0 +1,3 @@
+{
+ "test": true
+}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/non-object.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/non-object.any.js
new file mode 100644
index 0000000000..ae78ddf072
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/non-object.any.js
@@ -0,0 +1,14 @@
+// META: global=window,dedicatedworker,sharedworker
+
+for (const value of [null, true, false, "string"]) {
+ promise_test(async t => {
+ const result = await import(`./${value}.json`, { with: { type: "json" } });
+ assert_equals(result.default, value);
+ }, `Non-object: ${value}`);
+}
+
+promise_test(async t => {
+ const result = await import("./array.json", { with: { type: "json" } });
+ assert_array_equals(result.default, ["en", "try"]);
+}, "Non-object: array");
+
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/null.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/null.json
new file mode 100644
index 0000000000..19765bd501
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/null.json
@@ -0,0 +1 @@
+null
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.html
new file mode 100644
index 0000000000..88fb23a00d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>JSON modules: parse error</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+setup({
+ allow_uncaught_exception: true,
+});
+async_test(t => {
+ window.addEventListener("error", t.step_func_done(e => {
+ assert_true(e instanceof ErrorEvent, "ErrorEvent");
+ assert_equals(e.filename, new URL("parse-error.json", location).href);
+ assert_true(e.error instanceof SyntaxError, "SyntaxError");
+ }));
+});
+</script>
+<script type="module">
+import v from "./parse-error.json" with { type: "json" };
+</script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.json
new file mode 100644
index 0000000000..98232c64fc
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/parse-error.json
@@ -0,0 +1 @@
+{
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py
new file mode 100644
index 0000000000..e9f0f1789b
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py
@@ -0,0 +1,6 @@
+def main(request, response):
+ referrer = request.headers.get(b"referer", b"")
+ response_headers = [(b"Content-Type", b"application/json"),
+ (b"Access-Control-Allow-Origin", b"*")]
+ return (200, response_headers,
+ b'{"referrer": "' + referrer + b'"}')
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-policies.sub.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-policies.sub.html
new file mode 100644
index 0000000000..1509c853e2
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/referrer-policies.sub.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Referrers with JSON module requests</title>
+<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 referrerSame from "./referrer-checker.py?name=sameNoReferrerPolicy" with { type: "json"};
+ import referrerRemote from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py?name=remoteNoReferrerPolicy" with { type: "json"};
+
+ const origin = (new URL(location.href)).origin + "/";
+ const originUrl = location.href;
+
+ test(t => {
+ assert_equals(
+ referrerSame.referrer, originUrl,
+ "Referrer URL should be sent for the same-origin top-level script.");
+ }, "Importing a same-origin top-level script with the default referrer policy.");
+
+ test(t => {
+ assert_equals(
+ referrerRemote.referrer, origin,
+ "Referrer origin should be sent for the remote-origin top-level script.");
+ }, "Importing a remote-origin top-level script with the default referrer policy.");
+</script>
+<script type="module" referrerpolicy="origin">
+ import referrerSame from "./referrer-checker.py?name=sameReferrerPolicyOrigin" with { type: "json"};
+ import referrerRemote from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py?name=remoteReferrerPolicyOrigin" with { type: "json"};
+
+ const origin = (new URL(location.href)).origin + "/";
+
+ test(t => {
+ assert_equals(
+ referrerSame.referrer, origin,
+ "Referrer origin 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.referrer, origin,
+ "Referrer origin should be sent for the remote-origin top-level script.");
+ }, "Importing a remote-origin top-level script with the origin policy.");
+
+</script>
+<script type="module" referrerpolicy="no-referrer">
+ import referrerSame from "./referrer-checker.py?name=sameReferrerPolicyNoReferrer" with { type: "json"};
+ import referrerRemote from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py?name=remoteReferrerPolicyNoReferrer" with { type: "json"};
+
+ test(t => {
+ assert_equals(
+ referrerSame.referrer, "",
+ "No referrer should 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, "",
+ "No referrer should be sent for the remote-origin top-level script.");
+ }, "Importing a remote-origin top-level script with the no-referrer policy.");
+
+</script>
+<script type="module" referrerpolicy="unsafe-url">
+ import referrerSame from "./referrer-checker.py?name=sameNoReferrerPolicyUnsafeUrl" with { type: "json"};
+ import referrerRemote from "http://{{domains[www1]}}:{{ports[http][0]}}/html/semantics/scripting-1/the-script-element/json-module/referrer-checker.py?name=remoteNoReferrerPolicyUnsafeUrl" with { type: "json"};
+
+ const originUrl = location.href;
+
+ test(t => {
+ assert_equals(
+ referrerSame.referrer, originUrl,
+ "Referrer URL should be sent for the same-origin top-level script.");
+ }, "Importing a same-origin top-level script with the unsafe-url referrer policy.");
+
+ test(t => {
+ assert_equals(
+ referrerRemote.referrer, originUrl,
+ "Referrer URL should be sent for the remote-origin top-level script.");
+ }, "Importing a remote-origin top-level script with the unsafe-url referrer policy.");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/repeated-imports.any.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/repeated-imports.any.js
new file mode 100644
index 0000000000..722251b84d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/repeated-imports.any.js
@@ -0,0 +1,65 @@
+// META: global=window,dedicatedworker,sharedworker
+// META: script=/common/utils.js
+
+promise_test(async test => {
+ await promise_rejects_js(test, TypeError,
+ import("./module.json"),
+ "Dynamic import of a JSON module without a type attribute should fail");
+
+ // This time the import should succeed because we're using the correct
+ // import even though the previous attempt with the same specifier failed.
+ const result = await import("./module.json", { with: { type: "json" } });
+ assert_true(result.default.test);
+}, "Importing a specifier that previously failed due to an incorrect type attribute can succeed if the correct attribute is later given");
+
+promise_test(async test => {
+ // Append a URL fragment to the specifier so that this is independent
+ // from the previous test.
+ const result = await import("./module.json#2", { with: { type: "json" } });
+ assert_true(result.default.test);
+
+ await promise_rejects_js(test, TypeError,
+ import("./module.json#2"),
+ "Dynamic import should fail with the type attribute missing even if the same specifier previously succeeded");
+}, "Importing a specifier that previously succeeded with the correct type attribute should fail if the incorrect attribute is later given");
+
+promise_test(async test => {
+ const uuid_token = token();
+ // serve-json-then-js.py gives us JSON the first time
+ const result_json = await import(`../serve-json-then-js.py?key=${uuid_token}`, { with: { type: "json" } });
+ assert_equals(result_json.default.hello, "world");
+
+ // Import using the same specifier again; this time we get JS, which
+ // should succeed since we're not asserting a non-JS type this time.
+ const result_js = await import(`../serve-json-then-js.py?key=${uuid_token}`);
+ assert_equals(result_js.default, "hello");
+}, "Two modules of different type with the same specifier can load if the server changes its responses");
+
+promise_test(async test => {
+ const uuid_token = token();
+ // serve-json-then-js.py gives us JSON the first time
+ await promise_rejects_js(test, TypeError,
+ import(`../serve-json-then-js.py?key=${uuid_token}`),
+ "Dynamic import of JS with a JSON type attribute should fail");
+
+ // Import using the same specifier/module type pair again; this time we get JS,
+ // but the import should still fail because the module map entry for this
+ // specifier/module type pair already contains a failure.
+ await promise_rejects_js(test, TypeError,
+ import(`../serve-json-then-js.py?key=${uuid_token}`),
+ "import should always fail if the same specifier/type attribute pair failed previously");
+}, "An import should always fail if the same specifier/type attribute pair failed previously");
+
+promise_test(async test => {
+ const uuid_token = token();
+ // serve-json-then-js.py gives us JSON the first time
+ const result_json = await import(`../serve-json-then-js.py?key=${uuid_token}`, { with: { type: "json" } });
+ assert_equals(result_json.default.hello, "world");
+
+ // If this were to do another fetch, the import would fail because
+ // serve-json-then-js.py would give us JS this time. But, the module map
+ // entry for this specifier/module type pair already exists, so we
+ // successfully reuse the entry instead of fetching again.
+ const result_json_2 = await import(`../serve-json-then-js.py?key=${uuid_token}`, { with: { type: "json" } });
+ assert_equals(result_json_2.default.hello, "world");
+}, "If an import previously succeeded for a given specifier/type attribute pair, future uses of that pair should yield the same result");
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/script-element-json-src.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/script-element-json-src.html
new file mode 100644
index 0000000000..c6d7c9a76e
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/script-element-json-src.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>&lt;script&gt; with JSON src</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ window.log = [];
+
+ const test_load = async_test(
+ "Test that <script> doesn't load when the src is JSON.");
+ window.addEventListener("load", test_load.step_func_done(ev => {
+ assert_array_equals(log, ["error"]);
+ }));
+</script>
+<script type="module" src="./module.json" onload="t.unreached_func('JSON src should fail to load')" onerror="log.push('error')"></script>
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js
new file mode 100644
index 0000000000..cd39c789cb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker-dynamic-import.js
@@ -0,0 +1,5 @@
+onmessage = e => {
+ e.waitUntil(import("./module.json", { with: { type: "json" } })
+ .then(module => e.source.postMessage("LOADED"))
+ .catch(error => e.source.postMessage("FAILED")));
+ }; \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js
new file mode 100644
index 0000000000..65210fe3e7
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/serviceworker.js
@@ -0,0 +1 @@
+import './module.json' with { type: "json" }; \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/string.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/string.json
new file mode 100644
index 0000000000..ace2d72d9d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/string.json
@@ -0,0 +1 @@
+"string"
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/true.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/true.json
new file mode 100644
index 0000000000..27ba77ddaf
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/true.json
@@ -0,0 +1 @@
+true
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/utf-8.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/utf-8.json
new file mode 100644
index 0000000000..088d982358
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/utf-8.json
@@ -0,0 +1,4 @@
+{
+ "data": "śćążź",
+ "comment": "The data above are five Polish letters, similar to scazz. It can be read correctly only with utf-8 encoding."
+}
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html
new file mode 100644
index 0000000000..3232b84d27
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/valid-content-type.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>JSON modules: Content-Type</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+function check(t, v) {
+ t.step(() => {
+ assert_equals(typeof v, "object");
+ assert_array_equals(Object.keys(v), ["test"]);
+ assert_equals(v.test, true);
+ t.done();
+ });
+}
+const t1 = async_test("text/json");
+const t2 = async_test("application/json");
+const t3 = async_test("text/html+json");
+const t4 = async_test("image/svg+json");
+const t5 = async_test("text/json;boundary=something");
+const t6 = async_test("text/json;foo=bar");
+</script>
+<script type="module" onerror="t1.step(() => assert_unreached(event))">
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json" with { type: "json"};
+check(t1, v);
+</script>
+<script type="module" onerror="t2.step(() => assert_unreached(event))">
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=application/json" with { type: "json"};
+check(t2, v);
+</script>
+<script type="module" onerror="t3.step(() => assert_unreached(event))">
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/html%2Bjson" with { type: "json"};
+check(t3, v);
+</script>
+<script type="module" onerror="t4.step(() => assert_unreached(event))">
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=image/svg%2Bjson" with { type: "json"};
+check(t4, v);
+</script>
+<script type="module" onerror="t5.step(() => assert_unreached(event))">
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json;boundary=something" with { type: "json"};
+check(t5, v);
+</script>
+<script type="module" onerror="t6.step(() => assert_unreached(event))">
+import v from "../serve-with-content-type.py?fn=json-module/module.json&ct=text/json;foo=bar" with { type: "json"};
+check(t6, v);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/windows-1250.json b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/windows-1250.json
new file mode 100644
index 0000000000..490e752ce9
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/scripting-1/the-script-element/json-module/windows-1250.json
@@ -0,0 +1,4 @@
+{
+ "data": "�湿�",
+ "comment": "The data above are five Polish letters, similar to scazz. It can be read correctly only with windows1250 encoding."
+}