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 }