diff options
Diffstat (limited to 'browser/components/sessionstore/test/browser_589246.js')
-rw-r--r-- | browser/components/sessionstore/test/browser_589246.js | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/browser/components/sessionstore/test/browser_589246.js b/browser/components/sessionstore/test/browser_589246.js new file mode 100644 index 000000000..d1f539073 --- /dev/null +++ b/browser/components/sessionstore/test/browser_589246.js @@ -0,0 +1,242 @@ +/* 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/. */ + +// Mirrors WINDOW_ATTRIBUTES IN nsSessionStore.js +const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"]; + +var stateBackup = ss.getBrowserState(); + +var originalWarnOnClose = gPrefService.getBoolPref("browser.tabs.warnOnClose"); +var originalStartupPage = gPrefService.getIntPref("browser.startup.page"); +var originalWindowType = document.documentElement.getAttribute("windowtype"); + +var gotLastWindowClosedTopic = false; +var shouldPinTab = false; +var shouldOpenTabs = false; +var shouldCloseTab = false; +var testNum = 0; +var afterTestCallback; + +// Set state so we know the closed windows content +var testState = { + windows: [ + { tabs: [{ entries: [{ url: "http://example.org" }] }] } + ], + _closedWindows: [] +}; + +// We'll push a set of conditions and callbacks into this array +// Ideally we would also test win/linux under a complete set of conditions, but +// the tests for osx mirror the other set of conditions possible on win/linux. +var tests = []; + +// the third & fourth test share a condition check, keep it DRY +function checkOSX34Generator(num) { + return function(aPreviousState, aCurState) { + // In here, we should have restored the pinned tab, so only the unpinned tab + // should be in aCurState. So let's shape our expectations. + let expectedState = JSON.parse(aPreviousState); + expectedState[0].tabs.shift(); + // size attributes are stripped out in _prepDataForDeferredRestore in nsSessionStore. + // This isn't the best approach, but neither is comparing JSON strings + WINDOW_ATTRIBUTES.forEach(attr => delete expectedState[0][attr]); + + is(aCurState, JSON.stringify(expectedState), + "test #" + num + ": closedWindowState is as expected"); + }; +} +function checkNoWindowsGenerator(num) { + return function(aPreviousState, aCurState) { + is(aCurState, "[]", "test #" + num + ": there should be no closedWindowsLeft"); + }; +} + +// The first test has 0 pinned tabs and 1 unpinned tab +tests.push({ + pinned: false, + extra: false, + close: false, + checkWinLin: checkNoWindowsGenerator(1), + checkOSX: function(aPreviousState, aCurState) { + is(aCurState, aPreviousState, "test #1: closed window state is unchanged"); + } +}); + +// The second test has 1 pinned tab and 0 unpinned tabs. +tests.push({ + pinned: true, + extra: false, + close: false, + checkWinLin: checkNoWindowsGenerator(2), + checkOSX: checkNoWindowsGenerator(2) +}); + +// The third test has 1 pinned tab and 2 unpinned tabs. +tests.push({ + pinned: true, + extra: true, + close: false, + checkWinLin: checkNoWindowsGenerator(3), + checkOSX: checkOSX34Generator(3) +}); + +// The fourth test has 1 pinned tab, 2 unpinned tabs, and closes one unpinned tab. +tests.push({ + pinned: true, + extra: true, + close: "one", + checkWinLin: checkNoWindowsGenerator(4), + checkOSX: checkOSX34Generator(4) +}); + +// The fifth test has 1 pinned tab, 2 unpinned tabs, and closes both unpinned tabs. +tests.push({ + pinned: true, + extra: true, + close: "both", + checkWinLin: checkNoWindowsGenerator(5), + checkOSX: checkNoWindowsGenerator(5) +}); + + +function test() { + /** Test for Bug 589246 - Closed window state getting corrupted when closing + and reopening last browser window without exiting browser **/ + waitForExplicitFinish(); + // windows opening & closing, so extending the timeout + requestLongerTimeout(2); + + // We don't want the quit dialog pref + gPrefService.setBoolPref("browser.tabs.warnOnClose", false); + // Ensure that we would restore the session (important for Windows) + gPrefService.setIntPref("browser.startup.page", 3); + + runNextTestOrFinish(); +} + +function runNextTestOrFinish() { + if (tests.length) { + setupForTest(tests.shift()) + } + else { + // some state is cleaned up at the end of each test, but not all + ["browser.tabs.warnOnClose", "browser.startup.page"].forEach(function(p) { + if (gPrefService.prefHasUserValue(p)) + gPrefService.clearUserPref(p); + }); + + ss.setBrowserState(stateBackup); + executeSoon(finish); + } +} + +function setupForTest(aConditions) { + // reset some checks + gotLastWindowClosedTopic = false; + shouldPinTab = aConditions.pinned; + shouldOpenTabs = aConditions.extra; + shouldCloseTab = aConditions.close; + testNum++; + + // set our test callback + afterTestCallback = /Mac/.test(navigator.platform) ? aConditions.checkOSX + : aConditions.checkWinLin; + + // Add observers + Services.obs.addObserver(onLastWindowClosed, "browser-lastwindow-close-granted", false); + + // Set the state + Services.obs.addObserver(onStateRestored, "sessionstore-browser-state-restored", false); + ss.setBrowserState(JSON.stringify(testState)); +} + +function onStateRestored(aSubject, aTopic, aData) { + info("test #" + testNum + ": onStateRestored"); + Services.obs.removeObserver(onStateRestored, "sessionstore-browser-state-restored"); + + // change this window's windowtype so that closing a new window will trigger + // browser-lastwindow-close-granted. + document.documentElement.setAttribute("windowtype", "navigator:testrunner"); + + let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "http://example.com"); + newWin.addEventListener("load", function(aEvent) { + newWin.removeEventListener("load", arguments.callee, false); + + promiseBrowserLoaded(newWin.gBrowser.selectedBrowser).then(() => { + // pin this tab + if (shouldPinTab) + newWin.gBrowser.pinTab(newWin.gBrowser.selectedTab); + + newWin.addEventListener("unload", function () { + newWin.removeEventListener("unload", arguments.callee, false); + onWindowUnloaded(); + }, false); + // Open a new tab as well. On Windows/Linux this will be restored when the + // new window is opened below (in onWindowUnloaded). On OS X we'll just + // restore the pinned tabs, leaving the unpinned tab in the closedWindowsData. + if (shouldOpenTabs) { + let newTab = newWin.gBrowser.addTab("about:config"); + let newTab2 = newWin.gBrowser.addTab("about:buildconfig"); + + newTab.linkedBrowser.addEventListener("load", function() { + newTab.linkedBrowser.removeEventListener("load", arguments.callee, true); + + if (shouldCloseTab == "one") { + newWin.gBrowser.removeTab(newTab2); + } + else if (shouldCloseTab == "both") { + newWin.gBrowser.removeTab(newTab); + newWin.gBrowser.removeTab(newTab2); + } + newWin.BrowserTryToCloseWindow(); + }, true); + } + else { + newWin.BrowserTryToCloseWindow(); + } + }); + }, false); +} + +// This will be called before the window is actually closed +function onLastWindowClosed(aSubject, aTopic, aData) { + info("test #" + testNum + ": onLastWindowClosed"); + Services.obs.removeObserver(onLastWindowClosed, "browser-lastwindow-close-granted"); + gotLastWindowClosedTopic = true; +} + +// This is the unload event listener on the new window (from onStateRestored). +// Unload is fired after the window is closed, so sessionstore has already +// updated _closedWindows (which is important). We'll open a new window here +// which should actually trigger the bug. +function onWindowUnloaded() { + info("test #" + testNum + ": onWindowClosed"); + ok(gotLastWindowClosedTopic, "test #" + testNum + ": browser-lastwindow-close-granted was notified prior"); + + let previousClosedWindowData = ss.getClosedWindowData(); + + // Now we want to open a new window + let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:mozilla"); + newWin.addEventListener("load", function(aEvent) { + newWin.removeEventListener("load", arguments.callee, false); + + newWin.gBrowser.selectedBrowser.addEventListener("load", function () { + newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); + + // Good enough for checking the state + afterTestCallback(previousClosedWindowData, ss.getClosedWindowData()); + afterTestCleanup(newWin); + }, true); + + }, false); +} + +function afterTestCleanup(aNewWin) { + executeSoon(function() { + BrowserTestUtils.closeWindow(aNewWin).then(() => { + document.documentElement.setAttribute("windowtype", originalWindowType); + runNextTestOrFinish(); + }); + }); +} |