Bug 1633968 - Tests to verify the tab parameter of menus.onShown r=rpl
☠☠ backed out by 9194f91b1fa2 ☠ ☠
authorRob Wu <rob@robwu.nl>
Wed, 20 May 2020 22:56:17 +0000
changeset 531458 9dc3a4d3263094dcc060339a8b18f2190a5f70c5
parent 531457 55cc61b65e567fdb2908b4b0f49f05c7f8164f0d
child 531459 98080333994e06121f0f0a83741e50b48d11e904
push id37439
push userbtara@mozilla.com
push dateThu, 21 May 2020 21:49:34 +0000
treeherdermozilla-central@92c11f0bf14b [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,120 @@ 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() {
+  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) {