Skip to content

Commit

Permalink
Add test for ServiceWorkerContainer.register() from a Worker context. (
Browse files Browse the repository at this point in the history
…#50018)

See https://w3c.github.io/ServiceWorker/#serviceworkercontainer-interface

Calling ServiceWorkerContainer.register() from a Window context is
already covered by worker-constructor.html.

This commit covers the case when it's called from a Worker context,
more specifically particular dedicated, shared and service workers.

This passes in Firefox with the patch from
https://bugzilla.mozilla.org/show_bug.cgi?id=1940044 and
https://bugzilla.mozilla.org/show_bug.cgi?id=1901492.
  • Loading branch information
fred-wang authored Jan 10, 2025
1 parent 1c25948 commit f371b41
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id=log></div>

<script>

// This test checks ServiceWorkerContainer.register() from Worker scopes and
// follows the same logic as WorkerGlobalScope-importScripts/eval. For the case
// when it's called from Window scope, see worker-constructor.https.html.

const test_setup_policy = trustedTypes.createPolicy("hurrayanythinggoes", {
createScriptURL: x => x});
const test_url =
test_setup_policy.createScriptURL("support/ServiceWorkerContainer-register.https.js");

fetch_tests_from_worker(new Worker(test_url));

fetch_tests_from_worker(new SharedWorker(test_url));

if ('serviceWorker' in navigator) {
(async function() {
const scope = 'support/some/scope/for/this/test';
let reg = await navigator.serviceWorker.getRegistration(scope);
if (reg) await reg.unregister();
reg = await navigator.serviceWorker.register(test_url, {scope});
fetch_tests_from_worker(reg.installing);
})();
}

</script>
</body>
66 changes: 66 additions & 0 deletions trusted-types/support/ServiceWorkerContainer-register.https.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
let test_setup_policy = trustedTypes.createPolicy("hurrayanythinggoes", {
createScriptURL: x => x
});
importScripts(test_setup_policy.createScriptURL("/resources/testharness.js"));

// Determine worker type (for better logging)
let worker_type = "unknown";
if (this.DedicatedWorkerGlobalScope !== undefined) {
worker_type = "dedicated worker";
} else if (this.SharedWorkerGlobalScope !== undefined) {
worker_type = "shared worker";
} else if (this.ServiceWorkerGlobalScope !== undefined) {
worker_type = "service worker";
}

let test_policy = trustedTypes.createPolicy("xxx", {
createScriptURL: url => url.replace("play", "work")
});

promise_test(async t => {
assert_true("navigator" in self);
assert_true(self.navigator instanceof WorkerNavigator);
}, `WorkerNavigator exposed in ${worker_type}`);

if ('serviceWorker' in navigator) {

// Passing a trusted type to register() should work.
promise_test(async t => {
let trusted_url = test_policy.createScriptURL("player.https.js");
assert_true(this.trustedTypes.isScriptURL(trusted_url));
const scope = `scope1/for/${worker_type}`;
let reg = await self.navigator.serviceWorker.getRegistration(scope);
if (reg) await reg.unregister();
reg = await self.navigator.serviceWorker.register(trusted_url, {scope});
await new Promise(r => reg.addEventListener("updatefound", r));
}, `register() with TrustedScriptURL works in ${worker_type}`);

// Passing a plain string to register() should fail.
promise_test(async t => {
let untrusted_url = "worker.https.js";
const scope = `scope2/for/${worker_type}`;
let reg = await self.navigator.serviceWorker.getRegistration(scope);
if (reg) await reg.unregister();
promise_rejects_js(t, TypeError, self.navigator.serviceWorker.register(untrusted_url, {scope}));
}, `register() fails with plain string in ${worker_type}`);

// Passing a plain string to register() should work after registering a
// default policy.
promise_test(async t => {
trustedTypes.createPolicy("default", {
createScriptURL: (url, _, sink) => {
assert_equals(sink, "ServiceWorkerContainer register");
return url.replace("play", "work");
}
});

let untrusted_url = "player.https.js";
const scope = `scope3/for/${worker_type}`;
let reg = await self.navigator.serviceWorker.getRegistration(scope);
if (reg) await reg.unregister();
reg = await self.navigator.serviceWorker.register(untrusted_url, {scope});
await new Promise(r => reg.addEventListener("updatefound", r));
}, `register() fails with plain string in ${worker_type} with a default policy`);
}

done();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Content-Security-Policy: require-trusted-types-for 'script';
Empty file.

0 comments on commit f371b41

Please sign in to comment.