Bug 1633968 - Tests to verify the tab parameter of menus.onShown r=rpl
authorRob Wu <rob@robwu.nl>
Thu, 21 May 2020 20:35:28 +0000
changeset 531514 53abd4bfccb4aa33bc82dda93c5d00df8bc67b8a
parent 531513 885cb126af2f9a58bd689a647479438ffd18ddae
child 531515 95be09f031e4928ef5808f9b05ff54b48afd6438
push id37440
push userabutkovits@mozilla.com
push dateFri, 22 May 2020 09:43:16 +0000
treeherdermozilla-central@fbf71e4d2e21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrpl
bugs1633968
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1633968 - Tests to verify the tab parameter of menus.onShown r=rpl - Modify the existing `test_show_hide_tab` test to right-click on a background tab, to verify that the tab argument is the clicked tab rather than the currently selected tab. - Add a new test task (`test_show_hide_tab_via_tab_panel`) to serve as a regression test for bug 1633968. Differential Revision: https://phabricator.services.mozilla.com/D75865
browser/components/extensions/test/browser/browser_ext_menus_events.js
browser/components/extensions/test/browser/head.js
--- a/browser/components/extensions/test/browser/browser_ext_menus_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_events.js
@@ -28,16 +28,17 @@ async function grantOptionalPermission(e
 // doOpenMenu must open the menu and its returned promise must resolve after the
 // menu is shown. Similarly, doCloseMenu must hide the menu.
 async function testShowHideEvent({
   menuCreateParams,
   doOpenMenu,
   doCloseMenu,
   expectedShownEvent,
   expectedShownEventWithPermissions = null,
+  forceTabToBackground = false,
 }) {
   async function background() {
     function awaitMessage(expectedId) {
       return new Promise(resolve => {
         browser.test.log(`Waiting for message: ${expectedId}`);
         browser.test.onMessage.addListener(function listener(id, msg) {
           // Temporary work-around for https://bugzil.la/1428213
           // TODO Bug 1428213: remove workaround for onMessage.removeListener
@@ -97,16 +98,19 @@ async function testShowHideEvent({
     browser.test.assertEq(1, hiddenEvents.length, "expected onHidden");
     browser.test.sendMessage("onHidden-event-data", hiddenEvents[0]);
 
     await awaitMessage("optional-menu-shown-with-permissions");
     browser.test.assertEq(2, shownEvents.length, "expected second onShown");
     browser.test.sendMessage("onShown-event-data2", shownEvents[1]);
   }
 
+  const someOtherTab = gBrowser.selectedTab;
+  // Tab must initially open as a foreground tab, because the test extension
+  // looks for the active tab.
   const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
 
   let extension = ExtensionTestUtils.loadExtension({
     background,
     manifest: {
       page_action: {},
       browser_action: {
         default_popup: "popup.html",
@@ -117,17 +121,21 @@ async function testShowHideEvent({
     files: {
       "popup.html": `<!DOCTYPE html><meta charset="utf-8">Popup body`,
     },
   });
   await extension.startup();
   extension.sendMessage("create-params", menuCreateParams);
   let menuId = await extension.awaitMessage("menu-registered");
 
-  await doOpenMenu(extension);
+  if (forceTabToBackground) {
+    gBrowser.selectedTab = someOtherTab;
+  }
+
+  await doOpenMenu(extension, tab);
   extension.sendMessage("assert-menu-shown");
   let shownEvent = await extension.awaitMessage("onShown-event-data");
 
   // menuCreateParams.id is not set, therefore a numeric ID is generated.
   expectedShownEvent.menuIds = [menuId];
   Assert.deepEqual(shownEvent, expectedShownEvent, "expected onShown info");
 
   await doCloseMenu(extension);
@@ -136,17 +144,17 @@ async function testShowHideEvent({
   is(hiddenEvent, undefined, "expected no event data for onHidden event");
 
   if (expectedShownEventWithPermissions) {
     expectedShownEventWithPermissions.menuIds = [menuId];
     await grantOptionalPermission(extension, {
       permissions: [],
       origins: [PAGE_HOST_PATTERN],
     });
-    await doOpenMenu(extension);
+    await doOpenMenu(extension, tab);
     extension.sendMessage("optional-menu-shown-with-permissions");
     let shownEvent2 = await extension.awaitMessage("onShown-event-data2");
     Assert.deepEqual(
       shownEvent2,
       expectedShownEventWithPermissions,
       "expected onShown info when host permissions are enabled"
     );
     await doCloseMenu(extension);
@@ -340,42 +348,121 @@ add_task(async function test_show_hide_b
     },
     async doCloseMenu(extension) {
       await closeExtensionContextMenu();
       await closeBrowserAction(extension);
     },
   });
 });
 
-add_task(async function test_show_hide_tab() {
+// Common code used by test_show_hide_tab and test_show_hide_tab_via_tab_panel.
+async function testShowHideTabMenu({
+  doOpenTabContextMenu,
+  doCloseTabContextMenu,
+}) {
   await testShowHideEvent({
+    // To verify that the event matches the contextmenu target, switch to
+    // an unrelated tab before opening a contextmenu on the desired tab.
+    forceTabToBackground: true,
     menuCreateParams: {
       title: "tab menu item",
       contexts: ["tab"],
     },
     expectedShownEvent: {
       contexts: ["tab"],
       viewType: undefined,
       editable: false,
     },
     expectedShownEventWithPermissions: {
       contexts: ["tab"],
       viewType: undefined,
       editable: false,
       pageUrl: PAGE,
     },
-    async doOpenMenu() {
-      await openTabContextMenu();
+    async doOpenMenu(extension, contextTab) {
+      await doOpenTabContextMenu(contextTab);
     },
     async doCloseMenu() {
+      await doCloseTabContextMenu();
+    },
+  });
+}
+
+add_task(async function test_show_hide_tab() {
+  await testShowHideTabMenu({
+    async doOpenTabContextMenu(contextTab) {
+      await openTabContextMenu(contextTab);
+    },
+    async doCloseTabContextMenu() {
       await closeTabContextMenu();
     },
   });
 });
 
+// Checks that right-clicking on a tab in the tabs panel (the one that appears
+// when there are many tabs, or when browser.tabs.tabmanager.enabled = true)
+// results in an event that is associated with the expected tab.
+add_task(async function test_show_hide_tab_via_tab_panel() {
+  gTabsPanel.init();
+  const tabContainer = document.getElementById("tabbrowser-tabs");
+  let shouldAddOverflow = !tabContainer.hasAttribute("overflow");
+  const revertTabContainerAttribute = () => {
+    if (shouldAddOverflow) {
+      // Revert attribute if it was changed.
+      tabContainer.removeAttribute("overflow");
+      // The function is going to be called twice, but let's run the logic once.
+      shouldAddOverflow = false;
+    }
+  };
+  if (shouldAddOverflow) {
+    // Ensure the visibility of the "all tabs menu" button (#alltabs-button).
+    tabContainer.setAttribute("overflow", "true");
+    // Register cleanup function in case the test fails before we reach the end.
+    registerCleanupFunction(revertTabContainerAttribute);
+  }
+
+  const allTabsView = document.getElementById("allTabsMenu-allTabsView");
+
+  await testShowHideTabMenu({
+    async doOpenTabContextMenu(contextTab) {
+      // Show the tabs panel.
+      let allTabsPopupShownPromise = BrowserTestUtils.waitForEvent(
+        allTabsView,
+        "ViewShown"
+      );
+      gTabsPanel.showAllTabsPanel();
+      await allTabsPopupShownPromise;
+
+      // Find the menu item that is associated with the given tab
+      let index = Array.prototype.findIndex.call(
+        gTabsPanel.allTabsViewTabs.children,
+        toolbaritem => toolbaritem.tab === contextTab
+      );
+      ok(index !== -1, "sanity check: tabs panel has item for the tab");
+
+      // Finally, open the context menu on it.
+      await openChromeContextMenu(
+        "tabContextMenu",
+        `.all-tabs-item:nth-child(${index + 1})`
+      );
+    },
+    async doCloseTabContextMenu() {
+      await closeTabContextMenu();
+      let allTabsPopupHiddenPromise = BrowserTestUtils.waitForEvent(
+        allTabsView.panelMultiView,
+        "PanelMultiViewHidden"
+      );
+      gTabsPanel.hideAllTabsPanel();
+      await allTabsPopupHiddenPromise;
+    },
+  });
+
+  revertTabContainerAttribute();
+});
+
 add_task(async function test_show_hide_tools_menu() {
   await testShowHideEvent({
     menuCreateParams: {
       title: "menu item",
       contexts: ["tools_menu"],
     },
     expectedShownEvent: {
       contexts: ["tools_menu"],
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -664,24 +664,25 @@ async function openActionContextMenu(ext
 }
 
 function closeActionContextMenu(itemToSelect, kind, win = window) {
   let menuID =
     kind == "page" ? "pageActionContextMenu" : "toolbar-context-menu";
   return closeChromeContextMenu(menuID, itemToSelect, win);
 }
 
-function openTabContextMenu(win = window) {
+function openTabContextMenu(tab = gBrowser.selectedTab) {
   // The TabContextMenu initializes its strings only on a focus or mouseover event.
   // Calls focus event on the TabContextMenu before opening.
-  gBrowser.selectedTab.focus();
+  tab.focus();
+  let indexOfTab = Array.prototype.indexOf.call(tab.parentNode.children, tab);
   return openChromeContextMenu(
     "tabContextMenu",
-    ".tabbrowser-tab[selected]",
-    win
+    `.tabbrowser-tab:nth-child(${indexOfTab + 1})`,
+    tab.ownerGlobal
   );
 }
 
 function closeTabContextMenu(itemToSelect, win = window) {
   return closeChromeContextMenu("tabContextMenu", itemToSelect, win);
 }
 
 function getPageActionPopup(extension, win = window) {