[WPT] Eligibility: dedicated and shared workers (#31228)

When there are dedicated workers/shared workers,

Chrome: The page is not BFCached.
Firefox: The page is BFCached.
Safari: The page is BFCached for dedicated workers.
        Shared workers are not supported.

Bug: 1146955
Change-Id: Ia901715436e1a0c64c68ad5b537e99f685825489
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3220944
Reviewed-by: Ben Kelly <wanderview@chromium.org>
Reviewed-by: Fergal Daly <fergal@chromium.org>
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Cr-Commit-Position: refs/heads/main@{#968294}

Co-authored-by: Hiroshige Hayashizaki <hiroshige@chromium.org>
diff --git a/html/browsers/browsing-the-web/back-forward-cache/eligibility/dedicated-worker.html b/html/browsers/browsing-the-web/back-forward-cache/eligibility/dedicated-worker.html
new file mode 100644
index 0000000..4a9f551
--- /dev/null
+++ b/html/browsers/browsing-the-web/back-forward-cache/eligibility/dedicated-worker.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="../resources/helper.sub.js"></script>
+<script>
+// Check whether the page is BFCached when there are dedicated workers that are
+// already loaded.
+runBfcacheTest({
+  funcBeforeNavigation: async () => {
+    globalThis.worker = new Worker('../resources/echo-worker.js');
+    // Make sure the worker starts before navigation.
+    await WorkerHelper.pingWorker(globalThis.worker);
+  },
+  funcAfterAssertion: async (pageA) => {
+    // Confirm that the worker is still there.
+    assert_equals(
+      await pageA.execute_script(() => WorkerHelper.pingWorker(globalThis.worker)),
+      'PASS',
+      'Worker should still work after restored from BFCache');
+  }
+}, 'Eligibility: dedicated workers');
+</script>
diff --git a/html/browsers/browsing-the-web/back-forward-cache/eligibility/shared-worker.html b/html/browsers/browsing-the-web/back-forward-cache/eligibility/shared-worker.html
new file mode 100644
index 0000000..b142985
--- /dev/null
+++ b/html/browsers/browsing-the-web/back-forward-cache/eligibility/shared-worker.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="../resources/helper.sub.js"></script>
+<script>
+// Check whether the page is BFCached when there are shared workers that are
+// already loaded.
+runBfcacheTest({
+  funcBeforeNavigation: async () => {
+    globalThis.worker = new SharedWorker('../resources/echo-worker.js');
+    // Make sure the worker starts before navigation.
+    await WorkerHelper.pingWorker(globalThis.worker);
+  },
+  funcAfterAssertion: async (pageA) => {
+    // Confirm that the worker is still there.
+    assert_equals(
+      await pageA.execute_script(() => WorkerHelper.pingWorker(globalThis.worker)),
+      'PASS',
+      'SharedWorker should still work after restored from BFCache');
+  }
+}, 'Eligibility: shared workers');
+</script>
diff --git a/html/browsers/browsing-the-web/back-forward-cache/resources/echo-worker.js b/html/browsers/browsing-the-web/back-forward-cache/resources/echo-worker.js
new file mode 100644
index 0000000..3e3ecb5
--- /dev/null
+++ b/html/browsers/browsing-the-web/back-forward-cache/resources/echo-worker.js
@@ -0,0 +1,16 @@
+// On receiving a message from the parent Document, send back a message to the
+// parent Document. This is used to wait for worker initialization and test
+// that this worker is alive and working.
+
+// For dedicated workers.
+self.addEventListener('message', event => {
+  postMessage(event.data);
+});
+
+// For shared workers.
+onconnect = e => {
+  const port = e.ports[0];
+  port.onmessage = event => {
+    port.postMessage(event.data);
+  }
+};
diff --git a/html/browsers/browsing-the-web/back-forward-cache/resources/executor.html b/html/browsers/browsing-the-web/back-forward-cache/resources/executor.html
index 4741fb7..a93f68c 100644
--- a/html/browsers/browsing-the-web/back-forward-cache/resources/executor.html
+++ b/html/browsers/browsing-the-web/back-forward-cache/resources/executor.html
@@ -1,6 +1,7 @@
 <!DOCTYPE HTML>
 <script src="/common/dispatcher/dispatcher.js"></script>
 <script src="event-recorder.js" type="module"></script>
+<script src="worker-helper.js" type="module"></script>
 <script type="module">
 const params = new URLSearchParams(window.location.search);
 const uuid = params.get('uuid');
diff --git a/html/browsers/browsing-the-web/back-forward-cache/resources/worker-helper.js b/html/browsers/browsing-the-web/back-forward-cache/resources/worker-helper.js
new file mode 100644
index 0000000..d5f3a0c
--- /dev/null
+++ b/html/browsers/browsing-the-web/back-forward-cache/resources/worker-helper.js
@@ -0,0 +1,28 @@
+// Worker-related helper file to be used from executor.html.
+
+// The class `WorkerHelper` is exposed to `globalThis` because this should be
+// used via `eval()`.
+globalThis.WorkerHelper = class {
+  static pingWorker(worker) {
+    return new Promise((resolve, reject) => {
+      const message = 'message ' + Math.random();
+      const onmessage = e => {
+        if (e.data === message) {
+          resolve('PASS');
+        } else {
+          reject('pingWorker: expected ' + message + ' but got ' + e.data);
+        }
+      };
+      worker.onerror = reject;
+      if (worker instanceof Worker) {
+        worker.addEventListener('message', onmessage, {once: true});
+        worker.postMessage(message);
+      } else if (worker instanceof SharedWorker) {
+        worker.port.onmessage = onmessage;
+        worker.port.postMessage(message);
+      } else {
+        reject('Unexpected worker type');
+      }
+    });
+  }
+};