Service Worker: Add WPT to check if `client.url` is a blob URL

This CL adds a WPT to check if `client.url` of a blob URL worker is a
blob URL. The test succeeds when the PlzDedicatedWorker feature is
enabled.

Bug: 1017034
Change-Id: Ifd391512f2fa7213b7305d686ef3fb819ea5f620
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2526876
Commit-Queue: Asami Doi <asamidoi@chromium.org>
Reviewed-by: Makoto Shimazu <shimazu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828618}
diff --git a/service-workers/service-worker/client-url-of-blob-url-worker.https.html b/service-workers/service-worker/client-url-of-blob-url-worker.https.html
new file mode 100644
index 0000000..97a2fcf
--- /dev/null
+++ b/service-workers/service-worker/client-url-of-blob-url-worker.https.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Service Worker: client.url of a worker created from a blob URL</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+const SCRIPT = 'resources/client-url-of-blob-url-worker.js';
+const SCOPE = 'resources/client-url-of-blob-url-worker.html';
+
+promise_test(async (t) => {
+  const reg = await service_worker_unregister_and_register(t, SCRIPT, SCOPE);
+  t.add_cleanup(_ => reg.unregister());
+  await wait_for_state(t, reg.installing, 'activated');
+
+  const frame = await with_iframe(SCOPE);
+  t.add_cleanup(_ => frame.remove());
+  assert_not_equals(frame.contentWindow.navigator.serviceWorker.controller,
+                    null, 'frame should be controlled');
+
+  const response = await frame.contentWindow.createAndFetchFromBlobWorker();
+
+  assert_not_equals(response.result, 'one worker client should exist',
+                    'worker client should exist');
+  assert_equals(response.result, response.expected,
+                'client.url and worker location href should be the same');
+
+}, 'Client.url of a blob URL worker should be a blob URL.');
+</script>
diff --git a/service-workers/service-worker/resources/client-url-of-blob-url-worker.html b/service-workers/service-worker/resources/client-url-of-blob-url-worker.html
new file mode 100644
index 0000000..00f6ace
--- /dev/null
+++ b/service-workers/service-worker/resources/client-url-of-blob-url-worker.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<script>
+
+// Return a URL of a client when it's successful.
+function createAndFetchFromBlobWorker() {
+  const fetchURL = new URL('get-worker-client-url.txt', window.location).href;
+  const workerScript =
+    `self.onmessage = async (e) => {
+      const response = await fetch(e.data.url);
+      const text = await response.text();
+      self.postMessage({"result": text, "expected": self.location.href});
+    };`;
+  const blob = new Blob([workerScript], { type: 'text/javascript' });
+  const blobUrl = URL.createObjectURL(blob);
+
+  const worker = new Worker(blobUrl);
+  return new Promise((resolve, reject) => {
+    worker.onmessage = e => resolve(e.data);
+    worker.onerror = e => reject(e.message);
+    worker.postMessage({"url": fetchURL});
+  });
+}
+
+</script>
+</html>
diff --git a/service-workers/service-worker/resources/client-url-of-blob-url-worker.js b/service-workers/service-worker/resources/client-url-of-blob-url-worker.js
new file mode 100644
index 0000000..fd754f8
--- /dev/null
+++ b/service-workers/service-worker/resources/client-url-of-blob-url-worker.js
@@ -0,0 +1,10 @@
+addEventListener('fetch', e => {
+  if (e.request.url.includes('get-worker-client-url')) {
+    e.respondWith((async () => {
+      const clients = await self.clients.matchAll({type: 'worker'});
+      if (clients.length != 1)
+        return new Response('one worker client should exist');
+      return new Response(clients[0].url);
+    })());
+  }
+});