michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: Cu.import("resource://gre/modules/Promise.jsm"); michael@0: michael@0: function waitForCondition(condition, nextTest, errorMsg) { michael@0: var tries = 0; michael@0: var interval = setInterval(function() { michael@0: if (tries >= 30) { michael@0: ok(false, errorMsg); michael@0: moveOn(); michael@0: } michael@0: var conditionPassed; michael@0: try { michael@0: conditionPassed = condition(); michael@0: } catch (e) { michael@0: ok(false, e + "\n" + e.stack); michael@0: conditionPassed = false; michael@0: } michael@0: if (conditionPassed) { michael@0: moveOn(); michael@0: } michael@0: tries++; michael@0: }, 100); michael@0: var moveOn = function() { clearInterval(interval); nextTest(); }; michael@0: } michael@0: michael@0: function is_hidden(element) { michael@0: var style = element.ownerDocument.defaultView.getComputedStyle(element, ""); michael@0: if (style.display == "none") michael@0: return true; michael@0: if (style.visibility != "visible") michael@0: return true; michael@0: if (style.display == "-moz-popup") michael@0: return ["hiding","closed"].indexOf(element.state) != -1; michael@0: michael@0: // Hiding a parent element will hide all its children michael@0: if (element.parentNode != element.ownerDocument) michael@0: return is_hidden(element.parentNode); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: function is_element_visible(element, msg) { michael@0: isnot(element, null, "Element should not be null, when checking visibility"); michael@0: ok(!is_hidden(element), msg); michael@0: } michael@0: michael@0: function waitForElementToBeVisible(element, nextTest, msg) { michael@0: waitForCondition(() => !is_hidden(element), michael@0: () => { michael@0: ok(true, msg); michael@0: nextTest(); michael@0: }, michael@0: "Timeout waiting for visibility: " + msg); michael@0: } michael@0: michael@0: function waitForElementToBeHidden(element, nextTest, msg) { michael@0: waitForCondition(() => is_hidden(element), michael@0: () => { michael@0: ok(true, msg); michael@0: nextTest(); michael@0: }, michael@0: "Timeout waiting for invisibility: " + msg); michael@0: } michael@0: michael@0: function waitForPopupAtAnchor(popup, anchorNode, nextTest, msg) { michael@0: waitForCondition(() => popup.popupBoxObject.anchorNode == anchorNode, michael@0: () => { michael@0: ok(true, msg); michael@0: is_element_visible(popup, "Popup should be visible"); michael@0: nextTest(); michael@0: }, michael@0: "Timeout waiting for popup at anchor: " + msg); michael@0: } michael@0: michael@0: function promisePanelShown(win) { michael@0: let panelEl = win.PanelUI.panel; michael@0: return promisePanelElementShown(win, panelEl); michael@0: } michael@0: michael@0: function promisePanelElementShown(win, aPanel) { michael@0: let deferred = Promise.defer(); michael@0: let timeoutId = win.setTimeout(() => { michael@0: deferred.reject("Panel did not show within 5 seconds."); michael@0: }, 5000); michael@0: aPanel.addEventListener("popupshown", function onPanelOpen(e) { michael@0: aPanel.removeEventListener("popupshown", onPanelOpen); michael@0: win.clearTimeout(timeoutId); michael@0: deferred.resolve(); michael@0: }); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function is_element_hidden(element, msg) { michael@0: isnot(element, null, "Element should not be null, when checking visibility"); michael@0: ok(is_hidden(element), msg); michael@0: } michael@0: michael@0: function loadUITourTestPage(callback, host = "https://example.com/") { michael@0: if (gTestTab) michael@0: gBrowser.removeTab(gTestTab); michael@0: michael@0: let url = getRootDirectory(gTestPath) + "uitour.html"; michael@0: url = url.replace("chrome://mochitests/content/", host); michael@0: michael@0: gTestTab = gBrowser.addTab(url); michael@0: gBrowser.selectedTab = gTestTab; michael@0: michael@0: gTestTab.linkedBrowser.addEventListener("load", function onLoad() { michael@0: gTestTab.linkedBrowser.removeEventListener("load", onLoad, true); michael@0: michael@0: gContentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView); michael@0: gContentAPI = gContentWindow.Mozilla.UITour; michael@0: michael@0: waitForFocus(callback, gContentWindow); michael@0: }, true); michael@0: } michael@0: michael@0: function UITourTest() { michael@0: Services.prefs.setBoolPref("browser.uitour.enabled", true); michael@0: let testUri = Services.io.newURI("http://example.com", null, null); michael@0: Services.perms.add(testUri, "uitour", Services.perms.ALLOW_ACTION); michael@0: michael@0: waitForExplicitFinish(); michael@0: michael@0: registerCleanupFunction(function() { michael@0: delete window.UITour; michael@0: delete window.gContentWindow; michael@0: delete window.gContentAPI; michael@0: if (gTestTab) michael@0: gBrowser.removeTab(gTestTab); michael@0: delete window.gTestTab; michael@0: Services.prefs.clearUserPref("browser.uitour.enabled", true); michael@0: Services.perms.remove("example.com", "uitour"); michael@0: }); michael@0: michael@0: function done() { michael@0: executeSoon(() => { michael@0: if (gTestTab) michael@0: gBrowser.removeTab(gTestTab); michael@0: gTestTab = null; michael@0: michael@0: let highlight = document.getElementById("UITourHighlightContainer"); michael@0: is_element_hidden(highlight, "Highlight should be closed/hidden after UITour tab is closed"); michael@0: michael@0: let tooltip = document.getElementById("UITourTooltip"); michael@0: is_element_hidden(tooltip, "Tooltip should be closed/hidden after UITour tab is closed"); michael@0: michael@0: ok(!PanelUI.panel.hasAttribute("noautohide"), "@noautohide on the menu panel should have been cleaned up"); michael@0: ok(!PanelUI.panel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen"); michael@0: isnot(PanelUI.panel.state, "open", "The panel shouldn't be open"); michael@0: is(document.getElementById("PanelUI-menu-button").hasAttribute("open"), false, "Menu button should know that the menu is closed"); michael@0: michael@0: is(UITour.pinnedTabs.get(window), null, "Any pinned tab should be closed after UITour tab is closed"); michael@0: michael@0: executeSoon(nextTest); michael@0: }); michael@0: } michael@0: michael@0: function nextTest() { michael@0: if (tests.length == 0) { michael@0: finish(); michael@0: return; michael@0: } michael@0: let test = tests.shift(); michael@0: info("Starting " + test.name); michael@0: waitForFocus(function() { michael@0: loadUITourTestPage(function() { michael@0: test(done); michael@0: }); michael@0: }); michael@0: } michael@0: nextTest(); michael@0: }