Bug 1246044 - Part 1 - Split out the testing for radio groups and checkboxes into separate files. r=kmag
authorMatthew Wein <mwein@mozilla.com>
Tue, 05 Jul 2016 17:02:24 -0700
changeset 304222 b113ed488daf1ee36e3c23f6fd7d7528fcd56569
parent 304221 68be1552a5ee372558e2b263741b4ce95c9e6205
child 304223 2eb259ef14485698685bff5b4b6c0961a1e0739c
push id30418
push userkwierso@gmail.com
push dateFri, 08 Jul 2016 22:02:34 +0000
treeherdermozilla-central@bbb29a9b88dd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1246044
milestone50.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 1246044 - Part 1 - Split out the testing for radio groups and checkboxes into separate files. r=kmag MozReview-Commit-ID: KIwj3tZzyuz
browser/components/extensions/test/browser/.eslintrc
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/head.js
--- a/browser/components/extensions/test/browser/.eslintrc
+++ b/browser/components/extensions/test/browser/.eslintrc
@@ -14,13 +14,17 @@
     "PanelUI": false,
 
     // Test harness globals
     "ExtensionTestUtils": false,
     "TestUtils": false,
 
     "clickBrowserAction": true,
     "clickPageAction": true,
-    "CustomizableUI": true,
+    "closeContextMenu": true,
+    "closeExtensionContextMenu": true,
     "focusWindow": true,
     "makeWidgetId": true,
+    "openContextMenu": true,
+    "openExtensionContextMenu": true,
+    "CustomizableUI": true,
   }
 }
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -23,16 +23,18 @@ support-files =
 [browser_ext_browserAction_popup.js]
 [browser_ext_browserAction_popup_resize.js]
 [browser_ext_browserAction_simple.js]
 [browser_ext_commands_execute_page_action.js]
 [browser_ext_commands_getAll.js]
 [browser_ext_commands_onCommand.js]
 [browser_ext_contentscript_connect.js]
 [browser_ext_contextMenus.js]
+[browser_ext_contextMenus_checkboxes.js]
+[browser_ext_contextMenus_radioGroups.js]
 [browser_ext_currentWindow.js]
 [browser_ext_getViews.js]
 [browser_ext_history.js]
 [browser_ext_incognito_popup.js]
 [browser_ext_lastError.js]
 [browser_ext_optionsPage_privileges.js]
 [browser_ext_pageAction_context.js]
 [browser_ext_pageAction_popup.js]
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus.js
@@ -22,46 +22,25 @@ add_task(function* () {
       });
       browser.test.notifyPass();
     },
   });
 
   yield extension.startup();
   yield extension.awaitFinish();
 
-  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
-  let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
-  yield BrowserTestUtils.synthesizeMouseAtCenter("#img1", {
-    type: "contextmenu",
-    button: 2,
-  }, gBrowser.selectedBrowser);
-  yield popupShownPromise;
-
+  let contentAreaContextMenu = yield openContextMenu("#img1");
   let item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
   is(item.length, 1, "contextMenu item for image was found");
-
-  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
-  EventUtils.synthesizeMouseAtCenter(item[0], {});
-  yield popupHiddenPromise;
+  yield closeContextMenu();
 
-  contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
-  popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
-  yield BrowserTestUtils.synthesizeMouseAtCenter("body", {
-    type: "contextmenu",
-    button: 2,
-  }, gBrowser.selectedBrowser);
-  yield popupShownPromise;
-
+  contentAreaContextMenu = yield openContextMenu("body");
   item = contentAreaContextMenu.getElementsByAttribute("label", "Click me!");
   is(item.length, 0, "no contextMenu item for image was found");
-
-  // click something to close the context menu
-  popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
-  EventUtils.synthesizeMouseAtCenter(document.getElementById("context-selectall"), {});
-  yield popupHiddenPromise;
+  yield closeContextMenu();
 
   yield extension.unload();
 
   yield BrowserTestUtils.removeTab(tab1);
 });
 
 /* globals content */
 /* eslint-disable mozilla/no-cpows-in-tests */
@@ -137,260 +116,128 @@ 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();
+          browser.test.notifyFail("contextmenus");
         },
         () => {
-          browser.test.notifyPass();
+          browser.test.notifyPass("contextmenus");
         }
       );
     },
   });
 
   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)");
-    let topItem = items[0];
-    return topItem.childNodes[0];
-  }
+  yield extension.awaitFinish("contextmenus");
 
-  function* openExtensionMenu() {
-    contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
-    let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
-    yield BrowserTestUtils.synthesizeMouseAtCenter("#img1", {
-      type: "contextmenu",
-      button: 2,
-    }, gBrowser.selectedBrowser);
-    yield popupShownPromise;
+  let expectedClickInfo = {
+    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",
+  };
 
-    popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
-    EventUtils.synthesizeMouseAtCenter(getTop(), {});
-    yield popupShownPromise;
+  function checkClickInfo(result) {
+    for (let i of Object.keys(expectedClickInfo)) {
+      is(result.info[i], expectedClickInfo[i],
+         "click info " + i + " expected to be: " + expectedClickInfo[i] + " but was: " + info[i]);
+    }
+    is(expectedClickInfo.pageSrc, result.tab.url);
   }
 
-  function* closeContextMenu(itemToSelect, expectedClickInfo, hasOnclickProperty = true) {
-    function checkClickInfo(info, tab) {
-      for (let i of Object.keys(expectedClickInfo)) {
-        is(info[i], expectedClickInfo[i],
-           "click info " + i + " expected to be: " + expectedClickInfo[i] + " but was: " + info[i]);
-      }
-      is(expectedClickInfo.pageSrc, tab.url);
-    }
-    let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
-    EventUtils.synthesizeMouseAtCenter(itemToSelect, {});
-
-    if (hasOnclickProperty) {
-      let {info, tab} = yield extension.awaitMessage("onclick");
-      if (expectedClickInfo) {
-        checkClickInfo(info, tab);
-      }
-    }
-
-    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();
+  let extensionMenuRoot = yield openExtensionContextMenu();
 
   // Check some menu items
-  let top = getTop();
-  let items = top.getElementsByAttribute("label", "image");
+  let items = extensionMenuRoot.getElementsByAttribute("label", "image");
   is(items.length, 1, "contextMenu item for image was found (context=image)");
   let image = items[0];
 
-  items = top.getElementsByAttribute("label", "selection-edited");
+  items = extensionMenuRoot.getElementsByAttribute("label", "selection-edited");
   is(items.length, 0, "contextMenu item for selection was not found (context=image)");
 
-  items = top.getElementsByAttribute("label", "parentToDel");
+  items = extensionMenuRoot.getElementsByAttribute("label", "parentToDel");
   is(items.length, 0, "contextMenu item for removed parent was not found (context=image)");
 
-  items = top.getElementsByAttribute("label", "parent");
+  items = extensionMenuRoot.getElementsByAttribute("label", "parent");
   is(items.length, 1, "contextMenu item for parent was found (context=image)");
 
   is(items[0].childNodes[0].childNodes.length, 2, "child items for parent were found (context=image)");
 
   // 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 closeExtensionContextMenu(image);
 
-  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]);
+  let result = yield extension.awaitMessage("onclick");
+  checkClickInfo(result);
+  result = yield extension.awaitMessage("browser.contextMenus.onClicked");
+  checkClickInfo(result);
 
   // 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);
     range.setEnd(textNode, 100);
     selection.addRange(range);
   });
 
   // Bring up context menu again
-  yield openExtensionMenu();
+  extensionMenuRoot = yield openExtensionContextMenu();
 
   // Check some menu items
-  top = getTop();
-  items = top.getElementsByAttribute("label", "Without onclick property");
+  items = extensionMenuRoot.getElementsByAttribute("label", "Without onclick property");
   is(items.length, 1, "contextMenu item was found (context=page)");
 
-  yield closeContextMenu(items[0], {
+  yield closeExtensionContextMenu(items[0]);
+
+  expectedClickInfo = {
     menuItemId: "ext-without-onclick",
     pageUrl: "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html",
-  }, false /* hasOnclickProperty */);
+  };
+
+  result = yield extension.awaitMessage("browser.contextMenus.onClicked");
+  checkClickInfo(result);
 
   // Bring up context menu again
-  yield openExtensionMenu();
+  extensionMenuRoot = yield openExtensionContextMenu();
 
   // Check some menu items
-  top = getTop();
-  items = top.getElementsByAttribute("label", "selection is: 'just some text 123456789012345678901234567890...'");
+  items = extensionMenuRoot.getElementsByAttribute("label", "selection is: 'just some text 123456789012345678901234567890...'");
   is(items.length, 1, "contextMenu item for selection was found (context=selection)");
   let selectionItem = items[0];
 
-  items = top.getElementsByAttribute("label", "selection");
+  items = extensionMenuRoot.getElementsByAttribute("label", "selection");
   is(items.length, 0, "contextMenu item label update worked (context=selection)");
 
-  yield closeContextMenu(selectionItem, {
+  yield closeExtensionContextMenu(selectionItem);
+
+  expectedClickInfo = {
     menuItemId: "ext-selection",
     pageUrl: "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html",
     selectionText: "just some text 1234567890123456789012345678901234567890123456789012345678901234567890123456789012",
-  });
+  };
 
+  result = yield extension.awaitMessage("onclick");
+  checkClickInfo(result);
+  result = yield extension.awaitMessage("browser.contextMenus.onClicked");
+  checkClickInfo(result);
+
+  let contentAreaContextMenu = yield openContextMenu("#img1");
   items = contentAreaContextMenu.getElementsByAttribute("ext-type", "top-level-menu");
   is(items.length, 0, "top level item was not found (after removeAll()");
+  yield closeContextMenu();
 
   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,74 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+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("contextmenus-checkboxes");
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish("contextmenus-checkboxes");
+
+  function confirmCheckboxStates(extensionMenuRoot, expectedStates) {
+    let checkboxItems = extensionMenuRoot.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]})`);
+
+    return extensionMenuRoot.getElementsByAttribute("type", "checkbox");
+  }
+
+  let extensionMenuRoot = yield openExtensionContextMenu();
+  let items = confirmCheckboxStates(extensionMenuRoot, [false, true, false]);
+  yield closeExtensionContextMenu(items[0]);
+
+  extensionMenuRoot = yield openExtensionContextMenu();
+  items = confirmCheckboxStates(extensionMenuRoot, [true, true, false]);
+  yield closeExtensionContextMenu(items[2]);
+
+  extensionMenuRoot = yield openExtensionContextMenu();
+  items = confirmCheckboxStates(extensionMenuRoot, [true, true, true]);
+  yield closeExtensionContextMenu(items[0]);
+
+  extensionMenuRoot = yield openExtensionContextMenu();
+  items = confirmCheckboxStates(extensionMenuRoot, [false, true, true]);
+  yield closeExtensionContextMenu(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,78 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+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("contextmenus-radio-groups");
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish("contextmenus-radio-groups");
+
+  function confirmRadioGroupStates(extensionMenuRoot, expectedStates) {
+    let radioItems = extensionMenuRoot.getElementsByAttribute("type", "radio");
+    let radioGroup1 = extensionMenuRoot.getElementsByAttribute("label", "radio-group-1");
+    let radioGroup2 = extensionMenuRoot.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]})`);
+
+    return extensionMenuRoot.getElementsByAttribute("type", "radio");
+  }
+
+  let extensionMenuRoot = yield openExtensionContextMenu();
+  let items = confirmRadioGroupStates(extensionMenuRoot, [true, false, false]);
+  yield closeExtensionContextMenu(items[1]);
+
+  extensionMenuRoot = yield openExtensionContextMenu();
+  items = confirmRadioGroupStates(extensionMenuRoot, [true, true, false]);
+  yield closeExtensionContextMenu(items[2]);
+
+  extensionMenuRoot = yield openExtensionContextMenu();
+  items = confirmRadioGroupStates(extensionMenuRoot, [true, false, true]);
+  yield closeExtensionContextMenu(items[0]);
+
+  extensionMenuRoot = yield openExtensionContextMenu();
+  items = confirmRadioGroupStates(extensionMenuRoot, [true, false, true]);
+  yield closeExtensionContextMenu(items[0]);
+
+  yield extension.unload();
+  yield BrowserTestUtils.removeTab(tab1);
+});
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -3,16 +3,18 @@
 "use strict";
 
 /* exported CustomizableUI makeWidgetId focusWindow forceGC
  *          getBrowserActionWidget
  *          clickBrowserAction clickPageAction
  *          getBrowserActionPopup getPageActionPopup
  *          closeBrowserAction closePageAction
  *          promisePopupShown promisePopupHidden
+ *          openContextMenu closeContextMenu
+ *          openExtensionContextMenu closeExtensionContextMenu
  */
 
 var {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm");
 var {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm");
 
 // Bug 1239884: Our tests occasionally hit a long GC pause at unpredictable
 // times in debug builds, which results in intermittent timeouts. Until we have
 // a better solution, we force a GC after certain strategic tests, which tend to
@@ -99,16 +101,54 @@ function closeBrowserAction(extension, w
   let group = getBrowserActionWidget(extension);
 
   let node = win.document.getElementById(group.viewId);
   CustomizableUI.hidePanelForNode(node);
 
   return Promise.resolve();
 }
 
+function* openContextMenu(id) {
+  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+  let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
+  yield BrowserTestUtils.synthesizeMouseAtCenter(id, {type: "contextmenu", button: 2}, gBrowser.selectedBrowser);
+  yield popupShownPromise;
+  return contentAreaContextMenu;
+}
+
+function* closeContextMenu() {
+  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
+  contentAreaContextMenu.hidePopup();
+  yield popupHiddenPromise;
+}
+
+function* openExtensionContextMenu() {
+  let contextMenu = yield openContextMenu("#img1");
+  let topLevelMenu = contextMenu.getElementsByAttribute("ext-type", "top-level-menu");
+
+  // Return null if the extension only has one item and therefore no extension menu.
+  if (topLevelMenu.length == 0) {
+    return null;
+  }
+
+  let extensionMenu = topLevelMenu[0].childNodes[0];
+  let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+  EventUtils.synthesizeMouseAtCenter(extensionMenu, {});
+  yield popupShownPromise;
+  return extensionMenu;
+}
+
+function* closeExtensionContextMenu(itemToSelect) {
+  let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
+  let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
+  EventUtils.synthesizeMouseAtCenter(itemToSelect, {});
+  yield popupHiddenPromise;
+}
+
 function getPageActionPopup(extension, win = window) {
   let panelId = makeWidgetId(extension.id) + "-panel";
   return win.document.getElementById(panelId);
 }
 
 function clickPageAction(extension, win = window) {
   // This would normally be set automatically on navigation, and cleared
   // when the user types a value into the URL bar, to show and hide page