tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CustomizableUITestUtils.sys.mjs (5354B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 /**
      5 * Shared functions generally available for tests involving PanelMultiView and
      6 * the CustomizableUI elements in the browser window.
      7 */
      8 
      9 import { Assert } from "resource://testing-common/Assert.sys.mjs";
     10 
     11 import { BrowserTestUtils } from "resource://testing-common/BrowserTestUtils.sys.mjs";
     12 import { TestUtils } from "resource://testing-common/TestUtils.sys.mjs";
     13 
     14 const lazy = {};
     15 
     16 ChromeUtils.defineESModuleGetters(lazy, {
     17  CustomizableUI:
     18    "moz-src:///browser/components/customizableui/CustomizableUI.sys.mjs",
     19 });
     20 
     21 export class CustomizableUITestUtils {
     22  /**
     23   * Constructs an instance that operates with the specified browser window.
     24   */
     25  constructor(window) {
     26    this.window = window;
     27    this.document = window.document;
     28    this.PanelUI = window.PanelUI;
     29  }
     30 
     31  /**
     32   * Opens a closed PanelMultiView via the specified function while waiting for
     33   * the main view with the specified ID to become fully interactive.
     34   */
     35  async openPanelMultiView(panel, mainView, openFn) {
     36    if (panel.state == "open") {
     37      // Some tests may intermittently leave the panel open. We report this, but
     38      // don't fail so we don't introduce new intermittent test failures.
     39      Assert.ok(
     40        true,
     41        "A previous test left the panel open. This should be" +
     42          " fixed, but we can still do a best-effort recovery and" +
     43          " assume that the requested view will be made visible."
     44      );
     45      await openFn();
     46      return;
     47    }
     48 
     49    if (panel.state == "hiding") {
     50      // There may still be tests that don't wait after invoking a command that
     51      // causes the main menu panel to close. Depending on timing, the panel may
     52      // or may not be fully closed when the following test runs. We handle this
     53      // case gracefully so we don't risk introducing new intermittent test
     54      // failures that may show up at a later time.
     55      Assert.ok(
     56        true,
     57        "A previous test requested the panel to close but" +
     58          " didn't wait for the operation to complete. While" +
     59          " the test should be fixed, we can still continue."
     60      );
     61    } else {
     62      Assert.equal(panel.state, "closed", "The panel is closed to begin with.");
     63    }
     64 
     65    let promiseShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
     66    await openFn();
     67    await promiseShown;
     68  }
     69 
     70  /**
     71   * Closes an open PanelMultiView via the specified function while waiting for
     72   * the operation to complete.
     73   */
     74  async hidePanelMultiView(panel, closeFn) {
     75    Assert.ok(panel.state == "open", "The panel is open to begin with.");
     76 
     77    let promiseHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
     78    await closeFn();
     79    await promiseHidden;
     80  }
     81 
     82  /**
     83   * Opens the main menu and waits for it to become fully interactive.
     84   */
     85  async openMainMenu() {
     86    await this.openPanelMultiView(
     87      this.PanelUI.panel,
     88      this.PanelUI.mainView,
     89      () => this.PanelUI.show()
     90    );
     91  }
     92 
     93  /**
     94   * Closes the main menu and waits for the operation to complete.
     95   */
     96  async hideMainMenu() {
     97    await this.hidePanelMultiView(this.PanelUI.panel, () =>
     98      this.PanelUI.hide()
     99    );
    100  }
    101 
    102  /**
    103   * Add the search bar into the nav bar and verify it does not overflow.
    104   *
    105   * @returns {Promise}
    106   * @resolves The search bar element.
    107   * @rejects If search bar is not found, or overflows.
    108   */
    109  async addSearchBar() {
    110    lazy.CustomizableUI.addWidgetToArea(
    111      "search-container",
    112      lazy.CustomizableUI.AREA_NAVBAR,
    113      lazy.CustomizableUI.getPlacementOfWidget("urlbar-container").position + 1
    114    );
    115 
    116    // addWidgetToArea adds the search bar into the nav bar first.  If the
    117    // search bar overflows, OverflowableToolbar for the nav bar moves the
    118    // search bar into the overflow panel in its overflow event handler
    119    // asynchronously.
    120    //
    121    // We should first wait for the layout flush to make sure either the search
    122    // bar fits into the nav bar, or overflow event gets dispatched and the
    123    // overflow event handler is called.
    124    await this.window.promiseDocumentFlushed(() => {});
    125 
    126    // Check if the OverflowableToolbar is handling the overflow event.
    127    let navbar = this.window.document.getElementById(
    128      lazy.CustomizableUI.AREA_NAVBAR
    129    );
    130    await TestUtils.waitForCondition(() => {
    131      return !navbar.overflowable.isHandlingOverflow();
    132    });
    133 
    134    let searchbar = this.window.document.getElementById(
    135      Services.prefs.getBoolPref("browser.search.widget.new")
    136        ? "searchbar-new"
    137        : "searchbar"
    138    );
    139    if (!searchbar) {
    140      throw new Error("The search bar should exist.");
    141    }
    142 
    143    // If the search bar overflows, it's placed inside the overflow panel.
    144    //
    145    // We cannot use navbar's property to check if overflow happens, since it
    146    // can be different widget than the search bar that overflows.
    147    if (searchbar.closest("#widget-overflow")) {
    148      throw new Error(
    149        "The search bar should not overflow from the nav bar. " +
    150          "This test fails if the screen resolution is small and " +
    151          "the search bar overflows from the nav bar."
    152      );
    153    }
    154 
    155    return searchbar;
    156  }
    157 
    158  removeSearchBar() {
    159    lazy.CustomizableUI.removeWidgetFromArea("search-container");
    160  }
    161 }