summaryrefslogtreecommitdiffstats
path: root/browser/components/customizableui/test/CustomizableUITestUtils.jsm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--browser/components/customizableui/test/CustomizableUITestUtils.jsm167
1 files changed, 167 insertions, 0 deletions
diff --git a/browser/components/customizableui/test/CustomizableUITestUtils.jsm b/browser/components/customizableui/test/CustomizableUITestUtils.jsm
new file mode 100644
index 0000000000..89c32dbe08
--- /dev/null
+++ b/browser/components/customizableui/test/CustomizableUITestUtils.jsm
@@ -0,0 +1,167 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Shared functions generally available for tests involving PanelMultiView and
+ * the CustomizableUI elements in the browser window.
+ */
+
+var EXPORTED_SYMBOLS = ["CustomizableUITestUtils"];
+
+const { Assert } = ChromeUtils.importESModule(
+ "resource://testing-common/Assert.sys.mjs"
+);
+const { BrowserTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/BrowserTestUtils.sys.mjs"
+);
+const { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+const lazy = {};
+
+ChromeUtils.defineModuleGetter(
+ lazy,
+ "CustomizableUI",
+ "resource:///modules/CustomizableUI.jsm"
+);
+
+class CustomizableUITestUtils {
+ /**
+ * Constructs an instance that operates with the specified browser window.
+ */
+ constructor(window) {
+ this.window = window;
+ this.document = window.document;
+ this.PanelUI = window.PanelUI;
+ }
+
+ /**
+ * Opens a closed PanelMultiView via the specified function while waiting for
+ * the main view with the specified ID to become fully interactive.
+ */
+ async openPanelMultiView(panel, mainView, openFn) {
+ if (panel.state == "open") {
+ // Some tests may intermittently leave the panel open. We report this, but
+ // don't fail so we don't introduce new intermittent test failures.
+ Assert.ok(
+ true,
+ "A previous test left the panel open. This should be" +
+ " fixed, but we can still do a best-effort recovery and" +
+ " assume that the requested view will be made visible."
+ );
+ await openFn();
+ return;
+ }
+
+ if (panel.state == "hiding") {
+ // There may still be tests that don't wait after invoking a command that
+ // causes the main menu panel to close. Depending on timing, the panel may
+ // or may not be fully closed when the following test runs. We handle this
+ // case gracefully so we don't risk introducing new intermittent test
+ // failures that may show up at a later time.
+ Assert.ok(
+ true,
+ "A previous test requested the panel to close but" +
+ " didn't wait for the operation to complete. While" +
+ " the test should be fixed, we can still continue."
+ );
+ } else {
+ Assert.equal(panel.state, "closed", "The panel is closed to begin with.");
+ }
+
+ let promiseShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
+ await openFn();
+ await promiseShown;
+ }
+
+ /**
+ * Closes an open PanelMultiView via the specified function while waiting for
+ * the operation to complete.
+ */
+ async hidePanelMultiView(panel, closeFn) {
+ Assert.ok(panel.state == "open", "The panel is open to begin with.");
+
+ let promiseHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
+ await closeFn();
+ await promiseHidden;
+ }
+
+ /**
+ * Opens the main menu and waits for it to become fully interactive.
+ */
+ async openMainMenu() {
+ await this.openPanelMultiView(
+ this.PanelUI.panel,
+ this.PanelUI.mainView,
+ () => this.PanelUI.show()
+ );
+ }
+
+ /**
+ * Closes the main menu and waits for the operation to complete.
+ */
+ async hideMainMenu() {
+ await this.hidePanelMultiView(this.PanelUI.panel, () =>
+ this.PanelUI.hide()
+ );
+ }
+
+ /**
+ * Add the search bar into the nav bar and verify it does not overflow.
+ *
+ * @returns {Promise}
+ * @resolves The search bar element.
+ * @rejects If search bar is not found, or overflows.
+ */
+ async addSearchBar() {
+ lazy.CustomizableUI.addWidgetToArea(
+ "search-container",
+ lazy.CustomizableUI.AREA_NAVBAR,
+ lazy.CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
+ );
+
+ // addWidgetToArea adds the search bar into the nav bar first. If the
+ // search bar overflows, OverflowableToolbar for the nav bar moves the
+ // search bar into the overflow panel in its overflow event handler
+ // asynchronously.
+ //
+ // We should first wait for the layout flush to make sure either the search
+ // bar fits into the nav bar, or overflow event gets dispatched and the
+ // overflow event handler is called.
+ await this.window.promiseDocumentFlushed(() => {});
+
+ // Check if the OverflowableToolbar is handling the overflow event.
+ let navbar = this.window.document.getElementById(
+ lazy.CustomizableUI.AREA_NAVBAR
+ );
+ await TestUtils.waitForCondition(() => {
+ return !navbar.overflowable.isHandlingOverflow();
+ });
+
+ let searchbar = this.window.document.getElementById("searchbar");
+ if (!searchbar) {
+ throw new Error("The search bar should exist.");
+ }
+
+ // If the search bar overflows, it's placed inside the overflow panel.
+ //
+ // We cannot use navbar's property to check if overflow happens, since it
+ // can be different widget than the search bar that overflows.
+ if (searchbar.closest("#widget-overflow")) {
+ throw new Error(
+ "The search bar should not overflow from the nav bar. " +
+ "This test fails if the screen resolution is small and " +
+ "the search bar overflows from the nav bar."
+ );
+ }
+
+ return searchbar;
+ }
+
+ removeSearchBar() {
+ lazy.CustomizableUI.removeWidgetFromArea("search-container");
+ }
+}