tor-browser

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

browser_applications_selection.js (13399B)


      1 SimpleTest.requestCompleteLog();
      2 const { HandlerServiceTestUtils } = ChromeUtils.importESModule(
      3  "resource://testing-common/HandlerServiceTestUtils.sys.mjs"
      4 );
      5 
      6 let gHandlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
      7  Ci.nsIHandlerService
      8 );
      9 
     10 let gOldMailHandlers = [];
     11 let gDummyHandlers = [];
     12 let gOriginalPreferredMailHandler;
     13 let gOriginalPreferredPDFHandler;
     14 
     15 registerCleanupFunction(function () {
     16  function removeDummyHandlers(handlers) {
     17    // Remove any of the dummy handlers we created.
     18    for (let i = handlers.Count() - 1; i >= 0; i--) {
     19      try {
     20        if (
     21          gDummyHandlers.some(
     22            h =>
     23              h.uriTemplate ==
     24              handlers.queryElementAt(i, Ci.nsIWebHandlerApp).uriTemplate
     25          )
     26        ) {
     27          handlers.removeElementAt(i);
     28        }
     29      } catch (ex) {
     30        /* ignore non-web-app handlers */
     31      }
     32    }
     33  }
     34  // Re-add the original protocol handlers:
     35  let mailHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
     36  let mailHandlers = mailHandlerInfo.possibleApplicationHandlers;
     37  for (let h of gOldMailHandlers) {
     38    mailHandlers.appendElement(h);
     39  }
     40  removeDummyHandlers(mailHandlers);
     41  mailHandlerInfo.preferredApplicationHandler = gOriginalPreferredMailHandler;
     42  gHandlerService.store(mailHandlerInfo);
     43 
     44  let pdfHandlerInfo =
     45    HandlerServiceTestUtils.getHandlerInfo("application/pdf");
     46  removeDummyHandlers(pdfHandlerInfo.possibleApplicationHandlers);
     47  pdfHandlerInfo.preferredApplicationHandler = gOriginalPreferredPDFHandler;
     48  gHandlerService.store(pdfHandlerInfo);
     49 
     50  gBrowser.removeCurrentTab();
     51 });
     52 
     53 function scrubMailtoHandlers(handlerInfo) {
     54  // Remove extant web handlers because they have icons that
     55  // we fetch from the web, which isn't allowed in tests.
     56  let handlers = handlerInfo.possibleApplicationHandlers;
     57  for (let i = handlers.Count() - 1; i >= 0; i--) {
     58    try {
     59      let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
     60      gOldMailHandlers.push(handler);
     61      // If we get here, this is a web handler app. Remove it:
     62      handlers.removeElementAt(i);
     63    } catch (ex) {}
     64  }
     65 }
     66 
     67 add_setup(async function () {
     68  // Create our dummy handlers
     69  let handler1 = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance(
     70    Ci.nsIWebHandlerApp
     71  );
     72  handler1.name = "Handler 1";
     73  handler1.uriTemplate = "https://example.com/first/%s";
     74 
     75  let handler2 = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance(
     76    Ci.nsIWebHandlerApp
     77  );
     78  handler2.name = "Handler 2";
     79  handler2.uriTemplate = "https://example.org/second/%s";
     80  gDummyHandlers.push(handler1, handler2);
     81 
     82  function substituteWebHandlers(handlerInfo) {
     83    // Append the dummy handlers to replace them:
     84    let handlers = handlerInfo.possibleApplicationHandlers;
     85    handlers.appendElement(handler1);
     86    handlers.appendElement(handler2);
     87    gHandlerService.store(handlerInfo);
     88  }
     89  // Set up our mailto handler test infrastructure.
     90  let mailtoHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto");
     91  scrubMailtoHandlers(mailtoHandlerInfo);
     92  gOriginalPreferredMailHandler = mailtoHandlerInfo.preferredApplicationHandler;
     93  substituteWebHandlers(mailtoHandlerInfo);
     94 
     95  // Now do the same for pdf handler:
     96  let pdfHandlerInfo =
     97    HandlerServiceTestUtils.getHandlerInfo("application/pdf");
     98  // PDF doesn't have built-in web handlers, so no need to scrub.
     99  gOriginalPreferredPDFHandler = pdfHandlerInfo.preferredApplicationHandler;
    100  substituteWebHandlers(pdfHandlerInfo);
    101 
    102  await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
    103  info("Preferences page opened on the general pane.");
    104 
    105  await gBrowser.selectedBrowser.contentWindow.promiseLoadHandlersList;
    106  info("Apps list loaded.");
    107 });
    108 
    109 async function selectStandardOptions(itemToUse) {
    110  async function selectItemInPopup(item) {
    111    let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
    112    // Synthesizing the mouse on the .actionsMenu menulist somehow just selects
    113    // the top row. Probably something to do with the multiple layers of anon
    114    // content - workaround by using the `.open` setter instead.
    115    list.open = true;
    116    await popupShown;
    117    let popupHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden");
    118    if (typeof item == "function") {
    119      item = item();
    120    }
    121    popup.activateItem(item);
    122    await popupHidden;
    123    return item;
    124  }
    125 
    126  let itemType = itemToUse.getAttribute("type");
    127  // Center the item. Center rather than top so it doesn't get blocked by
    128  // the search header.
    129  itemToUse.scrollIntoView({ block: "center" });
    130  itemToUse.closest("richlistbox").selectItem(itemToUse);
    131  Assert.ok(itemToUse.selected, "Should be able to select our item.");
    132  // Force reflow to make sure it's visible and the container dropdown isn't
    133  // hidden.
    134  itemToUse.getBoundingClientRect().top;
    135  let list = itemToUse.querySelector(".actionsMenu");
    136  let popup = list.menupopup;
    137 
    138  // select one of our test cases:
    139  let handlerItem = list.querySelector("menuitem[data-l10n-args*='Handler 1']");
    140  await selectItemInPopup(handlerItem);
    141  let { preferredAction, alwaysAskBeforeHandling } =
    142    HandlerServiceTestUtils.getHandlerInfo(itemType);
    143  Assert.notEqual(
    144    preferredAction,
    145    Ci.nsIHandlerInfo.alwaysAsk,
    146    "Should have selected something other than 'always ask' (" + itemType + ")"
    147  );
    148  Assert.ok(
    149    !alwaysAskBeforeHandling,
    150    "Should have turned off asking before handling (" + itemType + ")"
    151  );
    152 
    153  // Test the alwaysAsk option
    154  let alwaysAskItem = list.getElementsByAttribute(
    155    "action",
    156    Ci.nsIHandlerInfo.alwaysAsk
    157  )[0];
    158  await selectItemInPopup(alwaysAskItem);
    159  Assert.equal(
    160    list.selectedItem,
    161    alwaysAskItem,
    162    "Should have selected always ask item (" + itemType + ")"
    163  );
    164  alwaysAskBeforeHandling =
    165    HandlerServiceTestUtils.getHandlerInfo(itemType).alwaysAskBeforeHandling;
    166  Assert.ok(
    167    alwaysAskBeforeHandling,
    168    "Should have turned on asking before handling (" + itemType + ")"
    169  );
    170 
    171  let useDefaultItem = list.getElementsByAttribute(
    172    "action",
    173    Ci.nsIHandlerInfo.useSystemDefault
    174  );
    175  useDefaultItem = useDefaultItem && useDefaultItem[0];
    176  if (useDefaultItem) {
    177    await selectItemInPopup(useDefaultItem);
    178    Assert.equal(
    179      list.selectedItem,
    180      useDefaultItem,
    181      "Should have selected 'use default' item (" + itemType + ")"
    182    );
    183    preferredAction =
    184      HandlerServiceTestUtils.getHandlerInfo(itemType).preferredAction;
    185    Assert.equal(
    186      preferredAction,
    187      Ci.nsIHandlerInfo.useSystemDefault,
    188      "Should have selected 'use default' (" + itemType + ")"
    189    );
    190  } else {
    191    // Whether there's a "use default" item depends on the OS, so it's not
    192    // possible to rely on it being the case or not.
    193    info("No 'Use default' item, so not testing (" + itemType + ")");
    194  }
    195 
    196  // Select a web app item.
    197  let webAppItems = Array.from(
    198    popup.getElementsByAttribute("action", Ci.nsIHandlerInfo.useHelperApp)
    199  );
    200  webAppItems = webAppItems.filter(
    201    item => item.handlerApp instanceof Ci.nsIWebHandlerApp
    202  );
    203  Assert.equal(
    204    webAppItems.length,
    205    2,
    206    "Should have 2 web application handler. (" + itemType + ")"
    207  );
    208  Assert.notEqual(
    209    webAppItems[0].label,
    210    webAppItems[1].label,
    211    "Should have 2 different web app handlers"
    212  );
    213  let selectedItem = await selectItemInPopup(webAppItems[0]);
    214 
    215  // Test that the selected item label is the same as the label
    216  // of the menu item.
    217  let win = gBrowser.selectedBrowser.contentWindow;
    218  await win.document.l10n.translateFragment(selectedItem);
    219  await win.document.l10n.translateFragment(itemToUse);
    220  Assert.equal(
    221    selectedItem.label,
    222    itemToUse.querySelector(".actionContainer label").value,
    223    "Should have selected correct item (" + itemType + ")"
    224  );
    225  let { preferredApplicationHandler } =
    226    HandlerServiceTestUtils.getHandlerInfo(itemType);
    227  preferredApplicationHandler.QueryInterface(Ci.nsIWebHandlerApp);
    228  Assert.equal(
    229    selectedItem.handlerApp.uriTemplate,
    230    preferredApplicationHandler.uriTemplate,
    231    "App should actually be selected in the backend. (" + itemType + ")"
    232  );
    233 
    234  // select the other web app item
    235  selectedItem = await selectItemInPopup(webAppItems[1]);
    236 
    237  // Test that the selected item label is the same as the label
    238  // of the menu item
    239  await win.document.l10n.translateFragment(selectedItem);
    240  await win.document.l10n.translateFragment(itemToUse);
    241  Assert.equal(
    242    selectedItem.label,
    243    itemToUse.querySelector(".actionContainer label").value,
    244    "Should have selected correct item (" + itemType + ")"
    245  );
    246  preferredApplicationHandler =
    247    HandlerServiceTestUtils.getHandlerInfo(
    248      itemType
    249    ).preferredApplicationHandler;
    250  preferredApplicationHandler.QueryInterface(Ci.nsIWebHandlerApp);
    251  Assert.equal(
    252    selectedItem.handlerApp.uriTemplate,
    253    preferredApplicationHandler.uriTemplate,
    254    "App should actually be selected in the backend. (" + itemType + ")"
    255  );
    256 }
    257 
    258 add_task(async function checkDropdownBehavior() {
    259  let win = gBrowser.selectedBrowser.contentWindow;
    260 
    261  let container = win.document.getElementById("handlersView");
    262 
    263  // First check a protocol handler item.
    264  let mailItem = container.querySelector("richlistitem[type='mailto']");
    265  Assert.ok(mailItem, "mailItem is present in handlersView.");
    266  await selectStandardOptions(mailItem);
    267 
    268  // Then check a content menu item.
    269  let pdfItem = container.querySelector("richlistitem[type='application/pdf']");
    270  Assert.ok(pdfItem, "pdfItem is present in handlersView.");
    271  await selectStandardOptions(pdfItem);
    272 });
    273 
    274 add_task(async function sortingCheck() {
    275  let win = gBrowser.selectedBrowser.contentWindow;
    276  const handlerView = win.document.getElementById("handlersView");
    277  const typeColumn = win.document.getElementById("typeColumn");
    278  Assert.ok(typeColumn, "typeColumn is present in handlersView.");
    279 
    280  let expectedNumberOfItems =
    281    handlerView.querySelectorAll("richlistitem").length;
    282 
    283  // Test default sorting
    284  assertSortByType("ascending");
    285 
    286  const oldDir = typeColumn.getAttribute("sortDirection");
    287 
    288  // click on an item and sort again:
    289  let itemToUse = handlerView.querySelector("richlistitem[type=mailto]");
    290  itemToUse.scrollIntoView({ block: "center" });
    291  itemToUse.closest("richlistbox").selectItem(itemToUse);
    292 
    293  // Test sorting on the type column
    294  typeColumn.click();
    295  assertSortByType("descending");
    296  Assert.notEqual(
    297    oldDir,
    298    typeColumn.getAttribute("sortDirection"),
    299    "Sort direction should change"
    300  );
    301 
    302  typeColumn.click();
    303  assertSortByType("ascending");
    304 
    305  const actionColumn = win.document.getElementById("actionColumn");
    306  Assert.ok(actionColumn, "actionColumn is present in handlersView.");
    307 
    308  // Test sorting on the action column
    309  const oldActionDir = actionColumn.getAttribute("sortDirection");
    310  actionColumn.click();
    311  assertSortByAction("ascending");
    312  Assert.notEqual(
    313    oldActionDir,
    314    actionColumn.getAttribute("sortDirection"),
    315    "Sort direction should change"
    316  );
    317 
    318  actionColumn.click();
    319  assertSortByAction("descending");
    320 
    321  // Restore the default sort order
    322  typeColumn.click();
    323  assertSortByType("ascending");
    324 
    325  function assertSortByAction(order) {
    326    Assert.equal(
    327      actionColumn.getAttribute("sortDirection"),
    328      order,
    329      `Sort direction should be ${order}`
    330    );
    331    let siteItems = handlerView.getElementsByTagName("richlistitem");
    332    Assert.equal(
    333      siteItems.length,
    334      expectedNumberOfItems,
    335      "Number of items should not change."
    336    );
    337    for (let i = 0; i < siteItems.length - 1; ++i) {
    338      let aType = (
    339        siteItems[i].getAttribute("actionDescription") || ""
    340      ).toLowerCase();
    341      let bType = (
    342        siteItems[i + 1].getAttribute("actionDescription") || ""
    343      ).toLowerCase();
    344      let result = 0;
    345      if (aType > bType) {
    346        result = 1;
    347      } else if (bType > aType) {
    348        result = -1;
    349      }
    350      if (order == "ascending") {
    351        Assert.lessOrEqual(
    352          result,
    353          0,
    354          "Should sort applications in the ascending order by action"
    355        );
    356      } else {
    357        Assert.greaterOrEqual(
    358          result,
    359          0,
    360          "Should sort applications in the descending order by action"
    361        );
    362      }
    363    }
    364  }
    365 
    366  function assertSortByType(order) {
    367    Assert.equal(
    368      typeColumn.getAttribute("sortDirection"),
    369      order,
    370      `Sort direction should be ${order}`
    371    );
    372 
    373    let siteItems = handlerView.getElementsByTagName("richlistitem");
    374    Assert.equal(
    375      siteItems.length,
    376      expectedNumberOfItems,
    377      "Number of items should not change."
    378    );
    379    for (let i = 0; i < siteItems.length - 1; ++i) {
    380      let aType = (
    381        siteItems[i].getAttribute("typeDescription") || ""
    382      ).toLowerCase();
    383      let bType = (
    384        siteItems[i + 1].getAttribute("typeDescription") || ""
    385      ).toLowerCase();
    386      let result = 0;
    387      if (aType > bType) {
    388        result = 1;
    389      } else if (bType > aType) {
    390        result = -1;
    391      }
    392      if (order == "ascending") {
    393        Assert.lessOrEqual(
    394          result,
    395          0,
    396          "Should sort applications in the ascending order by type"
    397        );
    398      } else {
    399        Assert.greaterOrEqual(
    400          result,
    401          0,
    402          "Should sort applications in the descending order by type"
    403        );
    404      }
    405    }
    406  }
    407 });