Bug 1246044 Split context menu tests into separate files, and make sure context menu is properly cleaned up after uninstall. f?kmag draft
authorMatthew Wein <mwein@mozilla.com>
Thu, 07 Apr 2016 15:34:20 -0700
changeset 348791 1c0eae518af672407699e20035aa149907bdd8c2
parent 348767 dfd17abadcdfecd1251371a17dac9289c80667f8
child 517939 514d203eb1c8a802c88852f86c79904e704f2b2f
push id14924
push usermwein@mozilla.com
push dateFri, 08 Apr 2016 04:09:41 +0000
bugs1246044
milestone48.0a1
Bug 1246044 Split context menu tests into separate files, and make sure context menu is properly cleaned up after uninstall. f?kmag MozReview-Commit-ID: 2cafAjmg4vR
browser/components/extensions/ext-contextMenus.js
browser/components/extensions/test/browser/browser.ini
browser/components/extensions/test/browser/browser_ext_contextMenus.js
browser/components/extensions/test/browser/browser_ext_contextMenus_checkboxes.js
browser/components/extensions/test/browser/browser_ext_contextMenus_radioGroups.js
browser/components/extensions/test/browser/browser_ext_contextMenus_uninstall.js
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -448,26 +448,26 @@ MenuItem.prototype = {
     return true;
   },
 };
 
 var gExtensionCount = 0;
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("startup", (type, extension) => {
   gContextMenuMap.set(extension, new Map());
-  gRootItems.delete(extension);
   if (++gExtensionCount == 1) {
     Services.obs.addObserver(contextMenuObserver,
                              "on-build-contextmenu",
                              false);
   }
 });
 
 extensions.on("shutdown", (type, extension) => {
   gContextMenuMap.delete(extension);
+  gRootItems.delete(extension);
   if (--gExtensionCount == 0) {
     Services.obs.removeObserver(contextMenuObserver,
                                 "on-build-contextmenu");
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 extensions.registerSchemaAPI("contextMenus", "contextMenus", (extension, context) => {
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -19,16 +19,19 @@ support-files =
 [browser_ext_browserAction_context.js]
 [browser_ext_browserAction_disabled.js]
 [browser_ext_pageAction_simple.js]
 [browser_ext_pageAction_context.js]
 [browser_ext_pageAction_popup.js]
 [browser_ext_browserAction_popup.js]
 [browser_ext_popup_api_injection.js]
 [browser_ext_contextMenus.js]
+[browser_ext_contextMenus_checkboxes.js]
+[browser_ext_contextMenus_radioGroups.js]
+[browser_ext_contextMenus_uninstall.js]
 [browser_ext_commands_execute_page_action.js]
 [browser_ext_commands_getAll.js]
 [browser_ext_commands_onCommand.js]
 [browser_ext_getViews.js]
 [browser_ext_lastError.js]
 [browser_ext_runtime_openOptionsPage.js]
 [browser_ext_runtime_setUninstallURL.js]
 [browser_ext_tabs_audio.js]
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -39,17 +39,16 @@ add_task(function* () {
           contexts: [context],
           id: "ext-" + context,
           onclick: genericOnClick,
         });
         if (context == "selection") {
           browser.contextMenus.update("ext-selection", {
             title: "selection is: '%s'",
             onclick: (info, tab) => {
-              browser.contextMenus.removeAll();
               genericOnClick(info, tab);
             },
           });
         }
       }
 
       let parent = browser.contextMenus.create({
         title: "parent",
@@ -76,58 +75,16 @@ add_task(function* () {
       browser.contextMenus.create({
         title: "child2",
         parentId: parentToDel,
         onclick: genericOnClick,
       });
       browser.contextMenus.remove(parentToDel);
 
       browser.contextMenus.create({
-        title: "radio-group-1",
-        type: "radio",
-        checked: true,
-        onclick: genericOnClick,
-      });
-
-      browser.contextMenus.create({
-        title: "Checkbox",
-        type: "checkbox",
-        onclick: genericOnClick,
-      });
-
-      browser.contextMenus.create({
-        title: "radio-group-2",
-        type: "radio",
-        onclick: genericOnClick,
-      });
-
-      browser.contextMenus.create({
-        title: "radio-group-2",
-        type: "radio",
-        onclick: genericOnClick,
-      });
-
-      browser.contextMenus.create({
-        type: "separator",
-      });
-
-      browser.contextMenus.create({
-        title: "Checkbox",
-        type: "checkbox",
-        checked: true,
-        onclick: genericOnClick,
-      });
-
-      browser.contextMenus.create({
-        title: "Checkbox",
-        type: "checkbox",
-        onclick: genericOnClick,
-      });
-
-      browser.contextMenus.create({
         title: "Without onclick property",
         id: "ext-without-onclick",
       });
 
       browser.contextMenus.update(parent, {parentId: child2}).then(
         () => {
           browser.test.notifyFail();
         },
@@ -141,17 +98,17 @@ add_task(function* () {
   yield extension.startup();
   yield extension.awaitFinish();
 
   let contentAreaContextMenu;
 
   function getTop() {
     contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
     let items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
-    is(items.length, 1, "top level item was found (context=selection)");
+    is(items.length, 1, "top level item was found");
     let topItem = items[0];
     return topItem.childNodes[0];
   }
 
   function* openExtensionMenu() {
     contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
     let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
     yield BrowserTestUtils.synthesizeMouseAtCenter("#img1", {
@@ -186,42 +143,16 @@ add_task(function* () {
     let {info, tab} = yield extension.awaitMessage("browser.contextMenus.onClicked");
     if (expectedClickInfo) {
       checkClickInfo(info, tab);
     }
 
     yield popupHiddenPromise;
   }
 
-  function confirmRadioGroupStates(expectedStates) {
-    let top = getTop();
-
-    let radioItems = top.getElementsByAttribute("type", "radio");
-    let radioGroup1 = top.getElementsByAttribute("label", "radio-group-1");
-    let radioGroup2 = top.getElementsByAttribute("label", "radio-group-2");
-
-    is(radioItems.length, 3, "there should be 3 radio items in the context menu");
-    is(radioGroup1.length, 1, "the first radio group should only have 1 radio item");
-    is(radioGroup2.length, 2, "the second radio group should only have 2 radio items");
-
-    is(radioGroup1[0].hasAttribute("checked"), expectedStates[0], `radio item 1 has state (checked=${expectedStates[0]})`);
-    is(radioGroup2[0].hasAttribute("checked"), expectedStates[1], `radio item 2 has state (checked=${expectedStates[1]})`);
-    is(radioGroup2[1].hasAttribute("checked"), expectedStates[2], `radio item 3 has state (checked=${expectedStates[2]})`);
-  }
-
-  function confirmCheckboxStates(expectedStates) {
-    let checkboxItems = getTop().getElementsByAttribute("type", "checkbox");
-
-    is(checkboxItems.length, 3, "there should be 3 checkbox items in the context menu");
-
-    is(checkboxItems[0].hasAttribute("checked"), expectedStates[0], `checkbox item 1 has state (checked=${expectedStates[0]})`);
-    is(checkboxItems[1].hasAttribute("checked"), expectedStates[1], `checkbox item 2 has state (checked=${expectedStates[1]})`);
-    is(checkboxItems[2].hasAttribute("checked"), expectedStates[2], `checkbox item 3 has state (checked=${expectedStates[2]})`);
-  }
-
   yield openExtensionMenu();
 
   // Check some menu items
   let top = getTop();
   let items = top.getElementsByAttribute("label", "image");
   is(items.length, 1, "contextMenu item for image was found (context=image)");
   let image = items[0];
 
@@ -239,55 +170,16 @@ add_task(function* () {
   // Click on ext-image item and check the click results
   yield closeContextMenu(image, {
     menuItemId: "ext-image",
     mediaType: "image",
     srcUrl: "http://mochi.test:8888/browser/browser/components/extensions/test/browser/ctxmenu-image.png",
     pageUrl: "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html",
   });
 
-  // Test radio groups
-  yield openExtensionMenu();
-  confirmRadioGroupStates([true, false, false]);
-  items = getTop().getElementsByAttribute("type", "radio");
-  yield closeContextMenu(items[1]);
-
-  yield openExtensionMenu();
-  confirmRadioGroupStates([true, true, false]);
-  items = getTop().getElementsByAttribute("type", "radio");
-  yield closeContextMenu(items[2]);
-
-  yield openExtensionMenu();
-  confirmRadioGroupStates([true, false, true]);
-  items = getTop().getElementsByAttribute("type", "radio");
-  yield closeContextMenu(items[0]);
-
-  yield openExtensionMenu();
-  confirmRadioGroupStates([true, false, true]);
-
-  // Test checkboxes
-  items = getTop().getElementsByAttribute("type", "checkbox");
-  confirmCheckboxStates([false, true, false]);
-  yield closeContextMenu(items[0]);
-
-  yield openExtensionMenu();
-  confirmCheckboxStates([true, true, false]);
-  items = getTop().getElementsByAttribute("type", "checkbox");
-  yield closeContextMenu(items[2]);
-
-  yield openExtensionMenu();
-  confirmCheckboxStates([true, true, true]);
-  items = getTop().getElementsByAttribute("type", "checkbox");
-  yield closeContextMenu(items[0]);
-
-  yield openExtensionMenu();
-  confirmCheckboxStates([false, true, true]);
-  items = getTop().getElementsByAttribute("type", "checkbox");
-  yield closeContextMenu(items[2]);
-
   // Select some text
   yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* (arg) {
     let doc = content.document;
     let range = doc.createRange();
     let selection = content.getSelection();
     selection.removeAllRanges();
     let textNode = doc.getElementById("img1").previousSibling;
     range.setStart(textNode, 0);
@@ -321,15 +213,11 @@ add_task(function* () {
   is(items.length, 0, "contextMenu item label update worked (context=selection)");
 
   yield closeContextMenu(selectionItem, {
     menuItemId: "ext-selection",
     pageUrl: "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html",
     selectionText: "just some text 1234567890123456789012345678901234567890123456789012345678901234567890123456789012",
   });
 
-  items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
-  is(items.length, 0, "top level item was not found (after removeAll()");
-
   yield extension.unload();
-
   yield BrowserTestUtils.removeTab(tab1);
 });
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_checkboxes.js
@@ -0,0 +1,105 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+/* globals content */
+/* eslint-disable mozilla/no-cpows-in-tests */
+add_task(function* () {
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
+    "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
+
+  gBrowser.selectedTab = tab1;
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["contextMenus"],
+    },
+
+    background: function() {
+      browser.contextMenus.create({
+        title: "Checkbox",
+        type: "checkbox",
+      });
+
+      browser.contextMenus.create({
+        type: "separator",
+      });
+
+      browser.contextMenus.create({
+        title: "Checkbox",
+        type: "checkbox",
+        checked: true,
+      });
+
+      browser.contextMenus.create({
+        title: "Checkbox",
+        type: "checkbox",
+      });
+
+      browser.test.notifyPass();
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish();
+
+  let contentAreaContextMenu;
+
+  function getTop() {
+    contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+    let items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
+    is(items.length, 1, "top level item was found");
+    let topItem = items[0];
+    return topItem.childNodes[0];
+  }
+
+  function* openExtensionMenu() {
+    contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+    let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+    yield BrowserTestUtils.synthesizeMouseAtCenter("#img1", {type: "contextmenu", button: 2}, gBrowser.selectedBrowser);
+    yield popupShownPromise;
+
+    popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+    EventUtils.synthesizeMouseAtCenter(getTop(), {});
+    yield popupShownPromise;
+  }
+
+  function* closeContextMenu(itemToSelect) {
+    let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
+    EventUtils.synthesizeMouseAtCenter(itemToSelect, {});
+    yield popupHiddenPromise;
+  }
+
+  function confirmCheckboxStates(expectedStates) {
+    let checkboxItems = getTop().getElementsByAttribute("type", "checkbox");
+
+    is(checkboxItems.length, 3, "there should be 3 checkbox items in the context menu");
+
+    is(checkboxItems[0].hasAttribute("checked"), expectedStates[0], `checkbox item 1 has state (checked=${expectedStates[0]})`);
+    is(checkboxItems[1].hasAttribute("checked"), expectedStates[1], `checkbox item 2 has state (checked=${expectedStates[1]})`);
+    is(checkboxItems[2].hasAttribute("checked"), expectedStates[2], `checkbox item 3 has state (checked=${expectedStates[2]})`);
+  }
+
+  yield openExtensionMenu();
+  let items = getTop().getElementsByAttribute("type", "checkbox");
+  confirmCheckboxStates([false, true, false]);
+  yield closeContextMenu(items[0]);
+
+  yield openExtensionMenu();
+  confirmCheckboxStates([true, true, false]);
+  items = getTop().getElementsByAttribute("type", "checkbox");
+  yield closeContextMenu(items[2]);
+
+  yield openExtensionMenu();
+  confirmCheckboxStates([true, true, true]);
+  items = getTop().getElementsByAttribute("type", "checkbox");
+  yield closeContextMenu(items[0]);
+
+  yield openExtensionMenu();
+  confirmCheckboxStates([false, true, true]);
+  items = getTop().getElementsByAttribute("type", "checkbox");
+  yield closeContextMenu(items[2]);
+
+  yield extension.unload();
+  yield BrowserTestUtils.removeTab(tab1);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_radioGroups.js
@@ -0,0 +1,110 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+/* globals content */
+/* eslint-disable mozilla/no-cpows-in-tests */
+add_task(function* () {
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
+    "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
+
+  gBrowser.selectedTab = tab1;
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["contextMenus"],
+    },
+
+    background: function() {
+      browser.contextMenus.create({
+        title: "radio-group-1",
+        type: "radio",
+        checked: true,
+      });
+
+      browser.contextMenus.create({
+        type: "separator",
+      });
+
+      browser.contextMenus.create({
+        title: "radio-group-2",
+        type: "radio",
+      });
+
+      browser.contextMenus.create({
+        title: "radio-group-2",
+        type: "radio",
+      });
+
+      browser.test.notifyPass();
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish();
+
+  let contentAreaContextMenu;
+
+  function getTop() {
+    contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+    let items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
+    is(items.length, 1, "top level item was found");
+    let topItem = items[0];
+    return topItem.childNodes[0];
+  }
+
+  function* openExtensionMenu() {
+    contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+    let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+    yield BrowserTestUtils.synthesizeMouseAtCenter("#img1", {type: "contextmenu", button: 2}, gBrowser.selectedBrowser);
+    yield popupShownPromise;
+
+    popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+    EventUtils.synthesizeMouseAtCenter(getTop(), {});
+    yield popupShownPromise;
+  }
+
+  function* closeContextMenu(itemToSelect) {
+    let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
+    EventUtils.synthesizeMouseAtCenter(itemToSelect, {});
+    yield popupHiddenPromise;
+  }
+
+  function confirmRadioGroupStates(expectedStates) {
+    let top = getTop();
+    let radioItems = top.getElementsByAttribute("type", "radio");
+    let radioGroup1 = top.getElementsByAttribute("label", "radio-group-1");
+    let radioGroup2 = top.getElementsByAttribute("label", "radio-group-2");
+
+    is(radioItems.length, 3, "there should be 3 radio items in the context menu");
+    is(radioGroup1.length, 1, "the first radio group should only have 1 radio item");
+    is(radioGroup2.length, 2, "the second radio group should only have 2 radio items");
+
+    is(radioGroup1[0].hasAttribute("checked"), expectedStates[0], `radio item 1 has state (checked=${expectedStates[0]})`);
+    is(radioGroup2[0].hasAttribute("checked"), expectedStates[1], `radio item 2 has state (checked=${expectedStates[1]})`);
+    is(radioGroup2[1].hasAttribute("checked"), expectedStates[2], `radio item 3 has state (checked=${expectedStates[2]})`);
+  }
+
+  yield openExtensionMenu();
+  confirmRadioGroupStates([true, false, false]);
+  let items = getTop().getElementsByAttribute("type", "radio");
+  yield closeContextMenu(items[1]);
+
+  yield openExtensionMenu();
+  confirmRadioGroupStates([true, true, false]);
+  items = getTop().getElementsByAttribute("type", "radio");
+  yield closeContextMenu(items[2]);
+
+  yield openExtensionMenu();
+  confirmRadioGroupStates([true, false, true]);
+  items = getTop().getElementsByAttribute("type", "radio");
+  yield closeContextMenu(items[0]);
+
+  yield openExtensionMenu();
+  confirmRadioGroupStates([true, false, true]);
+  items = getTop().getElementsByAttribute("type", "radio");
+  yield closeContextMenu(items[0]);
+
+  yield extension.unload();
+  yield BrowserTestUtils.removeTab(tab1);
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_uninstall.js
@@ -0,0 +1,70 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+/* globals content */
+/* eslint-disable mozilla/no-cpows-in-tests */
+add_task(function* () {
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
+    "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
+
+  gBrowser.selectedTab = tab1;
+
+  // Install an extension.
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["contextMenus"],
+    },
+
+    background: function() {
+      browser.contextMenus.create({title: "a"});
+      browser.contextMenus.create({title: "b"});
+      browser.test.notifyPass();
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish();
+
+  // Uninstall the extension.
+  yield extension.unload();
+
+  // Install a new extension.
+  extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["contextMenus"],
+    },
+    background: function() {
+      browser.contextMenus.create({title: "c"});
+      browser.contextMenus.create({title: "d"});
+      browser.test.notifyPass();
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish();
+
+  // Open the context menu.
+  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+  let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter("#img1", {type: "contextmenu", button: 2}, gBrowser.selectedBrowser);
+  yield popupShownPromise;
+  popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+  let items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
+  EventUtils.synthesizeMouseAtCenter(items[0].childNodes[0], {});
+  yield popupShownPromise;
+
+  // Make sure the context menu items from the previous extension are gone.
+  items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
+  is(items.length, 1, "only one top level menu item should exist");
+  items = contentAreaContextMenu.getElementsByAttribute("label", "c");
+
+  // Close the context menu.
+  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
+  EventUtils.synthesizeMouseAtCenter(items[0], {});
+  yield popupHiddenPromise;
+
+  // Uninstall the extension.
+  yield extension.unload();
+  yield BrowserTestUtils.removeTab(tab1);
+});