Bug 1316289 P2 Add wpt test to verify timers are restored after being loaded from bfcache. r=smaug
authorBen Kelly <ben@wanderview.com>
Thu, 10 Nov 2016 14:02:18 -0800
changeset 352151 4d1eb932fa31f2b27cdb2167011a907dceeef8a7
parent 352150 dbed090b39a49e46086507444c9cdf5984976d18
child 352152 4335472b7aa7eea431956bc2e07683951c7a51ef
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1316289
milestone52.0a1
Bug 1316289 P2 Add wpt test to verify timers are restored after being loaded from bfcache. r=smaug
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resources/post_name_on_load.html
testing/web-platform/tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -38612,16 +38612,22 @@
         ],
         "WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js": [
           {
             "path": "WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker.js",
             "timeout": "long",
             "url": "/WebCryptoAPI/generateKey/successes_RSASSA-PKCS1-v1_5.worker"
           }
         ],
+        "html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html": [
+          {
+            "path": "html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html",
+            "url": "/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html"
+          }
+        ],
         "html/browsers/the-window-object/window-open-noopener.html": [
           {
             "path": "html/browsers/the-window-object/window-open-noopener.html",
             "url": "/html/browsers/the-window-object/window-open-noopener.html"
           }
         ],
         "html/semantics/links/links-created-by-a-and-area-elements/htmlanchorelement_noopener.html": [
           {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resources/post_name_on_load.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<script>
+addEventListener('load', _ => {
+  let params = new URLSearchParams(window.location.search);
+  window.opener.postMessage(params.get('name'), '*');
+});
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/resume-timer-on-history-back.html
@@ -0,0 +1,145 @@
+<!doctype html>
+<title>Verify history.back() on a persisted page resumes timers</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="text/javascript">
+
+function make_post_back_url(name) {
+  return new URL('resources/post_name_on_load.html?name=' + name,
+                 window.location).href;
+}
+
+function wait_for_message(name) {
+  return new Promise(resolve => {
+    addEventListener('message', function onMsg(evt) {
+      if (evt.data !== name) {
+        return;
+      }
+      removeEventListener('message', onMsg);
+      resolve();
+    });
+  });
+}
+
+function with_window_by_name(name) {
+  let win = window.open(make_post_back_url(name));
+  return wait_for_message(name).then(_ => {
+    return win;
+  });
+}
+
+function with_nested_frame(win, url) {
+  return new Promise(resolve => {
+    let frame = win.document.createElement('iframe');
+    frame.addEventListener('load', function onLoad(evt) {
+      removeEventListener('load', onLoad);
+      resolve(frame);
+    });
+    frame.src = url;
+    win.document.body.appendChild(frame);
+  });
+}
+
+function delay(win, delay) {
+  return new Promise(resolve => {
+    win.setTimeout(_ => {
+      resolve(win);
+    }, delay);
+  });
+}
+
+function navigate_by_name(win, name) {
+  win.location = make_post_back_url(name);
+  return wait_for_message(name).then(_ => {
+    return win;
+  });
+}
+
+function go_back(win) {
+  return new Promise(resolve => {
+    win.onpagehide = e => resolve(win);
+    win.history.back();
+  });
+}
+
+let DELAY = 500;
+
+promise_test(t => {
+  // Create a new window so we can navigate it later.
+  return with_window_by_name('foo').then(win => {
+    // Schedule a timer within the new window.  Our intent is
+    // to navigate the window before the timer fires.
+    let delayFired = false;
+    let innerDelay = delay(win, DELAY);
+    innerDelay.then(_ => {
+      delayFired = true;
+    });
+
+    return navigate_by_name(win, 'bar').then(_ => {
+      // Since the window has navigated the timer should not
+      // fire.  We set a timer on our current test window
+      // to verify the other timer is not received.
+      assert_false(delayFired);
+      return delay(window, DELAY * 2);
+    }).then(_ => {
+      // The navigated window's timer should not have fired.
+      assert_false(delayFired);
+      // Now go back to the document that set the timer.
+      return go_back(win);
+    }).then(_ => {
+      // We wait for one of two conditions here.  For browsers
+      // with a bfcache the original suspended timer will fire.
+      // Alternatively, if the browser reloads the page the original
+      // message will be sent again.  Wait for either of these
+      // two events.
+      return Promise.race([wait_for_message('foo'), innerDelay]);
+    }).then(_ => {
+      win.close();
+    });
+  });
+}, 'history.back() handles top level page timer correctly');
+
+promise_test(t => {
+  let win;
+  // Create a new window so we can navigate it later.
+  return with_window_by_name('foo').then(w => {
+    win = w;
+
+    // Create a nested frame so we check if navigation and history.back()
+    // properly handle child window state.
+    return with_nested_frame(win, 'about:blank');
+
+  }).then(frame => {
+    // Schedule a timer within the nested frame contained by the new window.
+    // Our intent is to navigate the window before the timer fires.
+    let delayFired = false;
+    let innerDelay = delay(frame.contentWindow, DELAY);
+    innerDelay.then(_ => {
+      delayFired = true;
+    });
+
+    return navigate_by_name(win, 'bar').then(_ => {
+      // Since the window has navigated the timer should not
+      // fire.  We set a timer on our current test window
+      // to verify the other timer is not received.
+      assert_false(delayFired);
+      return delay(window, DELAY * 2);
+    }).then(_ => {
+      // The navigated window's timer should not have fired.
+      assert_false(delayFired);
+      // Now go back to the document containing the frame that set the timer.
+      return go_back(win);
+    }).then(_ => {
+      // We wait for one of two conditions here.  For browsers
+      // with a bfcache the original suspended timer will fire.
+      // Alternatively, if the browser reloads the page the original
+      // message will be sent again.  Wait for either of these
+      // two events.
+      return Promise.race([wait_for_message('foo'), innerDelay]);
+    }).then(_ => {
+      win.close();
+    });
+  });
+}, 'history.back() handles nested iframe timer correctly');
+
+</script>