Bug 1109875 - Fix sessionstore tests to properly wait for data from closed tabs r=billm
authorTim Taubert <ttaubert@mozilla.com>
Tue, 28 Apr 2015 16:30:47 +0200
changeset 242350 40f06e925ae25451402f2fb770ed2e6c10dc8ce9
parent 242349 e2ba32edadf3726f3bc42199c49ff55464b8c3cc
child 242351 5d06e3e4609a0cc3c84eadfc26f5a9e060ab919d
push id12729
push userttaubert@mozilla.com
push dateTue, 05 May 2015 12:28:17 +0000
treeherderfx-team@5d06e3e4609a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1109875
milestone40.0a1
Bug 1109875 - Fix sessionstore tests to properly wait for data from closed tabs r=billm
browser/components/sessionstore/test/browser_350525.js
browser/components/sessionstore/test/browser_367052.js
browser/components/sessionstore/test/browser_394759_perwindowpb.js
browser/components/sessionstore/test/browser_454908.js
browser/components/sessionstore/test/browser_456342.js
browser/components/sessionstore/test/browser_579879.js
browser/components/sessionstore/test/browser_581937.js
browser/components/sessionstore/test/browser_628270.js
browser/components/sessionstore/test/browser_911547.js
browser/components/sessionstore/test/browser_aboutPrivateBrowsing.js
browser/components/sessionstore/test/browser_broadcast.js
browser/components/sessionstore/test/browser_cleaner.js
browser/components/sessionstore/test/browser_dying_cache.js
browser/components/sessionstore/test/browser_formdata.js
browser/components/sessionstore/test/browser_frame_history.js
browser/components/sessionstore/test/browser_pageStyle.js
browser/components/sessionstore/test/browser_sessionHistory.js
browser/components/sessionstore/test/browser_sessionStorage.js
browser/components/sessionstore/test/browser_telemetry.js
browser/components/sessionstore/test/content.js
browser/components/sessionstore/test/head.js
--- a/browser/components/sessionstore/test/browser_350525.js
+++ b/browser/components/sessionstore/test/browser_350525.js
@@ -1,21 +1,21 @@
-function test() {
+"use strict";
+
+add_task(function* () {
   /** Test for Bug 350525 **/
 
   function test(aLambda) {
     try {
       return aLambda() || true;
     }
     catch (ex) { }
     return false;
   }
 
-  waitForExplicitFinish();
-
   ////////////////////////////
   // setWindowValue, et al. //
   ////////////////////////////
   let key = "Unique name: " + Date.now();
   let value = "Unique value: " + Math.random();
 
   // test adding
   ok(test(function() ss.setWindowValue(window, key, value)), "set a window value");
@@ -51,49 +51,46 @@ function test() {
 
   // value should not exist post-delete
   is(ss.getTabValue(tab, key), "", "tab value was deleted");
 
   // test deleting a non-existent value
   ok(test(function() ss.deleteTabValue(tab, key)), "delete non-existent tab value");
 
   // clean up
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   /////////////////////////////////////
   // getClosedTabCount, undoCloseTab //
   /////////////////////////////////////
 
   // get closed tab count
   let count = ss.getClosedTabCount(window);
   let max_tabs_undo = gPrefService.getIntPref("browser.sessionstore.max_tabs_undo");
   ok(0 <= count && count <= max_tabs_undo,
      "getClosedTabCount returns zero or at most max_tabs_undo");
 
   // create a new tab
   let testURL = "about:";
   tab = gBrowser.addTab(testURL);
-  promiseBrowserLoaded(tab.linkedBrowser).then(() => {
-    // make sure that the next closed tab will increase getClosedTabCount
-    gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
+  yield promiseBrowserLoaded(tab.linkedBrowser);
 
-    // remove tab
-    gBrowser.removeTab(tab);
+  // make sure that the next closed tab will increase getClosedTabCount
+  gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
+  registerCleanupFunction(() => gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"));
 
-    // getClosedTabCount
-    var newcount = ss.getClosedTabCount(window);
-    ok(newcount > count, "after closing a tab, getClosedTabCount has been incremented");
+  // remove tab
+  yield promiseRemoveTab(tab);
 
-    // undoCloseTab
-    tab = test(function() ss.undoCloseTab(window, 0));
-    ok(tab, "undoCloseTab doesn't throw")
-
-    promiseTabRestored(tab).then(() => {
-      is(tab.linkedBrowser.currentURI.spec, testURL, "correct tab was reopened");
+  // getClosedTabCount
+  let newcount = ss.getClosedTabCount(window);
+  ok(newcount > count, "after closing a tab, getClosedTabCount has been incremented");
 
-      // clean up
-      if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
-        gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
-      gBrowser.removeTab(tab);
-      finish();
-    });
-  });
-}
+  // undoCloseTab
+  tab = test(function() ss.undoCloseTab(window, 0));
+  ok(tab, "undoCloseTab doesn't throw")
+
+  yield promiseTabRestored(tab);
+  is(tab.linkedBrowser.currentURI.spec, testURL, "correct tab was reopened");
+
+  // clean up
+  gBrowser.removeTab(tab);
+});
--- a/browser/components/sessionstore/test/browser_367052.js
+++ b/browser/components/sessionstore/test/browser_367052.js
@@ -1,37 +1,41 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-function test() {
-  /** Test for Bug 367052 **/
+"use strict";
 
-  waitForExplicitFinish();
-
+add_task(function* () {
   // make sure that the next closed tab will increase getClosedTabCount
   let max_tabs_undo = gPrefService.getIntPref("browser.sessionstore.max_tabs_undo");
   gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
-  let closedTabCount = ss.getClosedTabCount(window);
+  registerCleanupFunction(() => gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo"));
+
+  // Empty the list of closed tabs.
+  while (ss.getClosedTabCount(window)) {
+    ss.forgetClosedTab(window, 0);
+  }
 
   // restore a blank tab
   let tab = gBrowser.addTab("about:");
-  promiseBrowserLoaded(tab.linkedBrowser).then(() => {
-    let history = tab.linkedBrowser.webNavigation.sessionHistory;
-    ok(history.count >= 1, "the new tab does have at least one history entry");
+  yield promiseBrowserLoaded(tab.linkedBrowser);
 
-    promiseTabState(tab, {entries: []}).then(() => {
-      // We may have a different sessionHistory object if the tab
-      // switched from non-remote to remote.
-      history = tab.linkedBrowser.webNavigation.sessionHistory;
-      ok(history.count == 0, "the tab was restored without any history whatsoever");
+  let count = yield promiseSHistoryCount(tab.linkedBrowser);
+  ok(count >= 1, "the new tab does have at least one history entry");
+
+  yield promiseTabState(tab, {entries: []});
 
-      gBrowser.removeTab(tab);
-      ok(ss.getClosedTabCount(window) == closedTabCount,
-         "The closed blank tab wasn't added to Recently Closed Tabs");
+  // We may have a different sessionHistory object if the tab
+  // switched from non-remote to remote.
+  count = yield promiseSHistoryCount(tab.linkedBrowser);
+  is(count, 0, "the tab was restored without any history whatsoever");
 
-      // clean up
-      if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
-        gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
-      finish();
-    });
+  yield promiseRemoveTab(tab);
+  is(ss.getClosedTabCount(window), 0,
+     "The closed blank tab wasn't added to Recently Closed Tabs");
+});
+
+function promiseSHistoryCount(browser) {
+  return ContentTask.spawn(browser, null, function* () {
+    return docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory.count;
   });
 }
--- a/browser/components/sessionstore/test/browser_394759_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_394759_perwindowpb.js
@@ -1,25 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/** Private Browsing Test for Bug 394759 **/
-
-let closedWindowCount = 0;
-// Prevent VM timers issues, cache now and increment it manually.
-let now = Date.now();
+"use strict";
 
 const TESTS = [
   { url: "about:config",
     key: "bug 394759 Non-PB",
-    value: "uniq" + (++now) },
+    value: "uniq" + r() },
   { url: "about:mozilla",
     key: "bug 394759 PB",
-    value: "uniq" + (++now) },
+    value: "uniq" + r() },
 ];
 
 function promiseTestOpenCloseWindow(aIsPrivate, aTest) {
   return Task.spawn(function*() {
     let win = yield promiseNewWindowLoaded({ "private": aIsPrivate });
     win.gBrowser.selectedBrowser.loadURI(aTest.url);
     yield promiseBrowserLoaded(win.gBrowser.selectedBrowser);
     yield Promise.resolve();
@@ -28,63 +24,21 @@ function promiseTestOpenCloseWindow(aIsP
     // Close.
     yield promiseWindowClosed(win);
   });
 }
 
 function promiseTestOnWindow(aIsPrivate, aValue) {
   return Task.spawn(function*() {
     let win = yield promiseNewWindowLoaded({ "private": aIsPrivate });
-    yield promiseCheckClosedWindows(aIsPrivate, aValue);
-    registerCleanupFunction(() => promiseWindowClosed(win));
-  });
-}
-
-function promiseCheckClosedWindows(aIsPrivate, aValue) {
-  return Task.spawn(function*() {
     let data = JSON.parse(ss.getClosedWindowData())[0];
     is(ss.getClosedWindowCount(), 1, "Check that the closed window count hasn't changed");
     ok(JSON.stringify(data).indexOf(aValue) > -1,
        "Check the closed window data was stored correctly");
-  });
-}
-
-function promiseBlankState() {
-  return Task.spawn(function*() {
-    // Set interval to a large time so state won't be written while we setup
-    // environment.
-    Services.prefs.setIntPref("browser.sessionstore.interval", 100000);
-    registerCleanupFunction(() =>  Services.prefs.clearUserPref("browser.sessionstore.interval"));
-
-    // Set up the browser in a blank state. Popup windows in previous tests
-    // result in different states on different platforms.
-    let blankState = JSON.stringify({
-      windows: [{
-        tabs: [{ entries: [{ url: "about:blank" }] }],
-        _closedTabs: []
-      }],
-      _closedWindows: []
-    });
-
-    ss.setBrowserState(blankState);
-
-    // Wait for the sessionstore.js file to be written before going on.
-    // Note: we don't wait for the complete event, since if asyncCopy fails we
-    // would timeout.
-
-    yield forceSaveState();
-    closedWindowCount = ss.getClosedWindowCount();
-    is(closedWindowCount, 0, "Correctly set window count");
-
-    // Remove the sessionstore.js file before setting the interval to 0
-    yield SessionFile.wipe();
-
-    // Make sure that sessionstore.js can be forced to be created by setting
-    // the interval pref to 0.
-    yield forceSaveState();
+    registerCleanupFunction(() => promiseWindowClosed(win));
   });
 }
 
 add_task(function* init() {
   forgetClosedWindows();
   while (ss.getClosedTabCount(window) > 0) {
     ss.forgetClosedTab(window, 0);
   }
--- a/browser/components/sessionstore/test/browser_454908.js
+++ b/browser/components/sessionstore/test/browser_454908.js
@@ -23,17 +23,17 @@ add_task(function* test_dont_save_passwo
   yield promiseBrowserLoaded(browser);
 
   // Fill in some values.
   let usernameValue = "User " + Math.random();
   yield setInputValue(browser, {id: "username", value: usernameValue});
   yield setInputValue(browser, {id: "passwd", value: PASS});
 
   // Close and restore the tab.
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   tab = ss.undoCloseTab(window, 0);
   browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
 
   // Check that password fields aren't saved/restored.
   let username = yield getInputValue(browser, {id: "username"});
   is(username, usernameValue, "username was saved/restored");
   let passwd = yield getInputValue(browser, {id: "passwd"});
@@ -41,12 +41,11 @@ add_task(function* test_dont_save_passwo
 
   // Write to disk and read our file.
   yield forceSaveState();
   yield promiseForEachSessionRestoreFile((state, key) =>
     // Ensure that we have not saved our password.
     ok(!state.includes(PASS), "password has not been written to file " + key)
   );
 
-
   // Cleanup.
   gBrowser.removeTab(tab);
 });
--- a/browser/components/sessionstore/test/browser_456342.js
+++ b/browser/components/sessionstore/test/browser_456342.js
@@ -14,17 +14,17 @@ add_task(function test_restore_nonstanda
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Fill in form values.
   let expectedValue = Math.random();
   yield setFormElementValues(browser, {value: expectedValue});
 
   // Remove tab and check collected form data.
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   let undoItems = JSON.parse(ss.getClosedTabData(window));
   let savedFormData = undoItems[0].state.formdata;
 
   let countGood = 0, countBad = 0;
   for (let id of Object.keys(savedFormData.id)) {
     if (savedFormData.id[id] == expectedValue) {
       countGood++;
     } else {
--- a/browser/components/sessionstore/test/browser_579879.js
+++ b/browser/components/sessionstore/test/browser_579879.js
@@ -1,21 +1,20 @@
-function test() {
-  waitForExplicitFinish();
+"use strict";
 
-  var tab1 = gBrowser.addTab("data:text/plain;charset=utf-8,foo");
+add_task(function* () {
+  let tab1 = gBrowser.addTab("data:text/plain;charset=utf-8,foo");
   gBrowser.pinTab(tab1);
 
-  promiseBrowserLoaded(tab1.linkedBrowser).then(() => {
-    var tab2 = gBrowser.addTab();
-    gBrowser.pinTab(tab2);
+  yield promiseBrowserLoaded(tab1.linkedBrowser);
+  let tab2 = gBrowser.addTab();
+  gBrowser.pinTab(tab2);
+
+  is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 is at the first position");
+  yield promiseRemoveTab(tab1);
 
-    is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 is at the first position");
-    gBrowser.removeTab(tab1);
-    tab1 = undoCloseTab();
-    ok(tab1.pinned, "pinned tab 1 has been restored as a pinned tab");
-    is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 has been restored to the first position");
+  tab1 = undoCloseTab();
+  ok(tab1.pinned, "pinned tab 1 has been restored as a pinned tab");
+  is(Array.indexOf(gBrowser.tabs, tab1), 0, "pinned tab 1 has been restored to the first position");
 
-    gBrowser.removeTab(tab1);
-    gBrowser.removeTab(tab2);
-    finish();
-  });
-}
+  gBrowser.removeTab(tab1);
+  gBrowser.removeTab(tab2);
+});
--- a/browser/components/sessionstore/test/browser_581937.js
+++ b/browser/components/sessionstore/test/browser_581937.js
@@ -1,36 +1,19 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
 // Tests that an about:blank tab with no history will not be saved into
 // session store and thus, it will not show up in Recently Closed Tabs.
 
-let tab;
-function test() {
-  waitForExplicitFinish();
-
-  gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", 0);
-  gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
+"use strict";
 
-  is(ss.getClosedTabCount(window), 0, "should be no closed tabs");
-
-  gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
-
-  tab = gBrowser.addTab();
-}
+add_task(function* () {
+  let tab = gBrowser.addTab("about:blank");
+  yield promiseBrowserLoaded(tab.linkedBrowser);
 
-function onTabOpen(aEvent) {
-  gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
-
-  // Let other listeners react to the TabOpen event before removing the tab.
-  executeSoon(function() {
-    is(gBrowser.browsers[1].currentURI.spec, "about:blank",
-       "we will be removing an about:blank tab");
+  is(tab.linkedBrowser.currentURI.spec, "about:blank",
+     "we will be removing an about:blank tab");
 
-    gBrowser.removeTab(tab);
-
-    is(ss.getClosedTabCount(window), 0, "should still be no closed tabs");
+  let r = `rand-${Math.random()}`;
+  ss.setTabValue(tab, "foobar", r);
 
-    executeSoon(finish);
-  });
-}
+  yield promiseRemoveTab(tab);
+  let closedTabData = ss.getClosedTabData(window);
+  ok(!closedTabData.contains(r), "tab not stored in _closedTabs");
+});
--- a/browser/components/sessionstore/test/browser_628270.js
+++ b/browser/components/sessionstore/test/browser_628270.js
@@ -25,25 +25,26 @@ function test() {
   whenTabIsLoaded(tab, function () {
     // hide the newly created tab
     assertNumberOfVisibleTabs(2, "there are two visible tabs");
     gBrowser.showOnlyTheseTabs([gBrowser.tabs[0]]);
     assertNumberOfVisibleTabs(1, "there is one visible tab");
     ok(tab.hidden, "newly created tab is now hidden");
 
     // close and restore hidden tab
-    gBrowser.removeTab(tab);
-    tab = ss.undoCloseTab(window, 0);
+    promiseRemoveTab(tab).then(() => {
+      tab = ss.undoCloseTab(window, 0);
 
-    // check that everything was restored correctly, clean up and finish
-    whenTabIsLoaded(tab, function () {
-      is(tab.linkedBrowser.currentURI.spec, "about:mozilla", "restored tab has correct url");
+      // check that everything was restored correctly, clean up and finish
+      whenTabIsLoaded(tab, function () {
+        is(tab.linkedBrowser.currentURI.spec, "about:mozilla", "restored tab has correct url");
 
-      gBrowser.removeTab(tab);
-      finish();
+        gBrowser.removeTab(tab);
+        finish();
+      });
     });
   });
 }
 
 function whenTabIsLoaded(tab, callback) {
   tab.linkedBrowser.addEventListener("load", function onLoad() {
     tab.linkedBrowser.removeEventListener("load", onLoad, true);
     callback();
--- a/browser/components/sessionstore/test/browser_911547.js
+++ b/browser/components/sessionstore/test/browser_911547.js
@@ -24,17 +24,17 @@ add_task(function* test() {
   // origin document) and navigate to the data URI in the link.
   browser.contentDocument.getElementById("test_data_link").click();
   yield promiseBrowserLoaded(browser);
 
   is(browser.contentDocument.getElementById("test_id2").value, "ok",
      "CSP should block the script loaded by the clicked data URI");
 
   // close the tab
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   // open new tab and recover the state
   tab = ss.undoCloseTab(window, 0);
   yield promiseTabRestored(tab);
   browser = tab.linkedBrowser;
 
   is(browser.contentDocument.getElementById("test_id2").value, "ok",
      "CSP should block the script loaded by the clicked data URI after restore");
--- a/browser/components/sessionstore/test/browser_aboutPrivateBrowsing.js
+++ b/browser/components/sessionstore/test/browser_aboutPrivateBrowsing.js
@@ -1,25 +1,21 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
 
 // Tests that an about:privatebrowsing tab with no history will not
 // be saved into session store and thus, it will not show up in
 // Recently Closed Tabs.
 
 add_task(function* () {
-  while (ss.getClosedTabCount(window)) {
-    ss.forgetClosedTab(window, 0);
-  }
-
-  is(ss.getClosedTabCount(window), 0, "should be no closed tabs");
-
   let tab = gBrowser.addTab("about:privatebrowsing");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   is(gBrowser.browsers[1].currentURI.spec, "about:privatebrowsing",
      "we will be removing an about:privatebrowsing tab");
 
-  gBrowser.removeTab(tab);
-  is(ss.getClosedTabCount(window), 0, "should still be no closed tabs");
+  let r = `rand-${Math.random()}`;
+  ss.setTabValue(tab, "foobar", r);
+
+  yield promiseRemoveTab(tab);
+  let closedTabData = ss.getClosedTabData(window);
+  ok(!closedTabData.contains(r), "tab not stored in _closedTabs");
 });
--- a/browser/components/sessionstore/test/browser_broadcast.js
+++ b/browser/components/sessionstore/test/browser_broadcast.js
@@ -9,17 +9,17 @@ const INITIAL_VALUE = "browser_broadcast
  * This test ensures we won't lose tab data queued in the content script when
  * closing a tab.
  */
 add_task(function flush_on_tabclose() {
   let tab = yield createTabWithStorageData(["http://example.com"]);
   let browser = tab.linkedBrowser;
 
   yield modifySessionStorage(browser, {test: "on-tab-close"});
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://example.com"].test, "on-tab-close",
     "sessionStorage data has been flushed on TabClose");
 });
 
 /**
  * This test ensures we won't lose tab data queued in the content script when
@@ -54,17 +54,17 @@ add_task(function flush_on_duplicate() {
 
   yield modifySessionStorage(browser, {test: "on-duplicate"});
   let tab2 = ss.duplicateTab(window, tab);
   let {storage} = JSON.parse(ss.getTabState(tab2));
   is(storage["http://example.com"].test, "on-duplicate",
     "sessionStorage data has been flushed when duplicating tabs");
 
   yield promiseTabRestored(tab2);
-  gBrowser.removeTab(tab2);
+  yield promiseRemoveTab(tab2);
   [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://example.com"].test, "on-duplicate",
     "sessionStorage data has been flushed when duplicating tabs");
 
   gBrowser.removeTab(tab);
 });
 
 /**
@@ -123,17 +123,17 @@ add_task(function flush_on_tabclose_racy
   // Flush to make sure we start with an empty queue.
   TabState.flush(browser);
 
   yield modifySessionStorage(browser, {test: "on-tab-close-racy"});
 
   // Flush all data contained in the content script but send it using
   // asynchronous messages.
   TabState.flushAsync(browser);
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://example.com"].test, "on-tab-close-racy",
     "sessionStorage data has been merged correctly to prevent data loss");
 });
 
 function promiseNewWindow() {
   let deferred = Promise.defer();
--- a/browser/components/sessionstore/test/browser_cleaner.js
+++ b/browser/components/sessionstore/test/browser_cleaner.js
@@ -66,18 +66,18 @@ add_task(function* test_open_and_close()
   is(state.windows[0].tabs[1].closedAt || false, false, "1. Second tab doesn't have closedAt");
 
 
 
   info("2. Making sure that after closing, we have closedAt");
 
   // Now close stuff, this should add closeAt
   yield promiseWindowClosed(newWin);
-  gBrowser.removeTab(newTab1);
-  gBrowser.removeTab(newTab2);
+  yield promiseRemoveTab(newTab1);
+  yield promiseRemoveTab(newTab2);
 
   state = CLOSED_STATE = JSON.parse(ss.getBrowserState());
 
   is(state.windows[0].closedAt || false, false, "2. Main window doesn't have closedAt");
   ok(isRecent(state._closedWindows[0].closedAt), "2. Second window was closed recently");
   ok(isRecent(state.windows[0]._closedTabs[0].closedAt), "2. First tab was closed recently");
   ok(isRecent(state.windows[0]._closedTabs[1].closedAt), "2. Second tab was closed recently");
 });
--- a/browser/components/sessionstore/test/browser_dying_cache.js
+++ b/browser/components/sessionstore/test/browser_dying_cache.js
@@ -15,17 +15,17 @@ add_task(function* test() {
   let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
   win.gBrowser.selectedBrowser.loadURIWithFlags("about:robots", flags);
   yield promiseBrowserLoaded(win.gBrowser.selectedBrowser);
 
   // Open a second tab and close the first one.
   let tab = win.gBrowser.addTab("about:mozilla");
   yield promiseBrowserLoaded(tab.linkedBrowser);
   TabState.flush(tab.linkedBrowser);
-  win.gBrowser.removeTab(win.gBrowser.tabs[0]);
+  yield promiseRemoveTab(win.gBrowser.tabs[0]);
 
   // Make sure our window is still tracked by sessionstore
   // and the window state is as expected.
   ok("__SSi" in win, "window is being tracked by sessionstore");
   ss.setWindowValue(win, "foo", "bar");
   checkWindowState(win);
 
   let state = ss.getWindowState(win);
--- a/browser/components/sessionstore/test/browser_formdata.js
+++ b/browser/components/sessionstore/test/browser_formdata.js
@@ -25,17 +25,17 @@ add_task(function test_formdata() {
       let browser = tab.linkedBrowser;
       yield promiseBrowserLoaded(browser);
 
       // Modify form data.
       yield setInputValue(browser, {id: "txt", value: OUTER_VALUE});
       yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0});
 
       // Remove the tab.
-      gBrowser.removeTab(tab);
+      yield promiseRemoveTab(tab);
     });
   }
 
   yield createAndRemoveTab();
   let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(formdata.id.txt, OUTER_VALUE, "outer value is correct");
   is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct");
 
@@ -114,17 +114,17 @@ add_task(function test_nested() {
   let tab = gBrowser.selectedTab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Modify the input field's value.
   yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m", frame: 0});
 
   // Remove the tab and check that we stored form data correctly.
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window));
   is(JSON.stringify(formdata), JSON.stringify(FORM_DATA),
     "formdata for iframe stored correctly");
 
   // Restore the closed tab.
   tab = ss.undoCloseTab(window, 0);
   browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
@@ -151,28 +151,28 @@ add_task(function test_design_mode() {
   let tab = gBrowser.selectedTab = gBrowser.addTab(URL);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Modify the document content.
   yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m"});
 
   // Close and restore the tab.
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   tab = ss.undoCloseTab(window, 0);
   browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
 
   // Check that the innerHTML value was restored.
   let html = yield getInnerHTML(browser);
   let expected = "<h1>Mmozilla</h1><script>document.designMode='on'</script>";
   is(html, expected, "editable document has been restored correctly");
 
   // Close and restore the tab.
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   tab = ss.undoCloseTab(window, 0);
   browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
 
   // Check that the innerHTML value was restored.
   html = yield getInnerHTML(browser);
   expected = "<h1>Mmozilla</h1><script>document.designMode='on'</script>";
   is(html, expected, "editable document has been restored correctly");
@@ -227,17 +227,17 @@ add_task(function test_ccNumbers() {
     let tab = gBrowser.addTab(URL);
     let browser = tab.linkedBrowser;
     yield promiseBrowserLoaded(browser);
 
     // Set form value.
     yield setInputValue(browser, {id: "txt", value: formValue});
 
     // Remove the tab.
-    gBrowser.removeTab(tab);
+    yield promiseRemoveTab(tab);
   }
 
   // Test that valid CC numbers are not collected.
   for (let number of validCCNumbers) {
     yield createAndRemoveTab(number);
     let [{state}] = JSON.parse(ss.getClosedTabData(window));
     ok(!("formdata" in state), "valid CC numbers are not collected");
   }
--- a/browser/components/sessionstore/test/browser_frame_history.js
+++ b/browser/components/sessionstore/test/browser_frame_history.js
@@ -27,17 +27,17 @@ add_task(function() {
   yield promise;
 
   info("Clicking on link 2, 1 load should take place");
   promise = waitForLoadsInBrowser(tab.linkedBrowser, 1);
   EventUtils.sendMouseEvent({type:"click"}, links[1], browser_b.contentWindow);
   yield promise;
 
   info("Close then un-close page, 4 loads should take place");
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   let newTab = ss.undoCloseTab(window, 0);
   yield waitForLoadsInBrowser(newTab.linkedBrowser, 4);
 
   info("Go back in time, 1 load should take place");
   gBrowser.goBack();
   yield waitForLoadsInBrowser(newTab.linkedBrowser, 1);
 
   let expectedURLEnds = ["a.html", "b.html", "c1.html"];
@@ -72,17 +72,17 @@ add_task(function() {
   yield promise;
 
   info("iframe: Clicking on link 2, 1 load should take place");
   promise = waitForLoadsInBrowser(tab.linkedBrowser, 1);
   EventUtils.sendMouseEvent({type:"click"}, links[1], browser_b.contentWindow);
   yield promise;
 
   info("iframe: Close then un-close page, 5 loads should take place");
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
   let newTab = ss.undoCloseTab(window, 0);
   yield waitForLoadsInBrowser(newTab.linkedBrowser, 5);
 
   info("iframe: Go back in time, 1 load should take place");
   gBrowser.goBack();
   yield waitForLoadsInBrowser(newTab.linkedBrowser, 1);
 
   let expectedURLEnds = ["a.html", "b.html", "c1.html"];
--- a/browser/components/sessionstore/test/browser_pageStyle.js
+++ b/browser/components/sessionstore/test/browser_pageStyle.js
@@ -54,17 +54,17 @@ add_task(function page_style() {
  * received and the page style is persisted correctly.
  */
 add_task(function nested_page_style() {
   let tab = gBrowser.addTab(URL_NESTED);
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   yield enableSubDocumentStyleSheetsForSet(browser, "alternate");
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   let [{state: {pageStyle}}] = JSON.parse(ss.getClosedTabData(window));
   let expected = JSON.stringify({children: [{pageStyle: "alternate"}]});
   is(JSON.stringify(pageStyle), expected, "correct pageStyle persisted");
 });
 
 function getStyleSheets(browser) {
   return sendMessage(browser, "ss-test:getStyleSheets");
--- a/browser/components/sessionstore/test/browser_sessionHistory.js
+++ b/browser/components/sessionstore/test/browser_sessionHistory.js
@@ -10,17 +10,17 @@ add_task(function test_load_start() {
   // Create a new tab.
   let tab = gBrowser.addTab("about:blank");
   let browser = tab.linkedBrowser;
   yield promiseBrowserLoaded(browser);
 
   // Load a new URI but remove the tab before it has finished loading.
   browser.loadURI("about:mozilla");
   yield promiseContentMessage(browser, "ss-test:OnHistoryReplaceEntry");
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   // Undo close the tab.
   tab = ss.undoCloseTab(window, 0);
   browser = tab.linkedBrowser;
   yield promiseTabRestored(tab);
 
   // Check that the correct URL was restored.
   is(browser.currentURI.spec, "about:mozilla", "url is correct");
--- a/browser/components/sessionstore/test/browser_sessionStorage.js
+++ b/browser/components/sessionstore/test/browser_sessionStorage.js
@@ -124,54 +124,54 @@ add_task(function purge_domain() {
 
 /**
  * This test ensures that collecting sessionStorage data respects the privacy
  * levels as set by the user.
  */
 add_task(function respect_privacy_level() {
   let tab = gBrowser.addTab(URL + "&secure");
   yield promiseBrowserLoaded(tab.linkedBrowser);
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   is(storage["https://example.com"].test, INNER_VALUE,
     "https sessionStorage data has been saved");
 
   // Disable saving data for encrypted sites.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
 
   tab = gBrowser.addTab(URL + "&secure");
   yield promiseBrowserLoaded(tab.linkedBrowser);
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   ok(!storage["https://example.com"],
     "https sessionStorage data has *not* been saved");
 
   // Disable saving data for any site.
   Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
 
   // Check that duplicating a tab copies all private data.
   tab = gBrowser.addTab(URL + "&secure");
   yield promiseBrowserLoaded(tab.linkedBrowser);
   let tab2 = gBrowser.duplicateTab(tab);
   yield promiseTabRestored(tab2);
-  gBrowser.removeTab(tab);
+  yield promiseRemoveTab(tab);
 
   // With privacy_level=2 the |tab| shouldn't have any sessionStorage data.
   [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   ok(!storage, "sessionStorage data has *not* been saved");
 
   // Restore the default privacy level and close the duplicated tab.
   Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
-  gBrowser.removeTab(tab2);
+  yield promiseRemoveTab(tab2);
 
   // With privacy_level=0 the duplicated |tab2| should persist all data.
   [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));
   is(storage["http://mochi.test:8888"].test, OUTER_VALUE,
     "http sessionStorage data has been saved");
   is(storage["https://example.com"].test, INNER_VALUE,
     "https sessionStorage data has been saved");
 });
--- a/browser/components/sessionstore/test/browser_telemetry.js
+++ b/browser/components/sessionstore/test/browser_telemetry.js
@@ -71,49 +71,49 @@ add_task(function history() {
     gt(statistics2[KEY], statistics[KEY], "The total size of HISTORY has increased");
 
 // Almost nothing else should
     for (let k of ["FORMDATA", "DOM_STORAGE", "CLOSED_WINDOWS", "CLOSED_TABS_IN_OPEN_WINDOWS"]) {
       is(statistics2[Keys[k]], statistics[Keys[k]], "The total size of " + k + " has not increased");
     }
   } finally {
     if (tab) {
-      gBrowser.removeTab(tab);
+      yield promiseRemoveTab(tab);
     }
   }
 });
 
 /**
  * Test CLOSED_TABS_IN_OPEN_WINDOWS key.
  */
 add_task(function close_tab() {
   let KEY = Keys.CLOSED_TABS_IN_OPEN_WINDOWS;
   let tab = gBrowser.addTab("http://example.org:80/?close_tab");
   yield promiseBrowserLoaded(tab.linkedBrowser);
   try {
     TabState.flush(tab.linkedBrowser);
     let statistics = yield promiseStats();
 
     info("Now closing a tab");
-    gBrowser.removeTab(tab);
+    yield promiseRemoveTab(tab);
     tab = null;
     let statistics2 = yield promiseStats();
 
     isnot(statistics[KEY], undefined, "Key was defined");
     isnot(statistics2[KEY], undefined, "Key is still defined");
     gt(statistics2[KEY], statistics[KEY], "The total size of CLOSED_TABS_IN_OPEN_WINDOWS has increased");
 
     // Almost nothing else should change
     for (let k of ["FORMDATA", "DOM_STORAGE", "CLOSED_WINDOWS"]) {
       is(statistics2[Keys[k]], statistics[Keys[k]], "The total size of " + k + " has not increased");
     }
 
   } finally {
     if (tab) {
-      gBrowser.removeTab(tab);
+      yield promiseRemoveTab(tab);
     }
   }
 });
 
 /**
  * Test OPEN_WINDOWS key.
  */
 add_task(function open_window() {
@@ -197,17 +197,17 @@ add_task(function dom_storage() {
 
     // Almost nothing else should change
     for (let k of ["CLOSED_TABS_IN_OPEN_WINDOWS", "FORMDATA", "CLOSED_WINDOWS"]) {
       is(statistics2[Keys[k]], statistics[Keys[k]], "The total size of " + k + " has not increased");
     }
 
   } finally {
     if (tab) {
-      gBrowser.removeTab(tab);
+      yield promiseRemoveTab(tab);
     }
   }
 });
 
 /**
  * Test FORMDATA key.
  */
 add_task(function formdata() {
@@ -230,17 +230,17 @@ add_task(function formdata() {
     gt(statistics2[KEY], statistics[KEY], "The total size of FORMDATA has increased");
 
     // Almost nothing else should
     for (let k of ["DOM_STORAGE", "CLOSED_WINDOWS", "CLOSED_TABS_IN_OPEN_WINDOWS"]) {
       is(statistics2[Keys[k]], statistics[Keys[k]], "The total size of " + k + " has not increased");
     }
   } finally {
     if (tab) {
-      gBrowser.removeTab(tab);
+      yield promiseRemoveTab(tab);
     }
   }
 });
 
 add_task(function* test_sessionRestoreInit() {
    let info = Cc["@mozilla.org/toolkit/app-startup;1"].
      getService(Ci.nsIAppStartup).
      getStartupInfo();
--- a/browser/components/sessionstore/test/content.js
+++ b/browser/components/sessionstore/test/content.js
@@ -60,18 +60,20 @@ let historyListener = {
   },
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsISHistoryListener,
     Ci.nsISupportsWeakReference
   ])
 };
 
-docShell.QueryInterface(Ci.nsIWebNavigation).
+let {sessionHistory} = docShell.QueryInterface(Ci.nsIWebNavigation);
+if (sessionHistory) {
   sessionHistory.addSHistoryListener(historyListener);
+}
 
 /**
  * This frame script is only loaded for sessionstore mochitests. It enables us
  * to modify and query docShell data when running with multiple processes.
  */
 
 addEventListener("hashchange", function () {
   sendAsyncMessage("ss-test:hashchange");
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -522,8 +522,22 @@ const FORM_HELPERS = [
   "getMultipleSelected", "setMultipleSelected",
   "getFileNameArray", "setFileNameArray",
 ];
 
 for (let name of FORM_HELPERS) {
   let msg = "ss-test:" + name;
   this[name] = (browser, data) => sendMessage(browser, msg, data);
 }
+
+function promiseRemoveTab(tab) {
+  return new Promise(resolve => {
+    let {messageManager: mm, frameLoader} = tab.linkedBrowser;
+    mm.addMessageListener("SessionStore:update", function onMessage(msg) {
+      if (msg.targetFrameLoader == frameLoader && msg.data.isFinal) {
+        mm.removeMessageListener("SessionStore:update", onMessage);
+        resolve();
+      }
+    }, true);
+
+    tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
+  });
+}