Bug 1543940 - Update tests to use toolbox.topDoc to query context-menu elements r=ochameau
authorJulian Descottes <jdescottes@mozilla.com>
Wed, 08 May 2019 21:36:37 +0000
changeset 473138 6907e6f93141299a40d3824c8cd8de8b00dcc765
parent 473137 a0768b78ff32581c457122430db68e11a0a5c479
child 473139 8fa4f7a2ab42ff565a7839bd401273c195f52bd4
push id113065
push useropoprus@mozilla.com
push dateThu, 09 May 2019 03:46:59 +0000
treeherdermozilla-inbound@34a824c75b7b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1543940
milestone68.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 1543940 - Update tests to use toolbox.topDoc to query context-menu elements r=ochameau Depends on D27695 Differential Revision: https://phabricator.services.mozilla.com/D27696
devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_devtoolstoolbox_contextmenu_markupview.js
devtools/client/accessibility/test/mochitest/test_accessible_row_context_menu.html
devtools/client/framework/test/browser_menu_api.js
devtools/client/framework/test/browser_toolbox_textbox_context_menu.js
devtools/client/framework/test/browser_toolbox_zoom_popup.js
devtools/client/framework/toolbox.js
devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js
devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js
devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js
devtools/client/inspector/test/browser_inspector_textbox-menu.js
devtools/client/inspector/test/browser_inspector_textbox-menu_reopen_toolbox.js
devtools/client/netmonitor/test/browser_net_block.js
devtools/client/netmonitor/test/browser_net_columns_last_column.js
devtools/client/netmonitor/test/browser_net_columns_reset.js
devtools/client/netmonitor/test/browser_net_columns_showhide.js
devtools/client/netmonitor/test/browser_net_copy_as_curl.js
devtools/client/netmonitor/test/browser_net_copy_as_fetch.js
devtools/client/netmonitor/test/browser_net_copy_headers.js
devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
devtools/client/netmonitor/test/browser_net_copy_params.js
devtools/client/netmonitor/test/browser_net_copy_response.js
devtools/client/netmonitor/test/browser_net_copy_svg_image_as_data_uri.js
devtools/client/netmonitor/test/browser_net_copy_url.js
devtools/client/netmonitor/test/browser_net_edit_resend_cancel.js
devtools/client/netmonitor/test/browser_net_edit_resend_caret.js
devtools/client/netmonitor/test/browser_net_edit_resend_with_filtering.js
devtools/client/netmonitor/test/browser_net_edit_resend_xhr.js
devtools/client/netmonitor/test/browser_net_open_in_debugger.js
devtools/client/netmonitor/test/browser_net_open_in_style_editor.js
devtools/client/netmonitor/test/browser_net_open_request_in_tab.js
devtools/client/netmonitor/test/browser_net_propertiesview-copy.js
devtools/client/netmonitor/test/browser_net_resend_xhr.js
devtools/client/netmonitor/test/browser_net_sort-reset.js
devtools/client/netmonitor/test/browser_net_telemetry_edit_resend.js
devtools/client/netmonitor/test/browser_net_telemetry_throttle_changed.js
devtools/client/netmonitor/test/browser_net_use_as_fetch.js
devtools/client/netmonitor/test/head.js
devtools/client/shared/components/throttling/NetworkThrottlingMenu.js
devtools/client/webconsole/test/mochitest/browser_jsterm_context_menu_labels.js
devtools/client/webconsole/test/mochitest/head.js
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_devtoolstoolbox_contextmenu_markupview.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_devtoolstoolbox_contextmenu_markupview.js
@@ -10,28 +10,28 @@ Services.scriptloader.loadSubScript(CHRO
  * Test context menu of markup view on about:devtools-toolbox page.
  */
 add_task(async function() {
   info("Force all debug target panes to be expanded");
   prepareCollapsibilitiesTest();
 
   const { document, tab, window } = await openAboutDebugging();
   await selectThisFirefoxPage(document, window.AboutDebugging.store);
-  const { devtoolsDocument, devtoolsTab, devtoolsWindow } =
+  const { devtoolsTab, devtoolsWindow } =
     await openAboutDevtoolsToolbox(document, tab, window);
 
   info("Select inspector tool");
   const toolbox = getToolbox(devtoolsWindow);
   await toolbox.selectTool("inspector");
 
   info("Show context menu of markup view");
   const markupDocument = toolbox.getPanel("inspector").markup.doc;
   EventUtils.synthesizeMouseAtCenter(markupDocument.body,
                                      { type: "contextmenu" },
                                      markupDocument.ownerGlobal);
 
   info("Check whether proper context menu of markup view will be shown");
-  await waitUntil(() => devtoolsDocument.querySelector("#node-menu-edithtml"));
+  await waitUntil(() => toolbox.topDoc.querySelector("#node-menu-edithtml"));
   ok(true, "Context menu of markup view should be shown");
 
   await closeAboutDevtoolsToolbox(document, devtoolsTab, window);
   await removeTab(tab);
 });
--- a/devtools/client/accessibility/test/mochitest/test_accessible_row_context_menu.html
+++ b/devtools/client/accessibility/test/mochitest/test_accessible_row_context_menu.html
@@ -105,21 +105,23 @@ window.onload = async function() {
       ui: { supports: {}},
       ...auditState,
     };
 
     info("Check contextmenu default behaviour.");
     renderAccessibilityRow(defaultProps, defaultState);
     let row = document.getElementById(ROW_ID);
 
+    info("Get topmost document where the context meny will be rendered");
+    const menuDoc = document.defaultView.windowRoot.ownerGlobal.document;
     await withMockEnv(async function() {
       Simulate.contextMenu(row);
 
-      const menu = document.getElementById("accessibility-row-contextmenu");
-      const printtojsonMenuItem = document.getElementById("menu-printtojson");
+      const menu = menuDoc.getElementById("accessibility-row-contextmenu");
+      const printtojsonMenuItem = menuDoc.getElementById("menu-printtojson");
 
       ok(menu, "Accessibility row context menu is open");
       ok(printtojsonMenuItem, "Print to JSON menu item is visible");
 
       const browserWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
       const defaultOpenWebLinkIn = browserWindow.openWebLinkIn;
 
       let openWebLinkInCalled;
@@ -144,25 +146,25 @@ window.onload = async function() {
     });
 
     info("Check accessibility row when context menu is not supported.");
     renderAccessibilityRow(defaultProps, mockState);
     row = document.getElementById(ROW_ID);
 
     info("Check contextmenu listener is not called when context menu is not supported.");
     Simulate.contextMenu(row);
-    let menu = document.getElementById("accessibility-row-contextmenu");
+    let menu = menuDoc.getElementById("accessibility-row-contextmenu");
     ok(!menu, "contextmenu event handler was never called.");
 
     info("Check accessibility row when no context menu is available.");
     renderAccessibilityRow(mockProps, defaultState);
     row = document.getElementById(ROW_ID);
 
     Simulate.contextMenu(row);
-    menu = document.getElementById("accessibility-row-contextmenu");
+    menu = menuDoc.getElementById("accessibility-row-contextmenu");
     ok(!menu, "contextmenu event handler was never called.");
   } catch (e) {
     ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
   } finally {
     SimpleTest.finish();
   }
 };
 </script>
--- a/devtools/client/framework/test/browser_menu_api.js
+++ b/devtools/client/framework/test/browser_menu_api.js
@@ -12,16 +12,20 @@ const Menu = require("devtools/client/fr
 const MenuItem = require("devtools/client/framework/menu-item");
 
 add_task(async function() {
   info("Create a test tab and open the toolbox");
   const tab = await addTab(URL);
   const target = await TargetFactory.forTab(tab);
   const toolbox = await gDevTools.showToolbox(target, "webconsole");
 
+  // This test will involve localized strings, make sure the necessary FTL file is
+  // available in the toolbox top window.
+  toolbox.topWindow.MozXULElement.insertFTLIfNeeded("toolkit/main-window/editmenu.ftl");
+
   await testMenuItems();
   await testMenuPopup(toolbox);
   await testSubmenu(toolbox);
 });
 
 function testMenuItems() {
   const menu = new Menu();
   const menuItem1 = new MenuItem();
@@ -77,23 +81,23 @@ async function testMenuPopup(toolbox) {
   // Append an invisible MenuItem, which shouldn't show up in the DOM
   menu.append(new MenuItem({
     label: "Invisible",
     visible: false,
   }));
 
   menu.popup(0, 0, toolbox.doc);
 
-  ok(toolbox.doc.querySelector("#menu-popup"), "A popup is in the DOM");
+  ok(toolbox.topDoc.querySelector("#menu-popup"), "A popup is in the DOM");
 
   const menuSeparators =
-    toolbox.doc.querySelectorAll("#menu-popup > menuseparator");
+    toolbox.topDoc.querySelectorAll("#menu-popup > menuseparator");
   is(menuSeparators.length, 1, "A separator is in the menu");
 
-  const menuItems = toolbox.doc.querySelectorAll("#menu-popup > menuitem");
+  const menuItems = toolbox.topDoc.querySelectorAll("#menu-popup > menuitem");
   is(menuItems.length, MENU_ITEMS.length, "Correct number of menuitems");
 
   is(menuItems[0].id, MENU_ITEMS[0].id, "Correct id for menuitem");
   is(menuItems[0].getAttribute("label"), MENU_ITEMS[0].label, "Correct label");
 
   is(menuItems[1].getAttribute("label"), MENU_ITEMS[1].label, "Correct label");
   is(menuItems[1].getAttribute("type"), "checkbox", "Correct type attr");
   is(menuItems[1].getAttribute("checked"), "true", "Has checked attr");
@@ -104,21 +108,21 @@ async function testMenuPopup(toolbox) {
 
   is(menuItems[3].getAttribute("label"), MENU_ITEMS[3].label, "Correct label");
   is(menuItems[3].getAttribute("disabled"), "true", "disabled attr menuitem");
 
   is(menuItems[4].getAttribute("data-l10n-id"), MENU_ITEMS[4].l10nID, "Correct localization attribute");
 
   await once(menu, "open");
   const closed = once(menu, "close");
-  EventUtils.synthesizeMouseAtCenter(menuItems[0], {}, toolbox.win);
+  EventUtils.synthesizeMouseAtCenter(menuItems[0], {}, toolbox.topWindow);
   await closed;
   ok(clickFired, "Click has fired");
 
-  ok(!toolbox.doc.querySelector("#menu-popup"), "Popup removed from the DOM");
+  ok(!toolbox.topDoc.querySelector("#menu-popup"), "Popup removed from the DOM");
 }
 
 async function testSubmenu(toolbox) {
   let clickFired = false;
   const menu = new Menu({
     id: "menu-popup",
   });
   const submenu = new Menu({
@@ -139,21 +143,21 @@ async function testSubmenu(toolbox) {
     label: "Submenu parent with attributes",
     id: "submenu-parent-with-attrs",
     submenu: submenu,
     accesskey: "A",
     disabled: true,
   }));
 
   menu.popup(0, 0, toolbox.doc);
-  ok(toolbox.doc.querySelector("#menu-popup"), "A popup is in the DOM");
-  is(toolbox.doc.querySelectorAll("#menu-popup > menuitem").length, 0,
+  ok(toolbox.topDoc.querySelector("#menu-popup"), "A popup is in the DOM");
+  is(toolbox.topDoc.querySelectorAll("#menu-popup > menuitem").length, 0,
     "No menuitem children");
 
-  const menus = toolbox.doc.querySelectorAll("#menu-popup > menu");
+  const menus = toolbox.topDoc.querySelectorAll("#menu-popup > menu");
   is(menus.length, 2, "Correct number of menus");
   ok(!menus[0].hasAttribute("label"), "No label: should be set by localization");
   ok(!menus[0].hasAttribute("disabled"), "Correct disabled state");
   is(menus[0].getAttribute("data-l10n-id"), "editmenu-copy", "Correct localization attribute");
 
   is(menus[1].getAttribute("accesskey"), "A", "Correct accesskey");
   ok(menus[1].hasAttribute("disabled"), "Correct disabled state");
   is(menus[1].id, "submenu-parent-with-attrs", "Correct id");
@@ -175,13 +179,13 @@ async function testSubmenu(toolbox) {
   EventUtils.synthesizeKey("KEY_ArrowLeft");
   await hidden;
 
   shown = once(menus[0], "popupshown");
   EventUtils.synthesizeKey("KEY_ArrowRight");
   await shown;
 
   info("Clicking the submenu item");
-  EventUtils.synthesizeMouseAtCenter(subMenuItems[0], {}, toolbox.win);
+  EventUtils.synthesizeMouseAtCenter(subMenuItems[0], {}, toolbox.topWindow);
 
   await closed;
   ok(clickFired, "Click has fired");
 }
--- a/devtools/client/framework/test/browser_toolbox_textbox_context_menu.js
+++ b/devtools/client/framework/test/browser_toolbox_textbox_context_menu.js
@@ -28,17 +28,17 @@ add_task(async function checkMenuEntrySt
   inspector.searchBox.focus();
   await onFocus;
 
   info("Opening context menu");
   const onContextMenuPopup = toolbox.once("menu-open");
   synthesizeContextMenuEvent(inspector.searchBox);
   await onContextMenuPopup;
 
-  const textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  const textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(textboxContextMenu, "The textbox context menu is loaded in the toolbox");
 
   const cmdUndo = textboxContextMenu.querySelector("#editmenu-undo");
   const cmdDelete = textboxContextMenu.querySelector("#editmenu-delete");
   const cmdSelectAll = textboxContextMenu.querySelector("#editmenu-selectAll");
   const cmdCut = textboxContextMenu.querySelector("#editmenu-cut");
   const cmdCopy = textboxContextMenu.querySelector("#editmenu-copy");
   const cmdPaste = textboxContextMenu.querySelector("#editmenu-paste");
@@ -79,43 +79,43 @@ add_task(async function automaticallyBin
   await checkTextBox(doc.querySelector("input[type=text]"), toolbox);
   await checkTextBox(doc.querySelector("textarea"), toolbox);
   await checkTextBox(doc.querySelector("input[type=search]"), toolbox);
   await checkTextBox(doc.querySelector("input:not([type])"), toolbox);
   await checkNonTextInput(doc.querySelector("input[type=radio]"), toolbox);
 });
 
 async function checkNonTextInput(input, toolbox) {
-  let textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  let textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(!textboxContextMenu, "The menu is closed");
 
   info("Simulating context click on the non text input and expecting no menu to open");
   const eventBubbledUp = new Promise(resolve => {
     input.ownerDocument.addEventListener("contextmenu", resolve, { once: true });
   });
   synthesizeContextMenuEvent(input);
   info("Waiting for event");
   await eventBubbledUp;
 
-  textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(!textboxContextMenu, "The menu is still closed");
 }
 
 async function checkTextBox(textBox, toolbox) {
-  let textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  let textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(!textboxContextMenu, "The menu is closed");
 
   info("Simulating context click on the textbox and expecting the menu to open");
   const onContextMenu = toolbox.once("menu-open");
   synthesizeContextMenuEvent(textBox);
   await onContextMenu;
 
-  textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(textboxContextMenu, "The menu is now visible");
 
   info("Closing the menu");
   const onContextMenuHidden = toolbox.once("menu-close");
   EventUtils.sendKey("ESCAPE", toolbox.win);
   await onContextMenuHidden;
 
-  textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(!textboxContextMenu, "The menu is closed again");
 }
--- a/devtools/client/framework/test/browser_toolbox_zoom_popup.js
+++ b/devtools/client/framework/test/browser_toolbox_zoom_popup.js
@@ -56,17 +56,17 @@ add_task(async function() {
   const menuList =
     [toolbox.win.document.getElementById("toolbox-meatball-menu-button"),
      toolbox.win.document.getElementById("command-button-frames"),
      toolbox.win.document.getElementById("tools-chevron-menu-button"),
      inspector.panelDoc.querySelector(".all-tabs-menu")];
 
   for (const menu of menuList) {
     const { buttonBounds, menuType, menuBounds, arrowBounds } =
-      await getButtonAndMenuInfo(toolbox.doc, menu);
+      await getButtonAndMenuInfo(toolbox, menu);
 
     switch (menuType) {
       case "native":
         {
           // Allow rounded error and platform offset value.
           // horizontal : eIntID_ContextMenuOffsetHorizontal of GTK and Windows
           //              uses 2.
           // vertical: eIntID_ContextMenuOffsetVertical of macOS uses -6.
@@ -111,17 +111,18 @@ add_task(async function() {
  * @return {Object}
  *         An object with the following properties:
  *         - buttonBounds {DOMRect} Bounds of the button.
  *         - menuType {string} Type of the menu, "native" or "doorhanger".
  *         - menuBounds {DOMRect} Bounds of the menu panel.
  *         - arrowBounds {DOMRect|null} Bounds of the arrow. Only set when
  *                       menuType is "doorhanger", null otherwise.
  */
-async function getButtonAndMenuInfo(doc, menuButton) {
+async function getButtonAndMenuInfo(toolbox, menuButton) {
+  const { doc, topDoc } = toolbox;
   info("Show popup menu with click event.");
   EventUtils.sendMouseEvent(
     {
       type: "click",
       screenX: 1,
     },
     menuButton,
     doc.defaultView);
@@ -130,17 +131,17 @@ async function getButtonAndMenuInfo(doc,
   let menuType;
   let arrowBounds = null;
   if (menuButton.hasAttribute("aria-controls")) {
     menuType = "doorhanger";
     menuPopup = doc.getElementById(menuButton.getAttribute("aria-controls"));
     await waitUntil(() => menuPopup.classList.contains("tooltip-visible"));
   } else {
     menuType = "native";
-    const popupset = doc.querySelector("popupset");
+    const popupset = topDoc.querySelector("popupset");
     await waitUntil(() => {
       menuPopup = popupset.querySelector("menupopup[menu-api=\"true\"]");
       return !!menuPopup && menuPopup.state === "open";
     });
   }
   ok(menuPopup, "Menu popup is displayed.");
 
   const buttonBounds = menuButton
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -3256,16 +3256,23 @@ Toolbox.prototype = {
     // Fire event for tests
     menu.once("open", () => this.emit("menu-open"));
     menu.once("close", () => this.emit("menu-close"));
 
     menu.popup(x, y, this.doc);
   },
 
   /**
+   *  Retrieve the current textbox context menu, if available.
+   */
+  getTextBoxContextMenu: function() {
+    return this.topDoc.getElementById("toolbox-menu");
+  },
+
+  /**
    * Connects to the Gecko Profiler when the developer tools are open. This is
    * necessary because of the WebConsole's `profile` and `profileEnd` methods.
    */
   async initPerformance() {
     // If:
     // - target does not have performance actor (addons)
     // - or client uses the new performance panel (incompatible with console.profile())
     // do not even register the shared performance connection.
--- a/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js
+++ b/devtools/client/inspector/computed/test/browser_computed_search-filter_context-menu.js
@@ -24,17 +24,17 @@ add_task(async function() {
   const onFocus = once(searchField, "focus");
   searchField.focus();
   await onFocus;
 
   let onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchField);
   await onContextMenuOpen;
 
-  let searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  let searchContextMenu = toolbox.getTextBoxContextMenu();
   ok(searchContextMenu,
     "The search filter context menu is loaded in the computed view");
 
   let cmdUndo = searchContextMenu.querySelector("#editmenu-undo");
   let cmdDelete = searchContextMenu.querySelector("#editmenu-delete");
   let cmdSelectAll = searchContextMenu.querySelector("#editmenu-selectAll");
   let cmdCut = searchContextMenu.querySelector("#editmenu-cut");
   let cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
@@ -58,31 +58,31 @@ add_task(async function() {
   info("Copy text in search field using the context menu");
   searchField.setUserInput(TEST_INPUT);
   searchField.select();
 
   onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchField);
   await onContextMenuOpen;
 
-  searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  searchContextMenu = toolbox.getTextBoxContextMenu();
   cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
   await waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
 
   onContextMenuClose = toolbox.once("menu-close");
   EventUtils.sendKey("ESCAPE", toolbox.win);
   await onContextMenuClose;
 
   info("Reopen context menu and check command properties");
 
   onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchField);
   await onContextMenuOpen;
 
-  searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  searchContextMenu = toolbox.getTextBoxContextMenu();
   cmdUndo = searchContextMenu.querySelector("#editmenu-undo");
   cmdDelete = searchContextMenu.querySelector("#editmenu-delete");
   cmdSelectAll = searchContextMenu.querySelector("#editmenu-selectAll");
   cmdCut = searchContextMenu.querySelector("#editmenu-cut");
   cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
   cmdPaste = searchContextMenu.querySelector("#editmenu-paste");
 
   is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled");
--- a/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js
+++ b/devtools/client/inspector/rules/test/browser_rules_search-filter_context-menu.js
@@ -23,17 +23,17 @@ add_task(async function() {
   const onFocus = once(searchField, "focus");
   searchField.focus();
   await onFocus;
 
   let onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchField);
   await onContextMenuOpen;
 
-  let searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  let searchContextMenu = toolbox.getTextBoxContextMenu();
   ok(searchContextMenu,
     "The search filter context menu is loaded in the rule view");
 
   let cmdUndo = searchContextMenu.querySelector("#editmenu-undo");
   let cmdDelete = searchContextMenu.querySelector("#editmenu-delete");
   let cmdSelectAll = searchContextMenu.querySelector("#editmenu-selectAll");
   let cmdCut = searchContextMenu.querySelector("#editmenu-cut");
   let cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
@@ -57,31 +57,31 @@ add_task(async function() {
   info("Copy text in search field using the context menu");
   searchField.setUserInput(TEST_INPUT);
   searchField.select();
 
   onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchField);
   await onContextMenuOpen;
 
-  searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  searchContextMenu = toolbox.getTextBoxContextMenu();
   cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
   await waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
 
   onContextMenuClose = toolbox.once("menu-close");
   EventUtils.sendKey("ESCAPE", toolbox.win);
   await onContextMenuClose;
 
   info("Reopen context menu and check command properties");
 
   onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchField);
   await onContextMenuOpen;
 
-  searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  searchContextMenu = toolbox.getTextBoxContextMenu();
   cmdUndo = searchContextMenu.querySelector("#editmenu-undo");
   cmdDelete = searchContextMenu.querySelector("#editmenu-delete");
   cmdSelectAll = searchContextMenu.querySelector("#editmenu-selectAll");
   cmdCut = searchContextMenu.querySelector("#editmenu-cut");
   cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
   cmdPaste = searchContextMenu.querySelector("#editmenu-paste");
 
   is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled");
--- a/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js
+++ b/devtools/client/inspector/test/browser_inspector_search-filter_context-menu.js
@@ -20,17 +20,17 @@ add_task(async function() {
   const onFocus = once(searchBox, "focus");
   searchBox.focus();
   await onFocus;
 
   let onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchBox);
   await onContextMenuOpen;
 
-  let searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  let searchContextMenu = toolbox.getTextBoxContextMenu();
   ok(searchContextMenu,
     "The search filter context menu is loaded in the computed view");
 
   let cmdUndo = searchContextMenu.querySelector("#editmenu-undo");
   let cmdDelete = searchContextMenu.querySelector("#editmenu-delete");
   let cmdSelectAll = searchContextMenu.querySelector("#editmenu-selectAll");
   let cmdCut = searchContextMenu.querySelector("#editmenu-cut");
   let cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
@@ -55,31 +55,31 @@ add_task(async function() {
   searchBox.setUserInput(TEST_INPUT);
   searchBox.select();
   searchBox.focus();
 
   onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchBox);
   await onContextMenuOpen;
 
-  searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  searchContextMenu = toolbox.getTextBoxContextMenu();
   cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
   await waitForClipboardPromise(() => cmdCopy.click(), TEST_INPUT);
 
   onContextMenuClose = toolbox.once("menu-close");
   EventUtils.sendKey("ESCAPE", toolbox.win);
   await onContextMenuClose;
 
   info("Reopen context menu and check command properties");
 
   onContextMenuOpen = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchBox);
   await onContextMenuOpen;
 
-  searchContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  searchContextMenu = toolbox.getTextBoxContextMenu();
   cmdUndo = searchContextMenu.querySelector("#editmenu-undo");
   cmdDelete = searchContextMenu.querySelector("#editmenu-delete");
   cmdSelectAll = searchContextMenu.querySelector("#editmenu-selectAll");
   cmdCut = searchContextMenu.querySelector("#editmenu-cut");
   cmdCopy = searchContextMenu.querySelector("#editmenu-copy");
   cmdPaste = searchContextMenu.querySelector("#editmenu-paste");
 
   is(cmdUndo.getAttribute("disabled"), "", "cmdUndo is enabled");
--- a/devtools/client/inspector/test/browser_inspector_textbox-menu.js
+++ b/devtools/client/inspector/test/browser_inspector_textbox-menu.js
@@ -76,27 +76,27 @@ add_task(async function() {
   await checkTextBox(inspector.panelDoc.activeElement, toolbox);
 
   // Move the mouse out of the box-model region to avoid triggering the box model
   // highlighter.
   EventUtils.synthesizeMouseAtCenter(tag, {}, inspector.panelWin);
 });
 
 async function checkTextBox(textBox, toolbox) {
-  let textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  let textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(!textboxContextMenu, "The menu is closed");
 
   info("Simulating context click on the textbox and expecting the menu to open");
   const onContextMenu = toolbox.once("menu-open");
   synthesizeContextMenuEvent(textBox);
   await onContextMenu;
 
-  textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(textboxContextMenu, "The menu is now visible");
 
   info("Closing the menu");
   const onContextMenuHidden = toolbox.once("menu-close");
   EventUtils.sendKey("ESCAPE", toolbox.win);
   await onContextMenuHidden;
 
-  textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  textboxContextMenu = toolbox.getTextBoxContextMenu();
   ok(!textboxContextMenu, "The menu is closed again");
 }
--- a/devtools/client/inspector/test/browser_inspector_textbox-menu_reopen_toolbox.js
+++ b/devtools/client/inspector/test/browser_inspector_textbox-menu_reopen_toolbox.js
@@ -26,17 +26,17 @@ async function checkContextMenuOnSearchb
   // Here we use the inspector searchbox for this test because it is always available.
   const searchbox = inspector.panelDoc.getElementById("inspector-searchbox");
 
   info("Simulating context click on the textbox and expecting the menu to open");
   const onContextMenu = toolbox.once("menu-open");
   synthesizeContextMenuEvent(searchbox);
   await onContextMenu;
 
-  const textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
+  const textboxContextMenu = toolbox.getTextBoxContextMenu();
   info("Wait until menu items are rendered");
   const pasteElement = textboxContextMenu.querySelector("#editmenu-paste");
   await waitUntil(() => !!pasteElement.getAttribute("label"));
 
   is(pasteElement.getAttribute("label"), "Paste", "Paste is visible and localized");
 
   info("Closing the menu");
   const onContextMenuHidden = toolbox.once("menu-close");
--- a/devtools/client/netmonitor/test/browser_net_block.js
+++ b/devtools/client/netmonitor/test/browser_net_block.js
@@ -6,21 +6,20 @@
 /**
  * Test blocking and unblocking a request.
  */
 
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  const { document, store, windowRequire, parent } = monitor.panelWin;
+  const { document, store, windowRequire } = monitor.panelWin;
   const {
     getSelectedRequest,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
-  const parentDocument = parent.document;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Reload to have one request in the list
   let waitForEvents = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await waitForEvents;
 
@@ -33,17 +32,17 @@ add_task(async function() {
     EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequest);
     await waitForHeaders;
     normalRequestState = getSelectedRequest(store.getState());
     normalRequestSize =
       firstRequest.querySelector(".requests-list-transferred").textContent;
     info("Captured normal request");
     // Mark as blocked
     EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest);
-    const contextBlock = parentDocument.querySelector("#request-list-context-block-url");
+    const contextBlock = getContextMenuItem(monitor, "request-list-context-block-url");
     contextBlock.click();
     info("Set request to blocked");
   }
 
   // Reload to have one request in the list
   info("Reloading to check block");
   // We can't use the normal waiting methods because a canceled request won't send all
   // the extra update packets.
@@ -59,17 +58,17 @@ add_task(async function() {
     blockedRequestSize =
       firstRequest.querySelector(".requests-list-transferred").textContent;
     EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequest);
     blockedRequestState = getSelectedRequest(store.getState());
     info("Captured blocked request");
     // Mark as unblocked
     EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest);
     const contextUnblock =
-      parentDocument.querySelector("#request-list-context-unblock-url");
+      getContextMenuItem(monitor, "request-list-context-unblock-url");
     contextUnblock.click();
     info("Set request to unblocked");
   }
 
   // Reload to have one request in the list
   info("Reloading to check unblock");
   waitForEvents = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
--- a/devtools/client/netmonitor/test/browser_net_columns_last_column.js
+++ b/devtools/client/netmonitor/test/browser_net_columns_last_column.js
@@ -7,17 +7,17 @@
  * Tests that last visible column can't be hidden. Note that the column
  * header is visible only if there are requests in the list.
  */
 
 add_task(async function() {
   const { monitor, tab } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  const { document, store, parent, windowRequire } = monitor.panelWin;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   const wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
   await wait;
 
   const initialColumns = store.getState().ui.columns;
@@ -46,13 +46,12 @@ add_task(async function() {
   }
 
   await teardown(monitor);
 
   async function testLastMenuItem(column) {
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelector(`#requests-list-${column}-button`));
 
-    const menuItem =
-      parent.document.querySelector(`#request-list-header-${column}-toggle`);
+    const menuItem = getContextMenuItem(monitor, `request-list-header-${column}-toggle`);
     ok(menuItem.disabled, "Last visible column menu item should be disabled.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_columns_reset.js
+++ b/devtools/client/netmonitor/test/browser_net_columns_reset.js
@@ -6,17 +6,17 @@
 /**
  * Tests reset column menu item. Note that the column
  * header is visible only if there are requests in the list.
  */
 add_task(async function() {
   const { monitor, tab } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  const { document, store, parent, windowRequire } = monitor.panelWin;
+  const { document, store, windowRequire } = monitor.panelWin;
   const { Prefs } = windowRequire("devtools/client/netmonitor/src/utils/prefs");
 
   const prefBefore = Prefs.visibleColumns;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   const wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
@@ -24,17 +24,17 @@ add_task(async function() {
 
   await hideColumn(monitor, "status");
   await hideColumn(monitor, "waterfall");
 
   const onRequestsFinished = waitForRequestsFinished(monitor);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-contentSize-button"));
 
-  parent.document.querySelector("#request-list-header-reset-columns").click();
+  getContextMenuItem(monitor, "request-list-header-reset-columns").click();
   await onRequestsFinished;
 
   ok(JSON.stringify(prefBefore) === JSON.stringify(Prefs.visibleColumns),
      "Reset columns item should reset columns pref");
 });
 
 /**
  * Helper function for waiting for all events to fire before resolving a promise.
--- a/devtools/client/netmonitor/test/browser_net_columns_showhide.js
+++ b/devtools/client/netmonitor/test/browser_net_columns_showhide.js
@@ -5,17 +5,17 @@
 
 /**
  * Test showing/hiding columns.
  */
 add_task(async function() {
   const { monitor, tab } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  const { document, store, parent, connector, windowRequire } = monitor.panelWin;
+  const { document, store, connector, windowRequire } = monitor.panelWin;
   const { requestData } = connector;
   const {
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   const wait = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await wait;
@@ -29,62 +29,62 @@ add_task(async function() {
 
   const requestsContainer = document.querySelector(".requests-list-row-group");
   ok(requestsContainer, "Container element exists as expected.");
   const headers = document.querySelector(".requests-list-headers");
 
   let columns = store.getState().ui.columns;
   for (const column in columns) {
     if (columns[column]) {
-      await testVisibleColumnContextMenuItem(column, document, parent);
+      await testVisibleColumnContextMenuItem(column, document, monitor);
       testColumnsAlignment(headers, requestsContainer);
-      await testHiddenColumnContextMenuItem(column, document, parent);
+      await testHiddenColumnContextMenuItem(column, document, monitor);
     } else {
-      await testHiddenColumnContextMenuItem(column, document, parent);
+      await testHiddenColumnContextMenuItem(column, document, monitor);
       testColumnsAlignment(headers, requestsContainer);
-      await testVisibleColumnContextMenuItem(column, document, parent);
+      await testVisibleColumnContextMenuItem(column, document, monitor);
     }
   }
 
   columns = store.getState().ui.columns;
   for (const column in columns) {
     if (columns[column]) {
-      await testVisibleColumnContextMenuItem(column, document, parent);
+      await testVisibleColumnContextMenuItem(column, document, monitor);
       // Right click on the white-space for the context menu to appear
       // and toggle column visibility
-      await testWhiteSpaceContextMenuItem(column, document, parent);
+      await testWhiteSpaceContextMenuItem(column, document, monitor);
     }
   }
 });
 
-async function testWhiteSpaceContextMenuItem(column, document, parent) {
+async function testWhiteSpaceContextMenuItem(column, document, monitor) {
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 
   info(`Right clicking on white-space in the header to get the context menu`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector(".requests-list-headers"));
 
   // Wait for next tick to do stuff async and force repaint.
   await waitForTick();
-  await toggleAndCheckColumnVisibility(column, document, parent);
+  await toggleAndCheckColumnVisibility(column, document, monitor);
 }
 
-async function testVisibleColumnContextMenuItem(column, document, parent) {
+async function testVisibleColumnContextMenuItem(column, document, monitor) {
   ok(document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be visible`);
 
   info(`Clicking context-menu item for ${column}`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-status-button") ||
     document.querySelector("#requests-list-waterfall-button"));
 
   await waitForTick();
 
-  const menuItem = parent.document.querySelector(`#request-list-header-${column}-toggle`);
+  const menuItem = getContextMenuItem(monitor, `request-list-header-${column}-toggle`);
 
   is(menuItem.getAttribute("type"), "checkbox",
      `${column} menu item should have type="checkbox" attribute`);
   is(menuItem.getAttribute("checked"), "true",
      `checked state of ${column} menu item should be correct`);
   ok(!menuItem.disabled, `disabled state of ${column} menu item should be correct`);
 
   const onHeaderRemoved = waitForDOM(document, `#requests-list-${column}-button`, 0);
@@ -92,31 +92,31 @@ async function testVisibleColumnContextM
 
   await onHeaderRemoved;
   await waitForTick();
 
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 }
 
-async function testHiddenColumnContextMenuItem(column, document, parent) {
+async function testHiddenColumnContextMenuItem(column, document, monitor) {
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 
   info(`Clicking context-menu item for ${column}`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-status-button") ||
     document.querySelector("#requests-list-waterfall-button"));
 
   await waitForTick();
-  await toggleAndCheckColumnVisibility(column, document, parent);
+  await toggleAndCheckColumnVisibility(column, document, monitor);
 }
 
-async function toggleAndCheckColumnVisibility(column, document, parent) {
-  const menuItem = parent.document.querySelector(`#request-list-header-${column}-toggle`);
+async function toggleAndCheckColumnVisibility(column, document, monitor) {
+  const menuItem = getContextMenuItem(monitor, `request-list-header-${column}-toggle`);
 
   is(menuItem.getAttribute("type"), "checkbox",
      `${column} menu item should have type="checkbox" attribute`);
   ok(!menuItem.getAttribute("checked"),
      `checked state of ${column} menu item should be correct`);
   ok(!menuItem.disabled, `disabled state of ${column} menu item should be correct`);
 
   const onHeaderAdded = waitForDOM(document, `#requests-list-${column}-button`, 1);
--- a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js
@@ -128,18 +128,18 @@ add_task(async function() {
     const { document } = monitor.panelWin;
 
     const items = document.querySelectorAll(".request-list-item");
     EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[0]);
 
     /* Ensure that the copy as cURL option is always visible */
-    const copyUrlParamsNode = monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-as-curl");
+    const copyUrlParamsNode = getContextMenuItem(monitor,
+      "request-list-context-copy-as-curl");
     is(!!copyUrlParamsNode, true,
       "The \"Copy as cURL\" context menu item should not be hidden.");
 
     await waitForClipboardPromise(function setup() {
       copyUrlParamsNode.click();
     }, function validate(result) {
       if (typeof result !== "string") {
         return false;
--- a/devtools/client/netmonitor/test/browser_net_copy_as_fetch.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_as_fetch.js
@@ -48,18 +48,18 @@ add_task(async function() {
     const { document } = monitor.panelWin;
 
     const items = document.querySelectorAll(".request-list-item");
     EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[0]);
 
     /* Ensure that the copy as fetch option is always visible */
-    const copyAsFetchNode = monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-as-fetch");
+    const copyAsFetchNode = getContextMenuItem(monitor,
+      "request-list-context-copy-as-fetch");
     is(!!copyAsFetchNode, true,
       "The \"Copy as Fetch\" context menu item should not be hidden.");
 
     await waitForClipboardPromise(function setup() {
       copyAsFetchNode.click();
     }, function validate(result) {
       if (typeof result !== "string") {
         return false;
--- a/devtools/client/netmonitor/test/browser_net_copy_headers.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_headers.js
@@ -42,18 +42,17 @@ add_task(async function() {
     "Accept-Encoding: gzip, deflate",
     "Connection: keep-alive",
     "Upgrade-Insecure-Requests: 1",
     "Pragma: no-cache",
     "Cache-Control: no-cache",
   ].join("\n");
 
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-request-headers").click();
+    getContextMenuItem(monitor, "request-list-context-copy-request-headers").click();
   }, function validate(result) {
     // Sometimes, a "Cookie" header is left over from other tests. Remove it:
     result = String(result).replace(/Cookie: [^\n]+\n/, "");
     return result === EXPECTED_REQUEST_HEADERS;
   });
   info("Clipboard contains the currently selected item's request headers.");
 
   const EXPECTED_RESPONSE_HEADERS = [
@@ -65,18 +64,17 @@ add_task(async function() {
     "server: httpd.js",
     "date: Sun, 3 May 2015 11:11:11 GMT",
   ].join("\n");
 
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[0]);
 
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#response-list-context-copy-response-headers").click();
+    getContextMenuItem(monitor, "response-list-context-copy-response-headers").click();
   }, function validate(result) {
     // Fake the "Last-Modified" and "Date" headers because they will vary:
     result = String(result)
       .replace(/last-modified: [^\n]+ GMT/, "last-modified: Sun, 3 May 2015 11:11:11 GMT")
       .replace(/date: [^\n]+ GMT/, "date: Sun, 3 May 2015 11:11:11 GMT");
     return result === EXPECTED_RESPONSE_HEADERS;
   });
   info("Clipboard contains the currently selected item's response headers.");
--- a/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
@@ -17,16 +17,15 @@ add_task(async function() {
   await performRequests(monitor, tab, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
 
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[5]);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[5]);
 
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-image-as-data-uri").click();
+    getContextMenuItem(monitor, "request-list-context-copy-image-as-data-uri").click();
   }, TEST_IMAGE_DATA_URI);
 
   ok(true, "Clipboard contains the currently selected image as data uri.");
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_copy_params.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_params.js
@@ -61,54 +61,53 @@ add_task(async function() {
 
   return teardown(monitor);
 
   function testCopyUrlParamsHidden(index, hidden) {
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[index]);
-    const copyUrlParamsNode = monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-url-params");
+    const copyUrlParamsNode = getContextMenuItem(monitor,
+      "request-list-context-copy-url-params");
     is(!!copyUrlParamsNode, !hidden,
       "The \"Copy URL Parameters\" context menu item should" + (hidden ? " " : " not ") +
         "be hidden.");
   }
 
   async function testCopyUrlParams(index, queryString) {
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[index]);
     await waitForClipboardPromise(function setup() {
-      monitor.panelWin.parent.document
-        .querySelector("#request-list-context-copy-url-params").click();
+      getContextMenuItem(monitor, "request-list-context-copy-url-params").click();
     }, queryString);
     ok(true, "The url query string copied from the selected item is correct.");
   }
 
   function testCopyPostDataHidden(index, hidden) {
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[index]);
-    const copyPostDataNode = monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-post-data");
+    const copyPostDataNode = getContextMenuItem(monitor,
+      "request-list-context-copy-post-data");
     is(!!copyPostDataNode, !hidden,
       "The \"Copy POST Data\" context menu item should" + (hidden ? " " : " not ") +
         "be hidden.");
   }
 
   function testCopyRequestDataLabel(index, method) {
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[index]);
-    const copyPostDataNode = monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-post-data");
+    const copyPostDataNode = getContextMenuItem(monitor,
+      "request-list-context-copy-post-data");
     is(copyPostDataNode.attributes.label.value, "Copy " + method + " Data",
       "The \"Copy Data\" context menu item should have label - Copy " + method + " Data");
   }
 
   async function testCopyPostData(index, postData) {
     // Wait for formDataSections and requestPostData state are ready in redux store
     // since copyPostData API needs to read these state.
     await waitUntil(() => {
@@ -117,14 +116,13 @@ add_task(async function() {
       const { formDataSections, requestPostData } = requests.get(actIDs[index]);
       return formDataSections && requestPostData;
     });
     EventUtils.sendMouseEvent({ type: "mousedown" },
       document.querySelectorAll(".request-list-item")[index]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[index]);
     await waitForClipboardPromise(function setup() {
-      monitor.panelWin.parent.document
-        .querySelector("#request-list-context-copy-post-data").click();
+      getContextMenuItem(monitor, "request-list-context-copy-post-data").click();
     }, postData);
     ok(true, "The post data string copied from the selected item is correct.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_copy_response.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_response.js
@@ -19,14 +19,13 @@ add_task(async function() {
   await performRequests(monitor, tab, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
 
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[3]);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[3]);
 
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-response").click();
+    getContextMenuItem(monitor, "request-list-context-copy-response").click();
   }, EXPECTED_RESULT);
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_copy_svg_image_as_data_uri.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_svg_image_as_data_uri.js
@@ -22,16 +22,15 @@ add_task(async function() {
   await wait;
 
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[0]);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[0]);
 
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-image-as-data-uri").click();
+    getContextMenuItem(monitor, "request-list-context-copy-image-as-data-uri").click();
   }, function check(text) {
     return text.startsWith("data:") && !/undefined/.test(text);
   });
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_copy_url.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_url.js
@@ -22,14 +22,13 @@ add_task(async function() {
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[0]);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[0]);
 
   const requestItem = getSortedRequests(store.getState()).get(0);
 
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-copy-url").click();
+    getContextMenuItem(monitor, "request-list-context-copy-url").click();
   }, requestItem.url);
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_edit_resend_cancel.js
+++ b/devtools/client/netmonitor/test/browser_net_edit_resend_cancel.js
@@ -6,37 +6,36 @@
 /**
  * Tests if original request's header panel is visible when custom request is cancelled.
  */
 
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  const { document, store, windowRequire, parent } = monitor.panelWin;
+  const { document, store, windowRequire } = monitor.panelWin;
   const {
     getSelectedRequest,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
-  const parentDocument = parent.document;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Reload to have one request in the list
   const waitForEvents = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await waitForEvents;
 
   // Context Menu > "Edit & Resend"
   const firstRequest = document.querySelectorAll(".request-list-item")[0];
   const waitForHeaders = waitUntil(() => document.querySelector(".headers-overview"));
   EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequest);
   await waitForHeaders;
   EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest);
   const firstRequestState = getSelectedRequest(store.getState());
-  const contextResend =  parentDocument.querySelector("#request-list-context-resend");
+  const contextResend = getContextMenuItem(monitor, "request-list-context-resend");
   contextResend.click();
 
   // Waits for "Edit & Resend" panel to appear > New request "Cancel"
   document.querySelector("#custom-request-close-button").click();
   const finalRequestState = getSelectedRequest(store.getState());
 
   ok(firstRequestState === finalRequestState,
     "Original request is selected after cancel button is clicked"
--- a/devtools/client/netmonitor/test/browser_net_edit_resend_caret.js
+++ b/devtools/client/netmonitor/test/browser_net_edit_resend_caret.js
@@ -10,18 +10,17 @@
  * header's value to empty string. Also make sure the "method" field stays empty
  * after removing it and resets to its original value when it looses focus.
  */
 
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  const { document, store, windowRequire, parent } = monitor.panelWin;
-  const parentDocument = parent.document;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Reload to have one request in the list.
   const waitForEvents = waitForNetworkEvents(monitor, 1);
   BrowserTestUtils.loadURI(tab.linkedBrowser, SIMPLE_URL);
   await waitForEvents;
 
@@ -29,17 +28,17 @@ add_task(async function() {
   const firstRequest = document.querySelectorAll(".request-list-item")[0];
   const waitForHeaders = waitUntil(() => document.querySelector(".headers-overview"));
   EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequest);
   await waitForHeaders;
   await waitForRequestData(store, ["requestHeaders"]);
   EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest);
 
   // Open "New Request" form
-  const contextResend =  parentDocument.querySelector("#request-list-context-resend");
+  const contextResend = getContextMenuItem(monitor, "request-list-context-resend");
   contextResend.click();
   await waitUntil(() => document.querySelector("#custom-headers-value"));
   const headersTextarea = document.querySelector("#custom-headers-value");
   await waitUntil(() => document.querySelector("#custom-method-value"));
   const methodField = document.querySelector("#custom-method-value");
   const originalMethodValue = methodField.value;
   const {
     getSelectedRequest,
--- a/devtools/client/netmonitor/test/browser_net_edit_resend_with_filtering.js
+++ b/devtools/client/netmonitor/test/browser_net_edit_resend_with_filtering.js
@@ -7,18 +7,17 @@
 
 /**
  * Tests if resending a XHR request while filtering XHR displays
  * the correct requests
  */
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(POST_RAW_URL);
 
-  const { document, store, windowRequire, parent } = monitor.panelWin;
-  const parentDocument = parent.document;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Execute XHR request and filter by XHR
   await performRequests(monitor, tab, 1);
   document.querySelector(".requests-list-filter-xhr-button").click();
 
   // Confirm XHR request and click it
@@ -27,17 +26,17 @@ add_task(async function() {
 
   const {
     getSelectedRequest,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
   const firstRequest = getSelectedRequest(store.getState());
 
   // Open context menu and execute "Edit & Resend".
   EventUtils.sendMouseEvent({ type: "contextmenu" }, xhrRequestItem);
-  parentDocument.querySelector("#request-list-context-resend").click();
+  getContextMenuItem(monitor, "request-list-context-resend").click();
 
   // Click Resend
   await waitUntil(() => document.querySelector("#custom-request-send-button"));
   document.querySelector("#custom-request-send-button").click();
 
   // Filtering by "other" so the resent request is visible after completion
   document.querySelector(".requests-list-filter-other-button").click();
 
--- a/devtools/client/netmonitor/test/browser_net_edit_resend_xhr.js
+++ b/devtools/client/netmonitor/test/browser_net_edit_resend_xhr.js
@@ -6,18 +6,17 @@
 /**
  * Tests if editing and resending a XHR request works and the
  * cloned request retains the same cause type.
  */
 
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(POST_RAW_URL);
 
-  const { document, store, windowRequire, parent } = monitor.panelWin;
-  const parentDocument = parent.document;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Executes 1 XHR request
   await performRequests(monitor, tab, 1);
 
   // Selects 1st XHR request
   const xhrRequest = document.querySelectorAll(".request-list-item")[0];
@@ -25,17 +24,17 @@ add_task(async function() {
 
   // Stores original request for comparison of values later
   const { getSelectedRequest }
   = windowRequire("devtools/client/netmonitor/src/selectors/index");
   const original = getSelectedRequest(store.getState());
 
   // Context Menu > "Edit & Resend"
   EventUtils.sendMouseEvent({ type: "contextmenu" }, xhrRequest);
-  parentDocument.querySelector("#request-list-context-resend").click();
+  getContextMenuItem(monitor, "request-list-context-resend").click();
 
   // Waits for "Edit & Resend" panel to appear > New request "Send"
   document.querySelector("#custom-request-send-button").click();
 
   // Selects cloned request
   const clonedRequest = document.querySelectorAll(".request-list-item")[1];
   EventUtils.sendMouseEvent({ type: "mousedown" }, clonedRequest);
   const cloned = getSelectedRequest(store.getState());
--- a/devtools/client/netmonitor/test/browser_net_open_in_debugger.js
+++ b/devtools/client/netmonitor/test/browser_net_open_in_debugger.js
@@ -7,31 +7,30 @@
  * Test the 'Open in debugger' feature
  */
 
 add_task(async function() {
   const { tab, monitor, toolbox} = await initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
   info("Starting test... ");
 
   const { document, store, windowRequire } = monitor.panelWin;
-  const contextMenuDoc = monitor.panelWin.parent.document;
   // Avoid async processing
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
 
-  wait = waitForDOM(contextMenuDoc, "#request-list-context-open-in-debugger");
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[2]);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[2]);
-  await wait;
+  await waitUntil(() =>
+    getContextMenuItem(monitor, "request-list-context-open-in-debugger"));
 
   const onDebuggerReady = toolbox.once("jsdebugger-ready");
-  contextMenuDoc.querySelector("#request-list-context-open-in-debugger").click();
+  getContextMenuItem(monitor, "request-list-context-open-in-debugger").click();
   await onDebuggerReady;
 
   ok(true, "Debugger has been open");
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_open_in_style_editor.js
+++ b/devtools/client/netmonitor/test/browser_net_open_in_style_editor.js
@@ -7,32 +7,30 @@
  * Test the 'Open in debugger' feature
  */
 
 add_task(async function() {
   const { tab, monitor, toolbox} = await initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
   info("Starting test... ");
 
   const { document, store, windowRequire } = monitor.panelWin;
-  const contextMenuDoc = monitor.panelWin.parent.document;
   // Avoid async processing
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, CONTENT_TYPE_WITHOUT_CACHE_REQUESTS);
 
-  wait = waitForDOM(contextMenuDoc, "#request-list-context-open-in-style-editor");
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll(".request-list-item")[1]);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelectorAll(".request-list-item")[1]);
-  await wait;
+  await waitUntil(() =>
+    getContextMenuItem(monitor, "request-list-context-open-in-style-editor"));
 
   const onStyleEditorReady = toolbox.once("styleeditor-ready");
-  monitor.panelWin.parent.document
-    .querySelector("#request-list-context-open-in-style-editor").click();
+  getContextMenuItem(monitor, "request-list-context-open-in-style-editor").click();
   await onStyleEditorReady;
 
   ok(true, "Style Editor has been open");
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js
+++ b/devtools/client/netmonitor/test/browser_net_open_request_in_tab.js
@@ -7,17 +7,16 @@
  * Tests if Open in new tab works by ContextMenu.
  */
 
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(OPEN_REQUEST_IN_TAB_URL);
   info("Starting test...");
 
   const { document, store, windowRequire } = monitor.panelWin;
-  const contextMenuDoc = monitor.panelWin.parent.document;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   let newTab;
 
   store.dispatch(Actions.batchEnable(false));
 
   // Post data may be fetched by the Header panel,
   // so set the Timings panel as the new default.
   store.getState().ui.detailsPanelSelectedTab = "timings";
@@ -41,26 +40,25 @@ add_task(async function() {
   newTab = await openLastRequestInTab();
   await checkTabResponse(newTab, "POST", "application/json", '{"foo":"bar"}');
   gBrowser.removeCurrentTab();
 
   await teardown(monitor);
 
   // OpenLastRequestInTab by ContextMenu
   async function openLastRequestInTab() {
-    const wait = waitForDOM(contextMenuDoc, "#request-list-context-newtab");
     const requestItems = document.querySelectorAll(".request-list-item");
     const lastRequest = requestItems[requestItems.length - 1];
     EventUtils.sendMouseEvent({ type: "mousedown" }, lastRequest);
     EventUtils.sendMouseEvent({ type: "contextmenu" }, lastRequest);
-    await wait;
+    await waitUntil(() =>
+      getContextMenuItem(monitor, "request-list-context-newtab"));
 
     const onTabOpen = once(gBrowser.tabContainer, "TabOpen", false);
-    monitor.panelWin.parent.document
-      .querySelector("#request-list-context-newtab").click();
+    getContextMenuItem(monitor, "request-list-context-newtab").click();
     await onTabOpen;
     info("A new tab has been opened");
 
     const awaitedTab = gBrowser.selectedTab;
     await BrowserTestUtils.browserLoaded(awaitedTab.linkedBrowser);
     info("The tab load completed");
 
     return awaitedTab;
--- a/devtools/client/netmonitor/test/browser_net_propertiesview-copy.js
+++ b/devtools/client/netmonitor/test/browser_net_propertiesview-copy.js
@@ -28,36 +28,33 @@ add_task(async function() {
 
   const objectRow = responsePanel.querySelectorAll(".objectRow")[1];
   const stringRow = responsePanel.querySelectorAll(".stringRow")[0];
 
   /* Test for copy an object */
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     objectRow);
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#properties-view-context-menu-copy").click();
+    getContextMenuItem(monitor, "properties-view-context-menu-copy").click();
   }, `{"obj":{"type":"string"}}`);
 
   /* Test for copy all */
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     objectRow);
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#properties-view-context-menu-copyall").click();
+    getContextMenuItem(monitor, "properties-view-context-menu-copyall").click();
   }, `{"JSON":{"obj":{"type":"string"}},` +
     `"Response payload":{"EDITOR_CONFIG":{"text":` +
     `"{\\"obj\\": {\\"type\\": \\"string\\" }}","mode":"application/json"}}}`);
 
   /* Test for copy a single row */
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     stringRow);
   await waitForClipboardPromise(function setup() {
-    monitor.panelWin.parent.document
-      .querySelector("#properties-view-context-menu-copy").click();
+    getContextMenuItem(monitor, "properties-view-context-menu-copy").click();
   }, "type: string");
 
   await teardown(monitor);
 });
 
 /**
  * Test if response/request Cookies in PropertiesView can be copied
  */
@@ -95,26 +92,24 @@ add_task(async function() {
     { bob: { httpOnly: true, value: "true" } },
     { foo: { httpOnly: true, value: "bar"  } },
     { tom: { httpOnly: true, value: "cool" } }];
   for (let i = 0; i < objectRows.length; i++) {
     const cur = objectRows[i];
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       cur);
     await waitForClipboardPromise(function setup() {
-      monitor.panelWin.parent.document
-        .querySelector("#properties-view-context-menu-copy").click();
+      getContextMenuItem(monitor, "properties-view-context-menu-copy").click();
     }, JSON.stringify(expectedResponseCookies[i]));
   }
 
   const expectedRequestCookies = ["bob: true", "foo: bar", "tom: cool"];
   for (let i = 0; i < expectedRequestCookies.length; i++) {
     const cur = stringRows[objectRows.length + i];
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       cur);
     await waitForClipboardPromise(function setup() {
-      monitor.panelWin.parent.document
-        .querySelector("#properties-view-context-menu-copy").click();
+      getContextMenuItem(monitor, "properties-view-context-menu-copy").click();
     }, expectedRequestCookies[i]);
   }
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_resend_xhr.js
+++ b/devtools/client/netmonitor/test/browser_net_resend_xhr.js
@@ -5,18 +5,17 @@
 
 /**
  * Tests if resending a request works.
  */
 
 add_task(async function() {
   const { tab, monitor } = await initNetMonitor(POST_RAW_URL);
 
-  const { document, store, windowRequire, parent } = monitor.panelWin;
-  const parentDocument = parent.document;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Executes 1 request
   await performRequests(monitor, tab, 1);
 
   // Selects 1st request
   const firstRequest = document.querySelectorAll(".request-list-item")[0];
@@ -24,17 +23,17 @@ add_task(async function() {
 
   // Stores original request for comparison of values later
   const { getSelectedRequest }
   = windowRequire("devtools/client/netmonitor/src/selectors/index");
   const originalRequest = getSelectedRequest(store.getState());
 
   // Context Menu > "Resend"
   EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest);
-  parentDocument.querySelector("#request-list-context-resend-only").click();
+  getContextMenuItem(monitor, "request-list-context-resend-only").click();
 
   // Selects request that was resent
   const selectedRequest = getSelectedRequest(store.getState());
 
   // Compares if the requests are the same.
   ok(originalRequest.url === selectedRequest.url,
   "Both requests are the same");
 
--- a/devtools/client/netmonitor/test/browser_net_sort-reset.js
+++ b/devtools/client/netmonitor/test/browser_net_sort-reset.js
@@ -12,17 +12,17 @@ add_task(async function() {
 
   const { monitor } = await initNetMonitor(SORTING_URL);
   info("Starting test... ");
 
   // It seems that this test may be slow on debug builds. This could be because
   // of the heavy dom manipulation associated with sorting.
   requestLongerTimeout(2);
 
-  const { parent, document, store, windowRequire } = monitor.panelWin;
+  const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   const {
     getDisplayedRequests,
     getSelectedRequest,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
@@ -64,26 +64,26 @@ add_task(async function() {
   testHeaders();
   await testContents([0, 2, 4, 3, 1]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#requests-list-status-button"));
   info("Testing sort reset using context menu 'Reset Sorting'");
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-contentSize-button"));
-  parent.document.querySelector("#request-list-header-reset-sorting").click();
+  getContextMenuItem(monitor, "request-list-header-reset-sorting").click();
   testHeaders();
   await testContents([0, 2, 4, 3, 1]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#requests-list-status-button"));
   info("Testing sort reset using context menu 'Reset Columns'");
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-contentSize-button"));
-  parent.document.querySelector("#request-list-header-reset-columns").click();
+  getContextMenuItem(monitor, "request-list-header-reset-columns").click();
   testHeaders();
   // add columns because verifyRequestItemTarget expects some extra columns
   showColumn(monitor, "protocol");
   showColumn(monitor, "remoteip");
   showColumn(monitor, "scheme");
   showColumn(monitor, "duration");
   showColumn(monitor, "latency");
   await testContents([0, 2, 4, 3, 1]);
--- a/devtools/client/netmonitor/test/browser_net_telemetry_edit_resend.js
+++ b/devtools/client/netmonitor/test/browser_net_telemetry_edit_resend.js
@@ -34,17 +34,17 @@ add_task(async function() {
   const firstRequest = document.querySelectorAll(".request-list-item")[0];
   const waitForHeaders = waitUntil(() => document.querySelector(".headers-overview"));
   EventUtils.sendMouseEvent({ type: "mousedown" }, firstRequest);
   await waitForHeaders;
   await waitForRequestData(store, ["requestHeaders", "responseHeaders"]);
   EventUtils.sendMouseEvent({ type: "contextmenu" }, firstRequest);
 
   // Open "New Request" form and resend.
-  monitor.panelWin.parent.document.querySelector("#request-list-context-resend").click();
+  getContextMenuItem(monitor, "request-list-context-resend").click();
   await waitUntil(() => document.querySelector("#custom-request-send-button"));
   document.querySelector("#custom-request-send-button").click();
 
   await waitForNetworkEvents(monitor, 1);
 
   // Verify existence of the telemetry event.
   checkTelemetryEvent({}, {
     method: "edit_resend",
--- a/devtools/client/netmonitor/test/browser_net_telemetry_throttle_changed.js
+++ b/devtools/client/netmonitor/test/browser_net_telemetry_throttle_changed.js
@@ -6,32 +6,35 @@
 "use strict";
 
 const ALL_CHANNELS = Ci.nsITelemetry.DATASET_ALL_CHANNELS;
 
 /**
  * Test the throttle_change telemetry event.
  */
 add_task(async function() {
-  const { monitor } = await initNetMonitor(SIMPLE_URL);
+  const { monitor, toolbox } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   const { document, store, windowRequire } = monitor.panelWin;
   const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
   store.dispatch(Actions.batchEnable(false));
 
   // Remove all telemetry events.
   Services.telemetry.clearEvents();
 
   // Ensure no events have been logged
   const snapshot = Services.telemetry.snapshotEvents(ALL_CHANNELS, true);
   ok(!snapshot.parent, "No events have been logged for the main process");
 
   document.getElementById("network-throttling-menu").click();
-  monitor.panelWin.parent.document.querySelector("menuitem[label='GPRS']").click();
+  // Throttling menu items cannot be retrieved by id so we can't use getContextMenuItem
+  // here. Instead use querySelector on the toolbox top document, where the context menu
+  // will be rendered.
+  toolbox.topWindow.document.querySelector("menuitem[label='GPRS']").click();
   await waitFor(monitor.panelWin.api, EVENTS.THROTTLING_CHANGED);
 
   // Verify existence of the telemetry event.
   checkTelemetryEvent({
     mode: "GPRS",
   }, {
     method: "throttle_changed",
   });
--- a/devtools/client/netmonitor/test/browser_net_use_as_fetch.js
+++ b/devtools/client/netmonitor/test/browser_net_use_as_fetch.js
@@ -48,18 +48,18 @@ add_task(async function() {
     const { document } = monitor.panelWin;
 
     const items = document.querySelectorAll(".request-list-item");
     EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]);
     EventUtils.sendMouseEvent({ type: "contextmenu" },
       document.querySelectorAll(".request-list-item")[0]);
 
     /* Ensure that the use as fetch option is always visible */
-    const useAsFetchNode = monitor.panelWin.parent.document
-      .querySelector("#request-list-context-use-as-fetch");
+    const useAsFetchNode = getContextMenuItem(monitor,
+      "request-list-context-use-as-fetch");
     is(!!useAsFetchNode, true,
       "The \"Use as Fetch\" context menu item should not be hidden.");
 
     useAsFetchNode.click();
     await toolbox.once("split-console");
     const hud = toolbox.getPanel("webconsole").hud;
     await hud.jsterm.once("set-input-value");
 
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -725,39 +725,39 @@ function testColumnsAlignment(headers, r
     is(headerColumn.getBoundingClientRect().left,
        requestColumn.getBoundingClientRect().left,
        "Headers for columns number " + i + " are aligned."
     );
   }
 }
 
 async function hideColumn(monitor, column) {
-  const { document, parent } = monitor.panelWin;
+  const { document } = monitor.panelWin;
 
   info(`Clicking context-menu item for ${column}`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector(".requests-list-headers"));
 
   const onHeaderRemoved = waitForDOM(document, `#requests-list-${column}-button`, 0);
-  parent.document.querySelector(`#request-list-header-${column}-toggle`).click();
+  getContextMenuItem(monitor, `request-list-header-${column}-toggle`).click();
   await onHeaderRemoved;
 
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 }
 
 async function showColumn(monitor, column) {
-  const { document, parent } = monitor.panelWin;
+  const { document } = monitor.panelWin;
 
   info(`Clicking context-menu item for ${column}`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector(".requests-list-headers"));
 
   const onHeaderAdded = waitForDOM(document, `#requests-list-${column}-button`, 1);
-  parent.document.querySelector(`#request-list-header-${column}-toggle`).click();
+  getContextMenuItem(monitor, `request-list-header-${column}-toggle`).click();
   await onHeaderAdded;
 
   ok(document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be visible`);
 }
 
 /**
  * Select a request and switch to its response panel.
@@ -862,8 +862,17 @@ function queryTelemetryEvents(query) {
     event[1] === category &&
     event[2] === query.method &&
     event[3] === object
   );
 
   // Return the `extra` field (which is event[5]e).
   return filtersChangedEvents.map(event => event[5]);
 }
+
+/**
+ * Retrieve the context menu element corresponding to the provided id, for the provided
+ * netmonitor instance.
+ */
+function getContextMenuItem(monitor, id) {
+  const Menu = require("devtools/client/framework/menu");
+  return Menu.getMenuElementById(id, monitor.panelWin.document);
+}
--- a/devtools/client/shared/components/throttling/NetworkThrottlingMenu.js
+++ b/devtools/client/shared/components/throttling/NetworkThrottlingMenu.js
@@ -27,22 +27,16 @@ class NetworkThrottlingMenu extends Pure
   static get propTypes() {
     return {
       networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
       onChangeNetworkThrottling: PropTypes.func.isRequired,
       useTopLevelWindow: PropTypes.bool,
     };
   }
 
-  static get defaultProps() {
-    return {
-      useTopLevelWindow: false,
-    };
-  }
-
   constructor(props) {
     super(props);
     this.onShowThrottlingMenu = this.onShowThrottlingMenu.bind(this);
   }
 
   onShowThrottlingMenu(event) {
     const {
       networkThrottling,
@@ -63,17 +57,17 @@ class NetworkThrottlingMenu extends Pure
 
     menuItems.unshift({
       label: NO_THROTTLING_LABEL,
       type: "checkbox",
       checked: !networkThrottling.enabled,
       click: () => onChangeNetworkThrottling(false, ""),
     });
 
-    showMenu(menuItems, { button: event.target, useTopLevelWindow });
+    showMenu(menuItems, { button: event.target });
   }
 
   render() {
     const { networkThrottling } = this.props;
     const selectedProfile = networkThrottling.enabled ?
       networkThrottling.profile : NO_THROTTLING_LABEL;
 
     return (
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_context_menu_labels.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_context_menu_labels.js
@@ -27,10 +27,10 @@ add_task(async function() {
   is(undoMenuItem.getAttribute("label"), "Undo",
     "Undo is visible and localized");
 });
 
 async function openTextBoxContextMenu(toolbox, element) {
   const onConsoleMenuOpened = toolbox.once("menu-open");
   synthesizeContextMenuEvent(element);
   await onConsoleMenuOpened;
-  return toolbox.doc.getElementById("toolbox-menu");
+  return toolbox.getTextBoxContextMenu();
 }
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -292,40 +292,44 @@ function findMessages(hud, text, selecto
  * @param element element
  *        The dom element on which the context menu event should be synthesized.
  * @return promise
  */
 async function openContextMenu(hud, element) {
   const onConsoleMenuOpened = hud.ui.wrapper.once("menu-open");
   synthesizeContextMenuEvent(element);
   await onConsoleMenuOpened;
-  const doc = hud.chromeWindow.document;
-  return doc.getElementById("webconsole-menu");
+  return _getContextMenu(hud);
 }
 
 /**
  * Hide the webconsole context menu popup. Returns a promise that will resolve when the
  * context menu popup is hidden or immediately if the popup can't be found.
  *
  * @param object hud
  *        The web console.
  * @return promise
  */
 function hideContextMenu(hud) {
-  const doc = hud.chromeWindow.document;
-  const popup = doc.getElementById("webconsole-menu");
+  const popup = _getContextMenu(hud);
   if (!popup) {
     return Promise.resolve();
   }
 
   const onPopupHidden = once(popup, "popuphidden");
   popup.hidePopup();
   return onPopupHidden;
 }
 
+function _getContextMenu(hud) {
+  const toolbox = gDevTools.getToolbox(hud.target);
+  const doc = toolbox ? toolbox.topWindow.document : hud.chromeWindow.document;
+  return doc.getElementById("webconsole-menu");
+}
+
 function loadDocument(url, browser = gBrowser.selectedBrowser) {
   BrowserTestUtils.loadURI(browser, url);
   return BrowserTestUtils.browserLoaded(browser);
 }
 
 /**
 * Returns a promise that resolves when the node passed as an argument mutate
 * according to the passed configuration.