Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | // Mirrors WINDOW_ATTRIBUTES IN nsSessionStore.js |
michael@0 | 6 | const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"]; |
michael@0 | 7 | |
michael@0 | 8 | let stateBackup = ss.getBrowserState(); |
michael@0 | 9 | |
michael@0 | 10 | let originalWarnOnClose = gPrefService.getBoolPref("browser.tabs.warnOnClose"); |
michael@0 | 11 | let originalStartupPage = gPrefService.getIntPref("browser.startup.page"); |
michael@0 | 12 | let originalWindowType = document.documentElement.getAttribute("windowtype"); |
michael@0 | 13 | |
michael@0 | 14 | let gotLastWindowClosedTopic = false; |
michael@0 | 15 | let shouldPinTab = false; |
michael@0 | 16 | let shouldOpenTabs = false; |
michael@0 | 17 | let shouldCloseTab = false; |
michael@0 | 18 | let testNum = 0; |
michael@0 | 19 | let afterTestCallback; |
michael@0 | 20 | |
michael@0 | 21 | // Set state so we know the closed windows content |
michael@0 | 22 | let testState = { |
michael@0 | 23 | windows: [ |
michael@0 | 24 | { tabs: [{ entries: [{ url: "http://example.org" }] }] } |
michael@0 | 25 | ], |
michael@0 | 26 | _closedWindows: [] |
michael@0 | 27 | }; |
michael@0 | 28 | |
michael@0 | 29 | // We'll push a set of conditions and callbacks into this array |
michael@0 | 30 | // Ideally we would also test win/linux under a complete set of conditions, but |
michael@0 | 31 | // the tests for osx mirror the other set of conditions possible on win/linux. |
michael@0 | 32 | let tests = []; |
michael@0 | 33 | |
michael@0 | 34 | // the third & fourth test share a condition check, keep it DRY |
michael@0 | 35 | function checkOSX34Generator(num) { |
michael@0 | 36 | return function(aPreviousState, aCurState) { |
michael@0 | 37 | // In here, we should have restored the pinned tab, so only the unpinned tab |
michael@0 | 38 | // should be in aCurState. So let's shape our expectations. |
michael@0 | 39 | let expectedState = JSON.parse(aPreviousState); |
michael@0 | 40 | expectedState[0].tabs.shift(); |
michael@0 | 41 | // size attributes are stripped out in _prepDataForDeferredRestore in nsSessionStore. |
michael@0 | 42 | // This isn't the best approach, but neither is comparing JSON strings |
michael@0 | 43 | WINDOW_ATTRIBUTES.forEach(function (attr) delete expectedState[0][attr]); |
michael@0 | 44 | |
michael@0 | 45 | is(aCurState, JSON.stringify(expectedState), |
michael@0 | 46 | "test #" + num + ": closedWindowState is as expected"); |
michael@0 | 47 | }; |
michael@0 | 48 | } |
michael@0 | 49 | function checkNoWindowsGenerator(num) { |
michael@0 | 50 | return function(aPreviousState, aCurState) { |
michael@0 | 51 | is(aCurState, "[]", "test #" + num + ": there should be no closedWindowsLeft"); |
michael@0 | 52 | }; |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | // The first test has 0 pinned tabs and 1 unpinned tab |
michael@0 | 56 | tests.push({ |
michael@0 | 57 | pinned: false, |
michael@0 | 58 | extra: false, |
michael@0 | 59 | close: false, |
michael@0 | 60 | checkWinLin: checkNoWindowsGenerator(1), |
michael@0 | 61 | checkOSX: function(aPreviousState, aCurState) { |
michael@0 | 62 | is(aCurState, aPreviousState, "test #1: closed window state is unchanged"); |
michael@0 | 63 | } |
michael@0 | 64 | }); |
michael@0 | 65 | |
michael@0 | 66 | // The second test has 1 pinned tab and 0 unpinned tabs. |
michael@0 | 67 | tests.push({ |
michael@0 | 68 | pinned: true, |
michael@0 | 69 | extra: false, |
michael@0 | 70 | close: false, |
michael@0 | 71 | checkWinLin: checkNoWindowsGenerator(2), |
michael@0 | 72 | checkOSX: checkNoWindowsGenerator(2) |
michael@0 | 73 | }); |
michael@0 | 74 | |
michael@0 | 75 | // The third test has 1 pinned tab and 2 unpinned tabs. |
michael@0 | 76 | tests.push({ |
michael@0 | 77 | pinned: true, |
michael@0 | 78 | extra: true, |
michael@0 | 79 | close: false, |
michael@0 | 80 | checkWinLin: checkNoWindowsGenerator(3), |
michael@0 | 81 | checkOSX: checkOSX34Generator(3) |
michael@0 | 82 | }); |
michael@0 | 83 | |
michael@0 | 84 | // The fourth test has 1 pinned tab, 2 unpinned tabs, and closes one unpinned tab. |
michael@0 | 85 | tests.push({ |
michael@0 | 86 | pinned: true, |
michael@0 | 87 | extra: true, |
michael@0 | 88 | close: "one", |
michael@0 | 89 | checkWinLin: checkNoWindowsGenerator(4), |
michael@0 | 90 | checkOSX: checkOSX34Generator(4) |
michael@0 | 91 | }); |
michael@0 | 92 | |
michael@0 | 93 | // The fifth test has 1 pinned tab, 2 unpinned tabs, and closes both unpinned tabs. |
michael@0 | 94 | tests.push({ |
michael@0 | 95 | pinned: true, |
michael@0 | 96 | extra: true, |
michael@0 | 97 | close: "both", |
michael@0 | 98 | checkWinLin: checkNoWindowsGenerator(5), |
michael@0 | 99 | checkOSX: checkNoWindowsGenerator(5) |
michael@0 | 100 | }); |
michael@0 | 101 | |
michael@0 | 102 | |
michael@0 | 103 | function test() { |
michael@0 | 104 | /** Test for Bug 589246 - Closed window state getting corrupted when closing |
michael@0 | 105 | and reopening last browser window without exiting browser **/ |
michael@0 | 106 | waitForExplicitFinish(); |
michael@0 | 107 | // windows opening & closing, so extending the timeout |
michael@0 | 108 | requestLongerTimeout(2); |
michael@0 | 109 | |
michael@0 | 110 | // We don't want the quit dialog pref |
michael@0 | 111 | gPrefService.setBoolPref("browser.tabs.warnOnClose", false); |
michael@0 | 112 | // Ensure that we would restore the session (important for Windows) |
michael@0 | 113 | gPrefService.setIntPref("browser.startup.page", 3); |
michael@0 | 114 | |
michael@0 | 115 | runNextTestOrFinish(); |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | function runNextTestOrFinish() { |
michael@0 | 119 | if (tests.length) { |
michael@0 | 120 | setupForTest(tests.shift()) |
michael@0 | 121 | } |
michael@0 | 122 | else { |
michael@0 | 123 | // some state is cleaned up at the end of each test, but not all |
michael@0 | 124 | ["browser.tabs.warnOnClose", "browser.startup.page"].forEach(function(p) { |
michael@0 | 125 | if (gPrefService.prefHasUserValue(p)) |
michael@0 | 126 | gPrefService.clearUserPref(p); |
michael@0 | 127 | }); |
michael@0 | 128 | |
michael@0 | 129 | ss.setBrowserState(stateBackup); |
michael@0 | 130 | executeSoon(finish); |
michael@0 | 131 | } |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | function setupForTest(aConditions) { |
michael@0 | 135 | // reset some checks |
michael@0 | 136 | gotLastWindowClosedTopic = false; |
michael@0 | 137 | shouldPinTab = aConditions.pinned; |
michael@0 | 138 | shouldOpenTabs = aConditions.extra; |
michael@0 | 139 | shouldCloseTab = aConditions.close; |
michael@0 | 140 | testNum++; |
michael@0 | 141 | |
michael@0 | 142 | // set our test callback |
michael@0 | 143 | afterTestCallback = /Mac/.test(navigator.platform) ? aConditions.checkOSX |
michael@0 | 144 | : aConditions.checkWinLin; |
michael@0 | 145 | |
michael@0 | 146 | // Add observers |
michael@0 | 147 | Services.obs.addObserver(onLastWindowClosed, "browser-lastwindow-close-granted", false); |
michael@0 | 148 | |
michael@0 | 149 | // Set the state |
michael@0 | 150 | Services.obs.addObserver(onStateRestored, "sessionstore-browser-state-restored", false); |
michael@0 | 151 | ss.setBrowserState(JSON.stringify(testState)); |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | function onStateRestored(aSubject, aTopic, aData) { |
michael@0 | 155 | info("test #" + testNum + ": onStateRestored"); |
michael@0 | 156 | Services.obs.removeObserver(onStateRestored, "sessionstore-browser-state-restored"); |
michael@0 | 157 | |
michael@0 | 158 | // change this window's windowtype so that closing a new window will trigger |
michael@0 | 159 | // browser-lastwindow-close-granted. |
michael@0 | 160 | document.documentElement.setAttribute("windowtype", "navigator:testrunner"); |
michael@0 | 161 | |
michael@0 | 162 | let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "http://example.com"); |
michael@0 | 163 | newWin.addEventListener("load", function(aEvent) { |
michael@0 | 164 | newWin.removeEventListener("load", arguments.callee, false); |
michael@0 | 165 | |
michael@0 | 166 | whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() { |
michael@0 | 167 | // pin this tab |
michael@0 | 168 | if (shouldPinTab) |
michael@0 | 169 | newWin.gBrowser.pinTab(newWin.gBrowser.selectedTab); |
michael@0 | 170 | |
michael@0 | 171 | newWin.addEventListener("unload", function () { |
michael@0 | 172 | newWin.removeEventListener("unload", arguments.callee, false); |
michael@0 | 173 | onWindowUnloaded(); |
michael@0 | 174 | }, false); |
michael@0 | 175 | // Open a new tab as well. On Windows/Linux this will be restored when the |
michael@0 | 176 | // new window is opened below (in onWindowUnloaded). On OS X we'll just |
michael@0 | 177 | // restore the pinned tabs, leaving the unpinned tab in the closedWindowsData. |
michael@0 | 178 | if (shouldOpenTabs) { |
michael@0 | 179 | let newTab = newWin.gBrowser.addTab("about:config"); |
michael@0 | 180 | let newTab2 = newWin.gBrowser.addTab("about:buildconfig"); |
michael@0 | 181 | |
michael@0 | 182 | newTab.linkedBrowser.addEventListener("load", function() { |
michael@0 | 183 | newTab.linkedBrowser.removeEventListener("load", arguments.callee, true); |
michael@0 | 184 | |
michael@0 | 185 | if (shouldCloseTab == "one") { |
michael@0 | 186 | newWin.gBrowser.removeTab(newTab2); |
michael@0 | 187 | } |
michael@0 | 188 | else if (shouldCloseTab == "both") { |
michael@0 | 189 | newWin.gBrowser.removeTab(newTab); |
michael@0 | 190 | newWin.gBrowser.removeTab(newTab2); |
michael@0 | 191 | } |
michael@0 | 192 | newWin.BrowserTryToCloseWindow(); |
michael@0 | 193 | }, true); |
michael@0 | 194 | } |
michael@0 | 195 | else { |
michael@0 | 196 | newWin.BrowserTryToCloseWindow(); |
michael@0 | 197 | } |
michael@0 | 198 | }); |
michael@0 | 199 | }, false); |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | // This will be called before the window is actually closed |
michael@0 | 203 | function onLastWindowClosed(aSubject, aTopic, aData) { |
michael@0 | 204 | info("test #" + testNum + ": onLastWindowClosed"); |
michael@0 | 205 | Services.obs.removeObserver(onLastWindowClosed, "browser-lastwindow-close-granted"); |
michael@0 | 206 | gotLastWindowClosedTopic = true; |
michael@0 | 207 | } |
michael@0 | 208 | |
michael@0 | 209 | // This is the unload event listener on the new window (from onStateRestored). |
michael@0 | 210 | // Unload is fired after the window is closed, so sessionstore has already |
michael@0 | 211 | // updated _closedWindows (which is important). We'll open a new window here |
michael@0 | 212 | // which should actually trigger the bug. |
michael@0 | 213 | function onWindowUnloaded() { |
michael@0 | 214 | info("test #" + testNum + ": onWindowClosed"); |
michael@0 | 215 | ok(gotLastWindowClosedTopic, "test #" + testNum + ": browser-lastwindow-close-granted was notified prior"); |
michael@0 | 216 | |
michael@0 | 217 | let previousClosedWindowData = ss.getClosedWindowData(); |
michael@0 | 218 | |
michael@0 | 219 | // Now we want to open a new window |
michael@0 | 220 | let newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:mozilla"); |
michael@0 | 221 | newWin.addEventListener("load", function(aEvent) { |
michael@0 | 222 | newWin.removeEventListener("load", arguments.callee, false); |
michael@0 | 223 | |
michael@0 | 224 | newWin.gBrowser.selectedBrowser.addEventListener("load", function () { |
michael@0 | 225 | newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); |
michael@0 | 226 | |
michael@0 | 227 | // Good enough for checking the state |
michael@0 | 228 | afterTestCallback(previousClosedWindowData, ss.getClosedWindowData()); |
michael@0 | 229 | afterTestCleanup(newWin); |
michael@0 | 230 | }, true); |
michael@0 | 231 | |
michael@0 | 232 | }, false); |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | function afterTestCleanup(aNewWin) { |
michael@0 | 236 | executeSoon(function() { |
michael@0 | 237 | aNewWin.close(); |
michael@0 | 238 | document.documentElement.setAttribute("windowtype", originalWindowType); |
michael@0 | 239 | runNextTestOrFinish(); |
michael@0 | 240 | }); |
michael@0 | 241 | } |