service worker: Add test for FetchEvent.handled
The spec PR is: https://github.com/w3c/ServiceWorker/pull/1496
diff --git a/service-workers/service-worker/fetch-event-handled.https.html b/service-workers/service-worker/fetch-event-handled.https.html
new file mode 100644
index 0000000..2d6f6c8
--- /dev/null
+++ b/service-workers/service-worker/fetch-event-handled.https.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<title>Service Worker: FetchEvent.handled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+let frame = null;
+let worker = null;
+const script = 'resources/fetch-event-handled-worker.js';
+const scope = 'resources/simple.html';
+
+// Wait for a message from the service worker and removes the message handler.
+function wait_for_message_from_worker() {
+ return new Promise((resolve) => {
+ const handler = (event) => {
+ frame.contentWindow.navigator.serviceWorker.removeEventListener(
+ 'message', handler);
+ resolve(event.data);
+ };
+ frame.contentWindow.navigator.serviceWorker.addEventListener(
+ 'message', handler);
+ });
+}
+
+// Global setup: this must be the first promise_test.
+promise_test(async (t) => {
+ const registration =
+ await service_worker_unregister_and_register(t, script, scope);
+ worker = registration.installing;
+ await wait_for_state(t, worker, 'activated');
+ frame = await with_iframe(scope);
+}, 'global setup');
+
+promise_test(async (t) => {
+ frame.contentWindow.fetch('dummy.txt?respondWith-not-called');
+ const message = await wait_for_message_from_worker();
+ assert_equals(message, 'RESOLVED');
+}, 'FetchEvent.handled should resolve when respondWith() is not called');
+
+promise_test(async (t) => {
+ frame.contentWindow.fetch(
+ 'dummy.txt?respondWith-not-called-and-event-canceled').catch((e) => {});
+ const message = await wait_for_message_from_worker();
+ assert_equals(message, 'REJECTED');
+}, 'FetchEvent.handled should reject when respondWith() is not called and the' +
+ ' event is canceled');
+
+promise_test(async (t) => {
+ frame.contentWindow.fetch(
+ 'dummy.txt?respondWith-called-and-promise-resolved');
+ const message = await wait_for_message_from_worker();
+ assert_equals(message, 'RESOLVED');
+}, 'FetchEvent.handled should resolve when the promise provided' +
+ ' to respondWith() is resolved');
+
+promise_test(async (t) => {
+ frame.contentWindow.fetch(
+ 'dummy.txt?respondWith-called-and-promise-resolved-to-invalid-response')
+ .catch((e) => {});
+ const message = await wait_for_message_from_worker();
+ assert_equals(message, 'REJECTED');
+}, 'FetchEvent.handled should reject when the promise provided' +
+ ' to respondWith() is resolved to an invalid response');
+
+promise_test(async (t) => {
+ frame.contentWindow.fetch(
+ 'dummy.txt?respondWith-called-and-promise-rejected').catch((e) => {});
+ const message = await wait_for_message_from_worker();
+ assert_equals(message, 'REJECTED');
+}, 'FetchEvent.handled should reject when the promise provided to' +
+ ' respondWith() is rejected');
+
+// Global cleanup: the final promise_test.
+promise_test(async (t) => {
+ if (frame)
+ frame.remove();
+ await service_worker_unregister(t, scope);
+}, 'global cleanup');
+</script>
+</html>
diff --git a/service-workers/service-worker/resources/fetch-event-handled-worker.js b/service-workers/service-worker/resources/fetch-event-handled-worker.js
new file mode 100644
index 0000000..4af58e2
--- /dev/null
+++ b/service-workers/service-worker/resources/fetch-event-handled-worker.js
@@ -0,0 +1,41 @@
+// This worker reports back the final state of FetchEvent.handled (RESOLVED or
+// REJECTED) to the test.
+
+// Send a message to the client with the client id.
+function send_message_to_client(message, clientId) {
+ clients.get(clientId).then((client) => {
+ client.postMessage(message);
+ });
+}
+
+self.addEventListener('fetch', function(event) {
+ const clientId = event.clientId;
+ try {
+ event.handled.then(() => {
+ send_message_to_client('RESOLVED', clientId);
+ }, () => {
+ send_message_to_client('REJECTED', clientId);
+ });
+ } catch (e) {
+ send_message_to_client('FAILED', clientId);
+ return;
+ }
+
+ const search = new URL(event.request.url).search;
+ switch (search) {
+ case '?respondWith-not-called':
+ break;
+ case '?respondWith-not-called-and-event-canceled':
+ event.preventDefault();
+ break;
+ case '?respondWith-called-and-promise-resolved':
+ event.respondWith(Promise.resolve(new Response('body')));
+ break;
+ case '?respondWith-called-and-promise-resolved-to-invalid-response':
+ event.respondWith(Promise.resolve('invalid response'));
+ break;
+ case '?respondWith-called-and-promise-rejected':
+ event.respondWith(Promise.reject(new Error('respondWith rejected')));
+ break;
+ }
+});