diff options
Diffstat (limited to 'browser/base/content/test/general/head.js')
-rw-r--r-- | browser/base/content/test/general/head.js | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js new file mode 100644 index 0000000000..9617d592eb --- /dev/null +++ b/browser/base/content/test/general/head.js @@ -0,0 +1,367 @@ +ChromeUtils.defineModuleGetter( + this, + "AboutNewTab", + "resource:///modules/AboutNewTab.jsm" +); +ChromeUtils.defineESModuleGetters(this, { + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", +}); +ChromeUtils.defineModuleGetter( + this, + "TabCrashHandler", + "resource:///modules/ContentCrashHandlers.jsm" +); + +/** + * Wait for a <notification> to be closed then call the specified callback. + */ +function waitForNotificationClose(notification, cb) { + let observer = new MutationObserver(function onMutatations(mutations) { + for (let mutation of mutations) { + for (let i = 0; i < mutation.removedNodes.length; i++) { + let node = mutation.removedNodes.item(i); + if (node != notification) { + continue; + } + observer.disconnect(); + cb(); + } + } + }); + observer.observe(notification.control.stack, { childList: true }); +} + +function closeAllNotifications() { + if (!gNotificationBox.currentNotification) { + return Promise.resolve(); + } + + return new Promise(resolve => { + for (let notification of gNotificationBox.allNotifications) { + waitForNotificationClose(notification, function() { + if (gNotificationBox.allNotifications.length === 0) { + resolve(); + } + }); + notification.close(); + } + }); +} + +function whenDelayedStartupFinished(aWindow, aCallback) { + Services.obs.addObserver(function observer(aSubject, aTopic) { + if (aWindow == aSubject) { + Services.obs.removeObserver(observer, aTopic); + executeSoon(aCallback); + } + }, "browser-delayed-startup-finished"); +} + +function openToolbarCustomizationUI(aCallback, aBrowserWin) { + if (!aBrowserWin) { + aBrowserWin = window; + } + + aBrowserWin.gCustomizeMode.enter(); + + aBrowserWin.gNavToolbox.addEventListener( + "customizationready", + function() { + executeSoon(function() { + aCallback(aBrowserWin); + }); + }, + { once: true } + ); +} + +function closeToolbarCustomizationUI(aCallback, aBrowserWin) { + aBrowserWin.gNavToolbox.addEventListener( + "aftercustomization", + function() { + executeSoon(aCallback); + }, + { once: true } + ); + + aBrowserWin.gCustomizeMode.exit(); +} + +function waitForCondition(condition, nextTest, errorMsg, retryTimes) { + retryTimes = typeof retryTimes !== "undefined" ? retryTimes : 30; + var tries = 0; + var interval = setInterval(function() { + if (tries >= retryTimes) { + ok(false, errorMsg); + moveOn(); + } + var conditionPassed; + try { + conditionPassed = condition(); + } catch (e) { + ok(false, e + "\n" + e.stack); + conditionPassed = false; + } + if (conditionPassed) { + moveOn(); + } + tries++; + }, 100); + var moveOn = function() { + clearInterval(interval); + nextTest(); + }; +} + +function promiseWaitForCondition(aConditionFn) { + return new Promise(resolve => { + waitForCondition(aConditionFn, resolve, "Condition didn't pass."); + }); +} + +function promiseWaitForEvent( + object, + eventName, + capturing = false, + chrome = false +) { + return new Promise(resolve => { + function listener(event) { + info("Saw " + eventName); + object.removeEventListener(eventName, listener, capturing, chrome); + resolve(event); + } + + info("Waiting for " + eventName); + object.addEventListener(eventName, listener, capturing, chrome); + }); +} + +/** + * Allows setting focus on a window, and waiting for that window to achieve + * focus. + * + * @param aWindow + * The window to focus and wait for. + * + * @return {Promise} + * @resolves When the window is focused. + * @rejects Never. + */ +function promiseWaitForFocus(aWindow) { + return new Promise(resolve => { + waitForFocus(resolve, aWindow); + }); +} + +function pushPrefs(...aPrefs) { + return SpecialPowers.pushPrefEnv({ set: aPrefs }); +} + +function popPrefs() { + return SpecialPowers.popPrefEnv(); +} + +function promiseWindowClosed(win) { + let promise = BrowserTestUtils.domWindowClosed(win); + win.close(); + return promise; +} + +function promiseOpenAndLoadWindow(aOptions, aWaitForDelayedStartup = false) { + return new Promise(resolve => { + let win = OpenBrowserWindow(aOptions); + if (aWaitForDelayedStartup) { + Services.obs.addObserver(function onDS(aSubject, aTopic, aData) { + if (aSubject != win) { + return; + } + Services.obs.removeObserver(onDS, "browser-delayed-startup-finished"); + resolve(win); + }, "browser-delayed-startup-finished"); + } else { + win.addEventListener( + "load", + function() { + resolve(win); + }, + { once: true } + ); + } + }); +} + +async function whenNewTabLoaded(aWindow, aCallback) { + aWindow.BrowserOpenTab(); + + let expectedURL = AboutNewTab.newTabURL; + let browser = aWindow.gBrowser.selectedBrowser; + let loadPromise = BrowserTestUtils.browserLoaded(browser, false, expectedURL); + let alreadyLoaded = await SpecialPowers.spawn(browser, [expectedURL], url => { + let doc = content.document; + return doc && doc.readyState === "complete" && doc.location.href == url; + }); + if (!alreadyLoaded) { + await loadPromise; + } + aCallback(); +} + +function whenTabLoaded(aTab, aCallback) { + promiseTabLoadEvent(aTab).then(aCallback); +} + +function promiseTabLoaded(aTab) { + return new Promise(resolve => { + whenTabLoaded(aTab, resolve); + }); +} + +/** + * Waits for a load (or custom) event to finish in a given tab. If provided + * load an uri into the tab. + * + * @param tab + * The tab to load into. + * @param [optional] url + * The url to load, or the current url. + * @return {Promise} resolved when the event is handled. + * @resolves to the received event + * @rejects if a valid load event is not received within a meaningful interval + */ +function promiseTabLoadEvent(tab, url) { + info("Wait tab event: load"); + + function handle(loadedUrl) { + if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) { + info(`Skipping spurious load event for ${loadedUrl}`); + return false; + } + + info("Tab event received: load"); + return true; + } + + let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle); + + if (url) { + BrowserTestUtils.loadURI(tab.linkedBrowser, url); + } + + return loaded; +} + +/** + * Returns a Promise that resolves once a new tab has been opened in + * a xul:tabbrowser. + * + * @param aTabBrowser + * The xul:tabbrowser to monitor for a new tab. + * @return {Promise} + * Resolved when the new tab has been opened. + * @resolves to the TabOpen event that was fired. + * @rejects Never. + */ +function waitForNewTabEvent(aTabBrowser) { + return BrowserTestUtils.waitForEvent(aTabBrowser.tabContainer, "TabOpen"); +} + +function is_hidden(element) { + var style = element.ownerGlobal.getComputedStyle(element); + if (style.display == "none") { + return true; + } + if (style.visibility != "visible") { + return true; + } + if (XULPopupElement.isInstance(element)) { + return ["hiding", "closed"].includes(element.state); + } + + // Hiding a parent element will hide all its children + if (element.parentNode != element.ownerDocument) { + return is_hidden(element.parentNode); + } + + return false; +} + +function is_element_visible(element, msg) { + isnot(element, null, "Element should not be null, when checking visibility"); + ok(BrowserTestUtils.is_visible(element), msg || "Element should be visible"); +} + +function is_element_hidden(element, msg) { + isnot(element, null, "Element should not be null, when checking visibility"); + ok(is_hidden(element), msg || "Element should be hidden"); +} + +function promisePopupShown(popup) { + return BrowserTestUtils.waitForPopupEvent(popup, "shown"); +} + +function promisePopupHidden(popup) { + return BrowserTestUtils.waitForPopupEvent(popup, "hidden"); +} + +function promiseNotificationShown(notification) { + let win = notification.browser.ownerGlobal; + if (win.PopupNotifications.panel.state == "open") { + return Promise.resolve(); + } + let panelPromise = promisePopupShown(win.PopupNotifications.panel); + notification.reshow(); + return panelPromise; +} + +/** + * Resolves when a bookmark with the given uri is added. + */ +function promiseOnBookmarkItemAdded(aExpectedURI) { + return new Promise((resolve, reject) => { + let listener = events => { + is(events.length, 1, "Should only receive one event."); + info("Added a bookmark to " + events[0].url); + PlacesUtils.observers.removeListener(["bookmark-added"], listener); + if (events[0].url == aExpectedURI.spec) { + resolve(); + } else { + reject(new Error("Added an unexpected bookmark")); + } + }; + info("Waiting for a bookmark to be added"); + PlacesUtils.observers.addListener(["bookmark-added"], listener); + }); +} + +async function loadBadCertPage(url) { + let loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + await loaded; + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { + content.document.getElementById("exceptionDialogButton").click(); + }); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); +} + +/** + * Waits for the stylesheets to be loaded into the browser menu. + * + * @param tab + * The tab that contains the webpage we're testing. + * @param styleSheetCount + * How many stylesheets we expect to be loaded. + * @return Promise + */ +async function promiseStylesheetsLoaded(tab, styleSheetCount) { + let styleMenu = tab.ownerGlobal.gPageStyleMenu; + let permanentKey = tab.permanentKey; + + await TestUtils.waitForCondition(() => { + let menu = styleMenu._pageStyleSheets.get(permanentKey); + info(`waiting for sheets: ${menu && menu.filteredStyleSheets.length}`); + return menu && menu.filteredStyleSheets.length >= styleSheetCount; + }, "waiting for style sheets to load"); +} |