forked from mirrors/gecko-dev
The browser-chrome test suite now detects and reports unhandled rejections of native Promises, in addition to those created by Promise.jsm. The whitelisting mechanism is updated to use primarily the PromiseTestUtils.expectUncaughtRejection function. Tests will fail if a rejection that is not whitelisted occurs, or if a whitelisted rejection does not occur anymore. MozReview-Commit-ID: 1beGB5GG8Ty --HG-- extra : rebase_source : b6573f8e2001f91d0e5a50f6376b191459549e94 extra : intermediate-source : 0411e687044ecc7b56684196238e6e6e68a9d685 extra : source : 8d53be05afc59519c5ce8cfae96d284a972fda71
482 lines
16 KiB
JavaScript
482 lines
16 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/. */
|
|
|
|
/**
|
|
* Checks that restoring the last browser window in session is actually
|
|
* working.
|
|
*
|
|
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=354894
|
|
* @note It is implicitly tested that restoring the last window works when
|
|
* non-browser windows are around. The "Run Tests" window as well as the main
|
|
* browser window (wherein the test code gets executed) won't be considered
|
|
* browser windows. To achiveve this said main browser window has it's windowtype
|
|
* attribute modified so that it's not considered a browser window any longer.
|
|
* This is crucial, because otherwise there would be two browser windows around,
|
|
* said main test window and the one opened by the tests, and hence the new
|
|
* logic wouldn't be executed at all.
|
|
* @note Mac only tests the new notifications, as restoring the last window is
|
|
* not enabled on that platform (platform shim; the application is kept running
|
|
* although there are no windows left)
|
|
* @note There is a difference when closing a browser window with
|
|
* BrowserTryToCloseWindow() as opposed to close(). The former will make
|
|
* nsSessionStore restore a window next time it gets a chance and will post
|
|
* notifications. The latter won't.
|
|
*/
|
|
|
|
// The rejection "RecentWindow.getMostRecentBrowserWindow(...) is null" is left
|
|
// unhandled in some cases. This bug should be fixed, but for the moment this
|
|
// file is whitelisted.
|
|
//
|
|
// NOTE: Whitelisting a class of rejections should be limited. Normally you
|
|
// should use "expectUncaughtRejection" to flag individual failures.
|
|
Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
|
PromiseTestUtils.whitelistRejectionsGlobally(/getMostRecentBrowserWindow/);
|
|
|
|
// Some urls that might be opened in tabs and/or popups
|
|
// Do not use about:blank:
|
|
// That one is reserved for special purposes in the tests
|
|
const TEST_URLS = ["about:mozilla", "about:buildconfig"];
|
|
|
|
// Number of -request notifications to except
|
|
// remember to adjust when adding new tests
|
|
const NOTIFICATIONS_EXPECTED = 6;
|
|
|
|
// Window features of popup windows
|
|
const POPUP_FEATURES = "toolbar=no,resizable=no,status=no";
|
|
|
|
// Window features of browser windows
|
|
const CHROME_FEATURES = "chrome,all,dialog=no";
|
|
|
|
const IS_MAC = navigator.platform.match(/Mac/);
|
|
|
|
/**
|
|
* Returns an Object with two properties:
|
|
* open (int):
|
|
* A count of how many non-closed navigator:browser windows there are.
|
|
* winstates (int):
|
|
* A count of how many windows there are in the SessionStore state.
|
|
*/
|
|
function getBrowserWindowsCount() {
|
|
let open = 0;
|
|
let e = Services.wm.getEnumerator("navigator:browser");
|
|
while (e.hasMoreElements()) {
|
|
if (!e.getNext().closed)
|
|
++open;
|
|
}
|
|
|
|
let winstates = JSON.parse(ss.getBrowserState()).windows.length;
|
|
|
|
return { open, winstates };
|
|
}
|
|
|
|
add_task(async function setup() {
|
|
// Make sure we've only got one browser window to start with
|
|
let { open, winstates } = getBrowserWindowsCount();
|
|
is(open, 1, "Should only be one open window");
|
|
is(winstates, 1, "Should only be one window state in SessionStore");
|
|
|
|
// This test takes some time to run, and it could timeout randomly.
|
|
// So we require a longer timeout. See bug 528219.
|
|
requestLongerTimeout(3);
|
|
|
|
// Make the main test window not count as a browser window any longer
|
|
let oldWinType = document.documentElement.getAttribute("windowtype");
|
|
document.documentElement.setAttribute("windowtype", "navigator:testrunner");
|
|
|
|
registerCleanupFunction(() => {
|
|
document.documentElement.setAttribute("windowtype", oldWinType);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Sets up one of our tests by setting the right preferences, and
|
|
* then opening up a browser window preloaded with some tabs.
|
|
*
|
|
* @param options (Object)
|
|
* An object that can contain the following properties:
|
|
*
|
|
* private:
|
|
* Whether or not the opened window should be private.
|
|
*
|
|
* denyFirst:
|
|
* Whether or not the first window that attempts to close
|
|
* via closeWindowForRestoration should be denied.
|
|
*
|
|
* @param testFunction (Function*)
|
|
* A generator function that yields Promises to be run
|
|
* once the test has been set up.
|
|
*
|
|
* @returns Promise
|
|
* Resolves once the test has been cleaned up.
|
|
*/
|
|
let setupTest = async function(options, testFunction) {
|
|
await pushPrefs(["browser.startup.page", 3],
|
|
["browser.tabs.warnOnClose", false]);
|
|
|
|
// Observe these, and also use to count the number of hits
|
|
let observing = {
|
|
"browser-lastwindow-close-requested": 0,
|
|
"browser-lastwindow-close-granted": 0
|
|
};
|
|
|
|
/**
|
|
* Helper: Will observe and handle the notifications for us
|
|
*/
|
|
let hitCount = 0;
|
|
function observer(aCancel, aTopic, aData) {
|
|
// count so that we later may compare
|
|
observing[aTopic]++;
|
|
|
|
// handle some tests
|
|
if (options.denyFirst && ++hitCount == 1) {
|
|
aCancel.QueryInterface(Ci.nsISupportsPRBool).data = true;
|
|
}
|
|
}
|
|
|
|
for (let o in observing) {
|
|
Services.obs.addObserver(observer, o);
|
|
}
|
|
|
|
let private = options.private || false;
|
|
let newWin = await promiseNewWindowLoaded({ private });
|
|
|
|
injectTestTabs(newWin);
|
|
|
|
await testFunction(newWin, observing);
|
|
|
|
let count = getBrowserWindowsCount();
|
|
is(count.open, 0, "Got right number of open windows");
|
|
is(count.winstates, 1, "Got right number of stored window states");
|
|
|
|
for (let o in observing) {
|
|
Services.obs.removeObserver(observer, o);
|
|
}
|
|
|
|
await popPrefs();
|
|
};
|
|
|
|
/**
|
|
* Loads a TEST_URLS into a browser window.
|
|
*
|
|
* @param win (Window)
|
|
* The browser window to load the tabs in
|
|
*/
|
|
function injectTestTabs(win) {
|
|
TEST_URLS.forEach(function(url) {
|
|
win.gBrowser.addTab(url);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Attempts to close a window via BrowserTryToCloseWindow so that
|
|
* we get the browser-lastwindow-close-requested and
|
|
* browser-lastwindow-close-granted observer notifications.
|
|
*
|
|
* @param win (Window)
|
|
* The window to try to close
|
|
* @returns Promise
|
|
* Resolves to true if the window closed, or false if the window
|
|
* was denied the ability to close.
|
|
*/
|
|
function closeWindowForRestoration(win) {
|
|
return new Promise((resolve) => {
|
|
let closePromise = BrowserTestUtils.windowClosed(win);
|
|
win.BrowserTryToCloseWindow();
|
|
if (!win.closed) {
|
|
resolve(false);
|
|
return;
|
|
}
|
|
|
|
closePromise.then(() => {
|
|
resolve(true);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Normal in-session restore
|
|
*
|
|
* @note: Non-Mac only
|
|
*
|
|
* Should do the following:
|
|
* 1. Open a new browser window
|
|
* 2. Add some tabs
|
|
* 3. Close that window
|
|
* 4. Opening another window
|
|
* 5. Checks that state is restored
|
|
*/
|
|
add_task(async function test_open_close_normal() {
|
|
if (IS_MAC) {
|
|
return;
|
|
}
|
|
|
|
await setupTest({ denyFirst: true }, async function(newWin, obs) {
|
|
let closed = await closeWindowForRestoration(newWin);
|
|
ok(!closed, "First close request should have been denied");
|
|
|
|
closed = await closeWindowForRestoration(newWin);
|
|
ok(closed, "Second close request should be accepted");
|
|
|
|
newWin = await promiseNewWindowLoaded();
|
|
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 2,
|
|
"Restored window in-session with otherpopup windows around");
|
|
|
|
// Note that this will not result in the the browser-lastwindow-close
|
|
// notifications firing for this other newWin.
|
|
await BrowserTestUtils.closeWindow(newWin);
|
|
|
|
// setupTest gave us a window which was denied for closing once, and then
|
|
// closed.
|
|
is(obs["browser-lastwindow-close-requested"], 2,
|
|
"Got expected browser-lastwindow-close-requested notifications");
|
|
is(obs["browser-lastwindow-close-granted"], 1,
|
|
"Got expected browser-lastwindow-close-granted notifications");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* PrivateBrowsing in-session restore
|
|
*
|
|
* @note: Non-Mac only
|
|
*
|
|
* Should do the following:
|
|
* 1. Open a new browser window A
|
|
* 2. Add some tabs
|
|
* 3. Close the window A as the last window
|
|
* 4. Open a private browsing window B
|
|
* 5. Make sure that B didn't restore the tabs from A
|
|
* 6. Close private browsing window B
|
|
* 7. Open a new window C
|
|
* 8. Make sure that new window C has restored tabs from A
|
|
*/
|
|
add_task(async function test_open_close_private_browsing() {
|
|
if (IS_MAC) {
|
|
return;
|
|
}
|
|
|
|
await setupTest({}, async function(newWin, obs) {
|
|
let closed = await closeWindowForRestoration(newWin);
|
|
ok(closed, "Should be able to close the window");
|
|
|
|
newWin = await promiseNewWindowLoaded({private: true});
|
|
is(newWin.gBrowser.browsers.length, 1,
|
|
"Did not restore in private browing mode");
|
|
|
|
closed = await closeWindowForRestoration(newWin);
|
|
ok(closed, "Should be able to close the window");
|
|
|
|
newWin = await promiseNewWindowLoaded();
|
|
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 2,
|
|
"Restored tabs in a new non-private window");
|
|
|
|
// Note that this will not result in the the browser-lastwindow-close
|
|
// notifications firing for this other newWin.
|
|
await BrowserTestUtils.closeWindow(newWin);
|
|
|
|
// We closed two windows with closeWindowForRestoration, and both
|
|
// should have been successful.
|
|
is(obs["browser-lastwindow-close-requested"], 2,
|
|
"Got expected browser-lastwindow-close-requested notifications");
|
|
is(obs["browser-lastwindow-close-granted"], 2,
|
|
"Got expected browser-lastwindow-close-granted notifications");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Open some popup windows to check those aren't restored, but the browser
|
|
* window is.
|
|
*
|
|
* @note: Non-Mac only
|
|
*
|
|
* Should do the following:
|
|
* 1. Open a new browser window
|
|
* 2. Add some tabs
|
|
* 3. Open some popups
|
|
* 4. Add another tab to one popup (so that it gets stored) and close it again
|
|
* 5. Close the browser window
|
|
* 6. Open another browser window
|
|
* 7. Make sure that the tabs of the closed browser window, but not the popup,
|
|
* are restored
|
|
*/
|
|
add_task(async function test_open_close_window_and_popup() {
|
|
if (IS_MAC) {
|
|
return;
|
|
}
|
|
|
|
await setupTest({}, async function(newWin, obs) {
|
|
let popupPromise = BrowserTestUtils.waitForNewWindow();
|
|
openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[0]);
|
|
let popup = await popupPromise;
|
|
|
|
let popup2Promise = BrowserTestUtils.waitForNewWindow();
|
|
openDialog(location, "popup2", POPUP_FEATURES, TEST_URLS[1]);
|
|
let popup2 = await popup2Promise;
|
|
|
|
popup2.gBrowser.addTab(TEST_URLS[0]);
|
|
|
|
let closed = await closeWindowForRestoration(newWin);
|
|
ok(closed, "Should be able to close the window");
|
|
|
|
await BrowserTestUtils.closeWindow(popup2);
|
|
|
|
newWin = await promiseNewWindowLoaded();
|
|
|
|
is(newWin.gBrowser.browsers.length, TEST_URLS.length + 2,
|
|
"Restored window and associated tabs in session");
|
|
|
|
await BrowserTestUtils.closeWindow(popup);
|
|
await BrowserTestUtils.closeWindow(newWin);
|
|
|
|
// We closed one window with closeWindowForRestoration, and it should
|
|
// have been successful.
|
|
is(obs["browser-lastwindow-close-requested"], 1,
|
|
"Got expected browser-lastwindow-close-requested notifications");
|
|
is(obs["browser-lastwindow-close-granted"], 1,
|
|
"Got expected browser-lastwindow-close-granted notifications");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Open some popup window to check it isn't restored. Instead nothing at all
|
|
* should be restored
|
|
*
|
|
* @note: Non-Mac only
|
|
*
|
|
* Should do the following:
|
|
* 1. Open a popup
|
|
* 2. Add another tab to the popup (so that it gets stored) and close it again
|
|
* 3. Open a window
|
|
* 4. Check that nothing at all is restored
|
|
* 5. Open two browser windows and close them again
|
|
* 6. undoCloseWindow() one
|
|
* 7. Open another browser window
|
|
* 8. Check that nothing at all is restored
|
|
*/
|
|
add_task(async function test_open_close_only_popup() {
|
|
if (IS_MAC) {
|
|
return;
|
|
}
|
|
|
|
await setupTest({}, async function(newWin, obs) {
|
|
// We actually don't care about the initial window in this test.
|
|
await BrowserTestUtils.closeWindow(newWin);
|
|
|
|
// This will cause nsSessionStore to restore a window the next time it
|
|
// gets a chance.
|
|
let popupPromise = BrowserTestUtils.waitForNewWindow();
|
|
openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[1]);
|
|
let popup = await popupPromise;
|
|
|
|
is(popup.gBrowser.browsers.length, 1,
|
|
"Did not restore the popup window (1)");
|
|
|
|
let closed = await closeWindowForRestoration(popup);
|
|
ok(closed, "Should be able to close the window");
|
|
|
|
popupPromise = BrowserTestUtils.waitForNewWindow();
|
|
openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[1]);
|
|
popup = await popupPromise;
|
|
|
|
popup.gBrowser.addTab(TEST_URLS[0]);
|
|
is(popup.gBrowser.browsers.length, 2,
|
|
"Did not restore to the popup window (2)");
|
|
|
|
await BrowserTestUtils.closeWindow(popup);
|
|
|
|
newWin = await promiseNewWindowLoaded();
|
|
isnot(newWin.gBrowser.browsers.length, 2,
|
|
"Did not restore the popup window");
|
|
is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1,
|
|
"Did not restore the popup window (2)");
|
|
await BrowserTestUtils.closeWindow(newWin);
|
|
|
|
// We closed one popup window with closeWindowForRestoration, and popup
|
|
// windows should never fire the browser-lastwindow notifications.
|
|
is(obs["browser-lastwindow-close-requested"], 0,
|
|
"Got expected browser-lastwindow-close-requested notifications");
|
|
is(obs["browser-lastwindow-close-granted"], 0,
|
|
"Got expected browser-lastwindow-close-granted notifications");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Open some windows and do undoCloseWindow. This should prevent any
|
|
* restoring later in the test
|
|
*
|
|
* @note: Non-Mac only
|
|
*
|
|
* Should do the following:
|
|
* 1. Open two browser windows and close them again
|
|
* 2. undoCloseWindow() one
|
|
* 3. Open another browser window
|
|
* 4. Make sure nothing at all is restored
|
|
*/
|
|
add_task(async function test_open_close_restore_from_popup() {
|
|
if (IS_MAC) {
|
|
return;
|
|
}
|
|
|
|
await setupTest({}, async function(newWin, obs) {
|
|
let newWin2 = await promiseNewWindowLoaded();
|
|
await injectTestTabs(newWin2);
|
|
|
|
let closed = await closeWindowForRestoration(newWin);
|
|
ok(closed, "Should be able to close the window");
|
|
closed = await closeWindowForRestoration(newWin2);
|
|
ok(closed, "Should be able to close the window");
|
|
|
|
let counts = getBrowserWindowsCount();
|
|
is(counts.open, 0, "Got right number of open windows");
|
|
is(counts.winstates, 1, "Got right number of window states");
|
|
|
|
newWin = undoCloseWindow(0);
|
|
await BrowserTestUtils.waitForEvent(newWin, "load");
|
|
|
|
// Make sure we wait until this window is restored.
|
|
await BrowserTestUtils.waitForEvent(newWin.gBrowser.tabContainer,
|
|
"SSTabRestored");
|
|
|
|
newWin2 = await promiseNewWindowLoaded();
|
|
|
|
is(newWin2.gBrowser.browsers.length, 1,
|
|
"Did not restore, as undoCloseWindow() was last called");
|
|
is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1,
|
|
"Did not restore, as undoCloseWindow() was last called (2)");
|
|
|
|
counts = getBrowserWindowsCount();
|
|
is(counts.open, 2, "Got right number of open windows");
|
|
is(counts.winstates, 3, "Got right number of window states");
|
|
|
|
await BrowserTestUtils.closeWindow(newWin);
|
|
await BrowserTestUtils.closeWindow(newWin2);
|
|
|
|
counts = getBrowserWindowsCount();
|
|
is(counts.open, 0, "Got right number of open windows");
|
|
is(counts.winstates, 1, "Got right number of window states");
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Test if closing can be denied on Mac.
|
|
* @note: Mac only
|
|
*/
|
|
add_task(async function test_mac_notifications() {
|
|
if (!IS_MAC) {
|
|
return;
|
|
}
|
|
|
|
await setupTest({ denyFirst: true }, async function(newWin, obs) {
|
|
let closed = await closeWindowForRestoration(newWin);
|
|
ok(!closed, "First close attempt should be denied");
|
|
closed = await closeWindowForRestoration(newWin);
|
|
ok(closed, "Second close attempt should be granted");
|
|
|
|
// We tried closing once, and got denied. Then we tried again and
|
|
// succeeded. That means 2 close requests, and 1 close granted.
|
|
is(obs["browser-lastwindow-close-requested"], 2,
|
|
"Got expected browser-lastwindow-close-requested notifications");
|
|
is(obs["browser-lastwindow-close-granted"], 1,
|
|
"Got expected browser-lastwindow-close-granted notifications");
|
|
});
|
|
});
|