browser/components/sessionstore/test/browser_589246.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/components/sessionstore/test/browser_589246.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,241 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +// Mirrors WINDOW_ATTRIBUTES IN nsSessionStore.js
     1.9 +const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"];
    1.10 +
    1.11 +let stateBackup = ss.getBrowserState();
    1.12 +
    1.13 +let originalWarnOnClose = gPrefService.getBoolPref("browser.tabs.warnOnClose");
    1.14 +let originalStartupPage = gPrefService.getIntPref("browser.startup.page");
    1.15 +let originalWindowType = document.documentElement.getAttribute("windowtype");
    1.16 +
    1.17 +let gotLastWindowClosedTopic = false;
    1.18 +let shouldPinTab = false;
    1.19 +let shouldOpenTabs = false;
    1.20 +let shouldCloseTab = false;
    1.21 +let testNum = 0;
    1.22 +let afterTestCallback;
    1.23 +
    1.24 +// Set state so we know the closed windows content
    1.25 +let testState = {
    1.26 +  windows: [
    1.27 +    { tabs: [{ entries: [{ url: "http://example.org" }] }] }
    1.28 +  ],
    1.29 +  _closedWindows: []
    1.30 +};
    1.31 +
    1.32 +// We'll push a set of conditions and callbacks into this array
    1.33 +// Ideally we would also test win/linux under a complete set of conditions, but
    1.34 +// the tests for osx mirror the other set of conditions possible on win/linux.
    1.35 +let tests = [];
    1.36 +
    1.37 +// the third & fourth test share a condition check, keep it DRY
    1.38 +function checkOSX34Generator(num) {
    1.39 +  return function(aPreviousState, aCurState) {
    1.40 +    // In here, we should have restored the pinned tab, so only the unpinned tab
    1.41 +    // should be in aCurState. So let's shape our expectations.
    1.42 +    let expectedState = JSON.parse(aPreviousState);
    1.43 +    expectedState[0].tabs.shift();
    1.44 +    // size attributes are stripped out in _prepDataForDeferredRestore in nsSessionStore.
    1.45 +    // This isn't the best approach, but neither is comparing JSON strings
    1.46 +    WINDOW_ATTRIBUTES.forEach(function (attr) delete expectedState[0][attr]);
    1.47 +
    1.48 +    is(aCurState, JSON.stringify(expectedState),
    1.49 +       "test #" + num + ": closedWindowState is as expected");
    1.50 +  };
    1.51 +}
    1.52 +function checkNoWindowsGenerator(num) {
    1.53 +  return function(aPreviousState, aCurState) {
    1.54 +    is(aCurState, "[]", "test #" + num + ": there should be no closedWindowsLeft");
    1.55 +  };
    1.56 +}
    1.57 +
    1.58 +// The first test has 0 pinned tabs and 1 unpinned tab
    1.59 +tests.push({
    1.60 +  pinned: false,
    1.61 +  extra: false,
    1.62 +  close: false,
    1.63 +  checkWinLin: checkNoWindowsGenerator(1),
    1.64 +  checkOSX: function(aPreviousState, aCurState) {
    1.65 +    is(aCurState, aPreviousState, "test #1: closed window state is unchanged");
    1.66 +  }
    1.67 +});
    1.68 +
    1.69 +// The second test has 1 pinned tab and 0 unpinned tabs.
    1.70 +tests.push({
    1.71 +  pinned: true,
    1.72 +  extra: false,
    1.73 +  close: false,
    1.74 +  checkWinLin: checkNoWindowsGenerator(2),
    1.75 +  checkOSX: checkNoWindowsGenerator(2)
    1.76 +});
    1.77 +
    1.78 +// The third test has 1 pinned tab and 2 unpinned tabs.
    1.79 +tests.push({
    1.80 +  pinned: true,
    1.81 +  extra: true,
    1.82 +  close: false,
    1.83 +  checkWinLin: checkNoWindowsGenerator(3),
    1.84 +  checkOSX: checkOSX34Generator(3)
    1.85 +});
    1.86 +
    1.87 +// The fourth test has 1 pinned tab, 2 unpinned tabs, and closes one unpinned tab.
    1.88 +tests.push({
    1.89 +  pinned: true,
    1.90 +  extra: true,
    1.91 +  close: "one",
    1.92 +  checkWinLin: checkNoWindowsGenerator(4),
    1.93 +  checkOSX: checkOSX34Generator(4)
    1.94 +});
    1.95 +
    1.96 +// The fifth test has 1 pinned tab, 2 unpinned tabs, and closes both unpinned tabs.
    1.97 +tests.push({
    1.98 +  pinned: true,
    1.99 +  extra: true,
   1.100 +  close: "both",
   1.101 +  checkWinLin: checkNoWindowsGenerator(5),
   1.102 +  checkOSX: checkNoWindowsGenerator(5)
   1.103 +});
   1.104 +
   1.105 +
   1.106 +function test() {
   1.107 +  /** Test for Bug 589246 - Closed window state getting corrupted when closing
   1.108 +      and reopening last browser window without exiting browser **/
   1.109 +  waitForExplicitFinish();
   1.110 +  // windows opening & closing, so extending the timeout
   1.111 +  requestLongerTimeout(2);
   1.112 +
   1.113 +  // We don't want the quit dialog pref
   1.114 +  gPrefService.setBoolPref("browser.tabs.warnOnClose", false);
   1.115 +  // Ensure that we would restore the session (important for Windows)
   1.116 +  gPrefService.setIntPref("browser.startup.page", 3);
   1.117 +
   1.118 +  runNextTestOrFinish();
   1.119 +}
   1.120 +
   1.121 +function runNextTestOrFinish() {
   1.122 +  if (tests.length) {
   1.123 +    setupForTest(tests.shift())
   1.124 +  }
   1.125 +  else {
   1.126 +    // some state is cleaned up at the end of each test, but not all
   1.127 +    ["browser.tabs.warnOnClose", "browser.startup.page"].forEach(function(p) {
   1.128 +      if (gPrefService.prefHasUserValue(p))
   1.129 +        gPrefService.clearUserPref(p);
   1.130 +    });
   1.131 +
   1.132 +    ss.setBrowserState(stateBackup);
   1.133 +    executeSoon(finish);
   1.134 +  }
   1.135 +}
   1.136 +
   1.137 +function setupForTest(aConditions) {
   1.138 +  // reset some checks
   1.139 +  gotLastWindowClosedTopic = false;
   1.140 +  shouldPinTab = aConditions.pinned;
   1.141 +  shouldOpenTabs = aConditions.extra;
   1.142 +  shouldCloseTab = aConditions.close;
   1.143 +  testNum++;
   1.144 +
   1.145 +  // set our test callback
   1.146 +  afterTestCallback = /Mac/.test(navigator.platform) ? aConditions.checkOSX
   1.147 +                                                     : aConditions.checkWinLin;
   1.148 +
   1.149 +  // Add observers
   1.150 +  Services.obs.addObserver(onLastWindowClosed, "browser-lastwindow-close-granted", false);
   1.151 +
   1.152 +  // Set the state
   1.153 +  Services.obs.addObserver(onStateRestored, "sessionstore-browser-state-restored", false);
   1.154 +  ss.setBrowserState(JSON.stringify(testState));
   1.155 +}
   1.156 +
   1.157 +function onStateRestored(aSubject, aTopic, aData) {
   1.158 +  info("test #" + testNum + ": onStateRestored");
   1.159 +  Services.obs.removeObserver(onStateRestored, "sessionstore-browser-state-restored");
   1.160 +
   1.161 +  // change this window's windowtype so that closing a new window will trigger
   1.162 +  // browser-lastwindow-close-granted.
   1.163 +  document.documentElement.setAttribute("windowtype", "navigator:testrunner");
   1.164 +
   1.165 +  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "http://example.com");
   1.166 +  newWin.addEventListener("load", function(aEvent) {
   1.167 +    newWin.removeEventListener("load", arguments.callee, false);
   1.168 +
   1.169 +    whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
   1.170 +      // pin this tab
   1.171 +      if (shouldPinTab)
   1.172 +        newWin.gBrowser.pinTab(newWin.gBrowser.selectedTab);
   1.173 +
   1.174 +      newWin.addEventListener("unload", function () {
   1.175 +        newWin.removeEventListener("unload", arguments.callee, false);
   1.176 +        onWindowUnloaded();
   1.177 +      }, false);
   1.178 +      // Open a new tab as well. On Windows/Linux this will be restored when the
   1.179 +      // new window is opened below (in onWindowUnloaded). On OS X we'll just
   1.180 +      // restore the pinned tabs, leaving the unpinned tab in the closedWindowsData.
   1.181 +      if (shouldOpenTabs) {
   1.182 +        let newTab = newWin.gBrowser.addTab("about:config");
   1.183 +        let newTab2 = newWin.gBrowser.addTab("about:buildconfig");
   1.184 +
   1.185 +        newTab.linkedBrowser.addEventListener("load", function() {
   1.186 +          newTab.linkedBrowser.removeEventListener("load", arguments.callee, true);
   1.187 +
   1.188 +          if (shouldCloseTab == "one") {
   1.189 +            newWin.gBrowser.removeTab(newTab2);
   1.190 +          }
   1.191 +          else if (shouldCloseTab == "both") {
   1.192 +            newWin.gBrowser.removeTab(newTab);
   1.193 +            newWin.gBrowser.removeTab(newTab2);
   1.194 +          }
   1.195 +          newWin.BrowserTryToCloseWindow();
   1.196 +        }, true);
   1.197 +      }
   1.198 +      else {
   1.199 +        newWin.BrowserTryToCloseWindow();
   1.200 +      }
   1.201 +    });
   1.202 +  }, false);
   1.203 +}
   1.204 +
   1.205 +// This will be called before the window is actually closed
   1.206 +function onLastWindowClosed(aSubject, aTopic, aData) {
   1.207 +  info("test #" + testNum + ": onLastWindowClosed");
   1.208 +  Services.obs.removeObserver(onLastWindowClosed, "browser-lastwindow-close-granted");
   1.209 +  gotLastWindowClosedTopic = true;
   1.210 +}
   1.211 +
   1.212 +// This is the unload event listener on the new window (from onStateRestored).
   1.213 +// Unload is fired after the window is closed, so sessionstore has already
   1.214 +// updated _closedWindows (which is important). We'll open a new window here
   1.215 +// which should actually trigger the bug.
   1.216 +function onWindowUnloaded() {
   1.217 +  info("test #" + testNum + ": onWindowClosed");
   1.218 +  ok(gotLastWindowClosedTopic, "test #" + testNum + ": browser-lastwindow-close-granted was notified prior");
   1.219 +
   1.220 +  let previousClosedWindowData = ss.getClosedWindowData();
   1.221 +
   1.222 +  // Now we want to open a new window
   1.223 +  let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:mozilla");
   1.224 +  newWin.addEventListener("load", function(aEvent) {
   1.225 +    newWin.removeEventListener("load", arguments.callee, false);
   1.226 +
   1.227 +    newWin.gBrowser.selectedBrowser.addEventListener("load", function () {
   1.228 +      newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
   1.229 +
   1.230 +      // Good enough for checking the state
   1.231 +      afterTestCallback(previousClosedWindowData, ss.getClosedWindowData());
   1.232 +      afterTestCleanup(newWin);
   1.233 +    }, true);
   1.234 +
   1.235 +  }, false);
   1.236 +}
   1.237 +
   1.238 +function afterTestCleanup(aNewWin) {
   1.239 +  executeSoon(function() {
   1.240 +    aNewWin.close();
   1.241 +    document.documentElement.setAttribute("windowtype", originalWindowType);
   1.242 +    runNextTestOrFinish();
   1.243 +  });
   1.244 +}

mercurial