Bug 1460088 [wpt PR 10909] - Add tests for Request.isHistoryNavigation, a=testonly
authorYutaka Hirano <yhirano@google.com>
Wed, 06 Jun 2018 16:20:39 +0000
changeset 476413 28a4916ff9d5655c7b816da2a9d4c7746f664304
parent 476412 ea36fd45cbf269a7f6f1a83b343e1704b7bea302
child 476414 52f7b72f0aa70e42072b1d0969741138460d6e67
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1460088, 10909
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1460088 [wpt PR 10909] - Add tests for Request.isHistoryNavigation, a=testonly Automatic update from web-platform-testsFetch: tests for Request's isHistoryNavigation See whatwg/fetch#718, whatwg/html#3674, and discussion in w3c/ServiceWorker#1167. -- wpt-commits: 8f805ef0b6a3ddb06c0266cc56557d05e36f3a3d wpt-pr: 10909
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/fetch/api/request/request-reset-attributes.https.html
testing/web-platform/tests/fetch/api/request/request-structure.html
testing/web-platform/tests/interfaces/fetch.idl
testing/web-platform/tests/service-workers/cache-storage/serviceworker/cache-keys-attributes-for-service-worker.https.html
testing/web-platform/tests/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html
testing/web-platform/tests/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html
testing/web-platform/tests/service-workers/service-worker/fetch-event.https.html
testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -13832,16 +13832,28 @@
     ]
    ],
    "selection/dir-manual.html": [
     [
      "/selection/dir-manual.html",
      {}
     ]
    ],
+   "service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html": [
+    [
+     "/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html",
+     {}
+    ]
+   ],
+   "service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html": [
+    [
+     "/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/fetch-event-is-reload-iframe-navigation-manual.https.html": [
     [
      "/service-workers/service-worker/fetch-event-is-reload-iframe-navigation-manual.https.html",
      {}
     ]
    ],
    "service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html": [
     [
@@ -559166,21 +559178,21 @@
    "0b9786a3878a361ba8ec3291216d475bd5148541",
    "testharness"
   ],
   "fetch/api/request/request-keepalive.html": [
    "e6c2afd6cef41d358016d4d021b7c3e0e1185704",
    "testharness"
   ],
   "fetch/api/request/request-reset-attributes.https.html": [
-   "13515368aec52eaa0d0add9ec84955cb21fa5fd0",
+   "1ce3d577ce907b40b7bd23e66db91e77b5557c5a",
    "testharness"
   ],
   "fetch/api/request/request-structure.html": [
-   "450f8c91149638fe77bab2b65f345e6e24646c95",
+   "ac359c239375f34f7704a4594b458ef38f8a82cb",
    "testharness"
   ],
   "fetch/api/request/request-type-attribute-historical.html": [
    "68620f3ea16b7ae1a9f1efde1cd0bb47f1150b9f",
    "testharness"
   ],
   "fetch/api/request/resources/cache.py": [
    "fa831de695ef775b03a2b89a6cb691636b26027f",
@@ -580906,17 +580918,17 @@
    "6bb93df3e14e49931f54eead37a009649e035bd1",
    "support"
   ],
   "interfaces/feature-policy.idl": [
    "cba4a18b5a6b69c467067dc4a7ac7449f39be6a1",
    "support"
   ],
   "interfaces/fetch.idl": [
-   "b84c0af66b1bc37170021af455f85d5b5c0f01b2",
+   "dd0830114bbed129ffd6af96b76ad0b1ec6ee5b5",
    "support"
   ],
   "interfaces/filter-effects.idl": [
    "901c6d05e91de736ae1d627eca584e5c024786fa",
    "support"
   ],
   "interfaces/fullscreen.idl": [
    "fda57b55aabdc54d674851851451c6c69c514ed1",
@@ -601574,17 +601586,17 @@
    "294e76cb7b067b17fc9a0850bdab1d6e169cc25a",
    "testharness"
   ],
   "service-workers/cache-storage/serviceworker/cache-delete.https.html": [
    "6484fca817f556be3ffead18f162649c0fbfba30",
    "testharness"
   ],
   "service-workers/cache-storage/serviceworker/cache-keys-attributes-for-service-worker.https.html": [
-   "ce03773200d0dc76199b0ea5353bc44be4e86793",
+   "f1456bd2f56e8bd17bb9664960347c33decb927f",
    "testharness"
   ],
   "service-workers/cache-storage/serviceworker/cache-keys.https.html": [
    "c1f638bea1f897b086ce403b7a87fe4fd7b77b25",
    "testharness"
   ],
   "service-workers/cache-storage/serviceworker/cache-match.https.html": [
    "385a521cd183a11c3ab88c8c9e8e22e109691764",
@@ -601965,16 +601977,24 @@
   "service-workers/service-worker/fetch-event-after-navigation-within-page.https.html": [
    "3071523401bd9147ac4dab89361e07de99babc9c",
    "testharness"
   ],
   "service-workers/service-worker/fetch-event-async-respond-with.https.html": [
    "00c90429203c85ae8f10a6a6604cdf9619524f06",
    "testharness"
   ],
+  "service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html": [
+   "210ee953eb55e685452d8c3958c0d7f89db76a90",
+   "manual"
+  ],
+  "service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html": [
+   "89b9a19d0a4857af03b588987d6463d1766636d1",
+   "manual"
+  ],
   "service-workers/service-worker/fetch-event-is-reload-iframe-navigation-manual.https.html": [
    "9f69732ecf50608ea2695e2fb348d8dff6df6791",
    "manual"
   ],
   "service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html": [
    "109c975e4c31e5e880b3308967c05623a76aacb4",
    "manual"
   ],
@@ -602030,17 +602050,17 @@
    "6bdea01ca619a894d07364a0485f717b46afe585",
    "manual"
   ],
   "service-workers/service-worker/fetch-event-within-sw.https.html": [
    "0dfff8289762988423eb8fda40ef47884c243427",
    "testharness"
   ],
   "service-workers/service-worker/fetch-event.https.html": [
-   "cf2d0ef7275fd08bd0fbd2dde4c8c4ee4a2452d6",
+   "6f437b4bce24bf25343dcfd90018dfe934ff3d8f",
    "testharness"
   ],
   "service-workers/service-worker/fetch-frame-resource.https.html": [
    "fec588cba5090da6bb4914c6719b8e4076a57c82",
    "testharness"
   ],
   "service-workers/service-worker/fetch-header-visibility.https.html": [
    "054a581d2585cf34e4f0626870c2a093d53dc09b",
@@ -602794,17 +602814,17 @@
    "085ecdbb182a461d42f10444e82bfbb1de3728be",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-event-respond-with-stops-propagation-worker.js": [
    "900fd1c2080fbb386589f7d6ee52c49da9d4fcb8",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-event-test-worker.js": [
-   "2cd3893314f0296b4c8260f250cc87b570c7d692",
+   "ff4814b069e74b22f66d4258ecc97f8c477e9b3c",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-event-within-sw-worker.js": [
    "3389a6ce1435fe1f16488c58b3545169a1afcad3",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-header-visibility-iframe.html": [
    "f5975491b4c516cdfc62eaaba019ab546451d6e7",
--- a/testing/web-platform/tests/fetch/api/request/request-reset-attributes.https.html
+++ b/testing/web-platform/tests/fetch/api/request/request-reset-attributes.https.html
@@ -2,16 +2,20 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/get-host-info.sub.js"></script>
 <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
 <body>
 <script>
 const worker = 'resources/request-reset-attributes-worker.js';
 
+function wait(ms) {
+  return new Promise(resolve => step_timeout(resolve, ms));
+}
+
 promise_test(async (t) => {
     const scope = 'resources/hello.txt?name=isReloadNavigation';
     let frame;
     let reg;
 
     try {
       reg = await service_worker_unregister_and_register(t, worker, scope);
       await wait_for_state(t, reg.installing, 'activated');
@@ -30,16 +34,51 @@ promise_test(async (t) => {
       }
       if (reg) {
         await reg.unregister();
       }
     }
   }, 'Request.isReloadNavigation is reset with non-empty RequestInit');
 
 promise_test(async (t) => {
+    const scope = '../resources/blank.html?name=isHistoryNavigation';
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(scope);
+      assert_equals(frame.contentDocument.body.textContent,
+                    'original: false, stored: false');
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.onload = resolve;
+        frame.src = '../resources/blank.html?ignore';
+      });
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.onload = resolve;
+        frame.contentWindow.history.go(-1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'original: true, stored: true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+}, 'Request.IsHistoryNavigation should persist.');
+
+promise_test(async (t) => {
     const scope = 'resources/hello.txt?name=mode';
     let frame;
     let reg;
 
     try {
       reg = await service_worker_unregister_and_register(t, worker, scope);
       await wait_for_state(t, reg.installing, 'activated');
       frame = await with_iframe(scope);
@@ -49,10 +88,9 @@ promise_test(async (t) => {
       if (frame) {
         frame.remove();
       }
       if (reg) {
         await reg.unregister();
       }
     }
   }, 'Request.mode is reset with non-empty RequestInit when it\'s "navigate"');
-
 </script>
--- a/testing/web-platform/tests/fetch/api/request/request-structure.html
+++ b/testing/web-platform/tests/fetch/api/request/request-structure.html
@@ -25,16 +25,18 @@
                         "destination",
                         "referrer",
                         "referrerPolicy",
                         "mode",
                         "credentials",
                         "cache",
                         "redirect",
                         "integrity",
+                        "isReloadNavigation",
+                        "isHistoryNavigation",
                         //Request implements Body
                         "bodyUsed"
                        ];
 
       function IsreadOnly(request, attributeToCheck) {
         var defaultValue = undefined;
         var newValue = undefined;
         switch (attributeToCheck) {
@@ -99,16 +101,21 @@
             newValue = true;
             break;
 
           case "isReloadNavigation":
             defaultValue = false;
             newValue = true;
             break;
 
+          case "isHistoryNavigation":
+            defaultValue = false;
+            newValue = true;
+            break;
+
           default:
             return;
         }
 
         request[attributeToCheck] = newValue;
         if (defaultValue === undefined)
           assert_not_equals(request[attributeToCheck], newValue, "Attribute " + attributeToCheck + " is read only");
         else
--- a/testing/web-platform/tests/interfaces/fetch.idl
+++ b/testing/web-platform/tests/interfaces/fetch.idl
@@ -34,16 +34,17 @@ interface Request {
   readonly attribute ReferrerPolicy referrerPolicy;
   readonly attribute RequestMode mode;
   readonly attribute RequestCredentials credentials;
   readonly attribute RequestCache cache;
   readonly attribute RequestRedirect redirect;
   readonly attribute DOMString integrity;
   readonly attribute boolean keepalive;
   readonly attribute boolean isReloadNavigation;
+  readonly attribute boolean isHistoryNavigation;
   readonly attribute AbortSignal signal;
 
   [NewObject] Request clone();
 };
 Request includes Body;
 
 dictionary RequestInit {
   ByteString method;
--- a/testing/web-platform/tests/service-workers/cache-storage/serviceworker/cache-keys-attributes-for-service-worker.https.html
+++ b/testing/web-platform/tests/service-workers/cache-storage/serviceworker/cache-keys-attributes-for-service-worker.https.html
@@ -2,16 +2,20 @@
 <title>Cache.keys (checking request attributes that can be set only on service workers)</title>
 <link rel="help" href="https://w3c.github.io/ServiceWorker/#cache-keys">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../../service-worker/resources/test-helpers.sub.js"></script>
 <script>
 const worker = '../resources/cache-keys-attributes-for-service-worker.js';
 
+function wait(ms) {
+  return new Promise(resolve => step_timeout(resolve, ms));
+}
+
 promise_test(async (t) => {
     const scope = '../resources/blank.html?name=isReloadNavigation';
     let frame;
     let reg;
 
     try {
       reg = await service_worker_unregister_and_register(t, worker, scope);
       await wait_for_state(t, reg.installing, 'activated');
@@ -28,9 +32,44 @@ promise_test(async (t) => {
       if (frame) {
         frame.remove();
       }
       if (reg) {
         await reg.unregister();
       }
     }
 }, 'Request.IsReloadNavigation should persist.');
+
+promise_test(async (t) => {
+    const scope = '../resources/blank.html?name=isHistoryNavigation';
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(scope);
+      assert_equals(frame.contentDocument.body.textContent,
+                    'original: false, stored: false');
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.onload = resolve;
+        frame.src = '../resources/blank.html?ignore';
+      });
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.onload = resolve;
+        frame.contentWindow.history.go(-1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'original: true, stored: true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+}, 'Request.IsHistoryNavigation should persist.');
 </script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<body>
+<p>Click <a href="resources/install-worker.html?isHistoryNavigation&amp;script=fetch-event-test-worker.js">this link</a>.
+   Once you see &quot;method = GET,...&quot; in the page, go to another page, and then go back to the page using the Backward button.
+   You should see &quot;method = GET, isHistoryNavigation = true&quot;.
+</p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<body>
+<p>Click <a href="resources/install-worker.html?isHistoryNavigation&amp;script=fetch-event-test-worker.js">this link</a>.
+   Once you see &quot;method = GET,...&quot; 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 &quot;method = GET, isHistoryNavigation = true&quot;.
+</p>
+</body>
+</html>
--- a/testing/web-platform/tests/service-workers/service-worker/fetch-event.https.html
+++ b/testing/web-platform/tests/service-workers/service-worker/fetch-event.https.html
@@ -765,10 +765,316 @@ promise_test(async (t) => {
         frame.remove();
       }
       if (reg) {
         await reg.unregister();
       }
     }
   }, 'FetchEvent#request.isReloadNavigation is true (with history traversal)');
 
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(scope);
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = anotherUrl;
+      });
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isHistoryNavigation is true (with history.go(-1))');
+
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(anotherUrl);
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = scope;
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-1);
+      });
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isHistoryNavigation is true (with history.go(1))');
+
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(anotherUrl);
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = scope;
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-1);
+      });
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = true');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(0);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isHistoryNavigation is false (with history.go(0))');
+
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(anotherUrl);
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = scope;
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-1);
+      });
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = true');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.location.reload();
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isHistoryNavigation is false (with location.reload)');
+
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    const oneAnotherUrl = new Request('resources/simple.html?').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(scope);
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = anotherUrl;
+      });
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = oneAnotherUrl;
+      });
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-2);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isHistoryNavigation is true (with history.go(-2))');
+
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    const oneAnotherUrl = new Request('resources/simple.html?').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(anotherUrl);
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = oneAnotherUrl;
+      });
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = scope;
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-2);
+      });
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(2);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isHistoryNavigation is true (with history.go(2))');
+
+promise_test(async (t) => {
+    const scope = 'resources/simple.html?isHistoryNavigation';
+    const anotherUrl = new Request('resources/simple.html').url;
+    let frame;
+    let reg;
+
+    try {
+      reg = await service_worker_unregister_and_register(t, worker, scope);
+      await wait_for_state(t, reg.installing, 'activated');
+      frame = await with_iframe(scope);
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = GET, isHistoryNavigation = false');
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        const form = frame.contentDocument.createElement('form');
+        form.method = 'POST';
+        form.name = 'form';
+        form.action = new Request(scope).url;
+        frame.contentDocument.body.appendChild(form);
+        form.submit();
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = POST, isHistoryNavigation = false');
+      // Use step_timeout(0) to ensure the history entry is created for Blink
+      // and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.src = anotherUrl;
+      });
+      assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
+      await wait(0);
+      await new Promise((resolve) => {
+        frame.addEventListener('load', resolve);
+        frame.contentWindow.history.go(-1);
+      });
+      assert_equals(frame.contentDocument.body.textContent,
+                    'method = POST, isHistoryNavigation = true');
+    } finally {
+      if (frame) {
+        frame.remove();
+      }
+      if (reg) {
+        await reg.unregister();
+      }
+    }
+  }, 'FetchEvent#request.isReloadNavigation is true (POST + history.go(-1))');
+
 </script>
 </body>
--- a/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/fetch-event-test-worker.js
@@ -132,16 +132,24 @@ function handleKeepalive(event) {
 function handleIsReloadNavigation(event) {
   const request = event.request;
   const body =
     `method = ${request.method}, ` +
     `isReloadNavigation = ${request.isReloadNavigation}`;
   event.respondWith(new Response(body));
 }
 
+function handleIsHistoryNavigation(event) {
+  const request = event.request;
+  const body =
+    `method = ${request.method}, ` +
+    `isHistoryNavigation = ${request.isHistoryNavigation}`;
+  event.respondWith(new Response(body));
+}
+
 self.addEventListener('fetch', function(event) {
     var url = event.request.url;
     var handlers = [
       { pattern: '?headers', fn: handleHeaders },
       { pattern: '?string', fn: handleString },
       { pattern: '?blob', fn: handleBlob },
       { pattern: '?referrerFull', fn: handleReferrerFull },
       { pattern: '?referrerPolicy', fn: handleReferrerPolicy },
@@ -155,16 +163,17 @@ self.addEventListener('fetch', function(
       { pattern: '?used-check', fn: handleUsedCheck },
       { pattern: '?fragment-check', fn: handleFragmentCheck },
       { pattern: '?cache', fn: handleCache },
       { pattern: '?eventsource', fn: handleEventSource },
       { pattern: '?integrity', fn: handleIntegrity },
       { pattern: '?request-body', fn: handleRequestBody },
       { pattern: '?keepalive', fn: handleKeepalive },
       { pattern: '?isReloadNavigation', fn: handleIsReloadNavigation },
+      { pattern: '?isHistoryNavigation', fn: handleIsHistoryNavigation },
     ];
 
     var handler = null;
     for (var i = 0; i < handlers.length; ++i) {
       if (url.indexOf(handlers[i].pattern) != -1) {
         handler = handlers[i];
         break;
       }