tor-browser

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

browser_alt_keyup_in_content.js (11793B)


      1 "use strict";
      2 
      3 add_task(async function runTests() {
      4  const menubar = document.getElementById("toolbar-menubar");
      5  const autohide = menubar.getAttribute("autohide");
      6  // This test requires that the window is active because of the limitation of
      7  // menubar.  Therefore, we should abort if the window becomes inactive during
      8  // the tests.
      9  let runningTests = true;
     10  function onWindowActive(aEvent) {
     11    // Don't warn after timed out.
     12    if (runningTests && aEvent.target === window) {
     13      info(
     14        "WARNING: This window shouldn't have been inactivated during tests, but received an activated event!"
     15      );
     16    }
     17  }
     18  function onWindowInactive(aEvent) {
     19    // Don't warn after timed out.
     20    if (runningTests && aEvent.target === window) {
     21      info(
     22        "WARNING: This window should be active during tests, but inactivated!"
     23      );
     24      window.focus();
     25    }
     26  }
     27  let menubarActivated = false;
     28  function onMenubarActive() {
     29    menubarActivated = true;
     30  }
     31  // In this test, menu popups shouldn't be open, but this helps avoiding
     32  // intermittent failure after inactivating the menubar.
     33  let popupEvents = 0;
     34  function getPopupInfo(aPopupEventTarget) {
     35    return `<${
     36      aPopupEventTarget.nodeName
     37    }${aPopupEventTarget.getAttribute("id") !== null ? ` id="${aPopupEventTarget.getAttribute("id")}"` : ""}>`;
     38  }
     39  function onPopupShown(aEvent) {
     40    // Don't warn after timed out.
     41    if (!runningTests) {
     42      return;
     43    }
     44    popupEvents++;
     45    info(
     46      `A popup (${getPopupInfo(
     47        aEvent.target
     48      )}) is shown (visible popups: ${popupEvents})`
     49    );
     50  }
     51  function onPopupHidden(aEvent) {
     52    // Don't warn after timed out.
     53    if (!runningTests) {
     54      return;
     55    }
     56    if (popupEvents === 0) {
     57      info(
     58        `WARNING: There are some unexpected popups which may be not cleaned up by the previous test (${getPopupInfo(
     59          aEvent.target
     60        )})`
     61      );
     62      return;
     63    }
     64    popupEvents--;
     65    info(
     66      `A popup (${getPopupInfo(
     67        aEvent.target
     68      )}) is hidden (visible popups: ${popupEvents})`
     69    );
     70  }
     71  try {
     72    Services.prefs.setBoolPref("ui.key.menuAccessKeyFocuses", true);
     73    // If this fails, you need to replace "KEY_Alt" with a variable whose
     74    // value is considered from the pref.
     75    is(
     76      Services.prefs.getIntPref("ui.key.menuAccessKey"),
     77      18,
     78      "This test assumes that Alt key activates the menubar"
     79    );
     80    window.addEventListener("activate", onWindowActive);
     81    window.addEventListener("deactivate", onWindowInactive);
     82    window.addEventListener("popupshown", onPopupShown);
     83    window.addEventListener("popuphidden", onPopupHidden);
     84    menubar.addEventListener("DOMMenuBarActive", onMenubarActive);
     85    async function doTest(aTest) {
     86      await new Promise(resolve => {
     87        if (Services.focus.activeWindow === window) {
     88          resolve();
     89          return;
     90        }
     91        info(
     92          `${aTest.description}: The testing window is inactive, trying to activate it...`
     93        );
     94        Services.focus.focusedWindow = window;
     95        TestUtils.waitForCondition(() => {
     96          if (Services.focus.activeWindow === window) {
     97            resolve();
     98            return true;
     99          }
    100          Services.focus.focusedWindow = window;
    101          return false;
    102        }, `${aTest.description}: Waiting the window is activated`);
    103      });
    104      let startTime = ChromeUtils.now();
    105      info(`Start to test: ${aTest.description}...`);
    106 
    107      async function ensureMenubarInactive() {
    108        if (!menubar.querySelector("[_moz-menuactive=true]")) {
    109          return;
    110        }
    111        info(`${aTest.description}: Inactivating the menubar...`);
    112        let waitForMenuBarInactive = BrowserTestUtils.waitForEvent(
    113          menubar,
    114          "DOMMenuBarInactive"
    115        );
    116        EventUtils.synthesizeKey("KEY_Escape", {}, window);
    117        await waitForMenuBarInactive;
    118        await TestUtils.waitForCondition(() => {
    119          return popupEvents === 0;
    120        }, `${aTest.description}: Waiting for closing all popups`);
    121      }
    122 
    123      try {
    124        await BrowserTestUtils.withNewTab(
    125          {
    126            gBrowser,
    127            url: aTest.url,
    128          },
    129          async browser => {
    130            info(`${aTest.description}: Waiting browser getting focus...`);
    131            await SimpleTest.promiseFocus(browser);
    132            await ensureMenubarInactive();
    133            menubarActivated = false;
    134 
    135            let keyupEventFiredInContent = false;
    136            BrowserTestUtils.addContentEventListener(
    137              browser,
    138              "keyup",
    139              () => {
    140                keyupEventFiredInContent = true;
    141              },
    142              { capture: true },
    143              event => {
    144                return event.key === "Alt";
    145              }
    146            );
    147 
    148            // For making sure adding the above content event listener and
    149            // it'll get `keyup` event, let's run `SpecialPowers.spawn` and
    150            // wait for focus in the content process.
    151            info(
    152              `${aTest.description}: Waiting content process getting focus...`
    153            );
    154            await SpecialPowers.spawn(
    155              browser,
    156              [aTest.description],
    157              async aTestDescription => {
    158                await ContentTaskUtils.waitForCondition(() => {
    159                  if (
    160                    content.browsingContext.isActive &&
    161                    content.document.hasFocus()
    162                  ) {
    163                    return true;
    164                  }
    165                  content.window.focus();
    166                  return false;
    167                }, `${aTestDescription}: Waiting for content gets focus in content process`);
    168              }
    169            );
    170 
    171            let waitForAllKeyUpEventsInChrome = new Promise(resolve => {
    172              // Wait 2 `keyup` events in the main process.  First one is
    173              // synthesized one.  The other is replay event from content.
    174              let firstKeyUpEvent;
    175              window.addEventListener(
    176                "keyup",
    177                function onKeyUpInChrome(event) {
    178                  if (!firstKeyUpEvent) {
    179                    firstKeyUpEvent = event;
    180                    return;
    181                  }
    182                  window.removeEventListener("keyup", onKeyUpInChrome, {
    183                    capture: true,
    184                  });
    185                  resolve();
    186                },
    187                { capture: true }
    188              );
    189            });
    190 
    191            let menubarActivatedPromise;
    192            if (aTest.expectMenubarActive) {
    193              menubarActivatedPromise = BrowserTestUtils.waitForEvent(
    194                menubar,
    195                "DOMMenuBarActive"
    196              );
    197            }
    198 
    199            EventUtils.synthesizeKey("KEY_Alt", {}, window);
    200            info(
    201              `${aTest.description}: Waiting keyup events of Alt in chrome...`
    202            );
    203            await waitForAllKeyUpEventsInChrome;
    204            info(`${aTest.description}: Waiting keyup event in content...`);
    205            try {
    206              await TestUtils.waitForCondition(() => {
    207                return keyupEventFiredInContent;
    208              }, `${aTest.description}: Waiting for content gets focus in chrome process`);
    209            } catch (ex) {
    210              ok(
    211                false,
    212                `${aTest.description}: Failed to synthesize Alt key press in the content process`
    213              );
    214              return;
    215            }
    216 
    217            if (aTest.expectMenubarActive) {
    218              await menubarActivatedPromise;
    219              ok(
    220                menubarActivated,
    221                `${aTest.description}: Menubar should've been activated by the synthesized Alt key press`
    222              );
    223            } else {
    224              // Wait some ticks to verify not receiving "DOMMenuBarActive" event.
    225              // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    226              await new Promise(resolve => setTimeout(resolve, 500));
    227              ok(
    228                !menubarActivated,
    229                `${aTest.description}: Menubar should not have been activated by the synthesized Alt key press`
    230              );
    231            }
    232          }
    233        );
    234      } catch (ex) {
    235        ok(
    236          false,
    237          `${aTest.description}: Thrown an exception: ${ex.toString()}`
    238        );
    239      } finally {
    240        await ensureMenubarInactive();
    241        info(`End testing: ${aTest.description}`);
    242        ChromeUtils.addProfilerMarker(
    243          "browser-test",
    244          { startTime, category: "Test" },
    245          aTest.description
    246        );
    247      }
    248    }
    249 
    250    // Testcases for users who use collapsible menubar (by default)
    251    menubar.setAttribute("autohide", "true");
    252    await doTest({
    253      description: "Testing menubar is shown by Alt keyup",
    254      url: "data:text/html;charset=utf-8,<p>static page</p>",
    255      expectMenubarActive: true,
    256    });
    257    await doTest({
    258      description:
    259        "Testing menubar is shown by Alt keyup when an <input> has focus",
    260      url:
    261        "data:text/html;charset=utf-8,<input>" +
    262        '<script>document.querySelector("input").focus()</script>',
    263      expectMenubarActive: true,
    264    });
    265    await doTest({
    266      description:
    267        "Testing menubar is shown by Alt keyup when an editing host has focus",
    268      url:
    269        "data:text/html;charset=utf-8,<p contenteditable></p>" +
    270        '<script>document.querySelector("p[contenteditable]").focus()</script>',
    271      expectMenubarActive: true,
    272    });
    273    await doTest({
    274      description:
    275        "Testing menubar won't be shown by Alt keyup due to suppressed by the page",
    276      url:
    277        "data:text/html;charset=utf-8,<p>dynamic page</p>" +
    278        '<script>window.addEventListener("keyup", event => { event.preventDefault(); })</script>',
    279      expectMenubarActive: false,
    280    });
    281 
    282    // Testcases for users who always show the menubar.
    283    menubar.setAttribute("autohide", "false");
    284    await doTest({
    285      description: "Testing menubar is activated by Alt keyup",
    286      url: "data:text/html;charset=utf-8,<p>static page</p>",
    287      expectMenubarActive: true,
    288    });
    289    await doTest({
    290      description:
    291        "Testing menubar is activated by Alt keyup when an <input> has focus",
    292      url:
    293        "data:text/html;charset=utf-8,<input>" +
    294        '<script>document.querySelector("input").focus()</script>',
    295      expectMenubarActive: true,
    296    });
    297    await doTest({
    298      description:
    299        "Testing menubar is activated by Alt keyup when an editing host has focus",
    300      url:
    301        "data:text/html;charset=utf-8,<p contenteditable></p>" +
    302        '<script>document.querySelector("p[contenteditable]").focus()</script>',
    303      expectMenubarActive: true,
    304    });
    305    await doTest({
    306      description:
    307        "Testing menubar won't be activated by Alt keyup due to suppressed by the page",
    308      url:
    309        "data:text/html;charset=utf-8,<p>dynamic page</p>" +
    310        '<script>window.addEventListener("keyup", event => { event.preventDefault(); })</script>',
    311      expectMenubarActive: false,
    312    });
    313    runningTests = false;
    314  } catch (ex) {
    315    ok(
    316      false,
    317      `Aborting this test due to unexpected the exception (${ex.toString()})`
    318    );
    319    runningTests = false;
    320  } finally {
    321    if (autohide !== null) {
    322      menubar.setAttribute("autohide", autohide);
    323    } else {
    324      menubar.removeAttribute("autohide");
    325    }
    326    Services.prefs.clearUserPref("ui.key.menuAccessKeyFocuses");
    327    menubar.removeEventListener("DOMMenuBarActive", onMenubarActive);
    328    window.removeEventListener("activate", onWindowActive);
    329    window.removeEventListener("deactivate", onWindowInactive);
    330    window.removeEventListener("popupshown", onPopupShown);
    331    window.removeEventListener("popuphidden", onPopupHidden);
    332  }
    333 });