diff --git a/html/syntax/preload-scanner.tentative/document-write/img-src.html b/html/syntax/preload-scanner.tentative/document-write/img-src.html
new file mode 100644
index 000000000000000..7147a8e561fc46b
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/document-write/img-src.html
@@ -0,0 +1,21 @@
+
+
+
+
Preload scanner, document.write(): img-src
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/document-write/picture-source-no-img.html b/html/syntax/preload-scanner.tentative/document-write/picture-source-no-img.html
new file mode 100644
index 000000000000000..618bf61c976318c
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/document-write/picture-source-no-img.html
@@ -0,0 +1,21 @@
+
+
+
+Preload scanner, document.write(): picture-source-no-img
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/document-write/script-src-unsupported-type.html b/html/syntax/preload-scanner.tentative/document-write/script-src-unsupported-type.html
new file mode 100644
index 000000000000000..983333002536936
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/document-write/script-src-unsupported-type.html
@@ -0,0 +1,21 @@
+
+
+
+Preload scanner, document.write(): script-src-unsupported-type
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/document-write/script-src.html b/html/syntax/preload-scanner.tentative/document-write/script-src.html
new file mode 100644
index 000000000000000..c16229bd8c5c8c2
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/document-write/script-src.html
@@ -0,0 +1,21 @@
+
+
+
+Preload scanner, document.write(): script-src
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/img-src.html b/html/syntax/preload-scanner.tentative/page-load/img-src.html
new file mode 100644
index 000000000000000..7de2467d778c315
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/img-src.html
@@ -0,0 +1,17 @@
+
+
+
+Preload scanner, page load: img-src
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/picture-source-no-img.html b/html/syntax/preload-scanner.tentative/page-load/picture-source-no-img.html
new file mode 100644
index 000000000000000..ab6a4646de44fde
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/picture-source-no-img.html
@@ -0,0 +1,17 @@
+
+
+
+Preload scanner, page load: picture-source-no-img
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/resources/img-src-framed.sub.html b/html/syntax/preload-scanner.tentative/page-load/resources/img-src-framed.sub.html
new file mode 100644
index 000000000000000..cfd9b91cbfe90b4
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/resources/img-src-framed.sub.html
@@ -0,0 +1,9 @@
+
+
+
+Preload scanner, page load (helper file): img-src
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/resources/picture-source-no-img-framed.sub.html b/html/syntax/preload-scanner.tentative/page-load/resources/picture-source-no-img-framed.sub.html
new file mode 100644
index 000000000000000..e40c1505382ace9
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/resources/picture-source-no-img-framed.sub.html
@@ -0,0 +1,9 @@
+
+
+
+Preload scanner, page load (helper file): picture-source-no-img
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/resources/script-src-framed.sub.html b/html/syntax/preload-scanner.tentative/page-load/resources/script-src-framed.sub.html
new file mode 100644
index 000000000000000..deeaa373fec7a25
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/resources/script-src-framed.sub.html
@@ -0,0 +1,9 @@
+
+
+
+Preload scanner, page load (helper file): script-src
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/resources/script-src-unsupported-type-framed.sub.html b/html/syntax/preload-scanner.tentative/page-load/resources/script-src-unsupported-type-framed.sub.html
new file mode 100644
index 000000000000000..e07bea55c9c10bc
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/resources/script-src-unsupported-type-framed.sub.html
@@ -0,0 +1,9 @@
+
+
+
+Preload scanner, page load (helper file): script-src-unsupported-type
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/script-src-unsupported-type.html b/html/syntax/preload-scanner.tentative/page-load/script-src-unsupported-type.html
new file mode 100644
index 000000000000000..36e0fb6567c398f
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/script-src-unsupported-type.html
@@ -0,0 +1,17 @@
+
+
+
+Preload scanner, page load: script-src-unsupported-type
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/page-load/script-src.html b/html/syntax/preload-scanner.tentative/page-load/script-src.html
new file mode 100644
index 000000000000000..10d3c9fd77e89ce
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/page-load/script-src.html
@@ -0,0 +1,17 @@
+
+
+
+Preload scanner, page load: script-src
+
+
+
+
+
+
diff --git a/html/syntax/preload-scanner.tentative/resources/preload-scanner-util.js b/html/syntax/preload-scanner.tentative/resources/preload-scanner-util.js
new file mode 100644
index 000000000000000..534de407a8c195a
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/resources/preload-scanner-util.js
@@ -0,0 +1,14 @@
+function expect_fetched(uuid, expectation) {
+ return new Promise((resolve, reject) => {
+ addEventListener('load', async () => {
+ const response = await fetch(`/html/syntax/preload-scanner.tentative/resources/stash.py?action=take&uuid=${uuid}`);
+ const result = await response.text();
+ if (expectation) {
+ assert_equals(result, 'fetched', 'expected the preload scanner to prefetch');
+ } else {
+ assert_equals(result, '', 'expected the preload scanner to NOT prefetch');
+ }
+ resolve();
+ });
+ });
+}
diff --git a/html/syntax/preload-scanner.tentative/resources/stash.py b/html/syntax/preload-scanner.tentative/resources/stash.py
new file mode 100755
index 000000000000000..370266f86eeb749
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/resources/stash.py
@@ -0,0 +1,5 @@
+def main(request, response):
+ if request.GET[b"action"] == b"put":
+ request.server.stash.put(request.GET[b"uuid"], b"fetched")
+ return u''
+ return request.server.stash.take(request.GET[b"uuid"])
diff --git a/html/syntax/preload-scanner.tentative/tools/generate.py b/html/syntax/preload-scanner.tentative/tools/generate.py
new file mode 100755
index 000000000000000..ea8fa7690961b58
--- /dev/null
+++ b/html/syntax/preload-scanner.tentative/tools/generate.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python3
+
+# Usage: python3 generate.py
+#
+# This will remove all existing files in the generated directories and generate new tests.
+
+
+# Notes on potential confusion with the 3 string substitution features in different layers:
+#
+# - In Python strings when calling .format(): {something} or {}
+# To get a literal {} use {{}}.
+# The template_* variables are ones below are those that will use .format().
+# https://docs.python.org/3/library/string.html#formatstrings
+# - JS template literals: ${something}
+# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
+# - wptserve server-side substitution when generating a response: {{GET[something]}}
+# https://web-platform-tests.org/writing-tests/server-pipes.html#sub
+
+import os, shutil
+
+target_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# Test data
+
+tests = [
+ # title, template_testcase_markup, expect_load
+ (u'script-src', u'', u'true'),
+ (u'img-src', u'', u'true'),
+ (u'script-src-unsupported-type', u'', u'false'),
+ (u'picture-source-no-img', u'', u'false'),
+]
+
+preamble = u"""
+
+"""
+
+url_wptserve_sub = u"/html/syntax/preload-scanner.tentative/resources/stash.py?action=put&uuid={{GET[uuid]}}"
+url_js_sub = u"/html/syntax/preload-scanner.tentative/resources/stash.py?action=put&uuid=${uuid}"
+
+
+# Templates
+
+# Scenario: page load
+
+template_pageload_toplevel = u"""{preamble}
+Preload scanner, page load: {title}
+
+
+
+
+
+
+"""
+
+template_pageload_framed = u"""{preamble}
+Preload scanner, page load (helper file): {title}
+
+
+{testcase_markup}
+"""
+
+# Scenario: document.write()
+
+template_docwrite = u"""{preamble}
+Preload scanner, document.write(): {title}
+
+
+
+
+
+
+"""
+
+# Scenario: - TODO(zcorpan)
+
+template_prerender_toplevel = u"""{preamble}
+Preload scanner, prerender: {title}
+...
+"""
+
+template_prerender_linked = u"""{preamble}
+Preload scanner, prerender (helper file): {title}
+...
+"""
+
+# Generate tests
+
+def wipe_dir(path):
+ path = os.path.join(target_dir, path)
+ if os.path.isdir(path) == False:
+ os.mkdir(path)
+ for filename in os.listdir(path):
+ file_path = os.path.join(path, filename)
+ if os.path.isfile(file_path) or os.path.islink(file_path):
+ os.unlink(file_path)
+
+def write_file(path, content):
+ path = os.path.join(target_dir, path)
+ file = open(os.path.join(target_dir, path), 'w')
+ file.write(content)
+ file.close()
+
+wipe_dir(u"page-load")
+wipe_dir(u"page-load/resources")
+wipe_dir(u"document-write")
+
+for testcase in tests:
+ title, template_testcase_markup, expect_load = testcase
+
+ pageload_testcase_markup = template_testcase_markup.format(url_wptserve_sub)
+ pageload_toplevel = template_pageload_toplevel.format(preamble=preamble, title=title, expect_load=expect_load)
+ write_file(f"page-load/{title}.html", pageload_toplevel)
+ pageload_framed = template_pageload_framed.format(preamble=preamble, title=title, testcase_markup=pageload_testcase_markup)
+ write_file(f"page-load/resources/{title}-framed.sub.html", pageload_framed)
+
+ docwrite_testcase_markup = template_testcase_markup.format(url_js_sub).replace(u"", u"<\/script>")
+ docwrite = template_docwrite.format(preamble=preamble, title=title, expect_load=expect_load, testcase_markup=docwrite_testcase_markup)
+ write_file(f"document-write/{title}.html", docwrite)
diff --git a/update-built-tests.sh b/update-built-tests.sh
index 3bc5e367948d9dc..bdc40953249eb9a 100755
--- a/update-built-tests.sh
+++ b/update-built-tests.sh
@@ -7,3 +7,4 @@ html/tools/build.sh
python mimesniff/mime-types/resources/generated-mime-types.py
python3 css/css-ui/tools/appearance-build-webkit-reftests.py
python3 WebIDL/tools/generate-setlike.py
+python3 html/syntax/preload-scanner.tentative/tools/generate.py