tor-browser

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

browser_PageActions_removeExtension.js (12083B)


      1 "use strict";
      2 
      3 // Initialization. Must run first.
      4 add_setup(async function () {
      5  // The page action urlbar button, and therefore the panel, is only shown when
      6  // the current tab is actionable -- i.e., a normal web page.  about:blank is
      7  // not, so open a new tab first thing, and close it when this test is done.
      8  let tab = await BrowserTestUtils.openNewForegroundTab({
      9    gBrowser,
     10    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
     11    url: "http://example.com/",
     12  });
     13 
     14  // The prompt service is mocked later, so set it up to be restored.
     15  let { prompt } = Services;
     16 
     17  registerCleanupFunction(async () => {
     18    BrowserTestUtils.removeTab(tab);
     19    Services.prompt = prompt;
     20  });
     21 });
     22 
     23 add_task(async function contextMenu_removeExtension_panel() {
     24  // We use an extension that shows a page action so that we can test the
     25  // "remove extension" item in the context menu.
     26  let extension = ExtensionTestUtils.loadExtension({
     27    manifest: {
     28      name: "Test contextMenu",
     29      page_action: { show_matches: ["<all_urls>"] },
     30    },
     31 
     32    useAddonManager: "temporary",
     33  });
     34 
     35  await extension.startup();
     36 
     37  let actionId = ExtensionCommon.makeWidgetId(extension.id);
     38 
     39  const url = "data:text/html,<h1>A Page</h1>";
     40  let win = await BrowserTestUtils.openNewBrowserWindow();
     41  await SimpleTest.promiseFocus(win);
     42  BrowserTestUtils.startLoadingURIString(win.gBrowser, url);
     43  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
     44 
     45  info("Shrink the window if necessary, check the meatball menu is visible");
     46  let originalOuterWidth = win.outerWidth;
     47  await promiseStableResize(500, win);
     48 
     49  // The pageAction implementation enables the button at the next animation
     50  // frame, so before we look for the button we should wait one animation frame
     51  // as well.
     52  await promiseAnimationFrame(win);
     53 
     54  let meatballButton = win.document.getElementById("pageActionButton");
     55  Assert.ok(BrowserTestUtils.isVisible(meatballButton));
     56 
     57  // Open the panel.
     58  await promisePageActionPanelOpen(win);
     59 
     60  info("Open the context menu");
     61  let panelButton = win.BrowserPageActions.panelButtonNodeForActionID(actionId);
     62  let contextMenuPromise = promisePanelShown("pageActionContextMenu", win);
     63  EventUtils.synthesizeMouseAtCenter(
     64    panelButton,
     65    {
     66      type: "contextmenu",
     67      button: 2,
     68    },
     69    win
     70  );
     71  let contextMenu = await contextMenuPromise;
     72 
     73  let removeExtensionItem = getRemoveExtensionItem(win);
     74  Assert.ok(removeExtensionItem, "'Remove' item exists");
     75  Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
     76  Assert.ok(!removeExtensionItem.disabled, "'Remove' item is not disabled");
     77 
     78  // Click the "remove extension" item, a prompt should be displayed and then
     79  // the add-on should be uninstalled. We mock the prompt service to confirm
     80  // the removal of the add-on.
     81  contextMenuPromise = promisePanelHidden("pageActionContextMenu", win);
     82  let addonUninstalledPromise = promiseAddonUninstalled(extension.id);
     83  mockPromptService();
     84  contextMenu.activateItem(removeExtensionItem);
     85  await Promise.all([contextMenuPromise, addonUninstalledPromise]);
     86 
     87  // Done, clean up.
     88  await extension.unload();
     89 
     90  await promiseStableResize(originalOuterWidth, win);
     91  await BrowserTestUtils.closeWindow(win);
     92 });
     93 
     94 add_task(async function contextMenu_removeExtension_urlbar() {
     95  // We use an extension that shows a page action so that we can test the
     96  // "remove extension" item in the context menu.
     97  let extension = ExtensionTestUtils.loadExtension({
     98    manifest: {
     99      name: "Test contextMenu",
    100      page_action: { show_matches: ["<all_urls>"] },
    101    },
    102 
    103    useAddonManager: "temporary",
    104  });
    105 
    106  await extension.startup();
    107  // The pageAction implementation enables the button at the next animation
    108  // frame, so before we look for the button we should wait one animation frame
    109  // as well.
    110  await promiseAnimationFrame();
    111 
    112  let actionId = ExtensionCommon.makeWidgetId(extension.id);
    113 
    114  // Open the context menu on the action's urlbar button.
    115  let urlbarButton = BrowserPageActions.urlbarButtonNodeForActionID(actionId);
    116  let contextMenuPromise = promisePanelShown("pageActionContextMenu");
    117  EventUtils.synthesizeMouseAtCenter(urlbarButton, {
    118    type: "contextmenu",
    119    button: 2,
    120  });
    121  let contextMenu = await contextMenuPromise;
    122 
    123  let menuItems = collectContextMenuItems();
    124  Assert.equal(menuItems.length, 2, "Context menu has two children");
    125  let removeExtensionItem = getRemoveExtensionItem();
    126  Assert.ok(removeExtensionItem, "'Remove' item exists");
    127  Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
    128  Assert.ok(!removeExtensionItem.disabled, "'Remove' item is not disabled");
    129  let manageExtensionItem = getManageExtensionItem();
    130  Assert.ok(manageExtensionItem, "'Manage' item exists");
    131  Assert.ok(!manageExtensionItem.hidden, "'Manage' item is visible");
    132  Assert.ok(!manageExtensionItem.disabled, "'Manage' item is not disabled");
    133 
    134  // Click the "remove extension" item, a prompt should be displayed and then
    135  // the add-on should be uninstalled. We mock the prompt service to cancel the
    136  // removal of the add-on.
    137  contextMenuPromise = promisePanelHidden("pageActionContextMenu");
    138  let promptService = mockPromptService();
    139  let promptCancelledPromise = new Promise(resolve => {
    140    promptService.confirmEx = () => resolve();
    141  });
    142  contextMenu.activateItem(removeExtensionItem);
    143  await Promise.all([contextMenuPromise, promptCancelledPromise]);
    144 
    145  // Done, clean up.
    146  await extension.unload();
    147 
    148  // urlbar tests that run after this one can break if the mouse is left over
    149  // the area where the urlbar popup appears, which seems to happen due to the
    150  // above synthesized mouse events.  Move it over the urlbar.
    151  EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousemove" });
    152  gURLBar.focus();
    153 });
    154 
    155 add_task(async function contextMenu_removeExtension_disabled_in_urlbar() {
    156  // We use an extension that shows a page action so that we can test the
    157  // "remove extension" item in the context menu.
    158  let extension = ExtensionTestUtils.loadExtension({
    159    manifest: {
    160      name: "Test contextMenu",
    161      page_action: { show_matches: ["<all_urls>"] },
    162    },
    163 
    164    useAddonManager: "temporary",
    165  });
    166 
    167  await extension.startup();
    168  // The pageAction implementation enables the button at the next animation
    169  // frame, so before we look for the button we should wait one animation frame
    170  // as well.
    171  await promiseAnimationFrame();
    172  // Add a policy to prevent the add-on from being uninstalled.
    173  await EnterprisePolicyTesting.setupPolicyEngineWithJson({
    174    policies: {
    175      Extensions: {
    176        Locked: [extension.id],
    177      },
    178    },
    179  });
    180 
    181  let actionId = ExtensionCommon.makeWidgetId(extension.id);
    182 
    183  // Open the context menu on the action's urlbar button.
    184  let urlbarButton = BrowserPageActions.urlbarButtonNodeForActionID(actionId);
    185  let contextMenuPromise = promisePanelShown("pageActionContextMenu");
    186  EventUtils.synthesizeMouseAtCenter(urlbarButton, {
    187    type: "contextmenu",
    188    button: 2,
    189  });
    190  let contextMenu = await contextMenuPromise;
    191 
    192  let menuItems = collectContextMenuItems();
    193  Assert.equal(menuItems.length, 2, "Context menu has two children");
    194  let removeExtensionItem = getRemoveExtensionItem();
    195  Assert.ok(removeExtensionItem, "'Remove' item exists");
    196  Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
    197  Assert.ok(removeExtensionItem.disabled, "'Remove' item is disabled");
    198  let manageExtensionItem = getManageExtensionItem();
    199  Assert.ok(manageExtensionItem, "'Manage' item exists");
    200  Assert.ok(!manageExtensionItem.hidden, "'Manage' item is visible");
    201  Assert.ok(!manageExtensionItem.disabled, "'Manage' item is not disabled");
    202 
    203  // Hide the context menu.
    204  contextMenuPromise = promisePanelHidden("pageActionContextMenu");
    205  contextMenu.hidePopup();
    206  await contextMenuPromise;
    207 
    208  // Done, clean up.
    209  await extension.unload();
    210  await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
    211 
    212  // urlbar tests that run after this one can break if the mouse is left over
    213  // the area where the urlbar popup appears, which seems to happen due to the
    214  // above synthesized mouse events.  Move it over the urlbar.
    215  EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousemove" });
    216  gURLBar.focus();
    217 });
    218 
    219 add_task(async function contextMenu_removeExtension_disabled_in_panel() {
    220  // We use an extension that shows a page action so that we can test the
    221  // "remove extension" item in the context menu.
    222  let extension = ExtensionTestUtils.loadExtension({
    223    manifest: {
    224      name: "Test contextMenu",
    225      page_action: { show_matches: ["<all_urls>"] },
    226    },
    227 
    228    useAddonManager: "temporary",
    229  });
    230 
    231  await extension.startup();
    232  // Add a policy to prevent the add-on from being uninstalled.
    233  await EnterprisePolicyTesting.setupPolicyEngineWithJson({
    234    policies: {
    235      Extensions: {
    236        Locked: [extension.id],
    237      },
    238    },
    239  });
    240 
    241  let actionId = ExtensionCommon.makeWidgetId(extension.id);
    242 
    243  const url = "data:text/html,<h1>A Page</h1>";
    244  let win = await BrowserTestUtils.openNewBrowserWindow();
    245  await SimpleTest.promiseFocus(win);
    246  BrowserTestUtils.startLoadingURIString(win.gBrowser, url);
    247  await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
    248 
    249  info("Shrink the window if necessary, check the meatball menu is visible");
    250  let originalOuterWidth = win.outerWidth;
    251  await promiseStableResize(500, win);
    252 
    253  // The pageAction implementation enables the button at the next animation
    254  // frame, so before we look for the button we should wait one animation frame
    255  // as well.
    256  await promiseAnimationFrame(win);
    257 
    258  let meatballButton = win.document.getElementById("pageActionButton");
    259  Assert.ok(BrowserTestUtils.isVisible(meatballButton));
    260 
    261  // Open the panel.
    262  await promisePageActionPanelOpen(win);
    263 
    264  info("Open the context menu");
    265  let panelButton = win.BrowserPageActions.panelButtonNodeForActionID(actionId);
    266  let contextMenuPromise = promisePanelShown("pageActionContextMenu", win);
    267  EventUtils.synthesizeMouseAtCenter(
    268    panelButton,
    269    {
    270      type: "contextmenu",
    271      button: 2,
    272    },
    273    win
    274  );
    275  let contextMenu = await contextMenuPromise;
    276 
    277  let removeExtensionItem = getRemoveExtensionItem(win);
    278  Assert.ok(removeExtensionItem, "'Remove' item exists");
    279  Assert.ok(!removeExtensionItem.hidden, "'Remove' item is visible");
    280  Assert.ok(removeExtensionItem.disabled, "'Remove' item is disabled");
    281 
    282  // Hide the context menu.
    283  contextMenuPromise = promisePanelHidden("pageActionContextMenu", win);
    284  contextMenu.hidePopup();
    285  await contextMenuPromise;
    286 
    287  // Done, clean up.
    288  await extension.unload();
    289  await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
    290 
    291  await promiseStableResize(originalOuterWidth, win);
    292  await BrowserTestUtils.closeWindow(win);
    293 });
    294 
    295 function promiseAddonUninstalled(addonId) {
    296  return new Promise(resolve => {
    297    let listener = {};
    298    listener.onUninstalled = addon => {
    299      if (addon.id == addonId) {
    300        AddonManager.removeAddonListener(listener);
    301        resolve();
    302      }
    303    };
    304    AddonManager.addAddonListener(listener);
    305  });
    306 }
    307 
    308 function mockPromptService() {
    309  let promptService = {
    310    // The prompt returns 1 for cancelled and 0 for accepted.
    311    _response: 0,
    312    QueryInterface: ChromeUtils.generateQI(["nsIPromptService"]),
    313    confirmEx: () => promptService._response,
    314  };
    315 
    316  Services.prompt = promptService;
    317 
    318  return promptService;
    319 }
    320 
    321 function getRemoveExtensionItem(win = window) {
    322  return win.document.querySelector(
    323    "#pageActionContextMenu > menuitem[label='Remove Extension']"
    324  );
    325 }
    326 
    327 function getManageExtensionItem(win = window) {
    328  return win.document.querySelector(
    329    "#pageActionContextMenu > menuitem[label='Manage Extension…']"
    330  );
    331 }
    332 
    333 function collectContextMenuItems(win = window) {
    334  let contextMenu = win.document.getElementById("pageActionContextMenu");
    335  return Array.prototype.filter.call(contextMenu.children, node => {
    336    return win.getComputedStyle(node).visibility == "visible";
    337  });
    338 }