203 lines
6.5 KiB
JavaScript
203 lines
6.5 KiB
JavaScript
/* 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/. */
|
|
|
|
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
|
|
|
// Some tests here assume that all restored tabs are loaded without waiting for
|
|
// the user to bring them to the foreground. We ensure this by resetting the
|
|
// related preference (see the "firefox.js" defaults file for details).
|
|
Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", false);
|
|
registerCleanupFunction(function () {
|
|
Services.prefs.clearUserPref("browser.sessionstore.restore_on_demand");
|
|
});
|
|
|
|
// This kicks off the search service used on about:home and allows the
|
|
// session restore tests to be run standalone without triggering errors.
|
|
Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs;
|
|
|
|
function provideWindow(aCallback, aURL, aFeatures) {
|
|
function callbackSoon(aWindow) {
|
|
executeSoon(function executeCallbackSoon() {
|
|
aCallback(aWindow);
|
|
});
|
|
}
|
|
|
|
let win = openDialog(getBrowserURL(), "", aFeatures || "chrome,all,dialog=no", aURL);
|
|
whenWindowLoaded(win, function onWindowLoaded(aWin) {
|
|
if (!aURL) {
|
|
info("Loaded a blank window.");
|
|
callbackSoon(aWin);
|
|
return;
|
|
}
|
|
|
|
aWin.gBrowser.selectedBrowser.addEventListener("load", function selectedBrowserLoadListener() {
|
|
aWin.gBrowser.selectedBrowser.removeEventListener("load", selectedBrowserLoadListener, true);
|
|
callbackSoon(aWin);
|
|
}, true);
|
|
});
|
|
}
|
|
|
|
// This assumes that tests will at least have some state/entries
|
|
function waitForBrowserState(aState, aSetStateCallback) {
|
|
let windows = [window];
|
|
let tabsRestored = 0;
|
|
let expectedTabsRestored = 0;
|
|
let expectedWindows = aState.windows.length;
|
|
let windowsOpen = 1;
|
|
let listening = false;
|
|
let windowObserving = false;
|
|
let restoreHiddenTabs = Services.prefs.getBoolPref(
|
|
"browser.sessionstore.restore_hidden_tabs");
|
|
|
|
aState.windows.forEach(function (winState) {
|
|
winState.tabs.forEach(function (tabState) {
|
|
if (restoreHiddenTabs || !tabState.hidden)
|
|
expectedTabsRestored++;
|
|
});
|
|
});
|
|
|
|
// There must be only hidden tabs and restoreHiddenTabs = false. We still
|
|
// expect one of them to be restored because it gets shown automatically.
|
|
if (!expectedTabsRestored)
|
|
expectedTabsRestored = 1;
|
|
|
|
function onSSTabRestored(aEvent) {
|
|
if (++tabsRestored == expectedTabsRestored) {
|
|
// Remove the event listener from each window
|
|
windows.forEach(function(win) {
|
|
win.gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, true);
|
|
});
|
|
listening = false;
|
|
info("running " + aSetStateCallback.name);
|
|
executeSoon(aSetStateCallback);
|
|
}
|
|
}
|
|
|
|
// Used to add our listener to further windows so we can catch SSTabRestored
|
|
// coming from them when creating a multi-window state.
|
|
function windowObserver(aSubject, aTopic, aData) {
|
|
if (aTopic == "domwindowopened") {
|
|
let newWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
|
newWindow.addEventListener("load", function() {
|
|
newWindow.removeEventListener("load", arguments.callee, false);
|
|
|
|
if (++windowsOpen == expectedWindows) {
|
|
Services.ww.unregisterNotification(windowObserver);
|
|
windowObserving = false;
|
|
}
|
|
|
|
// Track this window so we can remove the progress listener later
|
|
windows.push(newWindow);
|
|
// Add the progress listener
|
|
newWindow.gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, true);
|
|
}, false);
|
|
}
|
|
}
|
|
|
|
// We only want to register the notification if we expect more than 1 window
|
|
if (expectedWindows > 1) {
|
|
registerCleanupFunction(function() {
|
|
if (windowObserving) {
|
|
Services.ww.unregisterNotification(windowObserver);
|
|
}
|
|
});
|
|
windowObserving = true;
|
|
Services.ww.registerNotification(windowObserver);
|
|
}
|
|
|
|
registerCleanupFunction(function() {
|
|
if (listening) {
|
|
windows.forEach(function(win) {
|
|
win.gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, true);
|
|
});
|
|
}
|
|
});
|
|
// Add the event listener for this window as well.
|
|
listening = true;
|
|
gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, true);
|
|
|
|
// Finally, call setBrowserState
|
|
ss.setBrowserState(JSON.stringify(aState));
|
|
}
|
|
|
|
// Doesn't assume that the tab needs to be closed in a cleanup function.
|
|
// If that's the case, the test author should handle that in the test.
|
|
function waitForTabState(aTab, aState, aCallback) {
|
|
let listening = true;
|
|
|
|
function onSSTabRestored() {
|
|
aTab.removeEventListener("SSTabRestored", onSSTabRestored, false);
|
|
listening = false;
|
|
aCallback();
|
|
}
|
|
|
|
aTab.addEventListener("SSTabRestored", onSSTabRestored, false);
|
|
|
|
registerCleanupFunction(function() {
|
|
if (listening) {
|
|
aTab.removeEventListener("SSTabRestored", onSSTabRestored, false);
|
|
}
|
|
});
|
|
ss.setTabState(aTab, JSON.stringify(aState));
|
|
}
|
|
|
|
// waitForSaveState waits for a state write but not necessarily for the state to
|
|
// turn dirty.
|
|
function waitForSaveState(aSaveStateCallback) {
|
|
let observing = false;
|
|
let topic = "sessionstore-state-write";
|
|
|
|
let sessionSaveTimeout = 1000 +
|
|
Services.prefs.getIntPref("browser.sessionstore.interval");
|
|
|
|
function removeObserver() {
|
|
if (!observing)
|
|
return;
|
|
Services.obs.removeObserver(observer, topic, false);
|
|
observing = false;
|
|
}
|
|
|
|
let timeout = setTimeout(function () {
|
|
removeObserver();
|
|
aSaveStateCallback();
|
|
}, sessionSaveTimeout);
|
|
|
|
function observer(aSubject, aTopic, aData) {
|
|
removeObserver();
|
|
timeout = clearTimeout(timeout);
|
|
executeSoon(aSaveStateCallback);
|
|
}
|
|
|
|
registerCleanupFunction(function() {
|
|
removeObserver();
|
|
if (timeout) {
|
|
clearTimeout(timeout);
|
|
}
|
|
});
|
|
|
|
observing = true;
|
|
Services.obs.addObserver(observer, topic, false);
|
|
};
|
|
|
|
function whenBrowserLoaded(aBrowser, aCallback) {
|
|
aBrowser.addEventListener("load", function onLoad() {
|
|
aBrowser.removeEventListener("load", onLoad, true);
|
|
executeSoon(aCallback);
|
|
}, true);
|
|
}
|
|
|
|
function whenWindowLoaded(aWindow, aCallback) {
|
|
aWindow.addEventListener("load", function windowLoadListener() {
|
|
aWindow.removeEventListener("load", windowLoadListener, false);
|
|
executeSoon(function executeWhenWindowLoaded() {
|
|
aCallback(aWindow);
|
|
});
|
|
}, false);
|
|
}
|
|
|
|
var gUniqueCounter = 0;
|
|
function r() {
|
|
return Date.now() + "-" + (++gUniqueCounter);
|
|
}
|