summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/worklets/resources
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/worklets/resources')
-rw-r--r--testing/web-platform/tests/worklets/resources/addmodule-window.html27
-rw-r--r--testing/web-platform/tests/worklets/resources/credentials-tests.js130
-rw-r--r--testing/web-platform/tests/worklets/resources/credentials.py20
-rw-r--r--testing/web-platform/tests/worklets/resources/csp-tests.js147
-rw-r--r--testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers1
-rw-r--r--testing/web-platform/tests/worklets/resources/empty-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js3
-rw-r--r--testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js5
-rw-r--r--testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js5
-rw-r--r--testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js2
-rw-r--r--testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js2
-rw-r--r--testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js2
-rw-r--r--testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/import-tests.js162
-rw-r--r--testing/web-platform/tests/worklets/resources/referrer-checker.py24
-rw-r--r--testing/web-platform/tests/worklets/resources/referrer-tests.js201
-rw-r--r--testing/web-platform/tests/worklets/resources/referrer-window.html113
-rw-r--r--testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js108
-rw-r--r--testing/web-platform/tests/worklets/resources/service-worker.js4
-rw-r--r--testing/web-platform/tests/worklets/resources/set-cookie.py15
-rw-r--r--testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/throwing-worklet-script.js1
-rw-r--r--testing/web-platform/tests/worklets/resources/worklet-test-utils.js12
34 files changed, 998 insertions, 0 deletions
diff --git a/testing/web-platform/tests/worklets/resources/addmodule-window.html b/testing/web-platform/tests/worklets/resources/addmodule-window.html
new file mode 100644
index 0000000000..6263e6ef8e
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/addmodule-window.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Worklet: Referrer</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="worklet-test-utils.js"></script>
+</head>
+<body>
+<script>
+// Calls addModule() on a given worklet type with a script url.
+//
+// [Message Format]
+// - type: 'paint' (worklet types defined in get_worklet())
+// - script_url: 'worklet-script.js'
+window.onmessage = e => {
+ const worklet_type = e.data.type;
+ const script_url = e.data.script_url;
+ get_worklet(worklet_type).addModule(script_url)
+ .then(() => window.opener.postMessage('RESOLVED', '*'))
+ .catch(e => window.opener.postMessage('REJECTED', '*'));
+};
+
+window.opener.postMessage('LOADED', '*');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/worklets/resources/credentials-tests.js b/testing/web-platform/tests/worklets/resources/credentials-tests.js
new file mode 100644
index 0000000000..ec0b7014bf
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/credentials-tests.js
@@ -0,0 +1,130 @@
+function createCookieValue(settings) {
+ return settings.credentials + '-' + settings.origin;
+}
+
+function createSetCookieURL(settings) {
+ const params = new URLSearchParams;
+ params.append('name', 'cookieName');
+ params.append('value', createCookieValue(settings));
+ if (settings.origin == 'same') {
+ return get_host_info().HTTPS_ORIGIN +
+ '/worklets/resources/set-cookie.py?' + params;
+ }
+ if (settings.origin == 'remote') {
+ return get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/set-cookie.py?' + params;
+ }
+ assert_unreached('settings.origin has an invalid value.');
+}
+
+function createScriptURL(settings) {
+ const params = new URLSearchParams;
+ if (settings.expectCredentialsSent)
+ params.append('value', createCookieValue(settings));
+ if (settings.origin == 'same') {
+ return get_host_info().HTTPS_ORIGIN +
+ '/worklets/resources/credentials.py?' + params;
+ }
+ if (settings.origin == 'remote') {
+ return get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/credentials.py?' + params;
+ }
+ assert_unreached('settings.origin has an invalid value.');
+}
+
+function createWorkletOptions(settings) {
+ if (settings.credentials == '')
+ return {};
+ return { credentials: settings.credentials };
+}
+
+// Run a credentials test with the given settings.
+//
+// Example:
+// settings = {
+// workletType: 'paint',
+// credentials: 'include',
+// origin: 'same', // 'same' or 'remote'
+// expectCredentialsSent: true
+// };
+function runCredentialsTest(settings) {
+ const worklet = get_worklet(settings.workletType);
+ const setCookieURL = createSetCookieURL(settings);
+ const scriptURL = createScriptURL(settings);
+ const options = createWorkletOptions(settings);
+
+ // { credentials: 'include' } is necessary for configuring document's cookies
+ // with the Set-Cookie: header of the response.
+ return fetch(setCookieURL, { mode: 'cors', credentials: 'include' })
+ .then(response => worklet.addModule(scriptURL, options));
+}
+
+// Runs a series of tests related to credentials on a worklet.
+//
+// Usage:
+// runCredentialsTests("paint");
+function runCredentialsTests(worklet_type) {
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: '',
+ origin: 'same',
+ expectCredentialsSent: true });
+ }, 'Importing a same-origin script with the default WorkletOptions should ' +
+ 'send the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: '',
+ origin: 'remote',
+ expectCredentialsSent: false });
+ }, 'Importing a remote-origin script with the default WorkletOptions ' +
+ 'should not send the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: 'omit',
+ origin: 'same',
+ expectCredentialsSent: false });
+ }, 'Importing a same-origin script with credentials=omit should not send ' +
+ 'the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: 'omit',
+ origin: 'remote',
+ expectCredentialsSent: false });
+ }, 'Importing a remote-origin script with credentials=omit should not send ' +
+ 'the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: 'same-origin',
+ origin: 'same',
+ expectCredentialsSent: true });
+ }, 'Importing a same-origin script with credentials=same-origin should ' +
+ 'send the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: 'same-origin',
+ origin: 'remote',
+ expectCredentialsSent: false });
+ }, 'Importing a remote-origin script with credentials=same-origin should ' +
+ 'not send the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: 'include',
+ origin: 'same',
+ expectCredentialsSent: true });
+ }, 'Importing a same-origin script with credentials=include should send ' +
+ 'the credentials');
+
+ promise_test(() => {
+ return runCredentialsTest({ workletType: worklet_type,
+ credentials: 'include',
+ origin: 'remote',
+ expectCredentialsSent: true });
+ }, 'Importing a remote-origin script with credentials=include should ' +
+ 'send the credentials');
+}
diff --git a/testing/web-platform/tests/worklets/resources/credentials.py b/testing/web-platform/tests/worklets/resources/credentials.py
new file mode 100644
index 0000000000..d5fb05aeca
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/credentials.py
@@ -0,0 +1,20 @@
+# Returns a valid response when a request has appropriate credentials.
+def main(request, response):
+ cookie = request.cookies.first(b"cookieName", None)
+ expected_value = request.GET.first(b"value", None)
+ source_origin = request.headers.get(b"origin", None)
+ if source_origin is None:
+ # Same origin GET won't include origin header
+ source_origin = "%s://%s" % (request.url_parts.scheme,
+ request.url_parts.netloc)
+ if request.url_parts.port:
+ source_origin += ":%s" % request.url_parts.port
+
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", source_origin),
+ (b"Access-Control-Allow-Credentials", b"true")]
+
+ if cookie == expected_value:
+ return (200, response_headers, u"")
+
+ return (404, response_headers, u"")
diff --git a/testing/web-platform/tests/worklets/resources/csp-tests.js b/testing/web-platform/tests/worklets/resources/csp-tests.js
new file mode 100644
index 0000000000..ab698d0efd
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/csp-tests.js
@@ -0,0 +1,147 @@
+function openWindow(url) {
+ return new Promise(resolve => {
+ const win = window.open(url, '_blank');
+ add_result_callback(() => win.close());
+ window.onmessage = e => {
+ assert_equals(e.data, 'LOADED');
+ resolve(win);
+ };
+ });
+}
+
+function openWindowAndExpectResult(windowURL, scriptURL, type, expectation) {
+ return openWindow(windowURL).then(win => {
+ const promise = new Promise(r => window.onmessage = r);
+ win.postMessage({ type: type, script_url: scriptURL }, '*');
+ return promise;
+ }).then(msg_event => assert_equals(msg_event.data, expectation));
+}
+
+// Runs a series of tests related to content security policy on a worklet.
+//
+// Usage:
+// runContentSecurityPolicyTests("paint");
+function runContentSecurityPolicyTests(workletType) {
+ runSrcTests(workletType);
+ runMixedContentTests(workletType);
+}
+
+// script-src and worker-src tests.
+function runSrcTests(workletType) {
+ const kWindowConfigs = [
+ {
+ 'windowURL':
+ 'resources/addmodule-window.html?pipe=header(' +
+ 'Content-Security-Policy, script-src \'self\' \'unsafe-inline\')',
+ 'crossOriginExpectation': 'REJECTED',
+ 'message': 'should be blocked by the script-src \'self\' directive.'
+ },
+ {
+ 'windowURL':
+ 'resources/addmodule-window.html?pipe=header(' +
+ 'Content-Security-Policy, script-src ' + location.origin + ' ' +
+ get_host_info().HTTPS_REMOTE_ORIGIN + ' \'unsafe-inline\')',
+ 'crossOriginExpectation': 'RESOLVED',
+ 'message':
+ 'should not be blocked because the script-src directive ' +
+ 'specifying the origin allows it.'
+ },
+ {
+ 'windowURL':
+ 'resources/addmodule-window.html?pipe=header(' +
+ 'Content-Security-Policy, script-src * \'unsafe-inline\')',
+ 'crossOriginExpectation': 'RESOLVED',
+ 'message':
+ 'should not be blocked because the script-src * directive allows it.'
+ },
+ {
+ 'windowURL':
+ 'resources/addmodule-window.html?pipe=header(' +
+ 'Content-Security-Policy, worker-src \'self\' \'unsafe-inline\')',
+ 'crossOriginExpectation': 'RESOLVED',
+ 'message':
+ 'should not be blocked by the worker-src directive ' +
+ 'because worklets obey the script-src directive.'
+ }
+ ];
+ for (const windowConfig of kWindowConfigs) {
+ promise_test(t => {
+ const kScriptURL =
+ get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/empty-worklet-script-with-cors-header.js';
+ return openWindowAndExpectResult(
+ windowConfig.windowURL, kScriptURL, workletType,
+ windowConfig.crossOriginExpectation);
+ },
+ 'A remote-origin worklet ' + windowConfig.message);
+
+ promise_test(t => {
+ const kScriptURL = 'import-remote-origin-empty-worklet-script.sub.js';
+ return openWindowAndExpectResult(
+ windowConfig.windowURL, kScriptURL, workletType,
+ windowConfig.crossOriginExpectation);
+ },
+ 'A same-origin worklet importing a remote-origin script ' +
+ windowConfig.message);
+
+ promise_test(t => {
+ // A worklet on HTTPS_REMOTE_ORIGIN will import a child script on
+ // HTTPS_REMOTE_ORIGIN.
+ const kScriptURL =
+ get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/import-empty-worklet-script-with-cors-header.js';
+ return openWindowAndExpectResult(
+ windowConfig.windowURL, kScriptURL, workletType,
+ windowConfig.crossOriginExpectation);
+ },
+ 'A remote-origin worklet importing a remote-origin script ' +
+ windowConfig.message);
+
+ promise_test(t => {
+ const kScriptURL =
+ '/common/redirect.py?location=' + encodeURIComponent(
+ get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/empty-worklet-script-with-cors-header.js');
+ return openWindowAndExpectResult(
+ windowConfig.windowURL, kScriptURL, workletType,
+ windowConfig.crossOriginExpectation);
+ },
+ 'A remote-origin-redirected worklet ' + windowConfig.message);
+
+ promise_test(t => {
+ const kScriptURL =
+ 'import-remote-origin-redirected-empty-worklet-script.sub.js';
+ return openWindowAndExpectResult(
+ windowConfig.windowURL, kScriptURL, workletType,
+ windowConfig.crossOriginExpectation);
+ },
+ 'A same-origin worklet importing a remote-origin-redirected script ' +
+ windowConfig.message);
+ }
+}
+
+// Mixed content tests.
+function runMixedContentTests(workletType) {
+ const kInsecureURL =
+ get_host_info().HTTP_ORIGIN +
+ '/worklets/resources/empty-worklet-script-with-cors-header.js';
+ const kScriptConfigs = [
+ {URL: kInsecureURL,
+ message: 'An insecure-origin worklet'},
+ {URL: '/common/redirect.py?location=' + encodeURIComponent(kInsecureURL),
+ message: 'An insecure-origin-redirected worklet'},
+ {URL: 'import-insecure-origin-empty-worklet-script.sub.js',
+ message: 'A same-origin worklet importing an insecure-origin script'},
+ {URL: 'import-insecure-origin-redirected-empty-worklet-script.sub.js',
+ message: 'A same-origin worklet ' +
+ 'importing an insecure-origin-redirected script'}
+ ];
+ for (const scriptConfig of kScriptConfigs) {
+ promise_test(t => {
+ const kWindowURL = 'resources/addmodule-window.html';
+ return openWindowAndExpectResult(
+ kWindowURL, scriptConfig.URL, workletType, 'REJECTED');
+ },
+ scriptConfig.message + ' should be blocked because of mixed contents.');
+ }
+}
diff --git a/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js
new file mode 100644
index 0000000000..9513071c6f
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js
@@ -0,0 +1 @@
+// This file is served with "Access-Control-Allow-Origin" header.
diff --git a/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/empty-worklet-script-with-cors-header.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/worklets/resources/empty-worklet-script.js b/testing/web-platform/tests/worklets/resources/empty-worklet-script.js
new file mode 100644
index 0000000000..49ceb2648a
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/empty-worklet-script.js
@@ -0,0 +1 @@
+// Do nothing.
diff --git a/testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js
new file mode 100644
index 0000000000..2dc7e0bd3c
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-cyclic-worklet-script.js
@@ -0,0 +1 @@
+import './import-cyclic-worklet-script.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js
new file mode 100644
index 0000000000..bd04a189b2
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js
@@ -0,0 +1,3 @@
+// This file and descendant files are served with "Access-Control-Allow-Origin"
+// header.
+import './empty-worklet-script-with-cors-header.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-empty-worklet-script-with-cors-header.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js
new file mode 100644
index 0000000000..a04a2edf81
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-insecure-origin-empty-worklet-script.sub.js
@@ -0,0 +1,5 @@
+// Some tests rely on some unintuitive cleverness due to WPT's test setup:
+// 'Upgrade-Insecure-Requests' does not upgrade the port number, so we use URLs
+// in the form `http://[host]:[https-port]`. If the upgrade fails, the load will
+// fail, as we don't serve HTTP over the secure port.
+import 'http://{{host}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js
new file mode 100644
index 0000000000..888d876bff
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-insecure-origin-redirected-empty-worklet-script.sub.js
@@ -0,0 +1,5 @@
+// Some tests rely on some unintuitive cleverness due to WPT's test setup:
+// 'Upgrade-Insecure-Requests' does not upgrade the port number, so we use URLs
+// in the form `http://[host]:[https-port]`. If the upgrade fails, the load will
+// fail, as we don't serve HTTP over the secure port.
+import '/common/redirect.py?location=http://{{host}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js
new file mode 100644
index 0000000000..5fe8d91100
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-nested-internal-worklet-script.js
@@ -0,0 +1 @@
+import './empty-worklet-script.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js
new file mode 100644
index 0000000000..b63685f642
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-nested-worklet-script.js
@@ -0,0 +1 @@
+import './import-nested-internal-worklet-script.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js
new file mode 100644
index 0000000000..0837032f83
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-non-existent-worklet-script.js
@@ -0,0 +1 @@
+import './non-existent-worklet-script.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js
new file mode 100644
index 0000000000..1dcb6f3bcb
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js
@@ -0,0 +1,2 @@
+// Forward GET parameters to the server.
+import './referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}';
diff --git a/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-referrer-checker-worklet-script.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js
new file mode 100644
index 0000000000..06c1f87618
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-empty-worklet-script.sub.js
@@ -0,0 +1 @@
+import 'https://{{domains[www1]}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js
new file mode 100644
index 0000000000..7afa3523b9
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-redirected-empty-worklet-script.sub.js
@@ -0,0 +1 @@
+import '/common/redirect.py?location=https://{{domains[www1]}}:{{ports[https][0]}}/worklets/resources/empty-worklet-script-with-cors-header.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js
new file mode 100644
index 0000000000..f301701b1c
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js
@@ -0,0 +1,2 @@
+// Forward GET parameters to the server.
+import 'https://{{domains[www1]}}:{{ports[https][0]}}/worklets/resources/referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}';
diff --git a/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-remote-origin-referrer-checker-worklet-script.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js
new file mode 100644
index 0000000000..33af2258ff
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js
@@ -0,0 +1,2 @@
+// Forward GET parameters to the server.
+import '{{GET[requestor_origin]}}/worklets/resources/referrer-checker.py?referrer_policy={{GET[referrer_policy]}}&expected_referrer={{GET[expected_referrer]}}';
diff --git a/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js b/testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js
new file mode 100644
index 0000000000..1539ad004e
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-syntax-error-worklet-script.js
@@ -0,0 +1 @@
+import './syntax-error-worklet-script.js';
diff --git a/testing/web-platform/tests/worklets/resources/import-tests.js b/testing/web-platform/tests/worklets/resources/import-tests.js
new file mode 100644
index 0000000000..0c631a8a9f
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/import-tests.js
@@ -0,0 +1,162 @@
+// Runs a series of tests related to importing scripts on a worklet.
+//
+// Usage:
+// runImportTests("paint");
+function runImportTests(worklet_type) {
+ const worklet = get_worklet(worklet_type);
+
+ promise_test(() => {
+ const kScriptURL = 'resources/empty-worklet-script.js';
+ return worklet.addModule(kScriptURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined,
+ 'Promise should resolve with no arguments.');
+ });
+ }, 'Importing a script resolves the given promise.');
+
+ promise_test(() => {
+ const kScriptURL = 'resources/empty-worklet-script.js';
+ return Promise.all([
+ worklet.addModule(kScriptURL + '?1'),
+ worklet.addModule(kScriptURL + '?2'),
+ worklet.addModule(kScriptURL + '?3')
+ ]).then(undefined_args => {
+ assert_array_equals(undefined_args,
+ [undefined, undefined, undefined],
+ 'Promise should resolve with no arguments.');
+ });
+ }, 'Importing scripts resolves all the given promises.');
+
+ promise_test(() => {
+ const kScriptURL = 'resources/import-nested-worklet-script.js';
+ return worklet.addModule(kScriptURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined,
+ 'Promise should resolve with no arguments.');
+ });
+ }, 'Importing nested scripts resolves the given promise');
+
+ promise_test(() => {
+ const kScriptURL = 'resources/import-cyclic-worklet-script.js';
+ return worklet.addModule(kScriptURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined,
+ 'Promise should resolve with no arguments.');
+ });
+ }, 'Importing cyclic scripts resolves the given promise');
+
+ promise_test(() => {
+ const kScriptURL = 'resources/throwing-worklet-script.js';
+ return worklet.addModule(kScriptURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined,
+ 'Promise should resolve with no arguments.');
+ });
+ }, 'Importing a script which throws should still resolve the given ' +
+ 'promise.');
+
+ promise_test(t => {
+ const kScriptURL = 'non-existent-worklet-script.js';
+ return promise_rejects_dom(t, 'AbortError',
+ worklet.addModule(kScriptURL));
+ }, 'Importing a non-existent script rejects the given promise with an ' +
+ 'AbortError.');
+
+ promise_test(t => {
+ const kInvalidScriptURL = 'http://invalid:123$'
+ return promise_rejects_dom(t, 'SyntaxError',
+ worklet.addModule(kInvalidScriptURL));
+ }, 'Importing an invalid URL should reject the given promise with a ' +
+ 'SyntaxError.');
+
+ promise_test(() => {
+ const kBlob = new Blob([""], {type: 'text/javascript'});
+ const kBlobURL = URL.createObjectURL(kBlob);
+ return worklet.addModule(kBlobURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined);
+ });
+ }, 'Importing a blob URL should resolve the given promise.');
+
+ promise_test(t => {
+ const kFileURL = 'file:///empty-worklet-script.js';
+ return promise_rejects_dom(t, 'AbortError',
+ worklet.addModule(kFileURL));
+ }, 'Importing a file:// URL should reject the given promise.');
+
+ promise_test(() => {
+ const kDataURL = 'data:text/javascript, // Do nothing.';
+ return worklet.addModule(kDataURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined);
+ });
+ }, 'Importing a data URL should resolve the given promise.');
+
+ promise_test(t => {
+ const kScriptURL = 'about:blank';
+ return promise_rejects_dom(t, 'AbortError',
+ worklet.addModule(kScriptURL));
+ }, 'Importing about:blank should reject the given promise.');
+
+ promise_test(() => {
+ // Specify the Access-Control-Allow-Origin header to enable cross origin
+ // access.
+ const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/empty-worklet-script.js' +
+ '?pipe=header(Access-Control-Allow-Origin, *)';
+ return worklet.addModule(kScriptURL).then(undefined_arg => {
+ assert_equals(undefined_arg, undefined);
+ });
+ }, 'Importing a cross origin resource with the ' +
+ 'Access-Control-Allow-Origin header should resolve the given promise');
+
+ promise_test(t => {
+ // Don't specify the Access-Control-Allow-Origin header. addModule()
+ // should be rejected because of disallowed cross origin access.
+ const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/empty-worklet-script.js';
+ return promise_rejects_dom(t, 'AbortError',
+ worklet.addModule(kScriptURL));
+ }, 'Importing a cross origin resource without the ' +
+ 'Access-Control-Allow-Origin header should reject the given promise');
+
+ promise_test(() => {
+ const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/empty-worklet-script.js' +
+ '?pipe=header(Access-Control-Allow-Origin, ' +
+ location.origin + ')';
+ return worklet.addModule('/common/redirect.py?location=' +
+ encodeURIComponent(kScriptURL))
+ .then(undefined_arg => {
+ assert_equals(undefined_arg, undefined);
+ });
+ }, 'Importing a cross-origin-redirected resource with the ' +
+ 'Access-Control-Allow-Origin header should resolve the given promise');
+
+ promise_test(t => {
+ const kScriptURL = get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/empty-worklet-script.js';
+ return promise_rejects_dom(t, 'AbortError',
+ worklet.addModule(
+ '/common/redirect.py?location=' +
+ encodeURIComponent(kScriptURL)));
+ }, 'Importing a cross-origin-redirected resource without the ' +
+ 'Access-Control-Allow-Origin header should reject the given promise');
+
+ promise_test(t => {
+ const kScriptURL = 'resources/syntax-error-worklet-script.js';
+ return promise_rejects_js(t, SyntaxError,
+ worklet.addModule(kScriptURL));
+ }, 'Importing a script that has a syntax error should reject the given ' +
+ 'promise.');
+
+ promise_test(t => {
+ const kScriptURL = 'resources/import-syntax-error-worklet-script.js';
+ return promise_rejects_js(t, SyntaxError,
+ worklet.addModule(kScriptURL));
+ }, 'Importing a nested script that has a syntax error should reject the ' +
+ 'given promise.');
+
+ promise_test(t => {
+ const kBlob = new Blob(["import 'invalid-specifier.js';"],
+ {type: 'text/javascript'});
+ const kBlobURL = URL.createObjectURL(kBlob);
+ return promise_rejects_js(t, TypeError,
+ worklet.addModule(kBlobURL));
+ }, 'Importing a script that imports an invalid identifier should reject ' +
+ 'the given promise.');
+}
diff --git a/testing/web-platform/tests/worklets/resources/referrer-checker.py b/testing/web-platform/tests/worklets/resources/referrer-checker.py
new file mode 100644
index 0000000000..4c6ea6e5c2
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/referrer-checker.py
@@ -0,0 +1,24 @@
+# Returns a valid response when request's |referrer| matches
+# |expected_referrer|.
+def main(request, response):
+ # We want |referrer| to be the referrer header with no query params,
+ # because |expected_referrer| will not contain any query params, and
+ # thus cannot be compared with the actual referrer header if it were to
+ # contain query params. This works fine if the actual referrer has no
+ # query params too.
+ referrer = request.headers.get(b"referer", b"").split(b"?")[0]
+ referrer_policy = request.GET.first(b"referrer_policy")
+ expected_referrer = request.GET.first(b"expected_referrer", b"")
+ response_headers = [(b"Content-Type", b"text/javascript"),
+ (b"Access-Control-Allow-Origin", b"*")]
+
+ if referrer_policy == b"no-referrer" or referrer_policy == b"origin":
+ if referrer == expected_referrer:
+ return (200, response_headers, u"")
+ return (404, response_headers)
+
+ if referrer_policy == b"same-origin":
+ if referrer == expected_referrer:
+ return (200, response_headers, u"")
+ return (404, response_headers)
+ return (404, response_headers)
diff --git a/testing/web-platform/tests/worklets/resources/referrer-tests.js b/testing/web-platform/tests/worklets/resources/referrer-tests.js
new file mode 100644
index 0000000000..ab24945f31
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/referrer-tests.js
@@ -0,0 +1,201 @@
+function openWindow(t, url) {
+ return new Promise(resolve => {
+ let win = window.open(url, '_blank');
+ t.add_cleanup(() => win.close());
+ window.onmessage = e => {
+ assert_equals(e.data, 'LOADED');
+ resolve(win);
+ };
+ });
+}
+
+// Run a referrer policy test with the given settings.
+//
+// Example:
+// settings = {
+// workletType: 'paint',
+// fetchType: 'top-level' or 'descendant',
+// referrerPolicy: 'no-referrer',
+// scriptsOrigins: { topLevel: 'same', descendant: 'remote' }
+// };
+function runReferrerTest(t, settings) {
+ const kWindowURL =
+ 'resources/referrer-window.html' +
+ `?pipe=header(Referrer-Policy,${settings.referrerPolicy})`;
+ return openWindow(t, kWindowURL).then(win => {
+ const promise = new Promise(resolve => window.onmessage = resolve);
+ win.postMessage(settings, '*');
+ return promise;
+ }).then(msg_event => assert_equals(msg_event.data, 'RESOLVED'));
+}
+
+// Runs a series of tests related to the referrer policy on a worklet.
+//
+// Usage:
+// runReferrerTests("paint");
+function runReferrerTests(workletType) {
+ const worklet = get_worklet(workletType);
+
+ // Tests for top-level script fetch -----------------------------------------
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'top-level',
+ referrerPolicy: 'no-referrer',
+ scriptOrigins: { topLevel: 'same' } });
+ }, 'Importing a same-origin script from a page that has "no-referrer" ' +
+ 'referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'top-level',
+ referrerPolicy: 'no-referrer',
+ scriptOrigins: { topLevel: 'remote' } });
+ }, 'Importing a remote-origin script from a page that has "no-referrer" ' +
+ 'referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'top-level',
+ referrerPolicy: 'origin',
+ scriptOrigins: { topLevel: 'same' } });
+ }, 'Importing a same-origin script from a page that has "origin" ' +
+ 'referrer policy should send only an origin as referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'top-level',
+ referrerPolicy: 'origin',
+ scriptOrigins: { topLevel: 'remote' } });
+ }, 'Importing a remote-origin script from a page that has "origin" ' +
+ 'referrer policy should send only an origin as referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'top-level',
+ referrerPolicy: 'same-origin',
+ scriptOrigins: { topLevel: 'same' } });
+ }, 'Importing a same-origin script from a page that has "same-origin" ' +
+ 'referrer policy should send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'top-level',
+ referrerPolicy: 'same-origin',
+ scriptOrigins: { topLevel: 'remote' } });
+ }, 'Importing a remote-origin script from a page that has "same-origin" ' +
+ 'referrer policy should not send referrer.');
+
+ // Tests for descendant script fetch -----------------------------------------
+
+ // Referrer policy: no-referrer.
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'no-referrer',
+ scriptOrigins: { topLevel: 'same',
+ descendant: 'same' } });
+ }, 'Importing a same-origin script from a same-origin worklet script that ' +
+ 'has "no-referrer" referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'no-referrer',
+ scriptOrigins: { topLevel: 'same',
+ descendant: 'remote' } });
+ }, 'Importing a remote-origin script from a same-origin worklet script ' +
+ 'that has "no-referrer" referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'no-referrer',
+ scriptOrigins: { topLevel: 'remote',
+ descendant: 'same' } });
+ }, 'Importing a same-origin script from a remote-origin worklet script ' +
+ 'that has "no-referrer" referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'no-referrer',
+ scriptOrigins: { topLevel: 'remote',
+ descendant: 'remote' } });
+ }, 'Importing a remote-origin script from a remote-origin worklet script ' +
+ 'that has "no-referrer" referrer policy should not send referrer.');
+
+ // Referrer policy: origin.
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'origin',
+ scriptOrigins: { topLevel: 'same',
+ descendant: 'same' } });
+ }, 'Importing a same-origin script from a same-origin worklet script that ' +
+ 'has "origin" referrer policy should send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'origin',
+ scriptOrigins: { topLevel: 'same',
+ descendant: 'remote' } });
+ }, 'Importing a remote-origin script from a same-origin worklet script ' +
+ 'that has "origin" referrer policy should send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'origin',
+ scriptOrigins: { topLevel: 'remote',
+ descendant: 'same' } });
+ }, 'Importing a same-origin script from a remote-origin worklet script ' +
+ 'that has "origin" referrer policy should send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'origin',
+ scriptOrigins: { topLevel: 'remote',
+ descendant: 'remote' } });
+ }, 'Importing a remote-origin script from a remote-origin worklet script ' +
+ 'that has "origin" referrer policy should send referrer.');
+
+ // Referrer policy: same-origin.
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'same-origin',
+ scriptOrigins: { topLevel: 'same',
+ descendant: 'same' } });
+ }, 'Importing a same-origin script from a same-origin worklet script that ' +
+ 'has "same-origin" referrer policy should send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'same-origin',
+ scriptOrigins: { topLevel: 'same',
+ descendant: 'remote' } });
+ }, 'Importing a remote-origin script from a same-origin worklet script ' +
+ 'that has "same-origin" referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'same-origin',
+ scriptOrigins: { topLevel: 'remote',
+ descendant: 'same' } });
+ }, 'Importing a same-origin script from a remote-origin worklet script ' +
+ 'that has "same-origin" referrer policy should not send referrer.');
+
+ promise_test(t => {
+ return runReferrerTest(t, { workletType: workletType,
+ fetchType: 'descendant',
+ referrerPolicy: 'same-origin',
+ scriptOrigins: { topLevel: 'remote',
+ descendant: 'remote' } });
+ }, 'Importing a remote-origin script from a remote-origin worklet script ' +
+ 'that has "same-origin" referrer policy should send referrer.');
+}
diff --git a/testing/web-platform/tests/worklets/resources/referrer-window.html b/testing/web-platform/tests/worklets/resources/referrer-window.html
new file mode 100644
index 0000000000..1d8d38b719
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/referrer-window.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Worklet: Referrer</title>
+ <script src="/common/get-host-info.sub.js"></script>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="worklet-test-utils.js"></script>
+</head>
+<body>
+<script>
+function createScriptURLForTopLevel(scriptOrigin) {
+ if (scriptOrigin === 'same')
+ return new URL('referrer-checker.py', location.href);
+ if (scriptOrigin === 'remote') {
+ return new URL(get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/referrer-checker.py');
+ }
+ assert_unreached('scriptOrigin should be \'same\' or \'remote\'');
+}
+
+function createScriptURLForDecendant(scriptOrigins) {
+ if (scriptOrigins.topLevel === 'same' &&
+ scriptOrigins.descendant === 'same') {
+ return new URL('import-referrer-checker-worklet-script.sub.js',
+ location.href);
+ }
+ if (scriptOrigins.topLevel === 'same' &&
+ scriptOrigins.descendant === 'remote') {
+ return new URL(
+ 'import-remote-origin-referrer-checker-worklet-script.sub.js',
+ location.href);
+ }
+ if (scriptOrigins.topLevel === 'remote' &&
+ scriptOrigins.descendant === 'same') {
+ url = new URL(
+ get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/' +
+ 'import-same-origin-referrer-checker-worklet-script-from-remote-origin.sub.js');
+ return url;
+ }
+ if (scriptOrigins.topLevel === 'remote' &&
+ scriptOrigins.descendant === 'remote') {
+ return new URL(
+ get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/worklets/resources/import-referrer-checker-worklet-script.sub.js');
+ }
+ assert_unreached('scriptOrigins have an invalid origin combination.');
+}
+
+function isDestinationCrossOrigin(fetchType, scriptOrigins) {
+ if (fetchType === 'top-level')
+ return scriptOrigins.topLevel === 'remote';
+
+ // Compute a descendant's cross-origin-ness relative to the top-level script.
+ if (fetchType === 'descendant')
+ return scriptOrigins.descendant !== scriptOrigins.topLevel;
+ assert_unreached('fetchType has an invalid value.');
+}
+
+function createExpectedReferrer(
+ importerURL, fetchType, referrerPolicy, scriptOrigins) {
+ if (referrerPolicy === 'no-referrer')
+ return "";
+ if (referrerPolicy === 'same-origin') {
+ if (isDestinationCrossOrigin(fetchType, scriptOrigins))
+ return "";
+ // Delete query params to make it easier to match with an actual referrer in
+ // the referrer-checker.py.
+ const expectedReferrer = new URL(importerURL);
+ for (var key of expectedReferrer.searchParams.keys())
+ expectedReferrer.searchParams.delete(key);
+ return expectedReferrer;
+ }
+ if (referrerPolicy === 'origin')
+ return (new URL(importerURL)).origin + '/';
+ assert_unreached('referrerPolicy has an invalid value.');
+}
+
+window.onmessage = e => {
+ const workletType = e.data.workletType;
+ const fetchType = e.data.fetchType;
+ const referrerPolicy = e.data.referrerPolicy;
+ const scriptOrigins = e.data.scriptOrigins;
+
+ let scriptURL;
+ let expectedReferrer;
+ if (fetchType === 'top-level') {
+ scriptURL = createScriptURLForTopLevel(scriptOrigins.topLevel);
+ expectedReferrer = createExpectedReferrer(
+ location.href, fetchType, referrerPolicy, scriptOrigins);
+ } else if (fetchType === 'descendant') {
+ scriptURL = createScriptURLForDecendant(scriptOrigins);
+ expectedReferrer = createExpectedReferrer(
+ scriptURL, fetchType, referrerPolicy, scriptOrigins);
+ } else {
+ assert_unreached('fetchType should be \'top-level\' or \'descendant\'');
+ }
+
+ const params = new URLSearchParams;
+ params.append('requestor_origin', document.location.origin);
+ params.append('referrer_policy', referrerPolicy);
+ params.append('expected_referrer', expectedReferrer);
+
+ get_worklet(workletType).addModule(scriptURL + '?' + params)
+ .then(() => window.opener.postMessage('RESOLVED', '*'))
+ .catch(e => window.opener.postMessage(e.message, '*'));
+};
+
+window.opener.postMessage('LOADED', '*');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js b/testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js
new file mode 100644
index 0000000000..1298a626e4
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/service-worker-interception-tests.js
@@ -0,0 +1,108 @@
+function openWindow(t, url) {
+ return new Promise(resolve => {
+ const win = window.open(url, '_blank');
+ t.add_cleanup(() => win.close());
+ window.onmessage = e => {
+ assert_equals(e.data, 'LOADED');
+ resolve(win);
+ };
+ });
+}
+
+// Runs a series of tests related to service worker interception for a worklet.
+//
+// Usage:
+// runServiceWorkerInterceptionTests("paint");
+function runServiceWorkerInterceptionTests(worklet_type) {
+ const worklet = get_worklet(worklet_type);
+
+ // Tests that a worklet should be served by the owner document's service
+ // worker.
+ //
+ // [Current document] registers a service worker for Window's URL.
+ // --(open)--> [Window] should be controlled by the service worker.
+ // --(addModule)--> [Worklet] should be served by the service worker.
+ promise_test(async t => {
+ const kWindowURL = 'resources/addmodule-window.html';
+ const kServiceWorkerScriptURL = 'resources/service-worker.js';
+ // This doesn't contain the 'resources/' prefix because this will be
+ // imported from a html file under resources/.
+ const kWorkletScriptURL = 'non-existent-worklet-script.js';
+
+ const registration = await service_worker_unregister_and_register(
+ t, kServiceWorkerScriptURL, kWindowURL);
+ t.add_cleanup(() => registration.unregister());
+ await wait_for_state(t, registration.installing, 'activated');
+
+ const win = await openWindow(t, kWindowURL);
+ assert_not_equals(win.navigator.serviceWorker.controller, null,
+ 'The document should be controlled.');
+
+ // The worklet script on kWorkletScriptURL doesn't exist but the service
+ // worker serves it, so the addModule() should succeed.
+ win.postMessage({ type: worklet_type, script_url: kWorkletScriptURL }, '*');
+ const msgEvent = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msgEvent.data, 'RESOLVED');
+ }, 'addModule() on a controlled document should be intercepted by a ' +
+ 'service worker.');
+
+ // Tests that a worklet should not be served by a service worker other than
+ // the owner document's service worker.
+ //
+ // [Current document] registers a service worker for Worklet's URL.
+ // --(open)--> [Window] should not be controlled by the service worker.
+ // --(addModule)--> [Worklet] should not be served by the service worker.
+ promise_test(async t => {
+ const kWindowURL = 'resources/addmodule-window.html';
+ const kServiceWorkerScriptURL = 'resources/service-worker.js';
+ // This doesn't contain the 'resources/' prefix because this will be
+ // imported from a html file under resources/.
+ const kWorkletScriptURL = 'non-existent-worklet-script.js';
+
+ const registration = await service_worker_unregister_and_register(
+ t, kServiceWorkerScriptURL, 'resources/' + kWorkletScriptURL);
+ t.add_cleanup(() => registration.unregister());
+ await wait_for_state(t, registration.installing, 'activated');
+
+ const win = await openWindow(t, kWindowURL);
+ assert_equals(win.navigator.serviceWorker.controller, null,
+ 'The document should not be controlled.');
+
+ // The worklet script on kWorkletScriptURL doesn't exist and the service
+ // worker doesn't serve it, so the addModule() should fail.
+ win.postMessage({ type: worklet_type, script_url: kWorkletScriptURL }, '*');
+ const msgEvent = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msgEvent.data, 'REJECTED');
+ }, 'addModule() on a non-controlled document should not be intercepted by ' +
+ 'a service worker even if the script is under the service worker scope.');
+
+ // Tests that static import should be served by the owner document's service
+ // worker.
+ //
+ // [Current document] registers a service worker for Window's URL.
+ // --(open)--> [Window] should be controlled by the service worker.
+ // --(addModule)--> [Worklet] should be served by the service worker.
+ // --(static import)--> [Script] should be served by the service worker.
+ promise_test(async t => {
+ const kWindowURL = 'resources/addmodule-window.html';
+ const kServiceWorkerScriptURL = 'resources/service-worker.js';
+ // This doesn't contain the 'resources/' prefix because this will be
+ // imported from a html file under resources/.
+ const kWorkletScriptURL = 'import-non-existent-worklet-script.js';
+
+ const registration = await service_worker_unregister_and_register(
+ t, kServiceWorkerScriptURL, kWindowURL);
+ t.add_cleanup(() => registration.unregister());
+ await wait_for_state(t, registration.installing, 'activated');
+
+ const win = await openWindow(t, kWindowURL);
+ assert_not_equals(win.navigator.serviceWorker.controller, null,
+ 'The document should be controlled.');
+
+ // A script statically imported by the worklet doesn't exist but the service
+ // worker serves it, so the addModule() should succeed.
+ win.postMessage({ type: worklet_type, script_url: kWorkletScriptURL }, '*');
+ const msgEvent = await new Promise(resolve => window.onmessage = resolve);
+ assert_equals(msgEvent.data, 'RESOLVED');
+ }, 'Static import should be intercepted by a service worker.');
+}
diff --git a/testing/web-platform/tests/worklets/resources/service-worker.js b/testing/web-platform/tests/worklets/resources/service-worker.js
new file mode 100644
index 0000000000..67e6754cf0
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/service-worker.js
@@ -0,0 +1,4 @@
+self.addEventListener('fetch', e => {
+ if (e.request.url.indexOf('/non-existent-worklet-script.js') != -1)
+ e.respondWith(fetch('empty-worklet-script.js'));
+});
diff --git a/testing/web-platform/tests/worklets/resources/set-cookie.py b/testing/web-platform/tests/worklets/resources/set-cookie.py
new file mode 100644
index 0000000000..a36a69cce6
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/set-cookie.py
@@ -0,0 +1,15 @@
+def main(request, response):
+ name = request.GET.first(b"name")
+ value = request.GET.first(b"value")
+ source_origin = request.headers.get(b"origin")
+ if source_origin is None:
+ # Same origin GET won't include origin header
+ source_origin = "%s://%s" % (request.url_parts.scheme,
+ request.url_parts.netloc)
+ if request.url_parts.port:
+ source_origin += ":%s" % request.url_parts.port
+
+ response_headers = [(b"Set-Cookie", name + b"=" + value),
+ (b"Access-Control-Allow-Origin", source_origin),
+ (b"Access-Control-Allow-Credentials", b"true")]
+ return (200, response_headers, u"")
diff --git a/testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js b/testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js
new file mode 100644
index 0000000000..471697a43b
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/syntax-error-worklet-script.js
@@ -0,0 +1 @@
+;-)
diff --git a/testing/web-platform/tests/worklets/resources/throwing-worklet-script.js b/testing/web-platform/tests/worklets/resources/throwing-worklet-script.js
new file mode 100644
index 0000000000..6417d6c5f7
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/throwing-worklet-script.js
@@ -0,0 +1 @@
+throw Error();
diff --git a/testing/web-platform/tests/worklets/resources/worklet-test-utils.js b/testing/web-platform/tests/worklets/resources/worklet-test-utils.js
new file mode 100644
index 0000000000..797edc9e56
--- /dev/null
+++ b/testing/web-platform/tests/worklets/resources/worklet-test-utils.js
@@ -0,0 +1,12 @@
+// Returns a reference to a worklet object corresponding to a given type.
+function get_worklet(type) {
+ if (type == 'animation')
+ return CSS.animationWorklet;
+ if (type == 'layout')
+ return CSS.layoutWorklet;
+ if (type == 'paint')
+ return CSS.paintWorklet;
+ if (type == 'audio')
+ return new OfflineAudioContext(2,44100*40,44100).audioWorklet;
+ return undefined;
+}