Backed out changeset b4dcb47b8542 (bug 1449100) for dt failures in devtools/client/netmonitor/test/browser_net_pane-network-details.js on a CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Thu, 12 Apr 2018 06:09:19 +0300
changeset 412917 55a595f1101e1473c2a63dd04d710f4555f1c490
parent 412916 fbbc76f40fcc2dce6492a7edf260f101cab110e2
child 412918 72f15f83cdb6d373bccf3807c51173ec238668b3
push id33824
push userebalazs@mozilla.com
push dateThu, 12 Apr 2018 09:39:57 +0000
treeherdermozilla-central@246c614e1605 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1449100
milestone61.0a1
backs outb4dcb47b854282d4e439f678c79fc2527a215c0d
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
Backed out changeset b4dcb47b8542 (bug 1449100) for dt failures in devtools/client/netmonitor/test/browser_net_pane-network-details.js on a CLOSED TREE
devtools/client/locales/en-US/netmonitor.properties
devtools/client/netmonitor/src/assets/styles/Toolbar.css
devtools/client/netmonitor/src/assets/styles/netmonitor.css
devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
devtools/client/netmonitor/src/components/TabboxPanel.js
devtools/client/netmonitor/src/components/Toolbar.js
devtools/client/netmonitor/src/selectors/ui.js
devtools/client/netmonitor/test/browser_net_brotli.js
devtools/client/netmonitor/test/browser_net_clear.js
devtools/client/netmonitor/test/browser_net_json-b64.js
devtools/client/netmonitor/test/browser_net_json-long.js
devtools/client/netmonitor/test/browser_net_json-malformed.js
devtools/client/netmonitor/test/browser_net_json-null.js
devtools/client/netmonitor/test/browser_net_json_custom_mime.js
devtools/client/netmonitor/test/browser_net_json_text_mime.js
devtools/client/netmonitor/test/browser_net_jsonp.js
devtools/client/netmonitor/test/browser_net_large-response.js
devtools/client/netmonitor/test/browser_net_pane-collapse.js
devtools/client/netmonitor/test/browser_net_pane-toggle.js
devtools/client/netmonitor/test/browser_net_post-data-03.js
devtools/client/netmonitor/test/browser_net_post-data-04.js
devtools/client/netmonitor/test/browser_net_prefs-reload.js
devtools/client/netmonitor/test/browser_net_security-details.js
devtools/client/netmonitor/test/browser_net_security-error.js
devtools/client/netmonitor/test/browser_net_simple-request-details.js
devtools/client/netmonitor/test/browser_net_simple-request.js
devtools/client/netmonitor/test/browser_net_sort-01.js
devtools/client/netmonitor/test/browser_net_sort-02.js
devtools/client/netmonitor/test/browser_net_streaming-response.js
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -53,16 +53,20 @@ netmonitor.security.hostHeader=Host %S:
 # defined:
 #   Organization: <Not Available>
 netmonitor.security.notAvailable=<Not Available>
 
 # LOCALIZATION NOTE (collapseDetailsPane): This is the tooltip for the button
 # that collapses the network details pane in the UI.
 collapseDetailsPane=Hide request details
 
+# LOCALIZATION NOTE (expandDetailsPane): This is the tooltip for the button
+# that expands the network details pane in the UI.
+expandDetailsPane=Show request details
+
 # LOCALIZATION NOTE (headersEmptyText): This is the text displayed in the
 # headers tab of the network details pane when there are no headers available.
 headersEmptyText=No headers for this request
 
 # LOCALIZATION NOTE (headersFilterText): This is the text displayed in the
 # headers tab of the network details pane for the filtering input.
 headersFilterText=Filter headers
 
--- a/devtools/client/netmonitor/src/assets/styles/Toolbar.css
+++ b/devtools/client/netmonitor/src/assets/styles/Toolbar.css
@@ -40,8 +40,32 @@
   bottom: 1px;
 }
 
 .devtools-checkbox-label {
   margin-inline-start: 10px;
   margin-inline-end: 3px;
   white-space: nowrap;
 }
+
+/* Network details panel toggle */
+
+.network-details-panel-toggle:dir(ltr)::before,
+.network-details-panel-toggle.pane-collapsed:dir(rtl)::before {
+  background-image: var(--theme-pane-collapse-image);
+}
+
+.network-details-panel-toggle.pane-collapsed:dir(ltr)::before,
+.network-details-panel-toggle:dir(rtl)::before {
+  background-image: var(--theme-pane-expand-image);
+}
+
+/* Responsive web design support */
+
+@media (max-width: 700px) {
+  .network-details-panel-toggle:dir(ltr)::before {
+    transform: rotate(90deg);
+  }
+
+  .network-details-panel-toggle:dir(rtl)::before {
+    transform: rotate(-90deg);
+  }
+}
--- a/devtools/client/netmonitor/src/assets/styles/netmonitor.css
+++ b/devtools/client/netmonitor/src/assets/styles/netmonitor.css
@@ -1,13 +1,12 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-@import "resource://devtools/client/shared/components/SidebarToggle.css";
 @import "resource://devtools/client/shared/components/splitter/SplitBox.css";
 @import "resource://devtools/client/shared/components/tree/TreeView.css";
 @import "resource://devtools/client/shared/components/tabs/Tabs.css";
 @import "resource://devtools/client/shared/components/tabs/TabBar.css";
 @import "chrome://devtools/skin/components-frame.css";
 @import "chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css";
 @import "chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css";
 @import "chrome://devtools/content/sourceeditor/codemirror/mozilla.css";
--- a/devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
+++ b/devtools/client/netmonitor/src/components/NetworkDetailsPanel.js
@@ -26,17 +26,16 @@ const { div } = dom;
  */
 function NetworkDetailsPanel({
   connector,
   activeTabId,
   cloneSelectedRequest,
   request,
   selectTab,
   sourceMapService,
-  toggleNetworkDetails,
   openLink,
 }) {
   if (!request) {
     return null;
   }
 
   return (
     div({ className: "network-details-panel" },
@@ -44,17 +43,16 @@ function NetworkDetailsPanel({
         TabboxPanel({
           activeTabId,
           cloneSelectedRequest,
           connector,
           openLink,
           request,
           selectTab,
           sourceMapService,
-          toggleNetworkDetails,
         }) :
         CustomRequestPanel({
           connector,
           request,
         })
     )
   );
 }
@@ -64,23 +62,21 @@ NetworkDetailsPanel.displayName = "Netwo
 NetworkDetailsPanel.propTypes = {
   connector: PropTypes.object.isRequired,
   activeTabId: PropTypes.string,
   cloneSelectedRequest: PropTypes.func.isRequired,
   open: PropTypes.bool,
   request: PropTypes.object,
   selectTab: PropTypes.func.isRequired,
   sourceMapService: PropTypes.object,
-  toggleNetworkDetails: PropTypes.func.isRequired,
   openLink: PropTypes.func,
 };
 
 module.exports = connect(
   (state) => ({
     activeTabId: state.ui.detailsPanelSelectedTab,
     request: getSelectedRequest(state),
   }),
   (dispatch) => ({
     cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
     selectTab: (tabId) => dispatch(Actions.selectDetailsPanelTab(tabId)),
-    toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
   }),
 )(NetworkDetailsPanel);
--- a/devtools/client/netmonitor/src/components/TabboxPanel.js
+++ b/devtools/client/netmonitor/src/components/TabboxPanel.js
@@ -15,17 +15,16 @@ const TabPanel = createFactory(require("
 const CookiesPanel = createFactory(require("./CookiesPanel"));
 const HeadersPanel = createFactory(require("./HeadersPanel"));
 const ParamsPanel = createFactory(require("./ParamsPanel"));
 const ResponsePanel = createFactory(require("./ResponsePanel"));
 const SecurityPanel = createFactory(require("./SecurityPanel"));
 const StackTracePanel = createFactory(require("./StackTracePanel"));
 const TimingsPanel = createFactory(require("./TimingsPanel"));
 
-const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
 const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies");
 const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
 const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
 const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
 const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
 const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
 const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
 
@@ -36,35 +35,28 @@ const TIMINGS_TITLE = L10N.getStr("netmo
 function TabboxPanel({
   activeTabId,
   cloneSelectedRequest = () => {},
   connector,
   openLink,
   request,
   selectTab,
   sourceMapService,
-  toggleNetworkDetails,
 }) {
   if (!request) {
     return null;
   }
 
   return (
     Tabbar({
       activeTabId,
       menuDocument: window.parent.document,
       onSelect: selectTab,
       renderOnlySelected: true,
       showAllTabsMenu: true,
-      sidebarToggleButton: {
-        collapsed: false,
-        collapsePaneTitle: COLLAPSE_DETAILS_PANE,
-        expandPaneTitle: "",
-        onClick: toggleNetworkDetails,
-      },
     },
       TabPanel({
         id: PANELS.HEADERS,
         title: HEADERS_TITLE,
       },
         HeadersPanel({
           cloneSelectedRequest,
           connector,
--- a/devtools/client/netmonitor/src/components/Toolbar.js
+++ b/devtools/client/netmonitor/src/components/Toolbar.js
@@ -10,27 +10,30 @@ const dom = require("devtools/client/sha
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 const { connect } = require("devtools/client/shared/redux/visibility-handler-connect");
 
 const Actions = require("../actions/index");
 const { FILTER_SEARCH_DELAY, FILTER_TAGS } = require("../constants");
 const {
   getRecordingState,
   getTypeFilteredRequests,
+  isNetworkDetailsToggleButtonDisabled,
 } = require("../selectors/index");
 const { autocompleteProvider } = require("../utils/filter-autocomplete-provider");
 const { L10N } = require("../utils/l10n");
 const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
 
 // Components
 const SearchBox = createFactory(require("devtools/client/shared/components/SearchBox"));
 
 const { button, div, input, label, span } = dom;
 
 // Localization
+const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
+const EXPAND_DETAILS_PANE = L10N.getStr("expandDetailsPane");
 const SEARCH_KEY_SHORTCUT = L10N.getStr("netmonitor.toolbar.filterFreetext.key");
 const SEARCH_PLACE_HOLDER = L10N.getStr("netmonitor.toolbar.filterFreetext.label");
 const TOOLBAR_CLEAR = L10N.getStr("netmonitor.toolbar.clear");
 const TOOLBAR_TOGGLE_RECORDING = L10N.getStr("netmonitor.toolbar.toggleRecording");
 
 // Preferences
 const DEVTOOLS_DISABLE_CACHE_PREF = "devtools.cache.disabled";
 const DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF = "devtools.netmonitor.persistlog";
@@ -53,16 +56,19 @@ class Toolbar extends Component {
   static get propTypes() {
     return {
       connector: PropTypes.object.isRequired,
       toggleRecording: PropTypes.func.isRequired,
       recording: PropTypes.bool.isRequired,
       clearRequests: PropTypes.func.isRequired,
       requestFilterTypes: PropTypes.object.isRequired,
       setRequestFilterText: PropTypes.func.isRequired,
+      networkDetailsToggleDisabled: PropTypes.bool.isRequired,
+      networkDetailsOpen: PropTypes.bool.isRequired,
+      toggleNetworkDetails: PropTypes.func.isRequired,
       enablePersistentLogs: PropTypes.func.isRequired,
       togglePersistentLogs: PropTypes.func.isRequired,
       persistentLogsEnabled: PropTypes.bool.isRequired,
       disableBrowserCache: PropTypes.func.isRequired,
       toggleBrowserCache: PropTypes.func.isRequired,
       browserCacheDisabled: PropTypes.bool.isRequired,
       toggleRequestFilterType: PropTypes.func.isRequired,
       filteredRequests: PropTypes.array.isRequired,
@@ -81,17 +87,19 @@ class Toolbar extends Component {
   componentDidMount() {
     Services.prefs.addObserver(DEVTOOLS_ENABLE_PERSISTENT_LOG_PREF,
                                this.updatePersistentLogsEnabled);
     Services.prefs.addObserver(DEVTOOLS_DISABLE_CACHE_PREF,
                                this.updateBrowserCacheDisabled);
   }
 
   shouldComponentUpdate(nextProps) {
-    return this.props.persistentLogsEnabled !== nextProps.persistentLogsEnabled
+    return this.props.networkDetailsOpen !== nextProps.networkDetailsOpen
+    || this.props.networkDetailsToggleDisabled !== nextProps.networkDetailsToggleDisabled
+    || this.props.persistentLogsEnabled !== nextProps.persistentLogsEnabled
     || this.props.browserCacheDisabled !== nextProps.browserCacheDisabled
     || this.props.recording !== nextProps.recording
     || !Object.is(this.props.requestFilterTypes, nextProps.requestFilterTypes)
 
     // Filtered requests are useful only when searchbox is focused
     || !!(this.refs.searchbox && this.refs.searchbox.focused);
   }
 
@@ -136,16 +144,19 @@ class Toolbar extends Component {
   }
 
   render() {
     let {
       toggleRecording,
       clearRequests,
       requestFilterTypes,
       setRequestFilterText,
+      networkDetailsToggleDisabled,
+      networkDetailsOpen,
+      toggleNetworkDetails,
       togglePersistentLogs,
       persistentLogsEnabled,
       toggleBrowserCache,
       browserCacheDisabled,
       recording,
     } = this.props;
 
     // Render list of filter-buttons.
@@ -170,16 +181,29 @@ class Toolbar extends Component {
     // Calculate class-list for toggle recording button. The button
     // has two states: pause/play.
     let toggleRecordingButtonClass = [
       "devtools-button",
       "requests-list-pause-button",
       recording ? "devtools-pause-icon" : "devtools-play-icon",
     ].join(" ");
 
+    // Detail toggle button
+    let toggleDetailButtonClassList = [
+      "network-details-panel-toggle",
+      "devtools-button",
+    ];
+
+    if (!networkDetailsOpen) {
+      toggleDetailButtonClassList.push("pane-collapsed");
+    }
+    let toggleDetailButtonClass = toggleDetailButtonClassList.join(" ");
+    let toggleDetailButtonTitle = networkDetailsOpen ? COLLAPSE_DETAILS_PANE :
+      EXPAND_DETAILS_PANE;
+
     // Render the entire toolbar.
     return (
       span({ className: "devtools-toolbar devtools-toolbar-container" },
         span({ className: "devtools-toolbar-group" },
           button({
             className: toggleRecordingButtonClass,
             title: TOOLBAR_TOGGLE_RECORDING,
             onClick: toggleRecording,
@@ -224,34 +248,44 @@ class Toolbar extends Component {
             delay: FILTER_SEARCH_DELAY,
             keyShortcut: SEARCH_KEY_SHORTCUT,
             placeholder: SEARCH_PLACE_HOLDER,
             type: "filter",
             ref: "searchbox",
             onChange: setRequestFilterText,
             onFocus: this.onSearchBoxFocus,
             autocompleteProvider: this.autocompleteProvider,
-          })
+          }),
+          button({
+            className: toggleDetailButtonClass,
+            title: toggleDetailButtonTitle,
+            disabled: networkDetailsToggleDisabled,
+            tabIndex: "0",
+            onClick: toggleNetworkDetails,
+          }),
         )
       )
     );
   }
 }
 
 module.exports = connect(
   (state) => ({
     browserCacheDisabled: state.ui.browserCacheDisabled,
     filteredRequests: getTypeFilteredRequests(state),
+    networkDetailsToggleDisabled: isNetworkDetailsToggleButtonDisabled(state),
+    networkDetailsOpen: state.ui.networkDetailsOpen,
     persistentLogsEnabled: state.ui.persistentLogsEnabled,
     recording: getRecordingState(state),
     requestFilterTypes: state.filters.requestFilterTypes,
   }),
   (dispatch) => ({
     clearRequests: () => dispatch(Actions.clearRequests()),
     disableBrowserCache: (disabled) => dispatch(Actions.disableBrowserCache(disabled)),
     enablePersistentLogs: (enabled) => dispatch(Actions.enablePersistentLogs(enabled)),
     setRequestFilterText: (text) => dispatch(Actions.setRequestFilterText(text)),
     toggleBrowserCache: () => dispatch(Actions.toggleBrowserCache()),
+    toggleNetworkDetails: () => dispatch(Actions.toggleNetworkDetails()),
     toggleRecording: () => dispatch(Actions.toggleRecording()),
     togglePersistentLogs: () => dispatch(Actions.togglePersistentLogs()),
     toggleRequestFilterType: (type) => dispatch(Actions.toggleRequestFilterType(type)),
   }),
 )(Toolbar);
--- a/devtools/client/netmonitor/src/selectors/ui.js
+++ b/devtools/client/netmonitor/src/selectors/ui.js
@@ -1,19 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { createSelector } = require("devtools/client/shared/vendor/reselect");
 const { REQUESTS_WATERFALL } = require("../constants");
+const { getDisplayedRequests } = require("./requests");
 
 const EPSILON = 0.001;
 
+function isNetworkDetailsToggleButtonDisabled(state) {
+  return getDisplayedRequests(state).length == 0;
+}
+
 const getWaterfallScale = createSelector(
   state => state.requests,
   state => state.timingMarkers,
   state => state.ui,
   (requests, timingMarkers, ui) => {
     if (requests.firstStartedMillis === +Infinity || ui.waterfallWidth === null) {
       return null;
     }
@@ -26,10 +31,11 @@ const getWaterfallScale = createSelector
   // Reduce 20px for the last request's requests-list-timings-total
     return Math.min(Math.max(
       (ui.waterfallWidth - REQUESTS_WATERFALL.LABEL_WIDTH - 20) / longestWidth,
       EPSILON), 1);
   }
 );
 
 module.exports = {
+  isNetworkDetailsToggleButtonDisabled,
   getWaterfallScale,
 };
--- a/devtools/client/netmonitor/test/browser_net_brotli.js
+++ b/devtools/client/netmonitor/test/browser_net_brotli.js
@@ -44,17 +44,18 @@ add_task(async function() {
       fullMimeType: "text/plain",
       transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 60),
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 64),
       time: true
     });
 
   wait = waitForDOM(document, ".CodeMirror-code");
   let onResponseContent = monitor.panelWin.once(EVENTS.RECEIVED_RESPONSE_CONTENT);
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
   await onResponseContent;
   await testResponse("br");
   await teardown(monitor);
 
   function testResponse(type) {
--- a/devtools/client/netmonitor/test/browser_net_clear.js
+++ b/devtools/client/netmonitor/test/browser_net_clear.js
@@ -8,16 +8,17 @@
  */
 
 add_task(async function() {
   let { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  let detailsPanelToggleButton = document.querySelector(".network-details-panel-toggle");
   let clearButton = document.querySelector(".requests-list-clear-button");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Make sure we start in a sane state
   assertNoRequestState();
 
   // Load one request and assert it shows up in the list
@@ -34,39 +35,43 @@ add_task(async function() {
   // Load a second request and make sure they still show up
   onMonitorUpdated = waitForAllRequestsFinished(monitor);
   tab.linkedBrowser.reload();
   await onMonitorUpdated;
 
   assertSingleRequestState();
 
   // Make sure we can now open the network details panel
-  store.dispatch(Actions.toggleNetworkDetails());
-  let detailsPanelToggleButton = document.querySelector(".sidebar-toggle");
-  ok(detailsPanelToggleButton &&
+  EventUtils.sendMouseEvent({ type: "click" }, detailsPanelToggleButton);
+
+  ok(document.querySelector(".network-details-panel") &&
     !detailsPanelToggleButton.classList.contains("pane-collapsed"),
-    "The details pane should be visible.");
+    "The details pane should be visible after clicking the toggle button.");
 
   // Click clear and make sure the details pane closes
   EventUtils.sendMouseEvent({ type: "click" }, clearButton);
 
   assertNoRequestState();
   ok(!document.querySelector(".network-details-panel"),
     "The details pane should not be visible clicking 'clear'.");
 
   return teardown(monitor);
 
   /**
    * Asserts the state of the network monitor when one request has loaded
    */
   function assertSingleRequestState() {
     is(store.getState().requests.requests.size, 1,
       "The request menu should have one item at this point.");
+    is(detailsPanelToggleButton.hasAttribute("disabled"), false,
+      "The pane toggle button should be enabled after a request is made.");
   }
 
   /**
    * Asserts the state of the network monitor when no requests have loaded
    */
   function assertNoRequestState() {
     is(store.getState().requests.requests.size, 0,
       "The request menu should be empty at this point.");
+    is(detailsPanelToggleButton.hasAttribute("disabled"), true,
+      "The pane toggle button should be disabled when the request menu is cleared.");
   }
 });
--- a/devtools/client/netmonitor/test/browser_net_json-b64.js
+++ b/devtools/client/netmonitor/test/browser_net_json-b64.js
@@ -16,17 +16,18 @@ add_task(async function() {
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#response-panel");
 
   is(tabpanel.querySelector(".response-error-header") === null, true,
     "The response error header doesn't have the intended visibility.");
--- a/devtools/client/netmonitor/test/browser_net_json-long.js
+++ b/devtools/client/netmonitor/test/browser_net_json-long.js
@@ -46,17 +46,18 @@ add_task(async function() {
       type: "json",
       fullMimeType: "text/json; charset=utf-8",
       size: L10N.getFormatStr("networkMenu.sizeKB",
         L10N.numberWithDecimals(85975 / 1024, 2)),
       time: true
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab();
 
   await teardown(monitor);
 
--- a/devtools/client/netmonitor/test/browser_net_json-malformed.js
+++ b/devtools/client/netmonitor/test/browser_net_json-malformed.js
@@ -38,17 +38,18 @@ add_task(async function() {
     {
       status: 200,
       statusText: "OK",
       type: "json",
       fullMimeType: "text/json; charset=utf-8"
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#response-panel");
   is(tabpanel.querySelector(".response-error-header") === null, false,
     "The response error header doesn't have the intended visibility.");
   is(tabpanel.querySelector(".response-error-header").textContent,
--- a/devtools/client/netmonitor/test/browser_net_json-null.js
+++ b/devtools/client/netmonitor/test/browser_net_json-null.js
@@ -15,22 +15,17 @@ add_task(async function() {
   let { L10N } = windowRequire("devtools/client/netmonitor/src/utils/l10n");
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
-  let onReponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector("#response-tab"));
-  await onReponsePanelReady;
-
+  await openResponsePanel();
   checkResponsePanelDisplaysJSON();
 
   let tabpanel = document.querySelector("#response-panel");
   is(tabpanel.querySelectorAll(".tree-section").length, 2,
     "There should be 2 tree sections displayed in this tabpanel.");
   is(tabpanel.querySelectorAll(".treeRow:not(.tree-section)").length, 1,
     "There should be 1 json properties displayed in this tabpanel.");
   is(tabpanel.querySelectorAll(".empty-notice").length, 0,
@@ -57,9 +52,22 @@ add_task(async function() {
     let jsonView = panel.querySelector(".tree-section .treeLabel") || {};
     is(jsonView.textContent === L10N.getStr("jsonScopeName"), true,
       "The response json view has the intended visibility.");
     is(panel.querySelector(".CodeMirror-code") === null, false,
       "The response editor has the intended visibility.");
     is(panel.querySelector(".response-image-box") === null, true,
       "The response image box doesn't have the intended visibility.");
   }
+
+  /**
+   * Open the netmonitor details panel and switch to the response tab.
+   * Returns a promise that will resolve when the response panel DOM element is available.
+   */
+  function openResponsePanel() {
+    let onReponsePanelReady = waitForDOM(document, "#response-panel .CodeMirror-code");
+    EventUtils.sendMouseEvent({ type: "click" },
+      document.querySelector(".network-details-panel-toggle"));
+    EventUtils.sendMouseEvent({ type: "click" },
+      document.querySelector("#response-tab"));
+    return onReponsePanelReady;
+  }
 });
--- a/devtools/client/netmonitor/test/browser_net_json_custom_mime.js
+++ b/devtools/client/netmonitor/test/browser_net_json_custom_mime.js
@@ -40,17 +40,18 @@ add_task(async function() {
       statusText: "OK",
       type: "x-bigcorp-json",
       fullMimeType: "text/x-bigcorp-json; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 41),
       time: true
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab();
 
   await teardown(monitor);
 
--- a/devtools/client/netmonitor/test/browser_net_json_text_mime.js
+++ b/devtools/client/netmonitor/test/browser_net_json_text_mime.js
@@ -41,17 +41,18 @@ add_task(async function() {
       statusText: "OK",
       type: "plain",
       fullMimeType: "text/plain; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 41),
       time: true
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab();
 
   await teardown(monitor);
 
--- a/devtools/client/netmonitor/test/browser_net_jsonp.js
+++ b/devtools/client/netmonitor/test/browser_net_jsonp.js
@@ -59,17 +59,18 @@ add_task(async function() {
       type: "json",
       fullMimeType: "text/json; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 54),
       time: true
     });
 
   info("Testing first request");
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   testResponseTab("$_0123Fun", "Hello JSONP!");
 
   info("Testing second request");
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
--- a/devtools/client/netmonitor/test/browser_net_large-response.js
+++ b/devtools/client/netmonitor/test/browser_net_large-response.js
@@ -45,17 +45,18 @@ add_task(async function() {
     "GET",
     CONTENT_TYPE_SJS + "?fmt=html-long",
     {
       status: 200,
       statusText: "OK"
     });
 
   wait = waitForDOM(document, "#response-panel .CodeMirror-code");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   let text = document.querySelector(".CodeMirror-line").textContent;
 
   ok(text.match(/^<p>/), "The text shown in the source editor is incorrect.");
 
--- a/devtools/client/netmonitor/test/browser_net_pane-collapse.js
+++ b/devtools/client/netmonitor/test/browser_net_pane-collapse.js
@@ -6,47 +6,46 @@
 /**
  * Tests if the network monitor panes collapse properly.
  */
 
 add_task(async function() {
   let { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  let { document, store, windowRequire } = monitor.panelWin;
-  let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+  let { document, windowRequire } = monitor.panelWin;
   let { Prefs } = windowRequire("devtools/client/netmonitor/src/utils/prefs");
+  let detailsPaneToggleButton = document.querySelector(".network-details-panel-toggle");
 
   let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.reload();
   await wait;
 
   ok(!document.querySelector(".network-details-panel") &&
-     !document.querySelector(".sidebar-toggle"),
+     detailsPaneToggleButton.classList.contains("pane-collapsed"),
     "The details panel should initially be hidden.");
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" }, detailsPaneToggleButton);
 
   is(~~(document.querySelector(".network-details-panel").clientWidth),
     Prefs.networkDetailsWidth,
     "The details panel has an incorrect width.");
   ok(document.querySelector(".network-details-panel") &&
-     document.querySelector(".sidebar-toggle"),
+     !detailsPaneToggleButton.classList.contains("pane-collapsed"),
     "The details panel should at this point be visible.");
 
-  EventUtils.sendMouseEvent({ type: "click" },
-    document.querySelector(".sidebar-toggle"));
+  EventUtils.sendMouseEvent({ type: "click" }, detailsPaneToggleButton);
 
   ok(!document.querySelector(".network-details-panel") &&
-     !document.querySelector(".sidebar-toggle"),
+     detailsPaneToggleButton.classList.contains("pane-collapsed"),
     "The details panel should not be visible after collapsing.");
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" }, detailsPaneToggleButton);
 
   is(~~(document.querySelector(".network-details-panel").clientWidth),
     Prefs.networkDetailsWidth,
     "The details panel has an incorrect width after uncollapsing.");
   ok(document.querySelector(".network-details-panel") &&
-     document.querySelector(".sidebar-toggle"),
+     !detailsPaneToggleButton.classList.contains("pane-collapsed"),
     "The details panel should be visible again after uncollapsing.");
 
   await teardown(monitor);
 });
--- a/devtools/client/netmonitor/test/browser_net_pane-toggle.js
+++ b/devtools/client/netmonitor/test/browser_net_pane-toggle.js
@@ -16,50 +16,63 @@ add_task(async function() {
   let { EVENTS } = windowRequire("devtools/client/netmonitor/src/constants");
   let {
     getSelectedRequest,
     getSortedRequests,
   } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   store.dispatch(Actions.batchEnable(false));
 
-  ok(!document.querySelector(".sidebar-toggle"),
-    "The pane toggle button should not be visible.");
+  let toggleButton = document.querySelector(".network-details-panel-toggle");
+
+  is(toggleButton.hasAttribute("disabled"), true,
+    "The pane toggle button should be disabled when the frontend is opened.");
+  is(toggleButton.classList.contains("pane-collapsed"), true,
+    "The pane toggle button should indicate that the details pane is " +
+    "collapsed when the frontend is opened.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The details pane should be hidden when the frontend is opened.");
   is(getSelectedRequest(store.getState()), null,
     "There should be no selected item in the requests menu.");
 
   let networkEvent = monitor.panelWin.once(EVENTS.NETWORK_EVENT);
   tab.linkedBrowser.reload();
   await networkEvent;
 
-  ok(!document.querySelector(".sidebar-toggle"),
-    "The pane toggle button should not be visible after the first request.");
+  is(toggleButton.hasAttribute("disabled"), false,
+    "The pane toggle button should be enabled after the first request.");
+  is(toggleButton.classList.contains("pane-collapsed"), true,
+    "The pane toggle button should still indicate that the details pane is " +
+    "collapsed after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The details pane should still be hidden after the first request.");
   is(getSelectedRequest(store.getState()), null,
     "There should still be no selected item in the requests menu.");
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" }, toggleButton);
 
-  let toggleButton = document.querySelector(".sidebar-toggle");
-
+  is(toggleButton.hasAttribute("disabled"), false,
+    "The pane toggle button should still be enabled after being pressed.");
   is(toggleButton.classList.contains("pane-collapsed"), false,
     "The pane toggle button should now indicate that the details pane is " +
-    "not collapsed anymore.");
+    "not collapsed anymore after being pressed.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The details pane should not be hidden after toggle button was pressed.");
   isnot(getSelectedRequest(store.getState()), null,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
 
   EventUtils.sendMouseEvent({ type: "click" }, toggleButton);
 
+  is(toggleButton.hasAttribute("disabled"), false,
+    "The pane toggle button should still be enabled after being pressed again.");
+  is(toggleButton.classList.contains("pane-collapsed"), true,
+    "The pane toggle button should now indicate that the details pane is " +
+    "collapsed after being pressed again.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The details pane should now be hidden after the toggle button was pressed again.");
   is(getSelectedRequest(store.getState()), null,
     "There should now be no selected item in the requests menu.");
 
   await teardown(monitor);
 
   function getSelectedIndex(state) {
--- a/devtools/client/netmonitor/test/browser_net_post-data-03.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-03.js
@@ -19,17 +19,18 @@ add_task(async function() {
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
   // Wait for all tree view updated by react
   wait = waitForDOM(document, "#headers-panel .tree-section .treeLabel", 3);
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#headers-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#headers-panel");
   is(tabpanel.querySelectorAll(".tree-section .treeLabel").length, 3,
     "There should be 3 header sections displayed in this tabpanel.");
 
--- a/devtools/client/netmonitor/test/browser_net_post-data-04.js
+++ b/devtools/client/netmonitor/test/browser_net_post-data-04.js
@@ -19,17 +19,18 @@ add_task(async function() {
 
   store.dispatch(Actions.batchEnable(false));
 
   // Execute requests.
   await performRequests(monitor, tab, 1);
 
   // Wait for all tree view updated by react
   wait = waitForDOM(document, "#params-panel .tree-section");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#params-tab"));
   await wait;
 
   let tabpanel = document.querySelector("#params-panel");
 
   ok(tabpanel.querySelector(".treeTable"),
     "The request params doesn't have the indended visibility.");
--- a/devtools/client/netmonitor/test/browser_net_prefs-reload.js
+++ b/devtools/client/netmonitor/test/browser_net_prefs-reload.js
@@ -179,17 +179,18 @@ add_task(async function() {
     let newMonitor = await restartNetMonitor(monitor);
     monitor = newMonitor.monitor;
 
     let networkEvent = waitForNetworkEvents(monitor, 1);
     newMonitor.tab.linkedBrowser.reload();
     await networkEvent;
 
     let wait = waitForDOM(getDoc(), ".network-details-panel");
-    getStore().dispatch(Actions.toggleNetworkDetails());
+    EventUtils.sendMouseEvent({ type: "click" },
+      getDoc().querySelector(".network-details-panel-toggle"));
     await wait;
   }
 
   async function testBottom() {
     await restartNetMonitorAndSetupEnv();
 
     info("Testing prefs reload for a bottom host.");
     storeFirstPrefValues();
--- a/devtools/client/netmonitor/test/browser_net_security-details.js
+++ b/devtools/client/netmonitor/test/browser_net_security-details.js
@@ -19,17 +19,18 @@ add_task(async function() {
   info("Performing a secure request.");
   const REQUESTS_URL = "https://example.com" + CORS_SJS_PATH;
   let wait = waitForNetworkEvents(monitor, 1);
   await ContentTask.spawn(tab.linkedBrowser, REQUESTS_URL, async function(url) {
     content.wrappedJSObject.performRequests(1, url);
   });
   await wait;
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#security-tab"));
   await waitUntil(() => document.querySelector(
     "#security-panel .security-info-value"));
 
   let tabpanel = document.querySelector("#security-panel");
   let textboxes = tabpanel.querySelectorAll(".textbox-input");
 
--- a/devtools/client/netmonitor/test/browser_net_security-error.js
+++ b/devtools/client/netmonitor/test/browser_net_security-error.js
@@ -18,17 +18,18 @@ add_task(async function() {
 
   let requestsDone = waitForNetworkEvents(monitor, 1);
   await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
     content.wrappedJSObject.performRequests(1, "https://nocert.example.com");
   });
   await requestsDone;
 
   let securityInfoLoaded = waitForDOM(document, ".security-info-value");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
 
   await waitUntil(() => document.querySelector("#security-tab"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#security-tab"));
   await securityInfoLoaded;
 
   let errormsg = document.querySelector(".security-info-value");
   isnot(errormsg.textContent, "", "Error message is not empty.");
--- a/devtools/client/netmonitor/test/browser_net_simple-request-details.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-details.js
@@ -30,17 +30,18 @@ add_task(async function() {
 
   is(getSelectedRequest(store.getState()), undefined,
     "There shouldn't be any selected item in the requests menu.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after first request.");
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should not be hidden after toggle button was pressed.");
 
--- a/devtools/client/netmonitor/test/browser_net_simple-request.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request.js
@@ -16,43 +16,55 @@ add_task(async function() {
   let { tab, monitor } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
   let { document, store, windowRequire } = monitor.panelWin;
   let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
 
   store.dispatch(Actions.batchEnable(false));
 
+  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
+    true,
+    "The pane toggle button should be disabled when the frontend is opened.");
   ok(document.querySelector(".request-list-empty-notice"),
     "An empty notice should be displayed when the frontend is opened.");
   is(store.getState().requests.requests.size, 0,
     "The requests menu should be empty when the frontend is opened.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should be hidden when the frontend is opened.");
 
   await reloadAndWait();
 
+  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
+    false,
+    "The pane toggle button should be enabled after the first request.");
   ok(!document.querySelector(".request-list-empty-notice"),
     "The empty notice should be hidden after the first request.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after the first request.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after the first request.");
 
   await reloadAndWait();
 
+  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
+    false,
+    "The pane toggle button should be still be enabled after a reload.");
   ok(!document.querySelector(".request-list-empty-notice"),
     "The empty notice should be still hidden after a reload.");
   is(store.getState().requests.requests.size, 1,
     "The requests menu should not be empty after a reload.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after a reload.");
 
   store.dispatch(Actions.clearRequests());
 
+  is(document.querySelector(".network-details-panel-toggle").hasAttribute("disabled"),
+    true,
+    "The pane toggle button should be disabled when after clear.");
   ok(document.querySelector(".request-list-empty-notice"),
     "An empty notice should be displayed again after clear.");
   is(store.getState().requests.requests.size, 0,
     "The requests menu should be empty after clear.");
   is(!!document.querySelector(".network-details-panel"), false,
     "The network details panel should still be hidden after clear.");
 
   return teardown(monitor);
--- a/devtools/client/netmonitor/test/browser_net_sort-01.js
+++ b/devtools/client/netmonitor/test/browser_net_sort-01.js
@@ -46,17 +46,18 @@ add_task(async function() {
     url: "sjs_sorting-test-server.sjs?index=3&" + Math.random(),
     method: "GET3"
   }];
 
   let wait = waitForNetworkEvents(monitor, 5);
   await performRequestsInContent(requests);
   await wait;
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should be visible after toggle button was pressed.");
 
--- a/devtools/client/netmonitor/test/browser_net_sort-02.js
+++ b/devtools/client/netmonitor/test/browser_net_sort-02.js
@@ -46,17 +46,18 @@ add_task(async function() {
     url: "sjs_sorting-test-server.sjs?index=3&" + Math.random(),
     method: "GET3"
   }];
 
   let wait = waitForNetworkEvents(monitor, 5);
   await performRequestsInContent(requests);
   await wait;
 
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
 
   isnot(getSelectedRequest(store.getState()), undefined,
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should be visible after toggle button was pressed.");
 
--- a/devtools/client/netmonitor/test/browser_net_streaming-response.js
+++ b/devtools/client/netmonitor/test/browser_net_streaming-response.js
@@ -52,17 +52,18 @@ add_task(async function() {
       CONTENT_TYPE_SJS + "?fmt=" + fmt,
       {
         status: 200,
         statusText: "OK"
       });
   });
 
   wait = waitForDOM(document, "#response-panel");
-  store.dispatch(Actions.toggleNetworkDetails());
+  EventUtils.sendMouseEvent({ type: "click" },
+    document.querySelector(".network-details-panel-toggle"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector("#response-tab"));
   await wait;
 
   store.dispatch(Actions.selectRequest(null));
 
   await selectIndexAndWaitForSourceEditor(monitor, 0);
   // the hls-m3u8 part