summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/AppUiTestDelegate.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/AppUiTestDelegate.jsm')
-rw-r--r--browser/components/extensions/test/AppUiTestDelegate.jsm241
1 files changed, 241 insertions, 0 deletions
diff --git a/browser/components/extensions/test/AppUiTestDelegate.jsm b/browser/components/extensions/test/AppUiTestDelegate.jsm
new file mode 100644
index 0000000000..f33669176d
--- /dev/null
+++ b/browser/components/extensions/test/AppUiTestDelegate.jsm
@@ -0,0 +1,241 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { Assert } = ChromeUtils.importESModule(
+ "resource://testing-common/Assert.sys.mjs"
+);
+const { BrowserTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/BrowserTestUtils.sys.mjs"
+);
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const lazy = {};
+
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ CustomizableUI: "resource:///modules/CustomizableUI.jsm",
+});
+
+var EXPORTED_SYMBOLS = ["AppUiTestDelegate", "AppUiTestInternals"];
+
+async function promiseAnimationFrame(window) {
+ await new Promise(resolve => window.requestAnimationFrame(resolve));
+
+ let { tm } = Services;
+ return new Promise(resolve => tm.dispatchToMainThread(resolve));
+}
+
+function makeWidgetId(id) {
+ id = id.toLowerCase();
+ return id.replace(/[^a-z0-9_-]/g, "_");
+}
+
+async function getPageActionButtonId(window, extensionId) {
+ // This would normally be set automatically on navigation, and cleared
+ // when the user types a value into the URL bar, to show and hide page
+ // identity info and icons such as page action buttons.
+ //
+ // Unfortunately, that doesn't happen automatically in browser chrome
+ // tests.
+ window.gURLBar.setPageProxyState("valid");
+
+ let { gIdentityHandler } = window.gBrowser.ownerGlobal;
+ // If the current tab is blank and the previously selected tab was an internal
+ // page, the urlbar will now be showing the internal identity box due to the
+ // setPageProxyState call above. The page action button is hidden in that
+ // case, so make sure we're not showing the internal identity box.
+ gIdentityHandler._identityBox.classList.remove("chromeUI");
+
+ await promiseAnimationFrame(window);
+
+ return window.BrowserPageActions.urlbarButtonNodeIDForActionID(
+ makeWidgetId(extensionId)
+ );
+}
+
+async function getPageActionButton(window, extensionId) {
+ let pageActionId = await getPageActionButtonId(window, extensionId);
+ return window.document.getElementById(pageActionId);
+}
+
+async function clickPageAction(window, extensionId, modifiers = {}) {
+ let pageActionId = await getPageActionButtonId(window, extensionId);
+ await BrowserTestUtils.synthesizeMouseAtCenter(
+ `#${pageActionId}`,
+ modifiers,
+ window.browsingContext
+ );
+ return new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
+}
+
+function getBrowserActionWidgetId(extensionId) {
+ return makeWidgetId(extensionId) + "-browser-action";
+}
+
+function getBrowserActionWidget(extensionId) {
+ return lazy.CustomizableUI.getWidget(getBrowserActionWidgetId(extensionId));
+}
+
+async function showBrowserAction(window, extensionId) {
+ let group = getBrowserActionWidget(extensionId);
+ let widget = group.forWindow(window);
+ if (!widget.node) {
+ return;
+ }
+
+ let navbar = window.document.getElementById("nav-bar");
+ if (group.areaType == lazy.CustomizableUI.TYPE_TOOLBAR) {
+ Assert.equal(
+ widget.overflowed,
+ navbar.hasAttribute("overflowing"),
+ "Expect widget overflow state to match toolbar"
+ );
+ } else if (group.areaType == lazy.CustomizableUI.TYPE_PANEL) {
+ if (window.gUnifiedExtensions.isEnabled) {
+ let panel = window.gUnifiedExtensions.panel;
+ let shown = BrowserTestUtils.waitForPopupEvent(panel, "shown");
+ window.gUnifiedExtensions.togglePanel();
+ await shown;
+ } else {
+ await navbar.overflowable.show();
+ }
+ }
+}
+
+async function clickBrowserAction(window, extensionId, modifiers) {
+ await promiseAnimationFrame(window);
+ await showBrowserAction(window, extensionId);
+
+ if (modifiers) {
+ let widgetId = getBrowserActionWidgetId(extensionId);
+ BrowserTestUtils.synthesizeMouseAtCenter(
+ `#${widgetId}`,
+ modifiers,
+ window.browsingContext
+ );
+ } else {
+ let widget = getBrowserActionWidget(extensionId).forWindow(window);
+ widget.node.firstElementChild.click();
+ }
+}
+
+async function promisePopupShown(popup) {
+ return new Promise(resolve => {
+ if (popup.state == "open") {
+ resolve();
+ } else {
+ let onPopupShown = event => {
+ popup.removeEventListener("popupshown", onPopupShown);
+ resolve();
+ };
+ popup.addEventListener("popupshown", onPopupShown);
+ }
+ });
+}
+
+function awaitBrowserLoaded(browser) {
+ if (
+ browser.ownerGlobal.document.readyState === "complete" &&
+ browser.currentURI.spec !== "about:blank"
+ ) {
+ return Promise.resolve();
+ }
+ return new Promise(resolve => {
+ const listener = ev => {
+ if (browser.currentURI.spec === "about:blank") {
+ return;
+ }
+ browser.removeEventListener("AppTestDelegate:load", listener);
+ resolve();
+ };
+ browser.addEventListener("AppTestDelegate:load", listener);
+ });
+}
+
+function getPanelForNode(node) {
+ return node.closest("panel");
+}
+
+async function awaitExtensionPanel(window, extensionId, awaitLoad = true) {
+ let { originalTarget: browser } = await BrowserTestUtils.waitForEvent(
+ window.document,
+ "WebExtPopupLoaded",
+ true,
+ event => event.detail.extension.id === extensionId
+ );
+
+ await Promise.all([
+ promisePopupShown(getPanelForNode(browser)),
+
+ awaitLoad && awaitBrowserLoaded(browser),
+ ]);
+
+ return browser;
+}
+
+function closeBrowserAction(window, extensionId) {
+ let group = getBrowserActionWidget(extensionId);
+
+ let node = window.document.getElementById(group.viewId);
+ lazy.CustomizableUI.hidePanelForNode(node);
+
+ return Promise.resolve();
+}
+
+function getPageActionPopup(window, extensionId) {
+ let panelId = makeWidgetId(extensionId) + "-panel";
+ return window.document.getElementById(panelId);
+}
+
+function closePageAction(window, extensionId) {
+ let node = getPageActionPopup(window, extensionId);
+ if (node) {
+ return promisePopupShown(node).then(() => {
+ node.hidePopup();
+ });
+ }
+
+ return Promise.resolve();
+}
+
+function openNewForegroundTab(window, url, waitForLoad = true) {
+ return BrowserTestUtils.openNewForegroundTab(
+ window.gBrowser,
+ url,
+ waitForLoad
+ );
+}
+
+async function removeTab(tab) {
+ BrowserTestUtils.removeTab(tab);
+}
+
+// These metods are exported so that they can be used in head.js but are
+// *not* part of the AppUiTestDelegate API.
+var AppUiTestInternals = {
+ awaitBrowserLoaded,
+ getBrowserActionWidget,
+ getBrowserActionWidgetId,
+ getPageActionButton,
+ getPageActionPopup,
+ getPanelForNode,
+ makeWidgetId,
+ promiseAnimationFrame,
+ promisePopupShown,
+ showBrowserAction,
+};
+
+// These methods are part of the TestDelegate API and need to be compatible
+// with the `mobile` AppUiTestDelegate counterpart.
+var AppUiTestDelegate = {
+ awaitExtensionPanel,
+ clickBrowserAction,
+ clickPageAction,
+ closeBrowserAction,
+ closePageAction,
+ openNewForegroundTab,
+ removeTab,
+};