tor-browser

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

browser_app.js (12282B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const { UrlbarTestUtils } = ChromeUtils.importESModule(
      8  "resource://testing-common/UrlbarTestUtils.sys.mjs"
      9 );
     10 /* import-globals-from ../../mochitest/role.js */
     11 /* import-globals-from ../../mochitest/states.js */
     12 loadScripts(
     13  { name: "role.js", dir: MOCHITESTS_DIR },
     14  { name: "states.js", dir: MOCHITESTS_DIR }
     15 );
     16 
     17 function getMacAccessible(accOrElmOrID) {
     18  return new Promise(resolve => {
     19    let intervalId = setInterval(() => {
     20      let acc = getAccessible(accOrElmOrID);
     21      if (acc) {
     22        clearInterval(intervalId);
     23        resolve(
     24          acc.nativeInterface.QueryInterface(Ci.nsIAccessibleMacInterface)
     25        );
     26      }
     27    }, 10);
     28  });
     29 }
     30 
     31 add_setup(async function () {
     32  await SpecialPowers.pushPrefEnv({
     33    set: [["browser.urlbar.trustPanel.featureGate", false]],
     34  });
     35 });
     36 
     37 /**
     38 * Test a11yUtils announcements are exposed to VO
     39 */
     40 add_task(async () => {
     41  const tab = await BrowserTestUtils.openNewForegroundTab(
     42    gBrowser,
     43    "data:text/html,"
     44  );
     45  const alert = document.getElementById("a11y-announcement");
     46  ok(alert, "Found alert to send announcements");
     47 
     48  const alerted = waitForMacEvent("AXAnnouncementRequested", (iface, data) => {
     49    return data.AXAnnouncementKey == "hello world";
     50  });
     51 
     52  A11yUtils.announce({
     53    raw: "hello world",
     54  });
     55  await alerted;
     56  await BrowserTestUtils.removeTab(tab);
     57 });
     58 
     59 /**
     60 * Test browser tabs
     61 */
     62 add_task(async () => {
     63  let newTabs = await Promise.all([
     64    BrowserTestUtils.openNewForegroundTab(
     65      gBrowser,
     66      "data:text/html,<title>Two</title>"
     67    ),
     68    BrowserTestUtils.openNewForegroundTab(
     69      gBrowser,
     70      "data:text/html,<title>Three</title>"
     71    ),
     72    BrowserTestUtils.openNewForegroundTab(
     73      gBrowser,
     74      "data:text/html,<title>Four</title>"
     75    ),
     76  ]);
     77 
     78  // Mochitests spawn with a tab, and we've opened 3 more for a total of 4 tabs
     79  is(gBrowser.tabs.length, 4, "We now have 4 open tabs");
     80 
     81  let tablist = await getMacAccessible("tabbrowser-tabs");
     82  is(
     83    tablist.getAttributeValue("AXRole"),
     84    "AXTabGroup",
     85    "Correct role for tablist"
     86  );
     87 
     88  let tabMacAccs = tablist.getAttributeValue("AXTabs");
     89  is(tabMacAccs.length, 4, "4 items in AXTabs");
     90 
     91  let selectedTabs = tablist.getAttributeValue("AXSelectedChildren");
     92  is(selectedTabs.length, 1, "one selected tab");
     93 
     94  let tab = selectedTabs[0];
     95  is(tab.getAttributeValue("AXRole"), "AXRadioButton", "Correct role for tab");
     96  is(
     97    tab.getAttributeValue("AXSubrole"),
     98    "AXTabButton",
     99    "Correct subrole for tab"
    100  );
    101  is(tab.getAttributeValue("AXTitle"), "Four", "Correct title for tab");
    102 
    103  let tabToSelect = tabMacAccs[2];
    104  is(
    105    tabToSelect.getAttributeValue("AXTitle"),
    106    "Three",
    107    "Correct title for tab"
    108  );
    109 
    110  let actions = tabToSelect.actionNames;
    111  ok(true, actions);
    112  ok(actions.includes("AXPress"), "Has switch action");
    113 
    114  // When tab is clicked selection of tab group changes,
    115  // and focus goes to the web area. Wait for both.
    116  let evt = Promise.all([
    117    waitForMacEvent("AXSelectedChildrenChanged"),
    118    waitForMacEvent(
    119      "AXFocusedUIElementChanged",
    120      iface => iface.getAttributeValue("AXRole") == "AXWebArea"
    121    ),
    122  ]);
    123  tabToSelect.performAction("AXPress");
    124  await evt;
    125 
    126  selectedTabs = tablist.getAttributeValue("AXSelectedChildren");
    127  is(selectedTabs.length, 1, "one selected tab");
    128  is(
    129    selectedTabs[0].getAttributeValue("AXTitle"),
    130    "Three",
    131    "Correct title for tab"
    132  );
    133 
    134  // Close all open tabs
    135  await Promise.all(newTabs.map(t => BrowserTestUtils.removeTab(t)));
    136 });
    137 
    138 /**
    139 * Test ignored invisible items in root
    140 */
    141 add_task(async () => {
    142  await BrowserTestUtils.withNewTab(
    143    {
    144      gBrowser,
    145      url: "about:license",
    146    },
    147    async () => {
    148      let root = await getMacAccessible(document);
    149      let rootChildCount = () => root.getAttributeValue("AXChildren").length;
    150 
    151      // With no popups, the root accessible has 5 visible children:
    152      // 1. Tab bar (#TabsToolbar)
    153      // 2. Navigation bar (#nav-bar)
    154      // 3. Notifications toolbar (#notifications-toolbar)
    155      // 4. Content area (#tabbrowser-tabpanels)
    156      // 5. Accessibility announcements dialog (#a11y-announcement)
    157      let baseRootChildCount = 5;
    158      is(
    159        rootChildCount(),
    160        baseRootChildCount,
    161        `Root with no popups has ${baseRootChildCount} children`
    162      );
    163 
    164      // Open a context menu
    165      const menu = document.getElementById("contentAreaContextMenu");
    166      if (
    167        Services.prefs.getBoolPref("widget.macos.native-context-menus", false)
    168      ) {
    169        // Native context menu - do not expect accessibility notifications.
    170        let popupshown = BrowserTestUtils.waitForPopupEvent(menu, "shown");
    171        EventUtils.synthesizeMouseAtCenter(document.body, {
    172          type: "contextmenu",
    173        });
    174        await popupshown;
    175 
    176        is(
    177          rootChildCount(),
    178          baseRootChildCount,
    179          "Native context menus do not show up in the root children"
    180        );
    181 
    182        // Close context menu
    183        let popuphidden = BrowserTestUtils.waitForPopupEvent(menu, "hidden");
    184        menu.hidePopup();
    185        await popuphidden;
    186      } else {
    187        // Non-native menu
    188        EventUtils.synthesizeMouseAtCenter(document.body, {
    189          type: "contextmenu",
    190        });
    191        await waitForMacEvent("AXMenuOpened");
    192 
    193        // Now root has 1 more child
    194        is(rootChildCount(), baseRootChildCount + 1, "Root has 1 more child");
    195 
    196        // Close context menu
    197        let closed = waitForMacEvent("AXMenuClosed", "contentAreaContextMenu");
    198        EventUtils.synthesizeKey("KEY_Escape");
    199        await BrowserTestUtils.waitForPopupEvent(menu, "hidden");
    200        await closed;
    201      }
    202 
    203      // We're back to base child count
    204      is(rootChildCount(), baseRootChildCount, "Root has original child count");
    205 
    206      // Open site identity popup
    207      document.getElementById("identity-icon-box").click();
    208      const identityPopup = document.getElementById("identity-popup");
    209      await BrowserTestUtils.waitForPopupEvent(identityPopup, "shown");
    210 
    211      // Now root has another child
    212      is(rootChildCount(), baseRootChildCount + 1, "Root has another child");
    213 
    214      // Close popup
    215      let hide = waitForMacEvent("AXUIElementDestroyed");
    216      EventUtils.synthesizeKey("KEY_Escape");
    217      await BrowserTestUtils.waitForPopupEvent(identityPopup, "hidden");
    218      await hide;
    219 
    220      // We're back to the base child count
    221      is(rootChildCount(), baseRootChildCount, "Root has the base child count");
    222    }
    223  );
    224 });
    225 
    226 /**
    227 * Tests for location bar
    228 */
    229 add_task(async () => {
    230  await BrowserTestUtils.withNewTab(
    231    {
    232      gBrowser,
    233      // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    234      url: "http://example.com",
    235    },
    236    async () => {
    237      let input = await getMacAccessible(gURLBar.inputField);
    238      is(
    239        input.getAttributeValue("AXValue"),
    240        // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    241        UrlbarTestUtils.trimURL("http://example.com"),
    242        "Location bar has correct value"
    243      );
    244    }
    245  );
    246 });
    247 
    248 /**
    249 * Tests attributed text in nav bar has no invisible AXAttachments
    250 */
    251 add_task(async () => {
    252  await BrowserTestUtils.withNewTab(
    253    {
    254      gBrowser,
    255      // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    256      url: "http://example.com",
    257    },
    258    async () => {
    259      let root = await getMacAccessible(document);
    260      let navBar = await getMacAccessible("nav-bar");
    261      let elemRange = root.getParameterizedAttributeValue(
    262        "AXTextMarkerRangeForUIElement",
    263        navBar
    264      );
    265      let attributedString = root.getParameterizedAttributeValue(
    266        "AXAttributedStringForTextMarkerRange",
    267        elemRange
    268      );
    269      let attachmentRoles = attributedString.map(s =>
    270        s.AXAttachment ? s.AXAttachment.getAttributeValue("AXRole") : null
    271      );
    272      ok(
    273        !attachmentRoles.includes("AXMenu"),
    274        "Collapsed menu should be embedded in attributed text"
    275      );
    276    }
    277  );
    278 });
    279 
    280 /**
    281 * Test context menu
    282 */
    283 add_task(async () => {
    284  if (Services.prefs.getBoolPref("widget.macos.native-context-menus", false)) {
    285    ok(true, "We cannot inspect native context menu contents; skip this test.");
    286    return;
    287  }
    288 
    289  await BrowserTestUtils.withNewTab(
    290    {
    291      gBrowser,
    292      url: 'data:text/html,<a id="exampleLink" href="https://example.com">link</a>',
    293    },
    294    async browser => {
    295      if (!Services.search.isInitialized) {
    296        let aStatus = await Services.search.init();
    297        Assert.ok(Components.isSuccessCode(aStatus));
    298        Assert.ok(Services.search.isInitialized);
    299      }
    300 
    301      const hasContainers =
    302        Services.prefs.getBoolPref("privacy.userContext.enabled") &&
    303        !!ContextualIdentityService.getPublicIdentities().length;
    304      info(`${hasContainers ? "Do" : "Don't"} expect containers item.`);
    305      const hasInspectA11y =
    306        Services.prefs.getBoolPref("devtools.everOpened", false) ||
    307        Services.prefs.getIntPref("devtools.selfxss.count", 0) > 0;
    308      info(`${hasInspectA11y ? "Do" : "Don't"} expect inspect a11y item.`);
    309 
    310      // synthesize a right click on the link to open the link context menu
    311      let menu = document.getElementById("contentAreaContextMenu");
    312      await BrowserTestUtils.synthesizeMouseAtCenter(
    313        "#exampleLink",
    314        { type: "contextmenu" },
    315        browser
    316      );
    317      await waitForMacEvent("AXMenuOpened");
    318 
    319      menu = await getMacAccessible(menu);
    320      let menuChildren = menu.getAttributeValue("AXChildren");
    321      const expectedChildCount = 12 + +hasContainers + +hasInspectA11y;
    322      is(
    323        menuChildren.length,
    324        expectedChildCount,
    325        `Context menu on link contains ${expectedChildCount} items.`
    326      );
    327      // items at indicies 3, 9, and 11 are the splitters when containers exist
    328      // everything else should be a menu item, otherwise indicies of splitters are
    329      // 3, 8, and 10
    330      const splitterIndicies = hasContainers ? [4, 9, 11] : [3, 8, 10];
    331      for (let i = 0; i < menuChildren.length; i++) {
    332        if (splitterIndicies.includes(i)) {
    333          is(
    334            menuChildren[i].getAttributeValue("AXRole"),
    335            "AXSplitter",
    336            "found splitter in menu"
    337          );
    338        } else {
    339          is(
    340            menuChildren[i].getAttributeValue("AXRole"),
    341            "AXMenuItem",
    342            "found menu item in menu"
    343          );
    344        }
    345      }
    346 
    347      // check the containers sub menu in depth if it exists
    348      if (hasContainers) {
    349        is(
    350          menuChildren[1].getAttributeValue("AXVisibleChildren"),
    351          null,
    352          "Submenu 1 has no visible chldren when hidden"
    353        );
    354 
    355        // focus the first submenu
    356        EventUtils.synthesizeKey("KEY_ArrowDown");
    357        EventUtils.synthesizeKey("KEY_ArrowDown");
    358        EventUtils.synthesizeKey("KEY_ArrowRight");
    359        await waitForMacEvent("AXMenuOpened");
    360 
    361        // after the submenu is opened, refetch it
    362        menu = document.getElementById("contentAreaContextMenu");
    363        menu = await getMacAccessible(menu);
    364        menuChildren = menu.getAttributeValue("AXChildren");
    365 
    366        // verify submenu-menuitem's attributes
    367        is(
    368          menuChildren[1].getAttributeValue("AXChildren").length,
    369          1,
    370          "Submenu 1 has one child when open"
    371        );
    372        const subMenu = menuChildren[1].getAttributeValue("AXChildren")[0];
    373        is(
    374          subMenu.getAttributeValue("AXRole"),
    375          "AXMenu",
    376          "submenu has role of menu"
    377        );
    378        const subMenuChildren = subMenu.getAttributeValue("AXChildren");
    379        is(subMenuChildren.length, 4, "sub menu has 4 children");
    380        is(
    381          subMenu.getAttributeValue("AXVisibleChildren").length,
    382          4,
    383          "submenu has 4 visible children"
    384        );
    385 
    386        // close context menu
    387        EventUtils.synthesizeKey("KEY_Escape");
    388        await waitForMacEvent("AXMenuClosed");
    389      }
    390 
    391      EventUtils.synthesizeKey("KEY_Escape");
    392      await waitForMacEvent("AXMenuClosed");
    393    }
    394  );
    395 });