diff --git a/benchmark/misc/startup-core.js b/benchmark/misc/startup-core.js
index 414b00176ad2..d673d415b505 100644
--- a/benchmark/misc/startup-core.js
+++ b/benchmark/misc/startup-core.js
@@ -64,6 +64,7 @@ function main({ n, script, mode }) {
const warmup = 3;
const state = { n, finished: -warmup };
if (mode === 'worker') {
+ // eslint-disable-next-line no-global-assign
Worker = require('worker_threads').Worker;
spawnWorker(script, bench, state);
} else {
diff --git a/doc/api/cli.md b/doc/api/cli.md
index 9434e19d3b73..c41fe51d8466 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -1527,6 +1527,14 @@ changes:
Enable experimental WebAssembly System Interface (WASI) support.
+### `--experimental-web-worker`
+
+
+
+Enable experimental support for the Web Worker API.
+
### `--experimental-worker-inspection`
+
+> Stability: 1 - Experimental. Enable this API with the
+> [`--experimental-web-worker`][] CLI flag.
+
+A browser-compatible implementation of Web Workers of the [HTML Standard][],
+implemented on top of [`node:worker_threads`][]. Threads created with it
+are given the {DedicatedWorkerGlobalScope} API (`self`,
+`name`, `location`, `navigator`, `postMessage()`, `close()`, and
+`importScripts()`), in addition to the usual Node.js globals, such as `process`.
+
+```js
+// worker.js
+addEventListener('message', (event) => {
+ postMessage(`${event.data} from ${name}!`);
+});
+```
+
+```js
+// main.js
+const worker = new Worker('./worker.js', { name: 'greeter' });
+
+worker.addEventListener('message', (event) => {
+ console.log(event.data); // Prints: Hello from greeter!
+ worker.terminate();
+});
+
+worker.postMessage('Hello');
+```
+
+Because their lifetime and sharing model depend on origins and
+browsing contexts, Node.js does not currently implement `SharedWorker`.
+
+### Loading worker scripts
+
+Worker scripts are read synchronously from the local file system or from
+memory rather than fetched over the network, which changes which URLs are
+accepted and how failures are reported:
+
+* `new Worker()` and `importScripts()` accept only `file:`, `data:`, and
+ `blob:` URLs. Any other scheme makes `new Worker()` throw a
+ `NotSupportedError` and `importScripts()` throw a `NetworkError`.
+* A script that cannot be read makes `importScripts()` throw a `NetworkError`;
+ for `new Worker()` it fires an `error` event at the `Worker` object.
+* Redirects, the `nosniff` check, and HTTP MIME type validation do not apply.
+ MIME types are validated only for `data:` and `blob:` URLs. The
+ `credentials` option is validated for API compatibility but has no effect,
+ since no network request is made.
+* On the main thread, relative script URLs are resolved against the current
+ working directory, because there is no document base URL. Within a worker
+ they are resolved against the worker's own URL (as is done in the spec).
+* For `blob:` URLs, the script must be held in memory, so blobs backed by a file,
+ such as those returned by [`fs.openAsBlob()`][], cannot be used.
+
+### Differences from the HTML Standard
+
+Besides script loading, mentioned above:
+
+* Node.js has no origin model, so same-origin and cross-origin distinctions do
+ not exist and `location.origin` is `'null'` for every supported scheme.
+* `close()` terminates the worker immediately instead of following the
+ specification's "closing flag" algorithm, so code remaining in the current
+ task after `close()` is not executed.
+* The worker global is the normal Node.js global object with
+ `DedicatedWorkerGlobalScope` inserted into its prototype chain, rather than
+ a fresh global created from the interface. Node.js globals such as
+ `process`, `Buffer`, and `require()` remain available to worker scripts.
+* `ErrorEvent`s dispatched at `Worker` instances include `message` and
+ `error`, but `filename`, `lineno`, and `colno` are always `''`, `0`, and
+ `0`. An uncaught exception terminates the worker thread, and an unhandled
+ `error` event is not propagated further: it neither reaches the parent's
+ global scope nor affects the exit code of the process.
+* The following {WorkerGlobalScope} events are never dispatched, although
+ their handler properties exist: `languagechange`, `online`, and `offline`,
+ since these concepts do not exist in Node.js; `rejectionhandled` and
+ `unhandledrejection`, since Node.js exposes the equivalent does not
+ implement the `PromiseRejectionEvent` interface or the per-rejection
+ `preventDefault()` behavior required by the HTML Standard.
+
+### Web Workers and `node:worker_threads`
+
+Every Web Worker is backed by a [`node:worker_threads`][] {Worker}, so the
+two APIs share their threading, structured clone, and transfer semantics.
+Inside a worker, \[`worker_threads.parentPort`]\[] is the port behind
+`self.postMessage()` and the worker's `message` events, `isMainThread` is
+`false`, and `workerData` is `undefined`.
+
+As a rule of thumb, use [`node:worker_threads`][] directly when a program
+needs `workerData`, a custom `env` or `execArgv`, resource limits, stdio
+redirection, the `'online'` and `'exit'` events, or `worker.threadId`;
+`Worker` accepts only the `name`, `type`, and `credentials` options and,
+per the specification, its `terminate()` returns `undefined`, rather than
+a promise. Threads started through [`node:worker_threads`][] are ordinary
+Node.js threads and do not get the worker global scope APIs.
+
## Class: `WritableStream`
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/blank.html b/test/fixtures/wpt/service-workers/cache-storage/resources/blank.html
new file mode 100644
index 000000000000..a3c3a4689a62
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/blank.html
@@ -0,0 +1,2 @@
+
+Empty doc
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/cache-keys-attributes-for-service-worker.js b/test/fixtures/wpt/service-workers/cache-storage/resources/cache-keys-attributes-for-service-worker.js
new file mode 100644
index 000000000000..ee574d2cb77a
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/cache-keys-attributes-for-service-worker.js
@@ -0,0 +1,22 @@
+self.addEventListener('fetch', (event) => {
+ const params = new URL(event.request.url).searchParams;
+ if (params.has('ignore')) {
+ return;
+ }
+ if (!params.has('name')) {
+ event.respondWith(Promise.reject(TypeError('No name is provided.')));
+ return;
+ }
+
+ event.respondWith(Promise.resolve().then(async () => {
+ const name = params.get('name');
+ await caches.delete('foo');
+ const cache = await caches.open('foo');
+ await cache.put(event.request, new Response('hello'));
+ const keys = await cache.keys();
+
+ const original = event.request[name];
+ const stored = keys[0][name];
+ return new Response(`original: ${original}, stored: ${stored}`);
+ }));
+ });
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/common-worker.js b/test/fixtures/wpt/service-workers/cache-storage/resources/common-worker.js
new file mode 100644
index 000000000000..d0e8544b56c2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/common-worker.js
@@ -0,0 +1,15 @@
+self.onmessage = function(e) {
+ var cache_name = e.data.name;
+
+ self.caches.open(cache_name)
+ .then(function(cache) {
+ return Promise.all([
+ cache.put('https://example.com/a', new Response('a')),
+ cache.put('https://example.com/b', new Response('b')),
+ cache.put('https://example.com/c', new Response('c'))
+ ]);
+ })
+ .then(function() {
+ self.postMessage('ok');
+ });
+};
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/credentials-iframe.html b/test/fixtures/wpt/service-workers/cache-storage/resources/credentials-iframe.html
new file mode 100644
index 000000000000..00702df9e5b1
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/credentials-iframe.html
@@ -0,0 +1,38 @@
+
+
+Controlled frame for Cache API test with credentials
+
+
+Hello? Yes, this is iframe.
+
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/credentials-worker.js b/test/fixtures/wpt/service-workers/cache-storage/resources/credentials-worker.js
new file mode 100644
index 000000000000..43965b5fe4c9
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/credentials-worker.js
@@ -0,0 +1,59 @@
+var cache_name = 'credentials';
+
+function assert_equals(actual, expected, message) {
+ if (!Object.is(actual, expected))
+ throw Error(message + ': expected: ' + expected + ', actual: ' + actual);
+}
+
+self.onfetch = function(e) {
+ if (!/\.txt$/.test(e.request.url)) return;
+ var content = e.request.url;
+ var cache;
+ e.respondWith(
+ self.caches.open(cache_name)
+ .then(function(result) {
+ cache = result;
+ return cache.put(e.request, new Response(content));
+ })
+
+ .then(function() { return cache.match(e.request); })
+ .then(function(result) { return result.text(); })
+ .then(function(text) {
+ assert_equals(text, content, 'Cache.match() body should match');
+ })
+
+ .then(function() { return cache.matchAll(e.request); })
+ .then(function(results) {
+ assert_equals(results.length, 1, 'Should have one response');
+ return results[0].text();
+ })
+ .then(function(text) {
+ assert_equals(text, content, 'Cache.matchAll() body should match');
+ })
+
+ .then(function() { return self.caches.match(e.request); })
+ .then(function(result) { return result.text(); })
+ .then(function(text) {
+ assert_equals(text, content, 'CacheStorage.match() body should match');
+ })
+
+ .then(function() {
+ return new Response('dummy');
+ })
+ );
+};
+
+self.onmessage = function(e) {
+ if (e.data === 'keys') {
+ self.caches.open(cache_name)
+ .then(function(cache) { return cache.keys(); })
+ .then(function(requests) {
+ var urls = requests.map(function(request) { return request.url; });
+ self.clients.matchAll().then(function(clients) {
+ clients.forEach(function(client) {
+ client.postMessage(urls);
+ });
+ });
+ });
+ }
+};
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/iframe.html b/test/fixtures/wpt/service-workers/cache-storage/resources/iframe.html
new file mode 100644
index 000000000000..a2f1e502bb39
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/iframe.html
@@ -0,0 +1,18 @@
+
+ok
+
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/simple.txt b/test/fixtures/wpt/service-workers/cache-storage/resources/simple.txt
new file mode 100644
index 000000000000..9e3cb91fb9b9
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/simple.txt
@@ -0,0 +1 @@
+a simple text file
diff --git a/test/fixtures/wpt/service-workers/cache-storage/resources/test-helpers.js b/test/fixtures/wpt/service-workers/cache-storage/resources/test-helpers.js
new file mode 100644
index 000000000000..050ac0b54245
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/resources/test-helpers.js
@@ -0,0 +1,272 @@
+(function() {
+ var next_cache_index = 1;
+
+ // Returns a promise that resolves to a newly created Cache object. The
+ // returned Cache will be destroyed when |test| completes.
+ function create_temporary_cache(test) {
+ var uniquifier = String(++next_cache_index);
+ var cache_name = self.location.pathname + '/' + uniquifier;
+
+ test.add_cleanup(function() {
+ self.caches.delete(cache_name);
+ });
+
+ return self.caches.delete(cache_name)
+ .then(function() {
+ return self.caches.open(cache_name);
+ });
+ }
+
+ self.create_temporary_cache = create_temporary_cache;
+})();
+
+// Runs |test_function| with a temporary unique Cache passed in as the only
+// argument. The function is run as a part of Promise chain owned by
+// promise_test(). As such, it is expected to behave in a manner identical (with
+// the exception of the argument) to a function passed into promise_test().
+//
+// E.g.:
+// cache_test(function(cache) {
+// // Do something with |cache|, which is a Cache object.
+// }, "Some Cache test");
+function cache_test(test_function, description) {
+ promise_test(function(test) {
+ return create_temporary_cache(test)
+ .then(function(cache) { return test_function(cache, test); });
+ }, description);
+}
+
+// A set of Request/Response pairs to be used with prepopulated_cache_test().
+var simple_entries = [
+ {
+ name: 'a',
+ request: new Request('http://example.com/a'),
+ response: new Response('')
+ },
+
+ {
+ name: 'b',
+ request: new Request('http://example.com/b'),
+ response: new Response('')
+ },
+
+ {
+ name: 'a_with_query',
+ request: new Request('http://example.com/a?q=r'),
+ response: new Response('')
+ },
+
+ {
+ name: 'A',
+ request: new Request('http://example.com/A'),
+ response: new Response('')
+ },
+
+ {
+ name: 'a_https',
+ request: new Request('https://example.com/a'),
+ response: new Response('')
+ },
+
+ {
+ name: 'a_org',
+ request: new Request('http://example.org/a'),
+ response: new Response('')
+ },
+
+ {
+ name: 'cat',
+ request: new Request('http://example.com/cat'),
+ response: new Response('')
+ },
+
+ {
+ name: 'catmandu',
+ request: new Request('http://example.com/catmandu'),
+ response: new Response('')
+ },
+
+ {
+ name: 'cat_num_lives',
+ request: new Request('http://example.com/cat?lives=9'),
+ response: new Response('')
+ },
+
+ {
+ name: 'cat_in_the_hat',
+ request: new Request('http://example.com/cat/in/the/hat'),
+ response: new Response('')
+ },
+
+ {
+ name: 'non_2xx_response',
+ request: new Request('http://example.com/non2xx'),
+ response: new Response('', {status: 404, statusText: 'nope'})
+ },
+
+ {
+ name: 'error_response',
+ request: new Request('http://example.com/error'),
+ response: Response.error()
+ },
+];
+
+// A set of Request/Response pairs to be used with prepopulated_cache_test().
+// These contain a mix of test cases that use Vary headers.
+var vary_entries = [
+ {
+ name: 'vary_cookie_is_cookie',
+ request: new Request('http://example.com/c',
+ {headers: {'Cookies': 'is-for-cookie'}}),
+ response: new Response('',
+ {headers: {'Vary': 'Cookies'}})
+ },
+
+ {
+ name: 'vary_cookie_is_good',
+ request: new Request('http://example.com/c',
+ {headers: {'Cookies': 'is-good-enough-for-me'}}),
+ response: new Response('',
+ {headers: {'Vary': 'Cookies'}})
+ },
+
+ {
+ name: 'vary_cookie_absent',
+ request: new Request('http://example.com/c'),
+ response: new Response('',
+ {headers: {'Vary': 'Cookies'}})
+ }
+];
+
+// Run |test_function| with a Cache object and a map of entries. Prior to the
+// call, the Cache is populated by cache entries from |entries|. The latter is
+// expected to be an Object mapping arbitrary keys to objects of the form
+// {request: , response: }. Entries are
+// serially added to the cache in the order specified.
+//
+// |test_function| should return a Promise that can be used with promise_test.
+function prepopulated_cache_test(entries, test_function, description) {
+ cache_test(function(cache) {
+ var p = Promise.resolve();
+ var hash = {};
+ entries.forEach(function(entry) {
+ hash[entry.name] = entry;
+ p = p.then(function() {
+ return cache.put(entry.request.clone(), entry.response.clone())
+ .catch(function(e) {
+ assert_unreached(
+ 'Test setup failed for entry ' + entry.name + ': ' + e
+ );
+ });
+ });
+ });
+ return p
+ .then(function() {
+ assert_equals(Object.keys(hash).length, entries.length);
+ })
+ .then(function() {
+ return test_function(cache, hash);
+ });
+ }, description);
+}
+
+// Helper for testing with Headers objects. Compares Headers instances
+// by serializing |expected| and |actual| to arrays and comparing.
+function assert_header_equals(actual, expected, description) {
+ assert_class_string(actual, "Headers", description);
+ var header;
+ var actual_headers = [];
+ var expected_headers = [];
+ for (header of actual)
+ actual_headers.push(header[0] + ": " + header[1]);
+ for (header of expected)
+ expected_headers.push(header[0] + ": " + header[1]);
+ assert_array_equals(actual_headers, expected_headers,
+ description + " Headers differ.");
+}
+
+// Helper for testing with Response objects. Compares simple
+// attributes defined on the interfaces, as well as the headers. It
+// does not compare the response bodies.
+function assert_response_equals(actual, expected, description) {
+ assert_class_string(actual, "Response", description);
+ ["type", "url", "status", "ok", "statusText"].forEach(function(attribute) {
+ assert_equals(actual[attribute], expected[attribute],
+ description + " Attributes differ: " + attribute + ".");
+ });
+ assert_header_equals(actual.headers, expected.headers, description);
+}
+
+// Assert that the two arrays |actual| and |expected| contain the same
+// set of Responses as determined by assert_response_equals. The order
+// is not significant.
+//
+// |expected| is assumed to not contain any duplicates.
+function assert_response_array_equivalent(actual, expected, description) {
+ assert_true(Array.isArray(actual), description);
+ assert_equals(actual.length, expected.length, description);
+ expected.forEach(function(expected_element) {
+ // assert_response_in_array treats the first argument as being
+ // 'actual', and the second as being 'expected array'. We are
+ // switching them around because we want to be resilient
+ // against the |actual| array containing duplicates.
+ assert_response_in_array(expected_element, actual, description);
+ });
+}
+
+// Asserts that two arrays |actual| and |expected| contain the same
+// set of Responses as determined by assert_response_equals(). The
+// corresponding elements must occupy corresponding indices in their
+// respective arrays.
+function assert_response_array_equals(actual, expected, description) {
+ assert_true(Array.isArray(actual), description);
+ assert_equals(actual.length, expected.length, description);
+ actual.forEach(function(value, index) {
+ assert_response_equals(value, expected[index],
+ description + " : object[" + index + "]");
+ });
+}
+
+// Equivalent to assert_in_array, but uses assert_response_equals.
+function assert_response_in_array(actual, expected_array, description) {
+ assert_true(expected_array.some(function(element) {
+ try {
+ assert_response_equals(actual, element);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }), description);
+}
+
+// Helper for testing with Request objects. Compares simple
+// attributes defined on the interfaces, as well as the headers.
+function assert_request_equals(actual, expected, description) {
+ assert_class_string(actual, "Request", description);
+ ["url"].forEach(function(attribute) {
+ assert_equals(actual[attribute], expected[attribute],
+ description + " Attributes differ: " + attribute + ".");
+ });
+ assert_header_equals(actual.headers, expected.headers, description);
+}
+
+// Asserts that two arrays |actual| and |expected| contain the same
+// set of Requests as determined by assert_request_equals(). The
+// corresponding elements must occupy corresponding indices in their
+// respective arrays.
+function assert_request_array_equals(actual, expected, description) {
+ assert_true(Array.isArray(actual), description);
+ assert_equals(actual.length, expected.length, description);
+ actual.forEach(function(value, index) {
+ assert_request_equals(value, expected[index],
+ description + " : object[" + index + "]");
+ });
+}
+
+// Deletes all caches, returning a promise indicating success.
+function delete_all_caches() {
+ return self.caches.keys()
+ .then(function(keys) {
+ return Promise.all(keys.map(self.caches.delete.bind(self.caches)));
+ });
+}
diff --git a/test/fixtures/wpt/service-workers/cache-storage/sandboxed-iframes.https.html b/test/fixtures/wpt/service-workers/cache-storage/sandboxed-iframes.https.html
new file mode 100644
index 000000000000..098fa89daf44
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/cache-storage/sandboxed-iframes.https.html
@@ -0,0 +1,66 @@
+
+Cache Storage: Verify access in sandboxed iframes
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/idlharness.https.any.js b/test/fixtures/wpt/service-workers/idlharness.https.any.js
new file mode 100644
index 000000000000..8db5d4d10ff7
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/idlharness.https.any.js
@@ -0,0 +1,53 @@
+// META: global=window,worker
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: script=cache-storage/resources/test-helpers.js
+// META: script=service-worker/resources/test-helpers.sub.js
+// META: timeout=long
+
+// https://w3c.github.io/ServiceWorker
+
+idl_test(
+ ['service-workers'],
+ ['dom', 'html'],
+ async (idl_array, t) => {
+ self.cacheInstance = await create_temporary_cache(t);
+
+ idl_array.add_objects({
+ CacheStorage: ['caches'],
+ Cache: ['self.cacheInstance'],
+ ServiceWorkerContainer: ['navigator.serviceWorker']
+ });
+
+ // TODO: Add ServiceWorker and ServiceWorkerRegistration instances for the
+ // other worker scopes.
+ if (self.GLOBAL.isWindow()) {
+ idl_array.add_objects({
+ ServiceWorkerRegistration: ['registrationInstance'],
+ ServiceWorker: ['registrationInstance.installing']
+ });
+
+ const scope = 'service-worker/resources/scope/idlharness';
+ const registration = await service_worker_unregister_and_register(
+ t, 'service-worker/resources/empty-worker.js', scope);
+ t.add_cleanup(() => registration.unregister());
+
+ self.registrationInstance = registration;
+ } else if (self.ServiceWorkerGlobalScope) {
+ // self.ServiceWorkerGlobalScope should only be defined for the
+ // ServiceWorker scope, which allows us to detect and test the interfaces
+ // exposed only for ServiceWorker.
+ idl_array.add_objects({
+ Clients: ['clients'],
+ ExtendableEvent: ['new ExtendableEvent("type")'],
+ FetchEvent: ['new FetchEvent("type", { request: new Request("") })'],
+ ServiceWorkerGlobalScope: ['self'],
+ ServiceWorkerRegistration: ['registration'],
+ ServiceWorker: ['serviceWorker'],
+ // TODO: Test instances of Client and WindowClient, e.g.
+ // Client: ['self.clientInstance'],
+ // WindowClient: ['self.windowClientInstance']
+ });
+ }
+ }
+);
diff --git a/test/fixtures/wpt/service-workers/service-worker/Service-Worker-Allowed-header.https.html b/test/fixtures/wpt/service-workers/service-worker/Service-Worker-Allowed-header.https.html
new file mode 100644
index 000000000000..6f44bb17e7da
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/Service-Worker-Allowed-header.https.html
@@ -0,0 +1,88 @@
+
+Service Worker: Service-Worker-Allowed header
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/WEB_FEATURES.yml b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/WEB_FEATURES.yml
new file mode 100644
index 000000000000..41cd63e4cb42
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+rules:
+- isSecureContext*: [is-secure-context]
+- "*": [service-workers]
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html
new file mode 100644
index 000000000000..3e3cc8b2b089
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/close.https.html
@@ -0,0 +1,11 @@
+
+ServiceWorkerGlobalScope: close operation
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/error-message-event-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/error-message-event-worker.js
new file mode 100644
index 000000000000..525bc96e763e
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/error-message-event-worker.js
@@ -0,0 +1,2 @@
+self.onmessageerror = e => { e.source.postMessage("received error event"); };
+self.onmessage = e => { e.source.postMessage("received message event"); };
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/error-message-event.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/error-message-event.https.html
new file mode 100644
index 000000000000..0a35cc7c39cf
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/error-message-event.https.html
@@ -0,0 +1,48 @@
+
+
+
+Service Worker GlobalScope onerror event
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event-constructor.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event-constructor.https.html
new file mode 100644
index 000000000000..525245fe9ece
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event-constructor.https.html
@@ -0,0 +1,10 @@
+
+ServiceWorkerGlobalScope: ExtendableMessageEvent Constructor
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event.https.html
new file mode 100644
index 000000000000..89efd7a4a615
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event.https.html
@@ -0,0 +1,226 @@
+
+ServiceWorkerGlobalScope: ExtendableMessageEvent
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/fetch-on-the-right-interface.https.any.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/fetch-on-the-right-interface.https.any.js
new file mode 100644
index 000000000000..5ca5f65680c9
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/fetch-on-the-right-interface.https.any.js
@@ -0,0 +1,14 @@
+// META: title=fetch method on the right interface
+// META: global=serviceworker
+
+test(function() {
+ assert_false(self.hasOwnProperty('fetch'), 'ServiceWorkerGlobalScope ' +
+ 'instance should not have "fetch" method as its property.');
+ assert_inherits(self, 'fetch', 'ServiceWorkerGlobalScope should ' +
+ 'inherit "fetch" method.');
+ assert_own_property(Object.getPrototypeOf(Object.getPrototypeOf(self)), 'fetch',
+ 'WorkerGlobalScope should have "fetch" propery in its prototype.');
+ assert_equals(self.fetch, Object.getPrototypeOf(Object.getPrototypeOf(self)).fetch,
+ 'ServiceWorkerGlobalScope.fetch should be the same as ' +
+ 'WorkerGlobalScope.fetch.');
+}, 'Fetch method on the right interface');
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/isSecureContext.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/isSecureContext.https.html
new file mode 100644
index 000000000000..399820dd2c31
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/isSecureContext.https.html
@@ -0,0 +1,32 @@
+
+
+
+Service Worker: isSecureContext
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/isSecureContext.serviceworker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/isSecureContext.serviceworker.js
new file mode 100644
index 000000000000..5033594e34ba
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/isSecureContext.serviceworker.js
@@ -0,0 +1,5 @@
+importScripts("/resources/testharness.js");
+
+test(() => {
+ assert_true(self.isSecureContext, true);
+}, "isSecureContext");
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/message-event-ports-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/message-event-ports-worker.js
new file mode 100644
index 000000000000..78cd0d86c010
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/message-event-ports-worker.js
@@ -0,0 +1,3 @@
+self.onmessage = e => {
+ e.source.postMessage(e.ports === e.ports ? "same ports array" : "different ports array");
+};
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/message-event-ports.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/message-event-ports.https.html
new file mode 100644
index 000000000000..a0eac39e9b35
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/message-event-ports.https.html
@@ -0,0 +1,43 @@
+
+
+
+Service Worker GlobalScope onerror event
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/postmessage.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/postmessage.https.html
new file mode 100644
index 000000000000..99dedebf2e56
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/postmessage.https.html
@@ -0,0 +1,83 @@
+
+ServiceWorkerGlobalScope: postMessage
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html
new file mode 100644
index 000000000000..aa3c74a13bb2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/registration-attribute.https.html
@@ -0,0 +1,107 @@
+
+ServiceWorkerGlobalScope: registration
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/close-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/close-worker.js
new file mode 100644
index 000000000000..41a8bc069af8
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/close-worker.js
@@ -0,0 +1,5 @@
+importScripts('../../resources/worker-testharness.js');
+
+test(function() {
+ assert_false('close' in self);
+}, 'ServiceWorkerGlobalScope close operation');
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js
new file mode 100644
index 000000000000..f6838ffb3947
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js
@@ -0,0 +1,12 @@
+var source;
+
+self.addEventListener('message', function(e) {
+ source = e.source;
+ throw 'testError';
+});
+
+self.addEventListener('error', function(e) {
+ source.postMessage({
+ error: e.error, filename: e.filename, message: e.message, lineno: e.lineno,
+ colno: e.colno});
+});
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-constructor-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-constructor-worker.js
new file mode 100644
index 000000000000..42da5825c56d
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-constructor-worker.js
@@ -0,0 +1,197 @@
+importScripts('/resources/testharness.js');
+
+const TEST_OBJECT = { wanwan: 123 };
+const CHANNEL1 = new MessageChannel();
+const CHANNEL2 = new MessageChannel();
+const PORTS = [CHANNEL1.port1, CHANNEL1.port2, CHANNEL2.port1];
+function createEvent(initializer) {
+ if (initializer === undefined)
+ return new ExtendableMessageEvent('type');
+ return new ExtendableMessageEvent('type', initializer);
+}
+
+// These test cases are mostly copied from the following file in the Chromium
+// project (as of commit 848ad70823991e0f12b437d789943a4ab24d65bb):
+// third_party/WebKit/LayoutTests/fast/events/constructors/message-event-constructor.html
+
+test(function() {
+ assert_false(createEvent().bubbles);
+ assert_false(createEvent().cancelable);
+ assert_equals(createEvent().data, null);
+ assert_equals(createEvent().origin, '');
+ assert_equals(createEvent().lastEventId, '');
+ assert_equals(createEvent().source, null);
+ assert_array_equals(createEvent().ports, []);
+}, 'no initializer specified');
+
+test(function() {
+ assert_false(createEvent({ bubbles: false }).bubbles);
+ assert_true(createEvent({ bubbles: true }).bubbles);
+}, '`bubbles` is specified');
+
+test(function() {
+ assert_false(createEvent({ cancelable: false }).cancelable);
+ assert_true(createEvent({ cancelable: true }).cancelable);
+}, '`cancelable` is specified');
+
+test(function() {
+ assert_equals(createEvent({ data: TEST_OBJECT }).data, TEST_OBJECT);
+ assert_equals(createEvent({ data: undefined }).data, null);
+ assert_equals(createEvent({ data: null }).data, null);
+ assert_equals(createEvent({ data: false }).data, false);
+ assert_equals(createEvent({ data: true }).data, true);
+ assert_equals(createEvent({ data: '' }).data, '');
+ assert_equals(createEvent({ data: 'chocolate' }).data, 'chocolate');
+ assert_equals(createEvent({ data: 12345 }).data, 12345);
+ assert_equals(createEvent({ data: 18446744073709551615 }).data,
+ 18446744073709552000);
+ assert_equals(createEvent({ data: NaN }).data, NaN);
+ // Note that valueOf() is not called, when the left hand side is
+ // evaluated.
+ assert_false(
+ createEvent({ data: {
+ valueOf: function() { return TEST_OBJECT; } } }).data ==
+ TEST_OBJECT);
+ assert_equals(createEvent({ get data(){ return 123; } }).data, 123);
+ let thrown = { name: 'Error' };
+ assert_throws_exactly(thrown, function() {
+ createEvent({ get data() { throw thrown; } }); });
+}, '`data` is specified');
+
+test(function() {
+ assert_equals(createEvent({ origin: 'melancholy' }).origin, 'melancholy');
+ assert_equals(createEvent({ origin: '' }).origin, '');
+ assert_equals(createEvent({ origin: null }).origin, 'null');
+ assert_equals(createEvent({ origin: false }).origin, 'false');
+ assert_equals(createEvent({ origin: true }).origin, 'true');
+ assert_equals(createEvent({ origin: 12345 }).origin, '12345');
+ assert_equals(
+ createEvent({ origin: 18446744073709551615 }).origin,
+ '18446744073709552000');
+ assert_equals(createEvent({ origin: NaN }).origin, 'NaN');
+ assert_equals(createEvent({ origin: [] }).origin, '');
+ assert_equals(createEvent({ origin: [1, 2, 3] }).origin, '1,2,3');
+ assert_equals(
+ createEvent({ origin: { melancholy: 12345 } }).origin,
+ '[object Object]');
+ // Note that valueOf() is not called, when the left hand side is
+ // evaluated.
+ assert_equals(
+ createEvent({ origin: {
+ valueOf: function() { return 'melancholy'; } } }).origin,
+ '[object Object]');
+ assert_equals(
+ createEvent({ get origin() { return 123; } }).origin, '123');
+ let thrown = { name: 'Error' };
+ assert_throws_exactly(thrown, function() {
+ createEvent({ get origin() { throw thrown; } }); });
+}, '`origin` is specified');
+
+test(function() {
+ assert_equals(
+ createEvent({ lastEventId: 'melancholy' }).lastEventId, 'melancholy');
+ assert_equals(createEvent({ lastEventId: '' }).lastEventId, '');
+ assert_equals(createEvent({ lastEventId: null }).lastEventId, 'null');
+ assert_equals(createEvent({ lastEventId: false }).lastEventId, 'false');
+ assert_equals(createEvent({ lastEventId: true }).lastEventId, 'true');
+ assert_equals(createEvent({ lastEventId: 12345 }).lastEventId, '12345');
+ assert_equals(
+ createEvent({ lastEventId: 18446744073709551615 }).lastEventId,
+ '18446744073709552000');
+ assert_equals(createEvent({ lastEventId: NaN }).lastEventId, 'NaN');
+ assert_equals(createEvent({ lastEventId: [] }).lastEventId, '');
+ assert_equals(
+ createEvent({ lastEventId: [1, 2, 3] }).lastEventId, '1,2,3');
+ assert_equals(
+ createEvent({ lastEventId: { melancholy: 12345 } }).lastEventId,
+ '[object Object]');
+ // Note that valueOf() is not called, when the left hand side is
+ // evaluated.
+ assert_equals(
+ createEvent({ lastEventId: {
+ valueOf: function() { return 'melancholy'; } } }).lastEventId,
+ '[object Object]');
+ assert_equals(
+ createEvent({ get lastEventId() { return 123; } }).lastEventId,
+ '123');
+ let thrown = { name: 'Error' };
+ assert_throws_exactly(thrown, function() {
+ createEvent({ get lastEventId() { throw thrown; } }); });
+}, '`lastEventId` is specified');
+
+test(function() {
+ assert_equals(createEvent({ source: CHANNEL1.port1 }).source, CHANNEL1.port1);
+ assert_equals(
+ createEvent({ source: self.registration.active }).source,
+ self.registration.active);
+ assert_equals(
+ createEvent({ source: CHANNEL1.port1 }).source, CHANNEL1.port1);
+ assert_throws_js(
+ TypeError, function() { createEvent({ source: this }); },
+ 'source should be Client or ServiceWorker or MessagePort');
+}, '`source` is specified');
+
+test(function() {
+ // Valid message ports.
+ var passed_ports = createEvent({ ports: PORTS}).ports;
+ assert_equals(passed_ports[0], CHANNEL1.port1);
+ assert_equals(passed_ports[1], CHANNEL1.port2);
+ assert_equals(passed_ports[2], CHANNEL2.port1);
+ assert_array_equals(createEvent({ ports: [] }).ports, []);
+ assert_array_equals(createEvent({ ports: undefined }).ports, []);
+
+ // Invalid message ports.
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: [1, 2, 3] }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: TEST_OBJECT }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: null }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: this }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: false }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: true }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: '' }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: 'chocolate' }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: 12345 }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: 18446744073709551615 }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ ports: NaN }); });
+ assert_throws_js(TypeError,
+ function() { createEvent({ get ports() { return 123; } }); });
+ let thrown = { name: 'Error' };
+ assert_throws_exactly(thrown, function() {
+ createEvent({ get ports() { throw thrown; } }); });
+ // Note that valueOf() is not called, when the left hand side is
+ // evaluated.
+ var valueOf = function() { return PORTS; };
+ assert_throws_js(TypeError, function() {
+ createEvent({ ports: { valueOf: valueOf } }); });
+}, '`ports` is specified');
+
+test(function() {
+ var initializers = {
+ bubbles: true,
+ cancelable: true,
+ data: TEST_OBJECT,
+ origin: 'wonderful',
+ lastEventId: 'excellent',
+ source: CHANNEL1.port1,
+ ports: PORTS
+ };
+ assert_equals(createEvent(initializers).bubbles, true);
+ assert_equals(createEvent(initializers).cancelable, true);
+ assert_equals(createEvent(initializers).data, TEST_OBJECT);
+ assert_equals(createEvent(initializers).origin, 'wonderful');
+ assert_equals(createEvent(initializers).lastEventId, 'excellent');
+ assert_equals(createEvent(initializers).source, CHANNEL1.port1);
+ assert_equals(createEvent(initializers).ports[0], PORTS[0]);
+ assert_equals(createEvent(initializers).ports[1], PORTS[1]);
+ assert_equals(createEvent(initializers).ports[2], PORTS[2]);
+}, 'all initial values are specified');
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-loopback-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-loopback-worker.js
new file mode 100644
index 000000000000..13cae88d800d
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-loopback-worker.js
@@ -0,0 +1,36 @@
+importScripts('./extendable-message-event-utils.js');
+
+self.addEventListener('message', function(event) {
+ switch (event.data.type) {
+ case 'start':
+ self.registration.active.postMessage(
+ {type: '1st', client_id: event.source.id});
+ break;
+ case '1st':
+ // 1st loopback message via ServiceWorkerRegistration.active.
+ var results = {
+ trial: 1,
+ event: ExtendableMessageEventUtils.serialize(event)
+ };
+ var client_id = event.data.client_id;
+ event.source.postMessage({type: '2nd', client_id: client_id});
+ event.waitUntil(clients.get(client_id)
+ .then(function(client) {
+ client.postMessage({type: 'record', results: results});
+ }));
+ break;
+ case '2nd':
+ // 2nd loopback message via ExtendableMessageEvent.source.
+ var results = {
+ trial: 2,
+ event: ExtendableMessageEventUtils.serialize(event)
+ };
+ var client_id = event.data.client_id;
+ event.waitUntil(clients.get(client_id)
+ .then(function(client) {
+ client.postMessage({type: 'record', results: results});
+ client.postMessage({type: 'finish'});
+ }));
+ break;
+ }
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-ping-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-ping-worker.js
new file mode 100644
index 000000000000..d07b22959cc0
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-ping-worker.js
@@ -0,0 +1,23 @@
+importScripts('./extendable-message-event-utils.js');
+
+self.addEventListener('message', function(event) {
+ switch (event.data.type) {
+ case 'start':
+ // Send a ping message to another service worker.
+ self.registration.waiting.postMessage(
+ {type: 'ping', client_id: event.source.id});
+ break;
+ case 'pong':
+ var results = {
+ pingOrPong: 'pong',
+ event: ExtendableMessageEventUtils.serialize(event)
+ };
+ var client_id = event.data.client_id;
+ event.waitUntil(clients.get(client_id)
+ .then(function(client) {
+ client.postMessage({type: 'record', results: results});
+ client.postMessage({type: 'finish'});
+ }));
+ break;
+ }
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-pong-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-pong-worker.js
new file mode 100644
index 000000000000..5e9669e83c4b
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-pong-worker.js
@@ -0,0 +1,18 @@
+importScripts('./extendable-message-event-utils.js');
+
+self.addEventListener('message', function(event) {
+ switch (event.data.type) {
+ case 'ping':
+ var results = {
+ pingOrPong: 'ping',
+ event: ExtendableMessageEventUtils.serialize(event)
+ };
+ var client_id = event.data.client_id;
+ event.waitUntil(clients.get(client_id)
+ .then(function(client) {
+ client.postMessage({type: 'record', results: results});
+ event.source.postMessage({type: 'pong', client_id: client_id});
+ }));
+ break;
+ }
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-utils.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-utils.js
new file mode 100644
index 000000000000..d6a3b483f539
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-utils.js
@@ -0,0 +1,78 @@
+var ExtendableMessageEventUtils = {};
+
+// Create a representation of a given ExtendableMessageEvent that is suitable
+// for transmission via the `postMessage` API.
+ExtendableMessageEventUtils.serialize = function(event) {
+ var ports = event.ports.map(function(port) {
+ return { constructor: { name: port.constructor.name } };
+ });
+ return {
+ constructor: {
+ name: event.constructor.name
+ },
+ origin: event.origin,
+ lastEventId: event.lastEventId,
+ source: {
+ constructor: {
+ name: event.source.constructor.name
+ },
+ url: event.source.url,
+ frameType: event.source.frameType,
+ visibilityState: event.source.visibilityState,
+ focused: event.source.focused
+ },
+ ports: ports
+ };
+};
+
+// Compare the actual and expected values of an ExtendableMessageEvent that has
+// been transformed using the `serialize` function defined in this file.
+ExtendableMessageEventUtils.assert_equals = function(actual, expected) {
+ assert_equals(
+ actual.constructor.name, expected.constructor.name, 'event constructor'
+ );
+ assert_equals(actual.origin, expected.origin, 'event `origin` property');
+ assert_equals(
+ actual.lastEventId,
+ expected.lastEventId,
+ 'event `lastEventId` property'
+ );
+
+ assert_equals(
+ actual.source.constructor.name,
+ expected.source.constructor.name,
+ 'event `source` property constructor'
+ );
+ assert_equals(
+ actual.source.url, expected.source.url, 'event `source` property `url`'
+ );
+ assert_equals(
+ actual.source.frameType,
+ expected.source.frameType,
+ 'event `source` property `frameType`'
+ );
+ assert_equals(
+ actual.source.visibilityState,
+ expected.source.visibilityState,
+ 'event `source` property `visibilityState`'
+ );
+ assert_equals(
+ actual.source.focused,
+ expected.source.focused,
+ 'event `source` property `focused`'
+ );
+
+ assert_equals(
+ actual.ports.length,
+ expected.ports.length,
+ 'event `ports` property length'
+ );
+
+ for (var idx = 0; idx < expected.ports.length; ++idx) {
+ assert_equals(
+ actual.ports[idx].constructor.name,
+ expected.ports[idx].constructor.name,
+ 'MessagePort #' + idx + ' constructor'
+ );
+ }
+};
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-worker.js
new file mode 100644
index 000000000000..f5e7647e3e76
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/extendable-message-event-worker.js
@@ -0,0 +1,5 @@
+importScripts('./extendable-message-event-utils.js');
+
+self.addEventListener('message', function(event) {
+ event.source.postMessage(ExtendableMessageEventUtils.serialize(event));
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-loopback-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-loopback-worker.js
new file mode 100644
index 000000000000..083e9aa2a85d
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-loopback-worker.js
@@ -0,0 +1,15 @@
+self.addEventListener('message', function(event) {
+ if ('port' in event.data) {
+ var port = event.data.port;
+
+ var channel = new MessageChannel();
+ channel.port1.onmessage = function(event) {
+ if ('pong' in event.data)
+ port.postMessage(event.data.pong);
+ };
+ self.registration.active.postMessage({ping: channel.port2},
+ [channel.port2]);
+ } else if ('ping' in event.data) {
+ event.data.ping.postMessage({pong: 'OK'});
+ }
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-ping-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-ping-worker.js
new file mode 100644
index 000000000000..ebb1eccce2da
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-ping-worker.js
@@ -0,0 +1,15 @@
+self.addEventListener('message', function(event) {
+ if ('port' in event.data) {
+ var port = event.data.port;
+
+ var channel = new MessageChannel();
+ channel.port1.onmessage = function(event) {
+ if ('pong' in event.data)
+ port.postMessage(event.data.pong);
+ };
+
+ // Send a ping message to another service worker.
+ self.registration.waiting.postMessage({ping: channel.port2},
+ [channel.port2]);
+ }
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-pong-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-pong-worker.js
new file mode 100644
index 000000000000..4a0d90b6182f
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/postmessage-pong-worker.js
@@ -0,0 +1,4 @@
+self.addEventListener('message', function(event) {
+ if ('ping' in event.data)
+ event.data.ping.postMessage({pong: 'OK'});
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-newer-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-newer-worker.js
new file mode 100644
index 000000000000..44f3e2e8e9bd
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-newer-worker.js
@@ -0,0 +1,33 @@
+// TODO(nhiroki): stop using global states because service workers can be killed
+// at any point. Instead, we could post a message to the page on each event via
+// Client object (http://crbug.com/558244).
+var results = [];
+
+function stringify(worker) {
+ return worker ? worker.scriptURL : 'empty';
+}
+
+function record(event_name) {
+ results.push(event_name);
+ results.push(' installing: ' + stringify(self.registration.installing));
+ results.push(' waiting: ' + stringify(self.registration.waiting));
+ results.push(' active: ' + stringify(self.registration.active));
+}
+
+record('evaluate');
+
+self.registration.addEventListener('updatefound', function() {
+ record('updatefound');
+ var worker = self.registration.installing;
+ self.registration.installing.addEventListener('statechange', function() {
+ record('statechange(' + worker.state + ')');
+ });
+ });
+
+self.addEventListener('install', function(e) { record('install'); });
+
+self.addEventListener('activate', function(e) { record('activate'); });
+
+self.addEventListener('message', function(e) {
+ e.data.port.postMessage(results);
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-worker.js
new file mode 100644
index 000000000000..315f43759324
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/registration-attribute-worker.js
@@ -0,0 +1,139 @@
+importScripts('../../resources/test-helpers.sub.js');
+importScripts('../../resources/worker-testharness.js');
+
+// TODO(nhiroki): stop using global states because service workers can be killed
+// at any point. Instead, we could post a message to the page on each event via
+// Client object (http://crbug.com/558244).
+var events_seen = [];
+
+// TODO(nhiroki): Move these assertions to registration-attribute.html because
+// an assertion failure on the worker is not shown on the result page and
+// handled as timeout. See registration-attribute-newer-worker.js for example.
+
+assert_equals(
+ self.registration.scope,
+ normalizeURL('scope/registration-attribute'),
+ 'On worker script evaluation, registration attribute should be set');
+assert_equals(
+ self.registration.installing,
+ null,
+ 'On worker script evaluation, installing worker should be null');
+assert_equals(
+ self.registration.waiting,
+ null,
+ 'On worker script evaluation, waiting worker should be null');
+assert_equals(
+ self.registration.active,
+ null,
+ 'On worker script evaluation, active worker should be null');
+
+self.registration.addEventListener('updatefound', function() {
+ events_seen.push('updatefound');
+
+ assert_equals(
+ self.registration.scope,
+ normalizeURL('scope/registration-attribute'),
+ 'On updatefound event, registration attribute should be set');
+ assert_equals(
+ self.registration.installing.scriptURL,
+ normalizeURL('registration-attribute-worker.js'),
+ 'On updatefound event, installing worker should be set');
+ assert_equals(
+ self.registration.waiting,
+ null,
+ 'On updatefound event, waiting worker should be null');
+ assert_equals(
+ self.registration.active,
+ null,
+ 'On updatefound event, active worker should be null');
+
+ assert_equals(
+ self.registration.installing.state,
+ 'installing',
+ 'On updatefound event, worker should be in the installing state');
+
+ var worker = self.registration.installing;
+ self.registration.installing.addEventListener('statechange', function() {
+ events_seen.push('statechange(' + worker.state + ')');
+ });
+ });
+
+self.addEventListener('install', function(e) {
+ events_seen.push('install');
+
+ assert_equals(
+ self.registration.scope,
+ normalizeURL('scope/registration-attribute'),
+ 'On install event, registration attribute should be set');
+ assert_equals(
+ self.registration.installing.scriptURL,
+ normalizeURL('registration-attribute-worker.js'),
+ 'On install event, installing worker should be set');
+ assert_equals(
+ self.registration.waiting,
+ null,
+ 'On install event, waiting worker should be null');
+ assert_equals(
+ self.registration.active,
+ null,
+ 'On install event, active worker should be null');
+
+ assert_equals(
+ self.registration.installing.state,
+ 'installing',
+ 'On install event, worker should be in the installing state');
+ });
+
+self.addEventListener('activate', function(e) {
+ events_seen.push('activate');
+
+ assert_equals(
+ self.registration.scope,
+ normalizeURL('scope/registration-attribute'),
+ 'On activate event, registration attribute should be set');
+ assert_equals(
+ self.registration.installing,
+ null,
+ 'On activate event, installing worker should be null');
+ assert_equals(
+ self.registration.waiting,
+ null,
+ 'On activate event, waiting worker should be null');
+ assert_equals(
+ self.registration.active.scriptURL,
+ normalizeURL('registration-attribute-worker.js'),
+ 'On activate event, active worker should be set');
+
+ assert_equals(
+ self.registration.active.state,
+ 'activating',
+ 'On activate event, worker should be in the activating state');
+ });
+
+self.addEventListener('fetch', function(e) {
+ events_seen.push('fetch');
+
+ assert_equals(
+ self.registration.scope,
+ normalizeURL('scope/registration-attribute'),
+ 'On fetch event, registration attribute should be set');
+ assert_equals(
+ self.registration.installing,
+ null,
+ 'On fetch event, installing worker should be null');
+ assert_equals(
+ self.registration.waiting,
+ null,
+ 'On fetch event, waiting worker should be null');
+ assert_equals(
+ self.registration.active.scriptURL,
+ normalizeURL('registration-attribute-worker.js'),
+ 'On fetch event, active worker should be set');
+
+ assert_equals(
+ self.registration.active.state,
+ 'activated',
+ 'On fetch event, worker should be in the activated state');
+
+ e.respondWith(new Response(events_seen));
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-controlling-worker.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-controlling-worker.html
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-worker.js
new file mode 100644
index 000000000000..6da397dd1526
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/unregister-worker.js
@@ -0,0 +1,25 @@
+function matchQuery(query) {
+ return self.location.href.indexOf(query) != -1;
+}
+
+if (matchQuery('?evaluation'))
+ self.registration.unregister();
+
+self.addEventListener('install', function(e) {
+ if (matchQuery('?install')) {
+ // Don't do waitUntil(unregister()) as that would deadlock as specified.
+ self.registration.unregister();
+ }
+ });
+
+self.addEventListener('activate', function(e) {
+ if (matchQuery('?activate'))
+ e.waitUntil(self.registration.unregister());
+ });
+
+self.addEventListener('message', function(e) {
+ e.waitUntil(self.registration.unregister()
+ .then(function(result) {
+ e.data.port.postMessage({result: result});
+ }));
+ });
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/update-worker.js b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/update-worker.js
new file mode 100644
index 000000000000..8be8a1ffebe0
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/update-worker.js
@@ -0,0 +1,22 @@
+var events_seen = [];
+
+self.registration.addEventListener('updatefound', function() {
+ events_seen.push('updatefound');
+ });
+
+self.addEventListener('activate', function(e) {
+ events_seen.push('activate');
+ });
+
+self.addEventListener('fetch', function(e) {
+ events_seen.push('fetch');
+ e.respondWith(new Response(events_seen));
+ });
+
+self.addEventListener('message', function(e) {
+ events_seen.push('message');
+ self.registration.update();
+ });
+
+// update() during the script evaluation should be ignored.
+self.registration.update();
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html
new file mode 100644
index 000000000000..988f5466b9e1
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html
@@ -0,0 +1,31 @@
+
+ServiceWorkerGlobalScope: Error event error message
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html
new file mode 100644
index 000000000000..1a124d727687
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/unregister.https.html
@@ -0,0 +1,139 @@
+
+ServiceWorkerGlobalScope: unregister
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html
new file mode 100644
index 000000000000..a7dde2233972
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/update.https.html
@@ -0,0 +1,48 @@
+
+ServiceWorkerGlobalScope: update
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/WEB_FEATURES.yml b/test/fixtures/wpt/service-workers/service-worker/WEB_FEATURES.yml
new file mode 100644
index 000000000000..d729f2cd79b2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/WEB_FEATURES.yml
@@ -0,0 +1,4 @@
+rules:
+- registration-script-module.https.html: [js-modules-service-workers]
+- update-registration-with-type.https.html: [js-modules-service-workers]
+- "*": [service-workers]
diff --git a/test/fixtures/wpt/service-workers/service-worker/about-blank-replacement.https.html b/test/fixtures/wpt/service-workers/service-worker/about-blank-replacement.https.html
new file mode 100644
index 000000000000..b6efe3ec5620
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/about-blank-replacement.https.html
@@ -0,0 +1,181 @@
+
+Service Worker: about:blank replacement handling
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/activate-event-after-install-state-change.https.html b/test/fixtures/wpt/service-workers/service-worker/activate-event-after-install-state-change.https.html
new file mode 100644
index 000000000000..016a52c13c82
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/activate-event-after-install-state-change.https.html
@@ -0,0 +1,33 @@
+
+Service Worker: registration events
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/activation-after-registration.https.html b/test/fixtures/wpt/service-workers/service-worker/activation-after-registration.https.html
new file mode 100644
index 000000000000..29f97e3e3f4c
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/activation-after-registration.https.html
@@ -0,0 +1,28 @@
+
+Service Worker: Activation occurs after registration
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/activation.https.html b/test/fixtures/wpt/service-workers/service-worker/activation.https.html
new file mode 100644
index 000000000000..278454d3383e
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/activation.https.html
@@ -0,0 +1,168 @@
+
+
+
+service worker: activation
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/active.https.html b/test/fixtures/wpt/service-workers/service-worker/active.https.html
new file mode 100644
index 000000000000..350a34b802f7
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/active.https.html
@@ -0,0 +1,50 @@
+
+ServiceWorker: navigator.serviceWorker.active
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/add-routes.https.html b/test/fixtures/wpt/service-workers/service-worker/add-routes.https.html
new file mode 100644
index 000000000000..fbab7cdedfa3
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/add-routes.https.html
@@ -0,0 +1,27 @@
+
+
+Service Worker: addRoutes() executes in installing
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-affect-other-registration.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-affect-other-registration.https.html
new file mode 100644
index 000000000000..52555ac271b5
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-affect-other-registration.https.html
@@ -0,0 +1,136 @@
+
+
+Service Worker: claim() should affect other registration
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-fetch.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-fetch.https.html
new file mode 100644
index 000000000000..ae0082df06bf
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-fetch.https.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-not-using-registration.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-not-using-registration.https.html
new file mode 100644
index 000000000000..fd61d05ba4ea
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-not-using-registration.https.html
@@ -0,0 +1,131 @@
+
+Service Worker: claim client not using registration
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-shared-worker-fetch.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-shared-worker-fetch.https.html
new file mode 100644
index 000000000000..f5f44886baa2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-shared-worker-fetch.https.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html
new file mode 100644
index 000000000000..a02f8e9ca6f1
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-using-registration.https.html
@@ -0,0 +1,103 @@
+
+Service Worker: claim client using registration
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-with-redirect.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-with-redirect.https.html
new file mode 100644
index 000000000000..fd89cb9b00a1
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-with-redirect.https.html
@@ -0,0 +1,59 @@
+
+Service Worker: Claim() when update happens after redirect
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/claim-worker-fetch.https.html b/test/fixtures/wpt/service-workers/service-worker/claim-worker-fetch.https.html
new file mode 100644
index 000000000000..7cb26c742b97
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/claim-worker-fetch.https.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/client-id.https.html b/test/fixtures/wpt/service-workers/service-worker/client-id.https.html
new file mode 100644
index 000000000000..b93b34189999
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/client-id.https.html
@@ -0,0 +1,60 @@
+
+Service Worker: Client.id
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/client-navigate.https.html b/test/fixtures/wpt/service-workers/service-worker/client-navigate.https.html
new file mode 100644
index 000000000000..f40a08635cfd
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/client-navigate.https.html
@@ -0,0 +1,107 @@
+
+
+
+Service Worker: WindowClient.navigate
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html b/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html
new file mode 100644
index 000000000000..ba597d893d34
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html
@@ -0,0 +1,129 @@
+
+Service Worker: Client.url is Window creation URL tests
+
+
+
+
\ No newline at end of file
diff --git a/test/fixtures/wpt/service-workers/service-worker/client-url-of-blob-url-worker.https.html b/test/fixtures/wpt/service-workers/service-worker/client-url-of-blob-url-worker.https.html
new file mode 100644
index 000000000000..97a2fcf98f29
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/client-url-of-blob-url-worker.https.html
@@ -0,0 +1,29 @@
+
+Service Worker: client.url of a worker created from a blob URL
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-get-client-types.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-get-client-types.https.html
new file mode 100644
index 000000000000..63e3e51b3202
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-get-client-types.https.html
@@ -0,0 +1,108 @@
+
+Service Worker: Clients.get with window and worker clients
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-get-cross-origin.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-get-cross-origin.https.html
new file mode 100644
index 000000000000..1e4acfb286c6
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-get-cross-origin.https.html
@@ -0,0 +1,69 @@
+
+Service Worker: Clients.get across origins
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-get-resultingClientId.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-get-resultingClientId.https.html
new file mode 100644
index 000000000000..3419cf14b523
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-get-resultingClientId.https.html
@@ -0,0 +1,177 @@
+
+
+Test clients.get(resultingClientId)
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-get.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-get.https.html
new file mode 100644
index 000000000000..4cfbf595cade
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-get.https.html
@@ -0,0 +1,154 @@
+
+Service Worker: Clients.get
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https.html
new file mode 100644
index 000000000000..c29bac8b894a
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-blob-url-worker.https.html
@@ -0,0 +1,85 @@
+
+Service Worker: Clients.matchAll with a blob URL worker client
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-client-types.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
new file mode 100644
index 000000000000..54f182b6202c
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-client-types.https.html
@@ -0,0 +1,92 @@
+
+Service Worker: Clients.matchAll with various clientTypes
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-exact-controller.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-exact-controller.https.html
new file mode 100644
index 000000000000..a61c8af70196
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-exact-controller.https.html
@@ -0,0 +1,67 @@
+
+Service Worker: Clients.matchAll with exact controller
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-frozen.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-frozen.https.html
new file mode 100644
index 000000000000..479c28a60f2e
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-frozen.https.html
@@ -0,0 +1,64 @@
+
+Service Worker: Clients.matchAll
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html
new file mode 100644
index 000000000000..9f34e5709eb3
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-include-uncontrolled.https.html
@@ -0,0 +1,117 @@
+
+Service Worker: Clients.matchAll with includeUncontrolled
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-on-evaluation.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-on-evaluation.https.html
new file mode 100644
index 000000000000..8705f85b5684
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-on-evaluation.https.html
@@ -0,0 +1,24 @@
+
+Service Worker: Clients.matchAll on script evaluation
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall-order.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-order.https.html
new file mode 100644
index 000000000000..ec650f2264df
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall-order.https.html
@@ -0,0 +1,427 @@
+
+Service Worker: Clients.matchAll ordering
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/clients-matchall.https.html b/test/fixtures/wpt/service-workers/service-worker/clients-matchall.https.html
new file mode 100644
index 000000000000..ce44f1924d54
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/clients-matchall.https.html
@@ -0,0 +1,50 @@
+
+Service Worker: Clients.matchAll
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/controlled-dedicatedworker-postMessage.https.html b/test/fixtures/wpt/service-workers/service-worker/controlled-dedicatedworker-postMessage.https.html
new file mode 100644
index 000000000000..5ef91dd1b11c
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/controlled-dedicatedworker-postMessage.https.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/controlled-iframe-postMessage.https.html b/test/fixtures/wpt/service-workers/service-worker/controlled-iframe-postMessage.https.html
new file mode 100644
index 000000000000..c3f390a5a455
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/controlled-iframe-postMessage.https.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/controller-on-disconnect.https.html b/test/fixtures/wpt/service-workers/service-worker/controller-on-disconnect.https.html
new file mode 100644
index 000000000000..f23dfe71bac5
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/controller-on-disconnect.https.html
@@ -0,0 +1,40 @@
+
+Service Worker: Controller on load
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/controller-on-load.https.html b/test/fixtures/wpt/service-workers/service-worker/controller-on-load.https.html
new file mode 100644
index 000000000000..e4c5e5f81f81
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/controller-on-load.https.html
@@ -0,0 +1,46 @@
+
+Service Worker: Controller on load
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/controller-on-reload.https.html b/test/fixtures/wpt/service-workers/service-worker/controller-on-reload.https.html
new file mode 100644
index 000000000000..2e966d425788
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/controller-on-reload.https.html
@@ -0,0 +1,58 @@
+
+Service Worker: Controller on reload
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/controller-with-no-fetch-event-handler.https.html b/test/fixtures/wpt/service-workers/service-worker/controller-with-no-fetch-event-handler.https.html
new file mode 100644
index 000000000000..d947139c9e21
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/controller-with-no-fetch-event-handler.https.html
@@ -0,0 +1,56 @@
+
+
+Service Worker: controller without a fetch event handler
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/credentials.https.html b/test/fixtures/wpt/service-workers/service-worker/credentials.https.html
new file mode 100644
index 000000000000..0a90dc2897c2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/credentials.https.html
@@ -0,0 +1,100 @@
+
+
+Credentials for service worker scripts
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/css-sw-same-origin-substitution.https.html b/test/fixtures/wpt/service-workers/service-worker/css-sw-same-origin-substitution.https.html
new file mode 100644
index 000000000000..3a79c07f95c2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/css-sw-same-origin-substitution.https.html
@@ -0,0 +1,31 @@
+
+Service Worker: a same-origin response substituted for a cross-origin CSS request must not taint the stylesheet
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/data-iframe.html b/test/fixtures/wpt/service-workers/service-worker/data-iframe.html
new file mode 100644
index 000000000000..d767d574345b
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/data-iframe.html
@@ -0,0 +1,25 @@
+
+Service Workers in data iframes
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/data-transfer-files.https.html b/test/fixtures/wpt/service-workers/service-worker/data-transfer-files.https.html
new file mode 100644
index 000000000000..c503a28f965b
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/data-transfer-files.https.html
@@ -0,0 +1,41 @@
+
+
+Post a file in a navigation controlled by a service worker
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/dedicated-worker-service-worker-interception.https.html b/test/fixtures/wpt/service-workers/service-worker/dedicated-worker-service-worker-interception.https.html
new file mode 100644
index 000000000000..2144f4827121
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/dedicated-worker-service-worker-interception.https.html
@@ -0,0 +1,40 @@
+
+DedicatedWorker: ServiceWorker interception
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/detached-context.https.html b/test/fixtures/wpt/service-workers/service-worker/detached-context.https.html
new file mode 100644
index 000000000000..ce8e4cc8400c
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/detached-context.https.html
@@ -0,0 +1,124 @@
+
+
+Service WorkerRegistration from a removed iframe
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/detached-register-crash.https.html b/test/fixtures/wpt/service-workers/service-worker/detached-register-crash.https.html
new file mode 100644
index 000000000000..2785142a3cf4
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/detached-register-crash.https.html
@@ -0,0 +1,14 @@
+
+
+Assures navigator.serviceWorker.register() doesn't crash when rejecting being called in a detached frame
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/embed-and-object-are-not-intercepted.https.html b/test/fixtures/wpt/service-workers/service-worker/embed-and-object-are-not-intercepted.https.html
new file mode 100644
index 000000000000..581dbeca9772
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/embed-and-object-are-not-intercepted.https.html
@@ -0,0 +1,104 @@
+
+
+embed and object are not intercepted
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html b/test/fixtures/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html
new file mode 100644
index 000000000000..04e98266b4f1
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/extendable-event-async-waituntil.https.html
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/extendable-event-waituntil.https.html b/test/fixtures/wpt/service-workers/service-worker/extendable-event-waituntil.https.html
new file mode 100644
index 000000000000..33b4eac5c185
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/extendable-event-waituntil.https.html
@@ -0,0 +1,140 @@
+
+ExtendableEvent: waitUntil
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-audio-tainting.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-audio-tainting.https.html
new file mode 100644
index 000000000000..9821759bc7b3
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-audio-tainting.https.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-double-write.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-double-write.https.html
new file mode 100644
index 000000000000..dab2153baa6f
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-double-write.https.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+canvas tainting when written twice
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-image-cache.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-image-cache.https.html
new file mode 100644
index 000000000000..213238112257
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-image-cache.https.html
@@ -0,0 +1,16 @@
+
+
+Service Worker: canvas tainting of the fetched image using cached responses
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-image.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-image.https.html
new file mode 100644
index 000000000000..57dc7d98caa2
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-image.https.html
@@ -0,0 +1,16 @@
+
+
+Service Worker: canvas tainting of the fetched image
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html
new file mode 100644
index 000000000000..c37e8e562448
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html
@@ -0,0 +1,17 @@
+
+
+Service Worker: canvas tainting of the fetched video using cache responses
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video-with-range-request.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video-with-range-request.https.html
new file mode 100644
index 000000000000..0ee41e96f298
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video-with-range-request.https.html
@@ -0,0 +1,115 @@
+
+
+Canvas tainting due to video whose responses are fetched via a service worker including range requests
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html
new file mode 100644
index 000000000000..e8c23a2edd63
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html
@@ -0,0 +1,17 @@
+
+
+Service Worker: canvas tainting of the fetched video
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-cors-exposed-header-names.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-cors-exposed-header-names.https.html
new file mode 100644
index 000000000000..317b02175f2f
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-cors-exposed-header-names.https.html
@@ -0,0 +1,30 @@
+
+Service Worker: CORS-exposed header names should be transferred correctly
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-cors-xhr.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-cors-xhr.https.html
new file mode 100644
index 000000000000..f8ff445673bd
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-cors-xhr.https.html
@@ -0,0 +1,49 @@
+
+Service Worker: CORS XHR of fetch()
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-csp.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-csp.https.html
new file mode 100644
index 000000000000..9e7b242b69aa
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-csp.https.html
@@ -0,0 +1,138 @@
+
+Service Worker: CSP control of fetch()
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-error.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-error.https.html
new file mode 100644
index 000000000000..e9fdf5743120
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-error.https.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-event-add-async.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-event-add-async.https.html
new file mode 100644
index 000000000000..ac13e4f41675
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-event-add-async.https.html
@@ -0,0 +1,11 @@
+
+Service Worker: Fetch event added asynchronously doesn't throw
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-event-after-navigation-within-page.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-event-after-navigation-within-page.https.html
new file mode 100644
index 000000000000..4812d8a91551
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-event-after-navigation-within-page.https.html
@@ -0,0 +1,71 @@
+
+ServiceWorker: navigator.serviceWorker.waiting
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-event-async-respond-with.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-event-async-respond-with.https.html
new file mode 100644
index 000000000000..d9147f85494c
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-event-async-respond-with.https.html
@@ -0,0 +1,73 @@
+
+
+respondWith cannot be called asynchronously
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-event-handled.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-event-handled.https.html
new file mode 100644
index 000000000000..08b88ce3773d
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-event-handled.https.html
@@ -0,0 +1,86 @@
+
+
+Service Worker: FetchEvent.handled
+
+
+
+
+
diff --git a/test/fixtures/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html b/test/fixtures/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html
new file mode 100644
index 000000000000..3cf5922f396a
--- /dev/null
+++ b/test/fixtures/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html
@@ -0,0 +1,8 @@
+
+
+
Click this link.
+ Once you see "method = GET,..." in the page, go to another page, and then go back to the page using the Backward button.
+ You should see "method = GET, isHistoryNavigation = true".
+
Click this link.
+ Once you see "method = GET,..." in the page, go back to this page using the Backward button, and then go to the second page using the Forward button.
+ You should see "method = GET, isHistoryNavigation = true".
+