Bug 1245886 - Refactor performance tests. r=jsantell, a=test-only
authorVictor Porof <vporof@mozilla.com>
Wed, 16 Mar 2016 09:39:39 +0100
changeset 323768 9539d658b1a944f159893900ce0ec658ff89bfb2
parent 323767 53ae6c43eee21597c55e5f7ff5f65728d44cbabb
child 323769 bc74c5ca31af0d92ba293c9e4a5e7b127ad06682
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjsantell, test-only
bugs1245886
milestone47.0a2
Bug 1245886 - Refactor performance tests. r=jsantell, a=test-only
devtools/client/performance/events.js
devtools/client/performance/modules/constants.js
devtools/client/performance/modules/logic/telemetry.js
devtools/client/performance/modules/moz.build
devtools/client/performance/moz.build
devtools/client/performance/panel.js
devtools/client/performance/performance-controller.js
devtools/client/performance/performance-view.js
devtools/client/performance/test/browser.ini
devtools/client/performance/test/browser_aaa-run-first-leaktest.js
devtools/client/performance/test/browser_perf-button-states.js
devtools/client/performance/test/browser_perf-calltree-js-categories.js
devtools/client/performance/test/browser_perf-calltree-js-columns.js
devtools/client/performance/test/browser_perf-calltree-js-events.js
devtools/client/performance/test/browser_perf-calltree-memory-columns.js
devtools/client/performance/test/browser_perf-categories-js-calltree.js
devtools/client/performance/test/browser_perf-clear-01.js
devtools/client/performance/test/browser_perf-clear-02.js
devtools/client/performance/test/browser_perf-columns-js-calltree.js
devtools/client/performance/test/browser_perf-columns-memory-calltree.js
devtools/client/performance/test/browser_perf-console-record-01.js
devtools/client/performance/test/browser_perf-console-record-02.js
devtools/client/performance/test/browser_perf-console-record-03.js
devtools/client/performance/test/browser_perf-console-record-04.js
devtools/client/performance/test/browser_perf-console-record-05.js
devtools/client/performance/test/browser_perf-console-record-06.js
devtools/client/performance/test/browser_perf-console-record-07.js
devtools/client/performance/test/browser_perf-console-record-08.js
devtools/client/performance/test/browser_perf-console-record-09.js
devtools/client/performance/test/browser_perf-details-01-toggle.js
devtools/client/performance/test/browser_perf-details-01.js
devtools/client/performance/test/browser_perf-details-02-utility-fun.js
devtools/client/performance/test/browser_perf-details-02.js
devtools/client/performance/test/browser_perf-details-03-without-allocations.js
devtools/client/performance/test/browser_perf-details-03.js
devtools/client/performance/test/browser_perf-details-04-toolbar-buttons.js
devtools/client/performance/test/browser_perf-details-04.js
devtools/client/performance/test/browser_perf-details-05-preserve-view.js
devtools/client/performance/test/browser_perf-details-05.js
devtools/client/performance/test/browser_perf-details-06-rerender-on-selection.js
devtools/client/performance/test/browser_perf-details-06.js
devtools/client/performance/test/browser_perf-details-07-bleed-events.js
devtools/client/performance/test/browser_perf-details-07.js
devtools/client/performance/test/browser_perf-details-calltree-render.js
devtools/client/performance/test/browser_perf-details-flamegraph-render.js
devtools/client/performance/test/browser_perf-details-memory-calltree-render.js
devtools/client/performance/test/browser_perf-details-memory-flamegraph-render.js
devtools/client/performance/test/browser_perf-details-render-00-waterfall.js
devtools/client/performance/test/browser_perf-details-render-01-js-calltree.js
devtools/client/performance/test/browser_perf-details-render-02-js-flamegraph.js
devtools/client/performance/test/browser_perf-details-render-03-memory-calltree.js
devtools/client/performance/test/browser_perf-details-render-04-memory-flamegraph.js
devtools/client/performance/test/browser_perf-details-waterfall-gc-snap.js
devtools/client/performance/test/browser_perf-details-waterfall-render.js
devtools/client/performance/test/browser_perf-docload.js
devtools/client/performance/test/browser_perf-events-calltree.js
devtools/client/performance/test/browser_perf-gc-snap.js
devtools/client/performance/test/browser_perf-highlighted.js
devtools/client/performance/test/browser_perf-legacy-front-01.js
devtools/client/performance/test/browser_perf-legacy-front-02.js
devtools/client/performance/test/browser_perf-legacy-front-03.js
devtools/client/performance/test/browser_perf-legacy-front-04.js
devtools/client/performance/test/browser_perf-legacy-front-05.js
devtools/client/performance/test/browser_perf-legacy-front-06.js
devtools/client/performance/test/browser_perf-legacy-front-07.js
devtools/client/performance/test/browser_perf-legacy-front-08.js
devtools/client/performance/test/browser_perf-legacy-front-09.js
devtools/client/performance/test/browser_perf-loading-01.js
devtools/client/performance/test/browser_perf-loading-02.js
devtools/client/performance/test/browser_perf-marker-details-01.js
devtools/client/performance/test/browser_perf-marker-details.js
devtools/client/performance/test/browser_perf-markers-docload.js
devtools/client/performance/test/browser_perf-options-01-toggle-throw.js
devtools/client/performance/test/browser_perf-options-01.js
devtools/client/performance/test/browser_perf-options-02-toggle-throw-alt.js
devtools/client/performance/test/browser_perf-options-02.js
devtools/client/performance/test/browser_perf-options-03-toggle-meta.js
devtools/client/performance/test/browser_perf-options-03.js
devtools/client/performance/test/browser_perf-options-allocations.js
devtools/client/performance/test/browser_perf-options-enable-framerate-01.js
devtools/client/performance/test/browser_perf-options-enable-framerate-02.js
devtools/client/performance/test/browser_perf-options-enable-framerate.js
devtools/client/performance/test/browser_perf-options-enable-memory-01.js
devtools/client/performance/test/browser_perf-options-enable-memory-02.js
devtools/client/performance/test/browser_perf-options-flatten-tree-recursion-01.js
devtools/client/performance/test/browser_perf-options-flatten-tree-recursion-02.js
devtools/client/performance/test/browser_perf-options-invert-call-tree-01.js
devtools/client/performance/test/browser_perf-options-invert-call-tree-02.js
devtools/client/performance/test/browser_perf-options-invert-flame-graph-01.js
devtools/client/performance/test/browser_perf-options-invert-flame-graph-02.js
devtools/client/performance/test/browser_perf-options-profiler.js
devtools/client/performance/test/browser_perf-options-propagate-allocations.js
devtools/client/performance/test/browser_perf-options-propagate-profiler.js
devtools/client/performance/test/browser_perf-options-show-idle-blocks-01.js
devtools/client/performance/test/browser_perf-options-show-idle-blocks-02.js
devtools/client/performance/test/browser_perf-options-show-jit-optimizations.js
devtools/client/performance/test/browser_perf-options-show-platform-data-01.js
devtools/client/performance/test/browser_perf-options-show-platform-data-02.js
devtools/client/performance/test/browser_perf-overview-render-01.js
devtools/client/performance/test/browser_perf-overview-render-02.js
devtools/client/performance/test/browser_perf-overview-render-03.js
devtools/client/performance/test/browser_perf-overview-render-04.js
devtools/client/performance/test/browser_perf-overview-selection-01.js
devtools/client/performance/test/browser_perf-overview-selection-02.js
devtools/client/performance/test/browser_perf-overview-selection-03.js
devtools/client/performance/test/browser_perf-overview-time-interval.js
devtools/client/performance/test/browser_perf-private-browsing.js
devtools/client/performance/test/browser_perf-range-changed-render.js
devtools/client/performance/test/browser_perf-recording-notices-01.js
devtools/client/performance/test/browser_perf-recording-notices-02.js
devtools/client/performance/test/browser_perf-recording-notices-03.js
devtools/client/performance/test/browser_perf-recording-notices-04.js
devtools/client/performance/test/browser_perf-recording-notices-05.js
devtools/client/performance/test/browser_perf-recording-selected-01.js
devtools/client/performance/test/browser_perf-recording-selected-02.js
devtools/client/performance/test/browser_perf-recording-selected-03.js
devtools/client/performance/test/browser_perf-recording-selected-04.js
devtools/client/performance/test/browser_perf-recordings-clear-01.js
devtools/client/performance/test/browser_perf-recordings-clear-02.js
devtools/client/performance/test/browser_perf-recordings-io-04.js
devtools/client/performance/test/browser_perf-recordings-io-05.js
devtools/client/performance/test/browser_perf-recordings-io-06.js
devtools/client/performance/test/browser_perf-refresh.js
devtools/client/performance/test/browser_perf-states.js
devtools/client/performance/test/browser_perf-telemetry-01.js
devtools/client/performance/test/browser_perf-telemetry-02.js
devtools/client/performance/test/browser_perf-telemetry-03.js
devtools/client/performance/test/browser_perf-telemetry-04.js
devtools/client/performance/test/browser_perf-theme-toggle-01.js
devtools/client/performance/test/browser_perf-theme-toggle.js
devtools/client/performance/test/browser_perf-tree-abstract-01.js
devtools/client/performance/test/browser_perf-tree-abstract-02.js
devtools/client/performance/test/browser_perf-tree-abstract-03.js
devtools/client/performance/test/browser_perf-tree-abstract-04.js
devtools/client/performance/test/browser_perf-tree-view-01.js
devtools/client/performance/test/browser_perf-tree-view-02.js
devtools/client/performance/test/browser_perf-tree-view-03.js
devtools/client/performance/test/browser_perf-tree-view-04.js
devtools/client/performance/test/browser_perf-tree-view-05.js
devtools/client/performance/test/browser_perf-tree-view-06.js
devtools/client/performance/test/browser_perf-tree-view-07.js
devtools/client/performance/test/browser_perf-tree-view-08.js
devtools/client/performance/test/browser_perf-tree-view-09.js
devtools/client/performance/test/browser_perf-tree-view-10.js
devtools/client/performance/test/browser_perf-tree-view-11.js
devtools/client/performance/test/browser_perf-ui-recording.js
devtools/client/performance/test/browser_profiler_tree-abstract-01.js
devtools/client/performance/test/browser_profiler_tree-abstract-02.js
devtools/client/performance/test/browser_profiler_tree-abstract-03.js
devtools/client/performance/test/browser_profiler_tree-abstract-04.js
devtools/client/performance/test/browser_profiler_tree-view-01.js
devtools/client/performance/test/browser_profiler_tree-view-02.js
devtools/client/performance/test/browser_profiler_tree-view-03.js
devtools/client/performance/test/browser_profiler_tree-view-04.js
devtools/client/performance/test/browser_profiler_tree-view-05.js
devtools/client/performance/test/browser_profiler_tree-view-06.js
devtools/client/performance/test/browser_profiler_tree-view-07.js
devtools/client/performance/test/browser_profiler_tree-view-08.js
devtools/client/performance/test/browser_profiler_tree-view-09.js
devtools/client/performance/test/browser_profiler_tree-view-10.js
devtools/client/performance/test/browser_profiler_tree-view-11.js
devtools/client/performance/test/browser_timeline-filters-01.js
devtools/client/performance/test/browser_timeline-filters-02.js
devtools/client/performance/test/browser_timeline-waterfall-background.js
devtools/client/performance/test/browser_timeline-waterfall-generic.js
devtools/client/performance/test/browser_timeline-waterfall-rerender.js
devtools/client/performance/test/head.js
devtools/client/performance/test/helpers/actions.js
devtools/client/performance/test/helpers/dom-utils.js
devtools/client/performance/test/helpers/event-utils.js
devtools/client/performance/test/helpers/input-utils.js
devtools/client/performance/test/helpers/moz.build
devtools/client/performance/test/helpers/panel-utils.js
devtools/client/performance/test/helpers/prefs.js
devtools/client/performance/test/helpers/profiler-mm-utils.js
devtools/client/performance/test/helpers/synth-utils.js
devtools/client/performance/test/helpers/tab-utils.js
devtools/client/performance/test/helpers/urls.js
devtools/client/performance/test/helpers/wait-utils.js
devtools/client/performance/test/moz.build
devtools/client/performance/views/details-abstract-subview.js
devtools/client/performance/views/details-js-call-tree.js
devtools/client/performance/views/details-js-flamegraph.js
devtools/client/performance/views/details-memory-call-tree.js
devtools/client/performance/views/details-memory-flamegraph.js
devtools/client/performance/views/details-waterfall.js
devtools/client/performance/views/details.js
devtools/client/performance/views/overview.js
devtools/client/performance/views/recordings.js
devtools/client/performance/views/toolbar.js
devtools/client/shared/frame-script-utils.js
devtools/server/tests/browser/browser_markers-timestamp.js
devtools/server/tests/browser/browser_perf-profiler-01.js
devtools/server/tests/browser/browser_perf-profiler-02.js
devtools/server/tests/browser/browser_perf-profiler-03.js
devtools/shared/performance/moz.build
devtools/shared/performance/process-communication.js
--- a/devtools/client/performance/events.js
+++ b/devtools/client/performance/events.js
@@ -1,109 +1,108 @@
 /* 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";
 
-module.exports = {
-  // Fired by the PerformanceController and OptionsView when a pref changes.
+const ControllerEvents = {
+  // Fired when a performance pref changes (either because the user changed it
+  // via the tool's UI, by changing something about:config or programatically).
   PREF_CHANGED: "Performance:PrefChanged",
 
-  // Fired by the PerformanceController when the devtools theme changes.
+  // Fired when the devtools theme changes.
   THEME_CHANGED: "Performance:ThemeChanged",
 
-  // Emitted by the PerformanceView when the state (display mode) changes,
-  // for example when switching between "empty", "recording" or "recorded".
-  // This causes certain panels to be hidden or visible.
-  UI_STATE_CHANGED: "Performance:UI:StateChanged",
-
-  // Emitted by the PerformanceView on clear button click
-  UI_CLEAR_RECORDINGS: "Performance:UI:ClearRecordings",
-
-  // Emitted by the PerformanceView on record button click
-  UI_START_RECORDING: "Performance:UI:StartRecording",
-  UI_STOP_RECORDING: "Performance:UI:StopRecording",
+  // When a new recording model is received by the controller.
+  RECORDING_ADDED: "Performance:RecordingAdded",
 
-  // Emitted by the PerformanceView on import button click
-  UI_IMPORT_RECORDING: "Performance:UI:ImportRecording",
-  // Emitted by the RecordingsView on export button click
-  UI_EXPORT_RECORDING: "Performance:UI:ExportRecording",
+  // When a recording model gets removed from the controller.
+  RECORDING_DELETED: "Performance:RecordingDeleted",
 
-  // When a new recording is being tracked in the panel.
-  NEW_RECORDING: "Performance:NewRecording",
-
-  // When a new recording can't be successfully created when started.
-  NEW_RECORDING_FAILED: "Performance:NewRecordingFailed",
-
-  // When a recording is started or stopped or stopping via the PerformanceController
+  // When a recording model becomes "started", "stopping" or "stopped".
   RECORDING_STATE_CHANGE: "Performance:RecordingStateChange",
 
-  // Emitted by the PerformanceController or RecordingView
-  // when a recording model is selected
+  // When a recording is offering information on the profiler's circular buffer.
+  RECORDING_PROFILER_STATUS_UPDATE: "Performance:RecordingProfilerStatusUpdate",
+
+  // When a recording model becomes marked as selected.
   RECORDING_SELECTED: "Performance:RecordingSelected",
 
-  // When recordings have been cleared out
-  RECORDINGS_CLEARED: "Performance:RecordingsCleared",
+  // When starting a recording is attempted and fails because the backend
+  // does not permit it at this time.
+  BACKEND_FAILED_AFTER_RECORDING_START: "Performance:BackendFailedRecordingStart",
 
-  // When a recording is exported via the PerformanceController
+  // When a recording is started and the backend has started working.
+  BACKEND_READY_AFTER_RECORDING_START: "Performance:BackendReadyRecordingStart",
+
+  // When a recording is stopped and the backend has finished cleaning up.
+  BACKEND_READY_AFTER_RECORDING_STOP: "Performance:BackendReadyRecordingStop",
+
+  // When a recording is exported.
   RECORDING_EXPORTED: "Performance:RecordingExported",
 
-  // Emitted by the PerformanceController when a recording is imported.
-  // Unless you're interested in specifically imported recordings, like in tests
-  // or telemetry, you should probably use the normal RECORDING_STATE_CHANGE in the UI.
+  // When a recording is imported.
   RECORDING_IMPORTED: "Performance:RecordingImported",
 
-  // When the front has updated information on the profiler's circular buffer
-  PROFILER_STATUS_UPDATED: "Performance:BufferUpdated",
-
-  // When the PerformanceView updates the display of the buffer status
-  UI_BUFFER_STATUS_UPDATED: "Performance:UI:BufferUpdated",
-
-  // Emitted by the OptimizationsListView when it renders new optimization
-  // data and clears the optimization data
-  OPTIMIZATIONS_RESET: "Performance:UI:OptimizationsReset",
-  OPTIMIZATIONS_RENDERED: "Performance:UI:OptimizationsRendered",
-
-  // Emitted by the OverviewView when more data has been rendered
-  OVERVIEW_RENDERED: "Performance:UI:OverviewRendered",
-  FRAMERATE_GRAPH_RENDERED: "Performance:UI:OverviewFramerateRendered",
-  MARKERS_GRAPH_RENDERED: "Performance:UI:OverviewMarkersRendered",
-  MEMORY_GRAPH_RENDERED: "Performance:UI:OverviewMemoryRendered",
-
-  // Emitted by the OverviewView when a range has been selected in the graphs
-  OVERVIEW_RANGE_SELECTED: "Performance:UI:OverviewRangeSelected",
-
-  // Emitted by the DetailsView when a subview is selected
-  DETAILS_VIEW_SELECTED: "Performance:UI:DetailsViewSelected",
-
-  // Emitted by the WaterfallView when it has been rendered
-  WATERFALL_RENDERED: "Performance:UI:WaterfallRendered",
-
-  // Emitted by the JsCallTreeView when a call tree has been rendered
-  JS_CALL_TREE_RENDERED: "Performance:UI:JsCallTreeRendered",
-
-  // Emitted by the JsFlameGraphView when it has been rendered
-  JS_FLAMEGRAPH_RENDERED: "Performance:UI:JsFlameGraphRendered",
-
-  // Emitted by the MemoryCallTreeView when a call tree has been rendered
-  MEMORY_CALL_TREE_RENDERED: "Performance:UI:MemoryCallTreeRendered",
-
-  // Emitted by the MemoryFlameGraphView when it has been rendered
-  MEMORY_FLAMEGRAPH_RENDERED: "Performance:UI:MemoryFlameGraphRendered",
-
   // When a source is shown in the JavaScript Debugger at a specific location.
   SOURCE_SHOWN_IN_JS_DEBUGGER: "Performance:UI:SourceShownInJsDebugger",
   SOURCE_NOT_FOUND_IN_JS_DEBUGGER: "Performance:UI:SourceNotFoundInJsDebugger",
 
-  // These are short hands for the RECORDING_STATE_CHANGE event to make refactoring
-  // tests easier and in rare cases (telemetry). UI components should use
-  // RECORDING_STATE_CHANGE in almost all cases,
-  RECORDING_STARTED: "Performance:RecordingStarted",
-  RECORDING_WILL_STOP: "Performance:RecordingWillStop",
-  RECORDING_STOPPED: "Performance:RecordingStopped",
-
   // Fired by the PerformanceController when `populateWithRecordings` is finished.
   RECORDINGS_SEEDED: "Performance:RecordingsSeeded",
+};
 
-  // Emitted by the PerformanceController when `PerformanceController.stopRecording()`
-  // is completed; used in tests, to know when a manual UI click is finished.
-  CONTROLLER_STOPPED_RECORDING: "Performance:Controller:StoppedRecording",
+const ViewEvents = {
+  // Emitted by the `ToolbarView` when a preference changes.
+  UI_PREF_CHANGED: "Performance:UI:PrefChanged",
+
+  // When the state (display mode) changes, for example when switching between
+  // "empty", "recording" or "recorded". This causes certain parts of the UI
+  // to be hidden or visible.
+  UI_STATE_CHANGED: "Performance:UI:StateChanged",
+
+  // Emitted by the `PerformanceView` on clear button click.
+  UI_CLEAR_RECORDINGS: "Performance:UI:ClearRecordings",
+
+  // Emitted by the `PerformanceView` on record button click.
+  UI_START_RECORDING: "Performance:UI:StartRecording",
+  UI_STOP_RECORDING: "Performance:UI:StopRecording",
+
+  // Emitted by the `PerformanceView` on import/export button click.
+  UI_IMPORT_RECORDING: "Performance:UI:ImportRecording",
+  UI_EXPORT_RECORDING: "Performance:UI:ExportRecording",
+
+  // Emitted by the `PerformanceView` when the profiler's circular buffer
+  // status has been rendered.
+  UI_RECORDING_PROFILER_STATUS_RENDERED: "Performance:UI:RecordingProfilerStatusRendered",
+
+  // When a recording is selected in the UI.
+  UI_RECORDING_SELECTED: "Performance:UI:RecordingSelected",
+
+  // Emitted by the `DetailsView` when a subview is selected
+  UI_DETAILS_VIEW_SELECTED: "Performance:UI:DetailsViewSelected",
+
+  // Emitted by the `OverviewView` after something has been rendered.
+  UI_OVERVIEW_RENDERED: "Performance:UI:OverviewRendered",
+  UI_MARKERS_GRAPH_RENDERED: "Performance:UI:OverviewMarkersRendered",
+  UI_MEMORY_GRAPH_RENDERED: "Performance:UI:OverviewMemoryRendered",
+  UI_FRAMERATE_GRAPH_RENDERED: "Performance:UI:OverviewFramerateRendered",
+
+  // Emitted by the `OverviewView` when a range has been selected in the graphs.
+  UI_OVERVIEW_RANGE_SELECTED: "Performance:UI:OverviewRangeSelected",
+
+  // Emitted by the `WaterfallView` when it has been rendered.
+  UI_WATERFALL_RENDERED: "Performance:UI:WaterfallRendered",
+
+  // Emitted by the `JsCallTreeView` when it has been rendered.
+  UI_JS_CALL_TREE_RENDERED: "Performance:UI:JsCallTreeRendered",
+
+  // Emitted by the `JsFlameGraphView` when it has been rendered.
+  UI_JS_FLAMEGRAPH_RENDERED: "Performance:UI:JsFlameGraphRendered",
+
+  // Emitted by the `MemoryCallTreeView` when it has been rendered.
+  UI_MEMORY_CALL_TREE_RENDERED: "Performance:UI:MemoryCallTreeRendered",
+
+  // Emitted by the `MemoryFlameGraphView` when it has been rendered.
+  UI_MEMORY_FLAMEGRAPH_RENDERED: "Performance:UI:MemoryFlameGraphRendered",
 };
+
+module.exports = Object.assign({}, ControllerEvents, ViewEvents);
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/modules/constants.js
@@ -0,0 +1,9 @@
+/* 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";
+
+exports.Constants = {
+  FRAMERATE_GRAPH_LOW_RES_INTERVAL: 100, // ms
+  FRAMERATE_GRAPH_HIGH_RES_INTERVAL: 16, // ms
+};
--- a/devtools/client/performance/modules/logic/telemetry.js
+++ b/devtools/client/performance/modules/logic/telemetry.js
@@ -17,50 +17,54 @@ const RECORDING_FEATURES = [
 ];
 
 const SELECTED_VIEW_HISTOGRAM_NAME = "DEVTOOLS_PERFTOOLS_SELECTED_VIEW_MS";
 
 function PerformanceTelemetry (emitter) {
   this._emitter = emitter;
   this._telemetry = new Telemetry();
   this.onFlagEvent = this.onFlagEvent.bind(this);
-  this.onRecordingStopped = this.onRecordingStopped.bind(this);
+  this.onRecordingStateChange = this.onRecordingStateChange.bind(this);
   this.onViewSelected = this.onViewSelected.bind(this);
 
   for (let [event] of EVENT_MAP_FLAGS) {
     this._emitter.on(event, this.onFlagEvent);
   }
 
-  this._emitter.on(EVENTS.RECORDING_STOPPED, this.onRecordingStopped);
-  this._emitter.on(EVENTS.DETAILS_VIEW_SELECTED, this.onViewSelected);
+  this._emitter.on(EVENTS.RECORDING_STATE_CHANGE, this.onRecordingStateChange);
+  this._emitter.on(EVENTS.UI_DETAILS_VIEW_SELECTED, this.onViewSelected);
 
   if (DevToolsUtils.testing) {
     this.recordLogs();
   }
 }
 
 PerformanceTelemetry.prototype.destroy = function () {
   if (this._previousView) {
     this._telemetry.stopTimer(SELECTED_VIEW_HISTOGRAM_NAME, this._previousView);
   }
 
   this._telemetry.destroy();
   for (let [event] of EVENT_MAP_FLAGS) {
     this._emitter.off(event, this.onFlagEvent);
   }
-  this._emitter.off(EVENTS.RECORDING_STOPPED, this.onRecordingStopped);
-  this._emitter.off(EVENTS.DETAILS_VIEW_SELECTED, this.onViewSelected);
+  this._emitter.off(EVENTS.RECORDING_STATE_CHANGE, this.onRecordingStateChange);
+  this._emitter.off(EVENTS.UI_DETAILS_VIEW_SELECTED, this.onViewSelected);
   this._emitter = null;
 };
 
 PerformanceTelemetry.prototype.onFlagEvent = function (eventName, ...data) {
   this._telemetry.log(EVENT_MAP_FLAGS.get(eventName), true);
 };
 
-PerformanceTelemetry.prototype.onRecordingStopped = function (_, model) {
+PerformanceTelemetry.prototype.onRecordingStateChange = function (_, status, model) {
+  if (status != "recording-stopped") {
+    return;
+  }
+
   if (model.isConsole()) {
     this._telemetry.log("DEVTOOLS_PERFTOOLS_CONSOLE_RECORDING_COUNT", true);
   } else {
     this._telemetry.log("DEVTOOLS_PERFTOOLS_RECORDING_COUNT", true);
   }
 
   this._telemetry.log("DEVTOOLS_PERFTOOLS_RECORDING_DURATION_MS", model.getDuration());
 
--- a/devtools/client/performance/modules/moz.build
+++ b/devtools/client/performance/modules/moz.build
@@ -4,12 +4,13 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += [
     'logic',
     'widgets',
 ]
 
 DevToolsModules(
+    'constants.js',
     'global.js',
     'io.js',
     'markers.js',
 )
--- a/devtools/client/performance/moz.build
+++ b/devtools/client/performance/moz.build
@@ -2,16 +2,17 @@
 # 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/.
 
 DIRS += [
     'components',
     'legacy',
     'modules',
+    'test',
 ]
 
 DevToolsModules(
     'events.js',
     'panel.js'
 )
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
--- a/devtools/client/performance/panel.js
+++ b/devtools/client/performance/panel.js
@@ -9,17 +9,17 @@ const { Cc, Ci, Cu, Cr } = require("chro
 const { Task } = require("resource://gre/modules/Task.jsm");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/shared/event-emitter");
 
 function PerformancePanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
-  this._toolbox = toolbox;
+  this.toolbox = toolbox;
 
   EventEmitter.decorate(this);
 }
 
 exports.PerformancePanel = PerformancePanel;
 
 PerformancePanel.prototype = {
   /**
@@ -31,17 +31,17 @@ PerformancePanel.prototype = {
    */
   open: Task.async(function*() {
     if (this._opening) {
       return this._opening;
     }
     let deferred = promise.defer();
     this._opening = deferred.promise;
 
-    this.panelWin.gToolbox = this._toolbox;
+    this.panelWin.gToolbox = this.toolbox;
     this.panelWin.gTarget = this.target;
     this._checkRecordingStatus = this._checkRecordingStatus.bind(this);
 
     // Actor is already created in the toolbox; reuse
     // the same front, and the toolbox will also initialize the front,
     // but redo it here so we can hook into the same event to prevent race conditions
     // in the case of the front still being in the process of opening.
     let front = yield this.panelWin.gToolbox.initPerformance();
@@ -50,17 +50,17 @@ PerformancePanel.prototype = {
     // does not exist), and in that case, the tool shouldn't be available,
     // so let's ensure this assertion.
     if (!front) {
       Cu.reportError("No PerformanceFront found in toolbox.");
     }
 
     this.panelWin.gFront = front;
     let { PerformanceController, EVENTS } = this.panelWin;
-    PerformanceController.on(EVENTS.NEW_RECORDING, this._checkRecordingStatus);
+    PerformanceController.on(EVENTS.RECORDING_ADDED, this._checkRecordingStatus);
     PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._checkRecordingStatus);
     yield this.panelWin.startupPerformance();
 
     // Fire this once incase we have an in-progress recording (console profile)
     // that caused this start up, and no state change yet, so we can highlight the
     // tab if we need.
     this._checkRecordingStatus();
 
@@ -69,33 +69,33 @@ PerformancePanel.prototype = {
 
     deferred.resolve(this);
     return this._opening;
   }),
 
   // DevToolPanel API
 
   get target() {
-    return this._toolbox.target;
+    return this.toolbox.target;
   },
 
   destroy: Task.async(function*() {
     // Make sure this panel is not already destroyed.
     if (this._destroyed) {
       return;
     }
 
     let { PerformanceController, EVENTS } = this.panelWin;
-    PerformanceController.off(EVENTS.NEW_RECORDING, this._checkRecordingStatus);
+    PerformanceController.off(EVENTS.RECORDING_ADDED, this._checkRecordingStatus);
     PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._checkRecordingStatus);
     yield this.panelWin.shutdownPerformance();
     this.emit("destroyed");
     this._destroyed = true;
   }),
 
   _checkRecordingStatus: function () {
     if (this.panelWin.PerformanceController.isRecording()) {
-      this._toolbox.highlightTool("performance");
+      this.toolbox.highlightTool("performance");
     } else {
-      this._toolbox.unhighlightTool("performance");
+      this.toolbox.unhighlightTool("performance");
     }
   }
 };
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -107,44 +107,44 @@ var PerformanceController = {
     // Store data regarding if e10s is enabled.
     this._e10s = Services.appinfo.browserTabsRemoteAutostart;
     this._setMultiprocessAttributes();
 
     this._prefs = require("devtools/client/performance/modules/global").PREFS;
     this._prefs.registerObserver();
     this._prefs.on("pref-changed", this._onPrefChanged);
 
-    ToolbarView.on(EVENTS.PREF_CHANGED, this._onPrefChanged);
+    ToolbarView.on(EVENTS.UI_PREF_CHANGED, this._onPrefChanged);
     PerformanceView.on(EVENTS.UI_START_RECORDING, this.startRecording);
     PerformanceView.on(EVENTS.UI_STOP_RECORDING, this.stopRecording);
     PerformanceView.on(EVENTS.UI_IMPORT_RECORDING, this.importRecording);
     PerformanceView.on(EVENTS.UI_CLEAR_RECORDINGS, this.clearRecordings);
     RecordingsView.on(EVENTS.UI_EXPORT_RECORDING, this.exportRecording);
-    RecordingsView.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelectFromView);
-    DetailsView.on(EVENTS.DETAILS_VIEW_SELECTED, this._pipe);
+    RecordingsView.on(EVENTS.UI_RECORDING_SELECTED, this._onRecordingSelectFromView);
+    DetailsView.on(EVENTS.UI_DETAILS_VIEW_SELECTED, this._pipe);
 
     gDevTools.on("pref-changed", this._onThemeChanged);
   }),
 
   /**
    * Remove events handled by the PerformanceController
    */
   destroy: function() {
     this._telemetry.destroy();
     this._prefs.off("pref-changed", this._onPrefChanged);
     this._prefs.unregisterObserver();
 
-    ToolbarView.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
+    ToolbarView.off(EVENTS.UI_PREF_CHANGED, this._onPrefChanged);
     PerformanceView.off(EVENTS.UI_START_RECORDING, this.startRecording);
     PerformanceView.off(EVENTS.UI_STOP_RECORDING, this.stopRecording);
     PerformanceView.off(EVENTS.UI_IMPORT_RECORDING, this.importRecording);
     PerformanceView.off(EVENTS.UI_CLEAR_RECORDINGS, this.clearRecordings);
     RecordingsView.off(EVENTS.UI_EXPORT_RECORDING, this.exportRecording);
-    RecordingsView.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelectFromView);
-    DetailsView.off(EVENTS.DETAILS_VIEW_SELECTED, this._pipe);
+    RecordingsView.off(EVENTS.UI_RECORDING_SELECTED, this._onRecordingSelectFromView);
+    DetailsView.off(EVENTS.UI_DETAILS_VIEW_SELECTED, this._pipe);
 
     gDevTools.off("pref-changed", this._onThemeChanged);
   },
 
   /**
    * Enables front event listeners.
    *
    * The rationale behind this is given by the async intialization of all the
@@ -239,38 +239,36 @@ var PerformanceController = {
       withGCEvents: true,
       withAllocations: this.getOption("enable-allocations"),
       allocationsSampleProbability: this.getPref("memory-sample-probability"),
       allocationsMaxLogLength: this.getPref("memory-max-log-length"),
       bufferSize: this.getPref("profiler-buffer-size"),
       sampleFrequency: this.getPref("profiler-sample-frequency")
     };
 
+    let recordingStarted = yield gFront.startRecording(options);
+
     // In some cases, like when the target has a private browsing tab,
     // recording is not currently supported because of the profiler module.
     // Present a notification in this case alerting the user of this issue.
-    if (!(yield gFront.startRecording(options))) {
-      this.emit(EVENTS.NEW_RECORDING_FAILED);
+    if (!recordingStarted) {
+      this.emit(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START);
       PerformanceView.setState("unavailable");
+    } else {
+      this.emit(EVENTS.BACKEND_READY_AFTER_RECORDING_START);
     }
   }),
 
   /**
    * Stops recording with the PerformanceFront.
    */
   stopRecording: Task.async(function *() {
     let recording = this.getLatestManualRecording();
     yield gFront.stopRecording(recording);
-
-    // Emit another stop event here, as a lot of tests use
-    // the RECORDING_STOPPED event, but in the case of a UI click on a button,
-    // the RECORDING_STOPPED event happens from the server, where this request may
-    // not have yet finished, so listen to this in tests that fail because the `stopRecording`
-    // request is not yet completed. Should only be used in that scenario.
-    this.emit(EVENTS.CONTROLLER_STOPPED_RECORDING);
+    this.emit(EVENTS.BACKEND_READY_AFTER_RECORDING_STOP);
   }),
 
   /**
    * Saves the given recording to a file. Emits `EVENTS.RECORDING_EXPORTED`
    * when the file was saved.
    *
    * @param PerformanceRecording recording
    *        The model that holds the recording data.
@@ -318,17 +316,17 @@ var PerformanceController = {
    * Loads a recording from a file, adding it to the recordings list. Emits
    * `EVENTS.RECORDING_IMPORTED` when the file was loaded.
    *
    * @param nsILocalFile file
    *        The file to import the data from.
    */
   importRecording: Task.async(function*(_, file) {
     let recording = yield gFront.importRecording(file);
-    this._addNewRecording(recording);
+    this._addRecordingIfUnknown(recording);
 
     this.emit(EVENTS.RECORDING_IMPORTED, recording);
   }),
 
   /**
    * Sets the currently active PerformanceRecording. Should rarely be called directly,
    * as RecordingsView handles this when manually selected a recording item. Exceptions
    * are when clearing the view.
@@ -391,72 +389,40 @@ var PerformanceController = {
 
     this.emit(EVENTS.THEME_CHANGED, data.newValue);
   },
 
   /**
    * Fired from the front on any event. Propagates to other handlers from here.
    */
   _onFrontEvent: function (eventName, ...data) {
-    if (eventName === "profiler-status") {
-      this._onProfilerStatusUpdated(...data);
-      return;
-    }
-
-    if (["recording-started", "recording-stopped", "recording-stopping"].indexOf(eventName) !== -1) {
-      this._onRecordingStateChange(eventName, ...data);
+    switch (eventName) {
+      case "profiler-status":
+        let [profilerStatus] = data;
+        this.emit(EVENTS.RECORDING_PROFILER_STATUS_UPDATE, profilerStatus);
+        break;
+      case "recording-started":
+      case "recording-stopping":
+      case "recording-stopped":
+        let [recordingModel] = data;
+        this._addRecordingIfUnknown(recordingModel);
+        this.emit(EVENTS.RECORDING_STATE_CHANGE, eventName, recordingModel);
+        break;
     }
   },
 
   /**
-   * Emitted when the front updates PerformanceRecording's buffer status.
-   */
-  _onProfilerStatusUpdated: function (data) {
-    this.emit(EVENTS.PROFILER_STATUS_UPDATED, data);
-  },
-
-  /**
    * Stores a recording internally.
    *
    * @param {PerformanceRecordingFront} recording
    */
-  _addNewRecording: function (recording) {
+  _addRecordingIfUnknown: function (recording) {
     if (this._recordings.indexOf(recording) === -1) {
       this._recordings.push(recording);
-      this.emit(EVENTS.NEW_RECORDING, recording);
-    }
-  },
-
-  /**
-   * Fired when a recording model changes state.
-   *
-   * @param {string} state
-   *        Can be "recording-started", "recording-stopped" or "recording-stopping".
-   * @param {PerformanceRecording} model
-   */
-  _onRecordingStateChange: function (state, model) {
-    this._addNewRecording(model);
-
-    this.emit(EVENTS.RECORDING_STATE_CHANGE, state, model);
-
-    // Emit the state specific events for tests that I'm too
-    // lazy and frusterated to change right now. These events
-    // should only be used in tests and specific rare cases (telemetry),
-    // as the rest of the UI should react to general RECORDING_STATE_CHANGE
-    // events and NEW_RECORDING events to handle lazy recordings.
-    switch (state) {
-      case "recording-started":
-        this.emit(EVENTS.RECORDING_STARTED, model);
-        break;
-      case "recording-stopping":
-        this.emit(EVENTS.RECORDING_WILL_STOP, model);
-        break;
-      case "recording-stopped":
-        this.emit(EVENTS.RECORDING_STOPPED, model);
-        break;
+      this.emit(EVENTS.RECORDING_ADDED, recording);
     }
   },
 
   /**
    * Takes a recording and returns a value between 0 and 1 indicating how much
    * of the buffer is used.
    */
   getBufferUsageForRecording: function (recording) {
@@ -514,17 +480,17 @@ var PerformanceController = {
    * store of the UI. Used by the toolbox to lazily seed recordings that
    * were observed before the panel was loaded in the scenario where `console.profile()`
    * is used before the tool is loaded.
    *
    * @param {Array<PerformanceRecordingFront>} recordings
    */
   populateWithRecordings: function (recordings=[]) {
     for (let recording of recordings) {
-      PerformanceController._addNewRecording(recording);
+      PerformanceController._addRecordingIfUnknown(recording);
     }
     this.emit(EVENTS.RECORDINGS_SEEDED);
   },
 
   /**
    * Returns an object with `supported` and `enabled` properties indicating
    * whether or not the platform is capable of turning on e10s and whether or not
    * it's already enabled, respectively.
--- a/devtools/client/performance/performance-view.js
+++ b/devtools/client/performance/performance-view.js
@@ -61,20 +61,20 @@ var PerformanceView = {
     for (let button of $$(".record-button")) {
       button.addEventListener("click", this._onRecordButtonClick);
     }
     this._importButton.addEventListener("click", this._onImportButtonClick);
     this._clearButton.addEventListener("click", this._onClearButtonClick);
 
     // Bind to controller events to unlock the record button
     PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
-    PerformanceController.on(EVENTS.PROFILER_STATUS_UPDATED, this._onProfilerStatusUpdated);
+    PerformanceController.on(EVENTS.RECORDING_PROFILER_STATUS_UPDATE, this._onProfilerStatusUpdated);
     PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
-    PerformanceController.on(EVENTS.NEW_RECORDING, this._onRecordingStateChange);
-    PerformanceController.on(EVENTS.NEW_RECORDING_FAILED, this._onNewRecordingFailed);
+    PerformanceController.on(EVENTS.RECORDING_ADDED, this._onRecordingStateChange);
+    PerformanceController.on(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START, this._onNewRecordingFailed);
 
     if (yield PerformanceController.canCurrentlyRecord()) {
       this.setState("empty");
     } else {
       this.setState("unavailable");
     }
 
     // Initialize the ToolbarView first, because other views may need access
@@ -91,20 +91,20 @@ var PerformanceView = {
   destroy: Task.async(function* () {
     for (let button of $$(".record-button")) {
       button.removeEventListener("click", this._onRecordButtonClick);
     }
     this._importButton.removeEventListener("click", this._onImportButtonClick);
     this._clearButton.removeEventListener("click", this._onClearButtonClick);
 
     PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
-    PerformanceController.off(EVENTS.PROFILER_STATUS_UPDATED, this._onProfilerStatusUpdated);
+    PerformanceController.off(EVENTS.RECORDING_PROFILER_STATUS_UPDATE, this._onProfilerStatusUpdated);
     PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
-    PerformanceController.off(EVENTS.NEW_RECORDING, this._onRecordingStateChange);
-    PerformanceController.off(EVENTS.NEW_RECORDING_FAILED, this._onNewRecordingFailed);
+    PerformanceController.off(EVENTS.RECORDING_ADDED, this._onRecordingStateChange);
+    PerformanceController.off(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START, this._onNewRecordingFailed);
 
     yield ToolbarView.destroy();
     yield RecordingsView.destroy();
     yield OverviewView.destroy();
     yield DetailsView.destroy();
   }),
 
   /**
@@ -176,17 +176,17 @@ var PerformanceView = {
     // this could happen, as RecordingModel clamps.
     if (percent >= 99) {
       $container.setAttribute("buffer-status", "full");
     } else {
       $container.setAttribute("buffer-status", "in-progress");
     }
 
     $bufferLabel.value = L10N.getFormatStr("profiler.bufferFull", percent);
-    this.emit(EVENTS.UI_BUFFER_STATUS_UPDATED, percent);
+    this.emit(EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED, percent);
   },
 
   /**
    * Toggles the `locked` attribute on the record buttons based
    * on `lock`.
    *
    * @param {boolean} lock
    */
@@ -293,20 +293,20 @@ var PerformanceView = {
       this.setState("recorded");
     }
   },
 
   /**
    * Fired when the controller has updated information on the buffer's status.
    * Update the buffer status display if shown.
    */
-  _onProfilerStatusUpdated: function (_, data) {
+  _onProfilerStatusUpdated: function (_, profilerStatus) {
     // We only care about buffer status here, so check to see
     // if it has position.
-    if (!data || data.position === void 0) {
+    if (!profilerStatus || profilerStatus.position === void 0) {
       return;
     }
     // If this is our first buffer event, set the status and add a class
     if (!this._bufferStatusSupported) {
       this._bufferStatusSupported = true;
       $("#details-pane-container").setAttribute("buffer-status", "in-progress");
     }
 
--- a/devtools/client/performance/test/browser.ini
+++ b/devtools/client/performance/test/browser.ini
@@ -6,149 +6,117 @@ support-files =
   doc_innerHTML.html
   doc_markers.html
   doc_simple-test.html
   doc_worker.html
   js_simpleWorker.js
   head.js
 
 [browser_aaa-run-first-leaktest.js]
-[browser_perf-categories-js-calltree.js]
-[browser_perf-clear-01.js]
-[browser_perf-clear-02.js]
-skip-if = os == "linux" # Bug 1230031
-[browser_perf-columns-js-calltree.js]
-[browser_perf-columns-memory-calltree.js]
+[browser_perf-button-states.js]
+[browser_perf-calltree-js-categories.js]
+[browser_perf-calltree-js-columns.js]
+[browser_perf-calltree-js-events.js]
+[browser_perf-calltree-memory-columns.js]
 [browser_perf-console-record-01.js]
 [browser_perf-console-record-02.js]
 [browser_perf-console-record-03.js]
 [browser_perf-console-record-04.js]
 [browser_perf-console-record-05.js]
 [browser_perf-console-record-06.js]
 [browser_perf-console-record-07.js]
 [browser_perf-console-record-08.js]
 [browser_perf-console-record-09.js]
-[browser_perf-details-calltree-render.js]
-[browser_perf-details-flamegraph-render.js]
-[browser_perf-details-memory-calltree-render.js]
-[browser_perf-details-memory-flamegraph-render.js]
-[browser_perf-details-waterfall-gc-snap.js]
-skip-if = true # Bug 1161817
-[browser_perf-details-waterfall-render.js]
-[browser_perf-details-01.js]
-[browser_perf-details-02.js]
-[browser_perf-details-03.js]
-[browser_perf-details-04.js]
-[browser_perf-details-05.js]
-[browser_perf-details-06.js]
-[browser_perf-details-07.js]
-[browser_perf-events-calltree.js]
+[browser_perf-details-01-toggle.js]
+[browser_perf-details-02-utility-fun.js]
+[browser_perf-details-03-without-allocations.js]
+[browser_perf-details-04-toolbar-buttons.js]
+[browser_perf-details-05-preserve-view.js]
+[browser_perf-details-06-rerender-on-selection.js]
+[browser_perf-details-07-bleed-events.js]
+# [browser_perf-details-gc-snap.js] TODO bug 1256350
+[browser_perf-details-render-00-waterfall.js]
+[browser_perf-details-render-01-js-calltree.js]
+[browser_perf-details-render-02-js-flamegraph.js]
+[browser_perf-details-render-03-memory-calltree.js]
+[browser_perf-details-render-04-memory-flamegraph.js]
+[browser_perf-docload.js]
 [browser_perf-highlighted.js]
-[browser_perf-legacy-front-01.js]
-[browser_perf-legacy-front-02.js]
-[browser_perf-legacy-front-03.js]
-[browser_perf-legacy-front-04.js]
-[browser_perf-legacy-front-05.js]
-[browser_perf-legacy-front-06.js]
-[browser_perf-legacy-front-07.js]
-[browser_perf-legacy-front-08.js]
-[browser_perf-legacy-front-09.js]
 [browser_perf-loading-01.js]
 [browser_perf-loading-02.js]
-[browser_perf-marker-details-01.js]
-[browser_perf-markers-docload.js]
-[browser_perf-options-01.js]
-[browser_perf-options-02.js]
-[browser_perf-options-03.js]
+# [browser_perf-marker-details.js] TODO bug 1256350
+[browser_perf-options-01-toggle-throw.js]
+[browser_perf-options-02-toggle-throw-alt.js]
+[browser_perf-options-03-toggle-meta.js]
+[browser_perf-options-enable-framerate-01.js]
+[browser_perf-options-enable-framerate-02.js]
+[browser_perf-options-enable-memory-01.js]
+[browser_perf-options-enable-memory-02.js]
+[browser_perf-options-flatten-tree-recursion-01.js]
+[browser_perf-options-flatten-tree-recursion-02.js]
 [browser_perf-options-invert-call-tree-01.js]
 [browser_perf-options-invert-call-tree-02.js]
 [browser_perf-options-invert-flame-graph-01.js]
 [browser_perf-options-invert-flame-graph-02.js]
-[browser_perf-options-flatten-tree-recursion-01.js]
-[browser_perf-options-flatten-tree-recursion-02.js]
-[browser_perf-options-show-jit-optimizations.js]
+[browser_perf-options-propagate-allocations.js]
+[browser_perf-options-propagate-profiler.js]
+[browser_perf-options-show-idle-blocks-01.js]
+[browser_perf-options-show-idle-blocks-02.js]
+# [browser_perf-options-show-jit-optimizations.js] TODO bug 1256350
 [browser_perf-options-show-platform-data-01.js]
 [browser_perf-options-show-platform-data-02.js]
-[browser_perf-options-show-idle-blocks-01.js]
-[browser_perf-options-show-idle-blocks-02.js]
-[browser_perf-options-enable-memory-01.js]
-[browser_perf-options-enable-memory-02.js]
-[browser_perf-options-enable-framerate.js]
-[browser_perf-options-allocations.js]
-[browser_perf-options-profiler.js]
 [browser_perf-overview-render-01.js]
 [browser_perf-overview-render-02.js]
 [browser_perf-overview-render-03.js]
 [browser_perf-overview-render-04.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-overview-selection-01.js]
 [browser_perf-overview-selection-02.js]
 [browser_perf-overview-selection-03.js]
 [browser_perf-overview-time-interval.js]
-[browser_perf-private-browsing.js]
-skip-if = os == 'linux' # bug 1210140
-[browser_perf-states.js]
-skip-if = debug # bug 1203888
-[browser_perf-refresh.js]
-[browser_perf-ui-recording.js]
-skip-if = os == 'linux' # bug 1186322
+# [browser_perf-private-browsing.js] TODO bug 1256350
+[browser_perf-range-changed-render.js]
 [browser_perf-recording-notices-01.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-02.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-03.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-04.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-notices-05.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-recordings-io-01.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-recordings-io-02.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-recordings-io-03.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-recordings-io-04.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-recordings-io-05.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-recordings-io-06.js]
-skip-if = os == 'linux' # bug 1186322
-[browser_perf-range-changed-render.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-01.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-02.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-03.js]
-skip-if = os == 'linux' # bug 1186322
 [browser_perf-recording-selected-04.js]
-skip-if = os == 'linux' || debug # bug 1186322 for Linux, bug 1203895 for leaks
-[browser_perf-theme-toggle-01.js]
+[browser_perf-recordings-clear-01.js]
+[browser_perf-recordings-clear-02.js]
+# [browser_perf-recordings-io-01.js] TODO bug 1256350
+# [browser_perf-recordings-io-02.js] TODO bug 1256350
+# [browser_perf-recordings-io-03.js] TODO bug 1256350
+# [browser_perf-recordings-io-04.js] TODO bug 1256350
+# [browser_perf-recordings-io-05.js] TODO bug 1256350
+# [browser_perf-recordings-io-06.js] TODO bug 1256350
+[browser_perf-refresh.js]
+[browser_perf-states.js]
 [browser_perf-telemetry-01.js]
 [browser_perf-telemetry-02.js]
 [browser_perf-telemetry-03.js]
 [browser_perf-telemetry-04.js]
-[browser_profiler_tree-abstract-01.js]
-[browser_profiler_tree-abstract-02.js]
-[browser_profiler_tree-abstract-03.js]
-[browser_profiler_tree-abstract-04.js]
-[browser_profiler_tree-view-01.js]
-[browser_profiler_tree-view-02.js]
-[browser_profiler_tree-view-03.js]
-[browser_profiler_tree-view-04.js]
-[browser_profiler_tree-view-05.js]
-[browser_profiler_tree-view-06.js]
-[browser_profiler_tree-view-07.js]
-[browser_profiler_tree-view-08.js]
-[browser_profiler_tree-view-09.js]
-[browser_profiler_tree-view-10.js]
-[browser_profiler_tree-view-11.js]
-[browser_timeline-filters-01.js]
-skip-if = true # Bug 1176370
-[browser_timeline-filters-02.js]
+# [browser_perf-theme-toggle.js] TODO bug 1256350
+[browser_perf-tree-abstract-01.js]
+[browser_perf-tree-abstract-02.js]
+[browser_perf-tree-abstract-03.js]
+[browser_perf-tree-abstract-04.js]
+[browser_perf-tree-view-01.js]
+[browser_perf-tree-view-02.js]
+[browser_perf-tree-view-03.js]
+[browser_perf-tree-view-04.js]
+[browser_perf-tree-view-05.js]
+[browser_perf-tree-view-06.js]
+[browser_perf-tree-view-07.js]
+[browser_perf-tree-view-08.js]
+[browser_perf-tree-view-09.js]
+[browser_perf-tree-view-10.js]
+# [browser_perf-tree-view-11.js] TODO bug 1256350
+[browser_perf-ui-recording.js]
+# [browser_timeline-filters-01.js] TODO bug 1256350
+# [browser_timeline-filters-02.js] TODO bug 1256350
 [browser_timeline-waterfall-background.js]
 [browser_timeline-waterfall-generic.js]
-[browser_timeline-waterfall-rerender.js]
-skip-if = true # Bug 1170105
-[browser_timeline-waterfall-sidebar.js]
-skip-if = true # Bug 1161817
-[browser_timeline-waterfall-workers.js]
+# [browser_timeline-waterfall-rerender.js] TODO bug 1256350
+# [browser_timeline-waterfall-sidebar.js] TODO bug 1256350
+# [browser_timeline-waterfall-workers.js] TODO bug 1256350
--- a/devtools/client/performance/test/browser_aaa-run-first-leaktest.js
+++ b/devtools/client/performance/test/browser_aaa-run-first-leaktest.js
@@ -1,22 +1,28 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the performance tool leaks on initialization and sudden destruction.
  * You can also use this initialization format as a template for other tests.
  */
 
-function* spawnTest() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+
+add_task(function*() {
+  let { target, toolbox, panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
   ok(target, "Should have a target available.");
   ok(toolbox, "Should have a toolbox available.");
   ok(panel, "Should have a panel available.");
 
+  ok(panel.panelWin.gTarget, "Should have a target reference on the panel window.");
   ok(panel.panelWin.gToolbox, "Should have a toolbox reference on the panel window.");
-  ok(panel.panelWin.gTarget, "Should have a target reference on the panel window.");
   ok(panel.panelWin.gFront, "Should have a front reference on the panel window.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/test/browser_perf-button-states.js
@@ -0,0 +1,76 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Tests that the recording button states are set as expected.
+ */
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, EVENTS, PerformanceController, PerformanceView } = panel.panelWin;
+  let recordButton = $("#main-record-button");
+
+  ok(!recordButton.hasAttribute("checked"),
+    "The record button should not be checked yet.");
+  ok(!recordButton.hasAttribute("locked"),
+    "The record button should not be locked yet.");
+
+  let uiStartClick = once(PerformanceView, EVENTS.UI_START_RECORDING);
+  let recordingStarted = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-started" }
+  });
+  let backendStartReady = once(PerformanceController, EVENTS.BACKEND_READY_AFTER_RECORDING_START);
+  let uiStateRecording = once(PerformanceView, EVENTS.UI_STATE_CHANGED, {
+    expectedArgs: { "1": "recording" }
+  });
+
+  click(recordButton);
+  yield uiStartClick;
+
+  ok(recordButton.hasAttribute("checked"),
+    "The record button should now be checked.");
+  ok(recordButton.hasAttribute("locked"),
+    "The record button should be locked.");
+
+  yield recordingStarted;
+
+  ok(recordButton.hasAttribute("checked"),
+    "The record button should still be checked.");
+  ok(!recordButton.hasAttribute("locked"),
+    "The record button should not be locked.");
+
+  yield backendStartReady;
+  yield uiStateRecording;
+
+  let uiStopClick = once(PerformanceView, EVENTS.UI_STOP_RECORDING);
+  let recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopped" }
+  });
+  let backendStopReady = once(PerformanceController, EVENTS.BACKEND_READY_AFTER_RECORDING_STOP);
+  let uiStateRecorded = once(PerformanceView, EVENTS.UI_STATE_CHANGED, {
+    expectedArgs: { "1": "recorded" }
+  });
+
+  click(recordButton);
+  yield uiStopClick;
+  yield recordingStopped;
+
+  ok(!recordButton.hasAttribute("checked"),
+    "The record button should not be checked.");
+  ok(!recordButton.hasAttribute("locked"),
+    "The record button should not be locked.");
+
+  yield backendStopReady;
+  yield uiStateRecorded;
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-categories-js-calltree.js
rename to devtools/client/performance/test/browser_perf-calltree-js-categories.js
--- a/devtools/client/performance/test/browser_perf-categories-js-calltree.js
+++ b/devtools/client/performance/test/browser_perf-calltree-js-categories.js
@@ -1,49 +1,59 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that the categories are shown in the js call tree when platform data
- * is enabled.
+ * Tests that the categories are shown in the js call tree when
+ * platform data is enabled.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_SHOW_PLATFORM_DATA_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { busyWait } = require("devtools/client/performance/test/helpers/wait-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, $, $$, DetailsView, JsCallTreeView } = panel.panelWin;
 
-  // Enable platform data to show the categories.
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+  // Enable platform data to show the categories in the tree.
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
+  yield busyWait(100); // To show the `Gecko` category in the tree.
+  yield stopRecording(panel);
 
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  yield stopRecording(panel);
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
   yield rendered;
 
   is($(".call-tree-cells-container").hasAttribute("categories-hidden"), false,
     "The call tree cells container should show the categories now.");
   ok(geckoCategoryPresent($$),
     "A category node with the text `Gecko` is displayed in the tree.");
 
-  // Disable platform data to show the categories.
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
+  // Disable platform data to hide the categories.
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, false);
 
   is($(".call-tree-cells-container").getAttribute("categories-hidden"), "",
     "The call tree cells container should hide the categories now.");
   ok(!geckoCategoryPresent($$),
     "A category node with the text `Gecko` doesn't exist in the tree anymore.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
 
 function geckoCategoryPresent($$) {
-  for (let elem of $$('.call-tree-category')) {
-    if (elem.textContent.trim() == 'Gecko') {
-      return true
+  for (let elem of $$(".call-tree-category")) {
+    if (elem.textContent.trim() == "Gecko") {
+      return true;
     }
   }
-  return false
+  return false;
 }
rename from devtools/client/performance/test/browser_perf-columns-js-calltree.js
rename to devtools/client/performance/test/browser_perf-calltree-js-columns.js
--- a/devtools/client/performance/test/browser_perf-columns-js-calltree.js
+++ b/devtools/client/performance/test/browser_perf-calltree-js-columns.js
@@ -1,47 +1,57 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the js call tree view renders the correct columns.
  */
-function* spawnTest() {
-  // This test seems to take a long time to cleanup on Ubuntu VMs.
-  requestLongerTimeout(2);
 
-  let { panel } = yield initPerformance(SIMPLE_URL);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_SHOW_PLATFORM_DATA_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { busyWait } = require("devtools/client/performance/test/helpers/wait-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, $, $$, DetailsView, JsCallTreeView } = panel.panelWin;
 
-  // Enable platform data to show the `busyWait` function in the tree.
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+  // Enable platform data to show the platform functions in the tree.
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(1000);
-
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  yield busyWait(100); // To show the `busyWait` function in the tree.
   yield stopRecording(panel);
+
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
+  yield rendered;
+
   ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
-  yield rendered;
 
   testCells($, $$, {
     "duration": true,
     "percentage": true,
     "allocations": false,
     "self-duration": true,
     "self-percentage": true,
     "self-allocations": false,
     "samples": true,
     "function": true
   });
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
 
 function testCells($, $$, visibleCells) {
   for (let cell in visibleCells) {
     if (visibleCells[cell]) {
       ok($(`.call-tree-cell[type=${cell}]`),
         `At least one ${cell} column was visible in the tree.`);
     } else {
       ok(!$(`.call-tree-cell[type=${cell}]`),
rename from devtools/client/performance/test/browser_perf-events-calltree.js
rename to devtools/client/performance/test/browser_perf-calltree-js-events.js
--- a/devtools/client/performance/test/browser_perf-events-calltree.js
+++ b/devtools/client/performance/test/browser_perf-calltree-js-events.js
@@ -1,88 +1,51 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the call tree up/down events work for js calltree and memory calltree.
+ * Tests that the call tree up/down events work for js calltrees.
  */
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { synthesizeProfile } = require("devtools/client/performance/test/helpers/synth-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
 
-function* spawnTest() {
-  let focus = 0;
-  let focusEvent = () => focus++;
-
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, $, DetailsView, OverviewView, JsCallTreeView, MemoryCallTreeView } = panel.panelWin;
+  let { EVENTS, $, DetailsView, OverviewView, JsCallTreeView } = panel.panelWin;
 
+  yield startRecording(panel);
+  yield stopRecording(panel);
+
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
-  ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
-
-  // Make a recording just so the performance tool is in the correct state
-  yield startRecording(panel);
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  yield stopRecording(panel);
   yield rendered;
 
-  // Mock the profile used so we can get a deterministic tree created
-  let threadNode = new ThreadNode(gProfile.threads[0], OverviewView.getTimeInterval());
+  // Mock the profile used so we can get a deterministic tree created.
+  let profile = synthesizeProfile();
+  let threadNode = new ThreadNode(profile.threads[0], OverviewView.getTimeInterval());
   JsCallTreeView._populateCallTree(threadNode);
-  JsCallTreeView.emit(EVENTS.JS_CALL_TREE_RENDERED);
-
-  JsCallTreeView.on("focus", focusEvent);
+  JsCallTreeView.emit(EVENTS.UI_JS_CALL_TREE_RENDERED);
 
-  click(panel.panelWin, $("#js-calltree-view .call-tree-item"));
-  fireKey("VK_DOWN");
-  fireKey("VK_DOWN");
-  fireKey("VK_DOWN");
-  fireKey("VK_DOWN");
-
-  JsCallTreeView.off("focus", focusEvent);
-
-  is(focus, 4, "several focus events are fired for the js calltree.");
-
-  yield teardown(panel);
-  finish();
-};
+  let count = 0;
+  let onFocus = () => count++;
+  JsCallTreeView.on("focus", onFocus);
 
-var gProfile = {
-  meta: { version: 2 },
-  threads: [{
-    samples: [{
-      time: 5,
-      frames: [
-        { category: 8,  location: "(root)" },
-        { category: 8,  location: "A (http://foo/bar/baz:12)" },
-        { category: 16, location: "B (http://foo/bar/baz:34)" },
-        { category: 32, location: "C (http://foo/bar/baz:56)" }
-      ]
-    }, {
-      time: 5 + 1,
-      frames: [
-        { category: 8,  location: "(root)" },
-        { category: 8,  location: "A (http://foo/bar/baz:12)" },
-        { category: 16, location: "B (http://foo/bar/baz:34)" },
-        { category: 64, location: "D (http://foo/bar/baz:78)" }
-      ]
-    }, {
-      time: 5 + 1 + 2,
-      frames: [
-        { category: 8,  location: "(root)" },
-        { category: 8,  location: "A (http://foo/bar/baz:12)" },
-        { category: 16, location: "B (http://foo/bar/baz:34)" },
-        { category: 64, location: "D (http://foo/bar/baz:78)" }
-      ]
-    }, {
-      time: 5 + 1 + 2 + 7,
-      frames: [
-        { category: 8,   location: "(root)" },
-        { category: 8,   location: "A (http://foo/bar/baz:12)" },
-        { category: 128, location: "E (http://foo/bar/baz:90)" },
-        { category: 256, location: "F (http://foo/bar/baz:99)" }
-      ]
-    }],
-    markers: []
-  }]
-};
+  click($("#js-calltree-view .call-tree-item"));
+  key("VK_DOWN");
+  key("VK_DOWN");
+  key("VK_DOWN");
+  key("VK_DOWN");
 
-RecordingUtils.deflateProfile(gProfile);
+  JsCallTreeView.off("focus", onFocus);
+  is(count, 4, "Several focus events are fired for the calltree.");
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-columns-memory-calltree.js
rename to devtools/client/performance/test/browser_perf-calltree-memory-columns.js
--- a/devtools/client/performance/test/browser_perf-columns-memory-calltree.js
+++ b/devtools/client/performance/test/browser_perf-calltree-memory-columns.js
@@ -1,29 +1,41 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the memory call tree view renders the correct columns.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, $, $$, DetailsView, MemoryCallTreeView } = panel.panelWin;
 
-  // Enable memory to test.
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
+  yield stopRecording(panel);
 
-  let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
-  yield stopRecording(panel);
+  let rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   yield DetailsView.selectView("memory-calltree");
+  yield rendered;
+
   ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
-  yield rendered;
 
   testCells($, $$, {
     "duration": false,
     "percentage": false,
     "count": true,
     "count-percentage": true,
     "size": true,
     "size-percentage": true,
@@ -32,19 +44,18 @@ function* spawnTest() {
     "self-count": true,
     "self-count-percentage": true,
     "self-size": true,
     "self-size-percentage": true,
     "samples": false,
     "function": true
   });
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
 
 function testCells($, $$, visibleCells) {
   for (let cell in visibleCells) {
     if (visibleCells[cell]) {
       ok($(`.call-tree-cell[type=${cell}]`),
         `At least one ${cell} column was visible in the tree.`);
     } else {
       ok(!$(`.call-tree-cell[type=${cell}]`),
--- a/devtools/client/performance/test/browser_perf-console-record-01.js
+++ b/devtools/client/performance/test/browser_perf-console-record-01.js
@@ -1,42 +1,41 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler is populated by console recordings that have finished
  * before it was opened.
  */
 
-var WAIT_TIME = 10;
-
-function* spawnTest() {
-  let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
-  let front = toolbox.performance;
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-  let profileStart = once(front, "recording-started");
-  console.profile("rust");
-  yield profileStart;
+add_task(function*() {
+  let { target, toolbox, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
-  busyWait(WAIT_TIME);
-  let profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust");
-  yield profileEnd;
+  yield console.profile("rust");
+  yield console.profileEnd("rust");
 
-  yield gDevTools.showToolbox(target, "performance");
-  let panel = yield toolbox.getCurrentPanel().open();
-  let { panelWin: { PerformanceController, RecordingsView }} = panel;
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
+
+  yield waitUntil(() => PerformanceController.getRecordings().length == 1);
+  yield waitUntil(() => WaterfallView.wasRenderedAtLeastOnce);
 
   let recordings = PerformanceController.getRecordings();
-  yield waitUntil(() => PerformanceController.getRecordings().length === 1);
-  is(recordings.length, 1, "one recording found in the performance panel.");
-  is(recordings[0].isConsole(), true, "recording came from console.profile.");
-  is(recordings[0].getLabel(), "rust", "correct label in the recording model.");
+  is(recordings.length, 1, "One recording found in the performance panel.");
+  is(recordings[0].isConsole(), true, "Recording came from console.profile.");
+  is(recordings[0].getLabel(), "rust", "Correct label in the recording model.");
 
   is(RecordingsView.selectedItem.attachment, recordings[0],
-    "The profile from console should be selected as its the only one in the RecordingsView.");
-
+    "The profile from console should be selected as it's the only one.");
   is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
     "The profile label for the first recording is correct.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-02.js
+++ b/devtools/client/performance/test/browser_perf-console-record-02.js
@@ -1,48 +1,68 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler is populated by in-progress console recordings
  * when it is opened.
  */
 
-function* spawnTest() {
-  let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
-  let front = toolbox.performance;
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
 
-  let profileStart = once(front, "recording-started");
-  console.profile("rust");
-  yield profileStart;
-
-  profileStart = once(front, "recording-started");
-  console.profile("rust2");
-  yield profileStart;
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
-  yield gDevTools.showToolbox(target, "performance");
-  let panel = yield toolbox.getCurrentPanel().open();
-  let { panelWin: { PerformanceController, RecordingsView }} = panel;
+  yield console.profile("rust");
+  yield console.profile("rust2");
 
-  yield waitUntil(() => PerformanceController.getRecordings().length === 2);
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+
+  yield waitUntil(() => PerformanceController.getRecordings().length == 2);
+
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "two recordings found in the performance panel.");
-  is(recordings[0].isConsole(), true, "recording came from console.profile (1).");
-  is(recordings[0].getLabel(), "rust", "correct label in the recording model (1).");
-  is(recordings[0].isRecording(), true, "recording is still recording (1).");
-  is(recordings[1].isConsole(), true, "recording came from console.profile (2).");
-  is(recordings[1].getLabel(), "rust2", "correct label in the recording model (2).");
-  is(recordings[1].isRecording(), true, "recording is still recording (2).");
+  is(recordings.length, 2, "Two recordings found in the performance panel.");
+  is(recordings[0].isConsole(), true, "Recording came from console.profile (1).");
+  is(recordings[0].getLabel(), "rust", "Correct label in the recording model (1).");
+  is(recordings[0].isRecording(), true, "Recording is still recording (1).");
+  is(recordings[1].isConsole(), true, "Recording came from console.profile (2).");
+  is(recordings[1].getLabel(), "rust2", "Correct label in the recording model (2).");
+  is(recordings[1].isRecording(), true, "Recording is still recording (2).");
 
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should be selected.");
+  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+    "The profile label for the first recording is correct.");
 
-  let profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust");
-  yield profileEnd;
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
-  profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust2");
-  yield profileEnd;
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profileEnd("rust");
+  yield stopped;
 
-  yield teardown(panel);
-  finish();
-}
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+  });
+  yield console.profileEnd("rust2");
+  yield stopped;
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-03.js
+++ b/devtools/client/performance/test/browser_perf-console-record-03.js
@@ -1,48 +1,56 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler is populated by in-progress console recordings, and
  * also console recordings that have finished before it was opened.
  */
 
-function* spawnTest() {
-  let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
-  let front = toolbox.performance;
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
 
-  let profileStart = once(front, "recording-started");
-  console.profile("rust");
-  yield profileStart;
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
-  let profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust");
-  yield profileEnd;
+  yield console.profile("rust");
+  yield console.profileEnd("rust");
+  yield console.profile("rust2");
 
-  profileStart = once(front, "recording-started");
-  console.profile("rust2");
-  yield profileStart;
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
 
-  yield gDevTools.showToolbox(target, "performance");
-  let panel = yield toolbox.getCurrentPanel().open();
-  let { panelWin: { PerformanceController, RecordingsView }} = panel;
+  yield waitUntil(() => PerformanceController.getRecordings().length == 2);
+  yield waitUntil(() => WaterfallView.wasRenderedAtLeastOnce);
 
-  yield waitUntil(() => PerformanceController.getRecordings().length === 2);
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "two recordings found in the performance panel.");
-  is(recordings[0].isConsole(), true, "recording came from console.profile (1).");
-  is(recordings[0].getLabel(), "rust", "correct label in the recording model (1).");
-  is(recordings[0].isRecording(), false, "recording is still recording (1).");
-  is(recordings[1].isConsole(), true, "recording came from console.profile (2).");
-  is(recordings[1].getLabel(), "rust2", "correct label in the recording model (2).");
-  is(recordings[1].isRecording(), true, "recording is still recording (2).");
+  is(recordings.length, 2, "Two recordings found in the performance panel.");
+  is(recordings[0].isConsole(), true, "Recording came from console.profile (1).");
+  is(recordings[0].getLabel(), "rust", "Correct label in the recording model (1).");
+  is(recordings[0].isRecording(), false, "Recording is still recording (1).");
+  is(recordings[1].isConsole(), true, "Recording came from console.profile (2).");
+  is(recordings[1].getLabel(), "rust2", "Correct label in the recording model (2).");
+  is(recordings[1].isRecording(), true, "Recording is still recording (2).");
 
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should be selected.");
+  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+    "The profile label for the first recording is correct.");
 
-  profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust2");
-  yield profileEnd;
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+  });
+  yield console.profileEnd("rust2");
+  yield stopped;
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-04.js
+++ b/devtools/client/performance/test/browser_perf-console-record-04.js
@@ -1,34 +1,56 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the profiler can handle creation and stopping of console profiles
  * after being opened.
  */
 
-function* spawnTest() {
-  PMM_loadFrameScripts(gBrowser);
-  let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
 
-  yield consoleProfile(panel.panelWin, "rust");
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+
+  let started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profile("rust");
+  yield started;
 
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 1, "a recordings found in the performance panel.");
-  is(recordings[0].isConsole(), true, "recording came from console.profile.");
-  is(recordings[0].getLabel(), "rust", "correct label in the recording model.");
-  is(recordings[0].isRecording(), true, "recording is still recording.");
+  is(recordings.length, 1, "One recording found in the performance panel.");
+  is(recordings[0].isConsole(), true, "Recording came from console.profile.");
+  is(recordings[0].getLabel(), "rust", "Correct label in the recording model.");
+  is(recordings[0].isRecording(), true, "Recording is still recording.");
 
   is(RecordingsView.selectedItem.attachment, recordings[0],
-    "The first console recording should be selected.");
+    "The profile from console should be selected as it's the only one.");
+  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+    "The profile label for the first recording is correct.");
+
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
-  // Ensure overview is still rendering
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profileEnd("rust");
+  yield stopped;
 
-  yield consoleProfileEnd(panel.panelWin, "rust");
-
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-05.js
+++ b/devtools/client/performance/test/browser_perf-console-record-05.js
@@ -1,45 +1,89 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
  * Tests that multiple recordings with the same label (non-overlapping) appear
  * in the recording list.
  */
 
-function* spawnTest() {
-  PMM_loadFrameScripts(gBrowser);
-  let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
 
-  yield consoleProfile(panel.panelWin, "rust");
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+
+  let started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profile("rust");
+  yield started;
 
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 1, "a recordings found in the performance panel.");
-  is(recordings[0].isConsole(), true, "recording came from console.profile.");
-  is(recordings[0].getLabel(), "rust", "correct label in the recording model.");
-  is(recordings[0].isRecording(), true, "recording is still recording.");
+  is(recordings.length, 1, "One recording found in the performance panel.");
+  is(recordings[0].isConsole(), true, "Recording came from console.profile (1).");
+  is(recordings[0].getLabel(), "rust", "Correct label in the recording model (1).");
+  is(recordings[0].isRecording(), true, "Recording is still recording (1).");
 
   is(RecordingsView.selectedItem.attachment, recordings[0],
-    "The first console recording should be selected.");
+    "The profile from console should be selected as it's the only one.");
+  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+    "The profile label for the first recording is correct.");
+
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
-  // Ensure overview is still rendering
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profileEnd("rust");
+  yield stopped;
 
-  yield consoleProfileEnd(panel.panelWin, "rust");
+  started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile("rust");
+  yield started;
 
-  yield consoleProfile(panel.panelWin, "rust");
   recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "a recordings found in the performance panel.");
-  is(recordings[1].isConsole(), true, "recording came from console.profile.");
-  is(recordings[1].getLabel(), "rust", "correct label in the recording model.");
-  is(recordings[1].isRecording(), true, "recording is still recording.");
+  is(recordings.length, 2, "Two recordings found in the performance panel.");
+  is(recordings[1].isConsole(), true, "Recording came from console.profile (2).");
+  is(recordings[1].getLabel(), "rust", "Correct label in the recording model (2).");
+  is(recordings[1].isRecording(), true, "Recording is still recording (2).");
+
+  is(RecordingsView.selectedItem.attachment, recordings[0],
+    "The profile from console should still be selected");
+  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+    "The profile label for the first recording is correct.");
 
-  yield consoleProfileEnd(panel.panelWin, "rust");
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+  });
+  yield console.profileEnd("rust");
+  yield stopped;
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-06.js
+++ b/devtools/client/performance/test/browser_perf-console-record-06.js
@@ -1,54 +1,95 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that console recordings can overlap (not completely nested).
  */
 
-function* spawnTest() {
-  PMM_loadFrameScripts(gBrowser);
-  let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView, WaterfallView } = panel.panelWin;
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
 
-  yield consoleProfile(panel.panelWin, "rust");
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+
+  let started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profile("rust");
+  yield started;
 
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 1, "a recording found in the performance panel.");
+  is(recordings.length, 1, "A recording found in the performance panel.");
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should be selected.");
 
-  yield consoleProfile(panel.panelWin, "golang");
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
+
+  started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile("golang");
+  yield started;
 
   recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "two recordings found in the performance panel.");
+  is(recordings.length, 2, "Two recordings found in the performance panel.");
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should still be selected.");
 
-  // Ensure overview is still rendering
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
-  yield consoleProfileEnd(panel.panelWin, "rust");
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profileEnd("rust");
+  yield stopped;
 
   recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "two recordings found in the performance panel.");
+  is(recordings.length, 2, "Two recordings found in the performance panel.");
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should still be selected.");
-  is(RecordingsView.selectedItem.attachment.isRecording(), false,
+  is(recordings[0].isRecording(), false,
     "The first console recording should no longer be recording.");
 
-  let detailsRendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  yield consoleProfileEnd(panel.panelWin, "golang");
-  yield detailsRendered;
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+  });
+  yield console.profileEnd("golang");
+  yield stopped;
 
   recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "two recordings found in the performance panel.");
+  is(recordings.length, 2, "Two recordings found in the performance panel.");
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should still be selected.");
   is(recordings[1].isRecording(), false,
     "The second console recording should no longer be recording.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-07.js
+++ b/devtools/client/performance/test/browser_perf-console-record-07.js
@@ -1,62 +1,163 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that a call to console.profileEnd() with no label ends the
- * most recent console recording, and console.profileEnd() with a label that does not
- * match any pending recordings does nothing.
+ * most recent console recording, and console.profileEnd() with a label that
+ * does not match any pending recordings does nothing.
  */
 
-function* spawnTest() {
-  PMM_loadFrameScripts(gBrowser);
-  let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView, WaterfallView } = panel.panelWin;
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { idleWait } = require("devtools/client/performance/test/helpers/wait-utils");
+
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { PerformanceController, RecordingsView } = panel.panelWin;
+
+  let started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profile();
+  yield started;
 
-  yield consoleProfile(panel.panelWin);
-  yield consoleProfile(panel.panelWin, "1");
-  yield consoleProfile(panel.panelWin, "2");
+  started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile("1");
+  yield started;
+
+  started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile("2");
+  yield started;
 
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 3, "3 recordings found");
+  is(recordings.length, 3, "Three recordings found in the performance panel.");
+  is(recordings[0].getLabel(), "", "Checking label of recording 1");
+  is(recordings[1].getLabel(), "1", "Checking label of recording 2");
+  is(recordings[2].getLabel(), "2", "Checking label of recording 3");
   is(RecordingsView.selectedItem.attachment, recordings[0],
     "The first console recording should be selected.");
 
-  yield consoleProfileEnd(panel.panelWin);
+  is(recordings[0].isRecording(), true,
+    "All recordings should now be started. (1)");
+  is(recordings[1].isRecording(), true,
+    "All recordings should now be started. (2)");
+  is(recordings[2].isRecording(), true,
+    "All recordings should now be started. (3)");
 
-  // First off a label-less profileEnd to make sure no other recordings close
-  consoleProfileEnd(panel.panelWin, "fxos");
-  yield idleWait(500);
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+    // the view state won't switch to "recorded" unless the new
+    // finished recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profileEnd();
+  yield stopped;
 
   recordings = PerformanceController.getRecordings();
-  is(recordings.length, 3, "3 recordings found");
+  is(recordings.length, 3, "Three recordings found in the performance panel.");
+  is(RecordingsView.selectedItem.attachment, recordings[0],
+    "The first console recording should still be selected.");
 
-  is(recordings[0].getLabel(), "", "Checking label of recording 1");
-  is(recordings[1].getLabel(), "1", "Checking label of recording 2");
-  is(recordings[2].getLabel(), "2", "Checking label of recording 3");
   is(recordings[0].isRecording(), true,
     "The not most recent recording should not stop when calling console.profileEnd with no args.");
   is(recordings[1].isRecording(), true,
     "The not most recent recording should not stop when calling console.profileEnd with no args.");
   is(recordings[2].isRecording(), false,
-    "Only thw most recent recording should stop when calling console.profileEnd with no args.");
+    "Only the most recent recording should stop when calling console.profileEnd with no args.");
+
+  info("Trying to `profileEnd` a non-existent console recording.");
+  /* yield */ console.profileEnd("fxos");
+  yield idleWait(1000);
+
+  recordings = PerformanceController.getRecordings();
+  is(recordings.length, 3, "Three recordings found in the performance panel.");
+  is(RecordingsView.selectedItem.attachment, recordings[0],
+    "The first console recording should still be selected.");
+
+  is(recordings[0].isRecording(), true,
+    "The first recording should not be ended yet.");
+  is(recordings[1].isRecording(), true,
+    "The second recording should not be ended yet.");
+  is(recordings[2].isRecording(), false,
+    "The third recording should still be ended.");
 
-  let detailsRendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  yield consoleProfileEnd(panel.panelWin);
-  yield consoleProfileEnd(panel.panelWin);
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+    // the view state won't switch to "recorded" unless the new
+    // finished recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profileEnd();
+  yield stopped;
+
+  recordings = PerformanceController.getRecordings();
+  is(recordings.length, 3, "Three recordings found in the performance panel.");
+  is(RecordingsView.selectedItem.attachment, recordings[0],
+    "The first console recording should still be selected.");
+
+  is(recordings[0].isRecording(), true,
+    "The first recording should not be ended yet.");
+  is(recordings[1].isRecording(), false,
+    "The second recording should not be ended yet.");
+  is(recordings[2].isRecording(), false,
+    "The third recording should still be ended.");
+
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profileEnd();
+  yield stopped;
+
+  recordings = PerformanceController.getRecordings();
+  is(recordings.length, 3, "Three recordings found in the performance panel.");
+  is(RecordingsView.selectedItem.attachment, recordings[0],
+    "The first console recording should be selected.");
 
   is(recordings[0].isRecording(), false,
     "All recordings should now be ended. (1)");
   is(recordings[1].isRecording(), false,
     "All recordings should now be ended. (2)");
   is(recordings[2].isRecording(), false,
     "All recordings should now be ended. (3)");
 
-  yield detailsRendered;
+  info("Trying to `profileEnd` with no pending recordings.");
+  /* yield */ console.profileEnd();
+  yield idleWait(1000);
 
-  consoleProfileEnd(panel.panelWin);
-  yield idleWait(500);
-  ok(true, "Calling additional console.profileEnd() with no argument and no pending recordings does not throw.");
+  ok(true, "Calling console.profileEnd() with no argument and no pending recordings does not throw.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-console-record-08.js
+++ b/devtools/client/performance/test/browser_perf-console-record-08.js
@@ -1,88 +1,181 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler can correctly handle simultaneous console and manual
  * recordings (via `console.profile` and clicking the record button).
  */
 
-var C = 1; // is console
-var R = 2; // is recording
-var S = 4; // is selected
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { once, times } = require("devtools/client/performance/test/helpers/event-utils");
 
-function testRecordings (win, expected) {
-  let recordings = win.PerformanceController.getRecordings();
-  let current = win.PerformanceController.getCurrentRecording();
-  is(recordings.length, expected.length, "expected number of recordings");
-  recordings.forEach((recording, i) => {
-    ok(recording.isConsole() == !!(expected[i] & C), `recording ${i+1} has expected console state.`);
-    ok(recording.isRecording() == !!(expected[i] & R), `recording ${i+1} has expected console state.`);
-    ok((recording === current) == !!(expected[i] & S), `recording ${i+1} has expected selected state.`);
+add_task(function*() {
+  // This test seems to take a very long time to finish on Linux VMs.
+  requestLongerTimeout(4);
+
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
   });
-}
 
-function* spawnTest() {
-  PMM_loadFrameScripts(gBrowser);
-  let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, OverviewView, RecordingsView, WaterfallView } = panel.panelWin;
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { EVENTS, PerformanceController, RecordingsView, OverviewView } = panel.panelWin;
 
   info("Starting console.profile()...");
-  yield consoleProfile(panel.panelWin);
-  testRecordings(panel.panelWin, [C+S+R]);
+  let started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true
+  });
+  yield console.profile("rust");
+  yield started;
+  testRecordings(PerformanceController, [C+S+R]);
+
   info("Starting manual recording...");
   yield startRecording(panel);
-  testRecordings(panel.panelWin, [C+R, R+S]);
+  testRecordings(PerformanceController, [C+R, R+S]);
+
   info("Starting console.profile(\"3\")...");
-  yield consoleProfile(panel.panelWin, "3");
-  testRecordings(panel.panelWin, [C+R, R+S, C+R]);
-  info("Starting console.profile(\"3\")...");
-  yield consoleProfile(panel.panelWin, "4");
-  testRecordings(panel.panelWin, [C+R, R+S, C+R, C+R]);
+  started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile("3");
+  yield started;
+  testRecordings(PerformanceController, [C+R, R+S, C+R]);
+
+  info("Starting console.profile(\"4\")...");
+  started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress  recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile("4");
+  yield started;
+  testRecordings(PerformanceController, [C+R, R+S, C+R, C+R]);
 
   info("Ending console.profileEnd()...");
-  yield consoleProfileEnd(panel.panelWin);
-
-  testRecordings(panel.panelWin, [C+R, R+S, C+R, C]);
-  ok(OverviewView.isRendering(), "still rendering overview with manual recorded selected.");
-
-  let onSelected = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  info("Select last recording...");
-  RecordingsView.selectedIndex = 3;
-  yield onSelected;
-  testRecordings(panel.panelWin, [C+R, R, C+R, C+S]);
-  ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
+  let stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+    // the view state won't switch to "recorded" unless the new
+    // finished recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profileEnd();
+  yield stopped;
+  testRecordings(PerformanceController, [C+R, R+S, C+R, C]);
 
-  info("Manually stop manual recording...");
+  info("Select last recording...");
+  let recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  RecordingsView.selectedIndex = 3;
+  yield recordingSelected;
+  testRecordings(PerformanceController, [C+R, R, C+R, C+S]);
+  ok(!OverviewView.isRendering(), "Stop rendering overview when a completed recording is selected.");
+
+  info("Stop manual recording...");
   yield stopRecording(panel);
-  testRecordings(panel.panelWin, [C+R, S, C+R, C]);
-  ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
+  testRecordings(PerformanceController, [C+R, S, C+R, C]);
+  ok(!OverviewView.isRendering(), "Stop rendering overview when a completed recording is selected.");
 
-  onSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   info("Select first recording...");
+  recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
-  yield onSelected;
-  testRecordings(panel.panelWin, [C+R+S, 0, C+R, C]);
-  yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
-  ok(OverviewView.isRendering(), "should be rendering overview when selected recording in progress.");
+  yield recordingSelected;
+  testRecordings(PerformanceController, [C+R+S, 0, C+R, C]);
+  ok(OverviewView.isRendering(), "Should be rendering overview a recording in progress is selected.");
+
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
   info("Ending console.profileEnd()...");
-  yield consoleProfileEnd(panel.panelWin);
-  testRecordings(panel.panelWin, [C+R+S, 0, C, C]);
-  ok(OverviewView.isRendering(), "should still be rendering overview when selected recording in progress.");
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+    // the view state won't switch to "recorded" unless the new
+    // finished recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profileEnd();
+  yield stopped;
+  testRecordings(PerformanceController, [C+R+S, 0, C, C]);
+  ok(OverviewView.isRendering(), "Should be rendering overview a recording in progress is selected.");
+
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
+
   info("Start one more manual recording...");
   yield startRecording(panel);
-  testRecordings(panel.panelWin, [C+R, 0, C, C, R+S]);
-  ok(OverviewView.isRendering(), "should be rendering overview when selected recording in progress.");
+  testRecordings(PerformanceController, [C+R, 0, C, C, R+S]);
+  ok(OverviewView.isRendering(), "Should be rendering overview a recording in progress is selected.");
+
+  // Ensure overview is still rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
+
   info("Stop manual recording...");
   yield stopRecording(panel);
-  testRecordings(panel.panelWin, [C+R, 0, C, C, S]);
-  ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
+  testRecordings(PerformanceController, [C+R, 0, C, C, S]);
+  ok(!OverviewView.isRendering(), "Stop rendering overview when a completed recording is selected.");
 
   info("Ending console.profileEnd()...");
-  yield consoleProfileEnd(panel.panelWin);
-  testRecordings(panel.panelWin, [C, 0, C, C, S]);
-  ok(!OverviewView.isRendering(), "stop rendering overview when selected completed recording.");
+  stopped = waitForRecordingStoppedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when a finished recording is selected
+    skipWaitingForOverview: true,
+    skipWaitingForSubview: true,
+    // the view state won't switch to "recorded" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profileEnd();
+  yield stopped;
+  testRecordings(PerformanceController, [C, 0, C, C, S]);
+  ok(!OverviewView.isRendering(), "Stop rendering overview when a completed recording is selected.");
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
 
-  yield teardown(panel);
-  finish();
+const C = 1; // is console
+const R = 2; // is recording
+const S = 4; // is selected
+
+function testRecordings(controller, expected) {
+  let recordings = controller.getRecordings();
+  let current = controller.getCurrentRecording();
+  is(recordings.length, expected.length, "Expected number of recordings.");
+
+  recordings.forEach((recording, i) => {
+    ok(recording.isConsole() == !!(expected[i] & C),
+      `Recording ${i+1} has expected console state.`);
+    ok(recording.isRecording() == !!(expected[i] & R),
+      `Recording ${i+1} has expected console state.`);
+    ok((recording == current) == !!(expected[i] & S),
+      `Recording ${i+1} has expected selected state.`);
+  });
 }
--- a/devtools/client/performance/test/browser_perf-console-record-09.js
+++ b/devtools/client/performance/test/browser_perf-console-record-09.js
@@ -1,41 +1,63 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that an error is not thrown when clearing out the recordings if there's
- * an in-progress console profile and that console profiles are not cleared if in progress.
+ * an in-progress console profile and that console profiles are not cleared
+ * if in progress.
  */
 
-function* spawnTest() {
-  PMM_loadFrameScripts(gBrowser);
-  let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
-  let win = panel.panelWin;
-  let { gFront, PerformanceController } = win;
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
+const { idleWait } = require("devtools/client/performance/test/helpers/wait-utils");
+
+add_task(function*() {
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
+  let { PerformanceController } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   info("Starting console.profile()...");
-  yield consoleProfile(win);
+  let started = waitForRecordingStartedEvents(panel, {
+    // only emitted for manual recordings
+    skipWaitingForBackendReady: true,
+    // only emitted when an in-progress recording is selected
+    skipWaitingForOverview: true,
+    // the view state won't switch to "console-recording" unless the new
+    // in-progress recording is selected, which won't happen
+    skipWaitingForViewState: true,
+  });
+  yield console.profile();
+  yield started;
+
   yield PerformanceController.clearRecordings();
   let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 1, "1 recording found");
-  is(recordings[0].isConsole(), true, "recording from console.profile is not cleared.");
-  info("Ending console.profileEnd()...");
-  consoleMethod("profileEnd");
-  // Wait for the front to receive the stopped event
-  yield once(gFront, "recording-stopped");
+  is(recordings.length, 1, "One recording found in the performance panel.");
+  is(recordings[0].isConsole(), true, "Recording came from console.profile.");
+  is(recordings[0].getLabel(), "", "Correct label in the recording model.");
+  is(PerformanceController.getCurrentRecording(), recordings[0],
+    "There current recording should be the first one.");
 
-  // Wait an extra tick or two since the above promise will be resolved
-  // the same time as _onRecordingStateChange, which should not cause any throwing
-  yield idleWait(100);
+  info("Attempting to end console.profileEnd()...");
+  yield console.profileEnd();
+  yield idleWait(1000);
+
   ok(true, "Stopping an in-progress console profile after clearing recordings does not throw.");
 
   yield PerformanceController.clearRecordings();
+  recordings = PerformanceController.getRecordings();
   is(recordings.length, 0, "No recordings found");
   is(PerformanceController.getCurrentRecording(), null,
     "There should be no current recording.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-01.js
rename to devtools/client/performance/test/browser_perf-details-01-toggle.js
--- a/devtools/client/performance/test/browser_perf-details-01.js
+++ b/devtools/client/performance/test/browser_perf-details-01-toggle.js
@@ -1,54 +1,66 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the details view toggles subviews.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, $, DetailsView, document: doc } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+const { command } = require("devtools/client/performance/test/helpers/input-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, $, DetailsView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  info("views on startup");
-  checkViews(DetailsView, doc, "waterfall");
+  info("Checking views on startup.");
+  checkViews(DetailsView, $, "waterfall");
 
-  // Select calltree view
-  let viewChanged = onceSpread(DetailsView, EVENTS.DETAILS_VIEW_SELECTED);
+  // Select calltree view.
+  let viewChanged = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED, { spreadArgs: true });
   command($("toolbarbutton[data-view='js-calltree']"));
   let [_, viewName] = yield viewChanged;
-  is(viewName, "js-calltree", "DETAILS_VIEW_SELECTED fired with view name");
-  checkViews(DetailsView, doc, "js-calltree");
+  is(viewName, "js-calltree", "UI_DETAILS_VIEW_SELECTED fired with view name");
+  checkViews(DetailsView, $, "js-calltree");
 
-  // Select flamegraph view
-  viewChanged = onceSpread(DetailsView, EVENTS.DETAILS_VIEW_SELECTED);
+  // Select js flamegraph view.
+  viewChanged = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED, { spreadArgs: true });
   command($("toolbarbutton[data-view='js-flamegraph']"));
   [_, viewName] = yield viewChanged;
-  is(viewName, "js-flamegraph", "DETAILS_VIEW_SELECTED fired with view name");
-  checkViews(DetailsView, doc, "js-flamegraph");
+  is(viewName, "js-flamegraph", "UI_DETAILS_VIEW_SELECTED fired with view name");
+  checkViews(DetailsView, $, "js-flamegraph");
 
-  // Select waterfall view
-  viewChanged = onceSpread(DetailsView, EVENTS.DETAILS_VIEW_SELECTED);
+  // Select waterfall view.
+  viewChanged = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED, { spreadArgs: true });
   command($("toolbarbutton[data-view='waterfall']"));
   [_, viewName] = yield viewChanged;
-  is(viewName, "waterfall", "DETAILS_VIEW_SELECTED fired with view name");
-  checkViews(DetailsView, doc, "waterfall");
+  is(viewName, "waterfall", "UI_DETAILS_VIEW_SELECTED fired with view name");
+  checkViews(DetailsView, $, "waterfall");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
 
-function checkViews (DetailsView, doc, currentView) {
+function checkViews(DetailsView, $, currentView) {
   for (let viewName in DetailsView.components) {
-    let button = doc.querySelector(`toolbarbutton[data-view="${viewName}"]`);
+    let button = $(`toolbarbutton[data-view="${viewName}"]`);
 
     is(DetailsView.el.selectedPanel.id, DetailsView.components[currentView].id,
       `DetailsView correctly has ${currentView} selected.`);
-    if (viewName === currentView) {
-      ok(button.getAttribute("checked"), `${viewName} button checked`);
+
+    if (viewName == currentView) {
+      ok(button.getAttribute("checked"), `${viewName} button checked.`);
     } else {
-      ok(!button.getAttribute("checked"), `${viewName} button not checked`);
+      ok(!button.getAttribute("checked"), `${viewName} button not checked.`);
     }
   }
 }
rename from devtools/client/performance/test/browser_perf-details-02.js
rename to devtools/client/performance/test/browser_perf-details-02-utility-fun.js
--- a/devtools/client/performance/test/browser_perf-details-02.js
+++ b/devtools/client/performance/test/browser_perf-details-02-utility-fun.js
@@ -1,44 +1,53 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the details view utility functions work as advertised.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, DetailsView } = panel.panelWin;
-  let { WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, DetailsView, WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   ok(DetailsView.isViewSelected(WaterfallView),
     "The waterfall view is selected by default in the details view.");
 
-  let selected = DetailsView.whenViewSelected(JsCallTreeView);
-  let notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  // Select js calltree view.
+  let selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
   yield DetailsView.selectView("js-calltree");
-  yield Promise.all([selected, notified]);
+  yield selected;
 
   ok(DetailsView.isViewSelected(JsCallTreeView),
-    "The jscalltree view is now selected in the details view.");
+    "The js calltree view is now selected in the details view.");
 
-  selected = DetailsView.whenViewSelected(JsFlameGraphView);
-  notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  // Select js flamegraph view.
+  selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
   yield DetailsView.selectView("js-flamegraph");
-  yield Promise.all([selected, notified]);
+  yield selected;
 
   ok(DetailsView.isViewSelected(JsFlameGraphView),
-    "The flamegraph view is now selected in the details view.");
+    "The js flamegraph view is now selected in the details view.");
 
-  selected = DetailsView.whenViewSelected(WaterfallView);
-  notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  // Select waterfall view.
+  selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
   yield DetailsView.selectView("waterfall");
-  yield Promise.all([selected, notified]);
+  yield selected;
 
   ok(DetailsView.isViewSelected(WaterfallView),
     "The waterfall view is now selected in the details view.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-03.js
rename to devtools/client/performance/test/browser_perf-details-03-without-allocations.js
--- a/devtools/client/performance/test/browser_perf-details-03.js
+++ b/devtools/client/performance/test/browser_perf-details-03-without-allocations.js
@@ -1,79 +1,119 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that the details view hides the memory buttons when a recording does not
- * have memory data (withMemory: false), and that when a memory panel is selected,
- * switching to a panel that does not have memory goes to a default panel instead.
+ * Tests that the details view hides the allocations buttons when a recording
+ * does not have allocations data ("withAllocations": false), and that when an
+ * allocations panel is selected to a panel that does not have allocations goes
+ * to a default panel instead.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, DetailsView } = panel.panelWin;
-  let { $, RecordingsView, WaterfallView, MemoryCallTreeView, MemoryFlameGraphView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, false);
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, $, RecordingsView, DetailsView, WaterfallView, MemoryCallTreeView, MemoryFlameGraphView } = panel.panelWin;
+
+  let flameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
+  let callBtn = $("toolbarbutton[data-view='memory-calltree']");
+
+  // Disable allocations to prevent recording them.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, false);
+
   yield startRecording(panel);
   yield stopRecording(panel);
 
   ok(DetailsView.isViewSelected(WaterfallView),
     "The waterfall view is selected by default in the details view.");
 
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
+  // Re-enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
+
   // The toolbar buttons will always be hidden when a recording isn't available,
   // so make sure we have one that's finished.
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  let flameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
-  let callBtn = $("toolbarbutton[data-view='memory-calltree']");
+  ok(DetailsView.isViewSelected(WaterfallView),
+    "The waterfall view is still selected in the details view.");
 
-  is(flameBtn.hidden, false, "memory-flamegraph button shown when recording has memory data");
-  is(callBtn.hidden, false, "memory-calltree button shown when recording has memory data");
+  is(callBtn.hidden, false,
+    "The `memory-calltree` button is shown when recording has memory data.");
+  is(flameBtn.hidden, false,
+    "The `memory-flamegraph` button is shown when recording has memory data.");
 
-  let selected = DetailsView.whenViewSelected(MemoryCallTreeView);
-  let notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  let selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  let rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   DetailsView.selectView("memory-calltree");
-  yield Promise.all([selected, notified]);
+  yield selected;
+  yield rendered;
 
   ok(DetailsView.isViewSelected(MemoryCallTreeView),
     "The memory call tree view can now be selected.");
 
-  selected = DetailsView.whenViewSelected(MemoryFlameGraphView);
-  notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
   DetailsView.selectView("memory-flamegraph");
-  yield Promise.all([selected, notified]);
+  yield selected;
+  yield rendered;
 
   ok(DetailsView.isViewSelected(MemoryFlameGraphView),
     "The memory flamegraph view can now be selected.");
 
-  // Select the first recording with no memory data
-  selected = DetailsView.whenViewSelected(WaterfallView);
-  notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  // Select the first recording with no memory data.
+  selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   RecordingsView.selectedIndex = 0;
-  yield Promise.all([selected, notified]);
+  yield selected;
+  yield rendered;
+
+  ok(DetailsView.isViewSelected(WaterfallView),
+    "The waterfall view is now selected when switching back to a recording that does not have memory data.");
+
+  is(callBtn.hidden, true,
+    "The `memory-calltree` button is hidden when recording has no memory data.");
+  is(flameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when recording has no memory data.");
+
+  // Go back to the recording with memory data.
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
+  RecordingsView.selectedIndex = 1;
+  yield rendered;
 
   ok(DetailsView.isViewSelected(WaterfallView),
-    "The waterfall view is now selected when switching back to a recording that does not have memory data");
-  is(flameBtn.hidden, true, "memory-flamegraph button hidden when recording does not have memory data");
-  is(callBtn.hidden, true, "memory-calltree button hidden when recording does not have memory data");
+    "The waterfall view is still selected in the details view.");
 
-  // Go back to the recording with memory data
-  let render = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
-  RecordingsView.selectedIndex = 1;
-  yield render;
+  is(callBtn.hidden, false,
+    "The `memory-calltree` button is shown when recording has memory data.");
+  is(flameBtn.hidden, false,
+    "The `memory-flamegraph` button is shown when recording has memory data.");
 
-  selected = DetailsView.whenViewSelected(MemoryCallTreeView);
-  notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   DetailsView.selectView("memory-calltree");
-  yield Promise.all([selected, notified]);
+  yield selected;
+  yield rendered;
 
   ok(DetailsView.isViewSelected(MemoryCallTreeView),
-    "The memory call tree view can be selected again after going back to the view with memory data");
-  is(flameBtn.hidden, false, "memory-flamegraph button shown when recording has memory data");
-  is(callBtn.hidden, false, "memory-calltree button shown when recording has memory data");
+    "The memory call tree view can be selected again after going back to the view with memory data.");
 
-  yield teardown(panel);
-  finish();
-}
+  selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  DetailsView.selectView("memory-flamegraph");
+  yield selected;
+  yield rendered;
+
+  ok(DetailsView.isViewSelected(MemoryFlameGraphView),
+    "The memory flamegraph view can be selected again after going back to the view with memory data.");
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-04.js
rename to devtools/client/performance/test/browser_perf-details-04-toolbar-buttons.js
--- a/devtools/client/performance/test/browser_perf-details-04.js
+++ b/devtools/client/performance/test/browser_perf-details-04-toolbar-buttons.js
@@ -1,92 +1,136 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
  * Tests that the details view hides the toolbar buttons when a recording
  * doesn't exist or is in progress.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, $, $$, PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, $, PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
 
   let waterfallBtn = $("toolbarbutton[data-view='waterfall']");
   let jsFlameBtn = $("toolbarbutton[data-view='js-flamegraph']");
   let jsCallBtn = $("toolbarbutton[data-view='js-calltree']");
   let memFlameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
   let memCallBtn = $("toolbarbutton[data-view='memory-calltree']");
 
-  is(waterfallBtn.hidden, true, "waterfall button hidden when tool starts.");
-  is(jsFlameBtn.hidden, true, "js-flamegraph button hidden when tool starts.");
-  is(jsCallBtn.hidden, true, "js-calltree button hidden when tool starts.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when tool starts.");
-  is(memCallBtn.hidden, true, "memory-calltree button hidden when tool starts.");
+  is(waterfallBtn.hidden, true,
+    "The `waterfall` button is hidden when tool starts.");
+  is(jsFlameBtn.hidden, true,
+    "The `js-flamegraph` button is hidden when tool starts.");
+  is(jsCallBtn.hidden, true,
+    "The `js-calltree` button is hidden when tool starts.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when tool starts.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree` button is hidden when tool starts.");
 
   yield startRecording(panel);
 
-  is(waterfallBtn.hidden, true, "waterfall button hidden when recording starts.");
-  is(jsFlameBtn.hidden, true, "js-flamegraph button hidden when recording starts.");
-  is(jsCallBtn.hidden, true, "js-calltree button hidden when recording starts.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when recording starts.");
-  is(memCallBtn.hidden, true, "memory-calltree button hidden when recording starts.");
+  is(waterfallBtn.hidden, true,
+    "The `waterfall` button is hidden when recording starts.");
+  is(jsFlameBtn.hidden, true,
+    "The `js-flamegraph` button is hidden when recording starts.");
+  is(jsCallBtn.hidden, true,
+    "The `js-calltree` button is hidden when recording starts.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when recording starts.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree` button is hidden when recording starts.");
 
   yield stopRecording(panel);
 
-  is(waterfallBtn.hidden, false, "waterfall button visible when recording ends.");
-  is(jsFlameBtn.hidden, false, "js-flamegraph button visible when recording ends.");
-  is(jsCallBtn.hidden, false, "js-calltree button visible when recording ends.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when recording ends.");
-  is(memCallBtn.hidden, true, "memory-calltree button hidden when recording ends.");
+  is(waterfallBtn.hidden, false,
+    "The `waterfall` button is visible when recording ends.");
+  is(jsFlameBtn.hidden, false,
+    "The `js-flamegraph` button is visible when recording ends.");
+  is(jsCallBtn.hidden, false,
+    "The `js-calltree` button is visible when recording ends.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when recording ends.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree` button is hidden when recording ends.");
 
   yield startRecording(panel);
 
-  is(waterfallBtn.hidden, true, "waterfall button hidden when another recording starts.");
-  is(jsFlameBtn.hidden, true, "js-flamegraph button hidden when another recording starts.");
-  is(jsCallBtn.hidden, true, "js-calltree button hidden when another recording starts.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when another recording starts.");
-  is(memCallBtn.hidden, true, "memory-calltree button hidden when another recording starts.");
+  is(waterfallBtn.hidden, true,
+    "The `waterfall` button is hidden when another recording starts.");
+  is(jsFlameBtn.hidden, true,
+    "The `js-flamegraph` button is hidden when another recording starts.");
+  is(jsCallBtn.hidden, true,
+    "The `js-calltree` button is hidden when another recording starts.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when another recording starts.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree` button is hidden when another recording starts.");
 
-  let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  let render = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  mousedown(panel.panelWin, $$(".recording-item")[0]);
-  yield Promise.all([select, render]);
+  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  let rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
+  RecordingsView.selectedIndex = 0;
+  yield selected;
+  yield rendered;
 
   is(RecordingsView.selectedIndex, 0,
     "The first recording was selected again.");
 
-  is(waterfallBtn.hidden, false, "waterfall button visible when first recording selected.");
-  is(jsFlameBtn.hidden, false, "js-flamegraph button visible when first recording selected.");
-  is(jsCallBtn.hidden, false, "js-calltree button visible when first recording selected.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when first recording selected.");
-  is(memCallBtn.hidden, true, "memory-calltree button hidden when first recording selected.");
+  is(waterfallBtn.hidden, false,
+    "The `waterfall` button is visible when first recording selected.");
+  is(jsFlameBtn.hidden, false,
+    "The `js-flamegraph` button is visible when first recording selected.");
+  is(jsCallBtn.hidden, false,
+    "The `js-calltree` button is visible when first recording selected.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when first recording selected.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree` button is hidden when first recording selected.");
 
-  select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  mousedown(panel.panelWin, $$(".recording-item")[1]);
-  yield select;
+  selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  RecordingsView.selectedIndex = 1;
+  yield selected;
 
   is(RecordingsView.selectedIndex, 1,
     "The second recording was selected again.");
 
-  is(waterfallBtn.hidden, true, "waterfall button still hidden when second recording selected.");
-  is(jsFlameBtn.hidden, true, "js-flamegraph button still hidden when second recording selected.");
-  is(jsCallBtn.hidden, true, "js-calltree button still hidden when second recording selected.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button still hidden when second recording selected.");
-  is(memCallBtn.hidden, true, "memory-calltree button still hidden when second recording selected.");
+  is(waterfallBtn.hidden, true,
+    "The `waterfall button` still is hidden when second recording selected.");
+  is(jsFlameBtn.hidden, true,
+    "The `js-flamegraph button` still is hidden when second recording selected.");
+  is(jsCallBtn.hidden, true,
+    "The `js-calltree button` still is hidden when second recording selected.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph button` still is hidden when second recording selected.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree button` still is hidden when second recording selected.");
 
-  render = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   yield stopRecording(panel);
-  yield render;
+  yield rendered;
 
   is(RecordingsView.selectedIndex, 1,
     "The second recording is still selected.");
 
-  is(waterfallBtn.hidden, false, "waterfall button visible when second recording finished.");
-  is(jsFlameBtn.hidden, false, "js-flamegraph button visible when second recording finished.");
-  is(jsCallBtn.hidden, false, "js-calltree button visible when second recording finished.");
-  is(memFlameBtn.hidden, true, "memory-flamegraph button hidden when second recording finished.");
-  is(memCallBtn.hidden, true, "memory-calltree button hidden when second recording finished.");
+  is(waterfallBtn.hidden, false,
+    "The `waterfall` button is visible when second recording finished.");
+  is(jsFlameBtn.hidden, false,
+    "The `js-flamegraph` button is visible when second recording finished.");
+  is(jsCallBtn.hidden, false,
+    "The `js-calltree` button is visible when second recording finished.");
+  is(memFlameBtn.hidden, true,
+    "The `memory-flamegraph` button is hidden when second recording finished.");
+  is(memCallBtn.hidden, true,
+    "The `memory-calltree` button is hidden when second recording finished.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-05.js
rename to devtools/client/performance/test/browser_perf-details-05-preserve-view.js
--- a/devtools/client/performance/test/browser_perf-details-05.js
+++ b/devtools/client/performance/test/browser_perf-details-05-preserve-view.js
@@ -1,40 +1,49 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that the details view utility functions work as advertised.
+ * Tests that the same details view is selected after recordings are cleared
+ * and a new recording starts.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, DetailsView } = panel.panelWin;
-  let { PerformanceController, WaterfallView, JsCallTreeView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, PerformanceController, DetailsView, JsCallTreeView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  ok(DetailsView.isViewSelected(WaterfallView),
-    "The waterfall view is selected by default in the details view.");
-
-  let selected = DetailsView.whenViewSelected(JsCallTreeView);
-  let notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
+  let selected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
-  yield Promise.all([selected, notified]);
+  yield selected;
+  yield rendered;
 
   ok(DetailsView.isViewSelected(JsCallTreeView),
-    "The jscalltree view is now selected in the details view.");
+    "The js calltree view is now selected in the details view.");
 
+  let cleared = once(PerformanceController, EVENTS.RECORDING_SELECTED, { expectedArgs: { "1": null } });
   yield PerformanceController.clearRecordings();
+  yield cleared;
 
   yield startRecording(panel);
-  let render = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  yield stopRecording(panel);
-  yield render;
+  yield stopRecording(panel, {
+    expectedViewClass: "JsCallTreeView",
+    expectedViewEvent: "UI_JS_CALL_TREE_RENDERED"
+  });
 
   ok(DetailsView.isViewSelected(JsCallTreeView),
-    "The jscalltree view is still selected in the details view");
+    "The js calltree view is still selected in the details view.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-07.js
rename to devtools/client/performance/test/browser_perf-details-06-rerender-on-selection.js
--- a/devtools/client/performance/test/browser_perf-details-07.js
+++ b/devtools/client/performance/test/browser_perf-details-06-rerender-on-selection.js
@@ -1,63 +1,72 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that when flame chart views scroll to change selection,
- * other detail views are rerendered
+ * other detail views are rerendered.
  */
-var HORIZONTAL_AXIS = 1;
-var VERTICAL_AXIS = 2;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+const { scrollCanvasGraph, HORIZONTAL_AXIS } = require("devtools/client/performance/test/helpers/input-utils");
 
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, OverviewView, DetailsView, WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, OverviewView, DetailsView, WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  let waterfallRendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  let calltreeRendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  let flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-
+  let waterfallRendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   OverviewView.setTimeInterval({ startTime: 10, endTime: 20 });
-  DetailsView.selectView("waterfall");
   yield waterfallRendered;
-  DetailsView.selectView("js-calltree");
-  yield calltreeRendered;
-  DetailsView.selectView("js-flamegraph");
+
+  // Select the call tree to make sure it's initialized and ready to receive
+  // redrawing requests once reselected.
+  let callTreeRendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  yield DetailsView.selectView("js-calltree");
+  yield callTreeRendered;
+
+  // Switch to the flamegraph and perform a scroll over the visualization.
+  // The waterfall and call tree should get rerendered when reselected.
+  let flamegraphRendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  yield DetailsView.selectView("js-flamegraph");
   yield flamegraphRendered;
 
-  waterfallRendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  calltreeRendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  let overviewRangeSelected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
+  let overviewRangeSelected = once(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED);
+  let waterfallRerendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
+  let callTreeRerendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
 
-  once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED).then(() =>
-    ok(false, "FlameGraphView should not rerender, but be handled via its graph widget"));
+  once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED).then(() => {
+    ok(false, "FlameGraphView should not publicly rerender, the internal state " +
+              "and drawing should be handled by the underlying widget.");
+  });
 
   // Reset the range to full view, trigger a "selection" event as if
   // our mouse has done this
-  scroll(JsFlameGraphView.graph, 200, HORIZONTAL_AXIS, 10);
+  scrollCanvasGraph(JsFlameGraphView.graph, {
+    axis: HORIZONTAL_AXIS,
+    wheel: 200,
+    x: 10
+  });
 
-  DetailsView.selectView("waterfall");
-  yield waterfallRendered;
-  ok(true, "Waterfall rerendered by flame graph changing interval");
-
-  DetailsView.selectView("js-calltree");
-  yield calltreeRendered;
-  ok(true, "CallTree rerendered by flame graph changing interval");
+  yield overviewRangeSelected;
+  ok(true, "Overview range was changed.");
 
-  yield teardown(panel);
-  finish();
-}
-
-// EventUtils just doesn't work!
+  yield DetailsView.selectView("waterfall");
+  yield waterfallRerendered;
+  ok(true, "Waterfall rerendered by flame graph changing interval.");
 
-function scroll(graph, wheel, axis, x, y = 1) {
-  x /= window.devicePixelRatio;
-  y /= window.devicePixelRatio;
-  graph._onMouseMove({ testX: x, testY: y });
-  graph._onMouseWheel({ testX: x, testY: y, axis, detail: wheel, axis,
-    HORIZONTAL_AXIS,
-    VERTICAL_AXIS
-  });
-}
+  yield DetailsView.selectView("js-calltree");
+  yield callTreeRerendered;
+  ok(true, "CallTree rerendered by flame graph changing interval.");
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-details-06.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
-
-/**
- * Tests that the views with `shouldUpdateWhileMouseIsActive` works as intended.
- */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, OverviewView, DetailsView, WaterfallView, JsFlameGraphView } = panel.panelWin;
-
-  yield startRecording(panel);
-  yield stopRecording(panel);
-
-  // Set the debounce on WaterfallView and JsFlameGraphView to 0
-  WaterfallView.rangeChangeDebounceTime = 0;
-  JsFlameGraphView.rangeChangeDebounceTime = 0;
-
-  yield DetailsView.selectView("js-flamegraph");
-  let duration = PerformanceController.getCurrentRecording().getDuration();
-
-  // Fake an active mouse
-  Object.defineProperty(OverviewView, "isMouseActive", { value: true });
-
-  // Flame Graph should update on every selection, debounced, while mouse is down
-  let flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
-  yield flamegraphRendered;
-  ok(true, "FlameGraph rerenders when mouse is active (1)");
-
-  flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
-  yield flamegraphRendered;
-  ok(true, "FlameGraph rerenders when mouse is active (2)");
-
-  ok(OverviewView.isMouseActive, "Fake mouse is still active");
-
-  // Fake an inactive mouse for rerender
-  Object.defineProperty(OverviewView, "isMouseActive", { value: false });
-  yield DetailsView.selectView("waterfall");
-
-  // Fake an active mouse for rerender
-  Object.defineProperty(OverviewView, "isMouseActive", { value: true });
-
-  let oneSecondElapsed = false;
-  let waterfallRendered = false;
-
-  WaterfallView.on(EVENTS.WATERFALL_RENDERED, () => waterfallRendered = true);
-
-  // Keep firing range selection events for one second
-  idleWait(1000).then(() => oneSecondElapsed = true);
-  yield waitUntil(() => {
-    OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
-    return oneSecondElapsed;
-  });
-
-  ok(OverviewView.isMouseActive, "Fake mouse is still active");
-  ok(!waterfallRendered, "the waterfall view should not have been rendered while mouse is active.");
-
-  yield teardown(panel);
-  finish();
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/test/browser_perf-details-07-bleed-events.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Tests that events don't bleed between detail views.
+ */
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, DetailsView, WaterfallView, JsCallTreeView } = panel.panelWin;
+
+  yield startRecording(panel);
+  yield stopRecording(panel);
+
+  // The waterfall should render by default, and we want to make
+  // sure that the render events don't bleed between detail views
+  // so test that's the case after both views have been created.
+  let callTreeRendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  yield DetailsView.selectView("js-calltree");
+  yield callTreeRendered;
+
+  let waterfallSelected = once(DetailsView, EVENTS.UI_DETAILS_VIEW_SELECTED);
+  yield DetailsView.selectView("waterfall");
+  yield waterfallSelected;
+
+  once(JsCallTreeView, EVENTS.UI_WATERFALL_RENDERED).then(() =>
+    ok(false, "JsCallTreeView should not receive UI_WATERFALL_RENDERED event."));
+
+  yield startRecording(panel);
+  yield stopRecording(panel);
+
+  let callTreeRerendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  yield DetailsView.selectView("js-calltree");
+  yield callTreeRerendered;
+
+  ok(true, "Test passed.");
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-waterfall-render.js
rename to devtools/client/performance/test/browser_perf-details-render-00-waterfall.js
--- a/devtools/client/performance/test/browser_perf-details-waterfall-render.js
+++ b/devtools/client/performance/test/browser_perf-details-render-00-waterfall.js
@@ -1,33 +1,39 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the waterfall view renders content after recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, DetailsView, WaterfallView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, DetailsView, WaterfallView } = panel.panelWin;
 
   yield startRecording(panel);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
+  yield stopRecording(panel); // Already waits for EVENTS.UI_WATERFALL_RENDERED.
 
-  let rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  yield stopRecording(panel);
   ok(DetailsView.isViewSelected(WaterfallView),
     "The waterfall view is selected by default in the details view.");
-  yield rendered;
 
   ok(true, "WaterfallView rendered after recording is stopped.");
 
   yield startRecording(panel);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
+  yield stopRecording(panel); // Already waits for EVENTS.UI_WATERFALL_RENDERED.
 
-  rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  yield stopRecording(panel);
-  yield rendered;
+  ok(DetailsView.isViewSelected(WaterfallView),
+    "The waterfall view is still selected in the details view.");
 
   ok(true, "WaterfallView rendered again after recording completed a second time.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-calltree-render.js
rename to devtools/client/performance/test/browser_perf-details-render-01-js-calltree.js
--- a/devtools/client/performance/test/browser_perf-details-calltree-render.js
+++ b/devtools/client/performance/test/browser_perf-details-render-01-js-calltree.js
@@ -1,49 +1,40 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that the call tree view renders content after recording.
+ * Tests that the js call tree view renders content after recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, DetailsView, WaterfallView, JsCallTreeView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
-  ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
   yield rendered;
 
   ok(true, "JsCallTreeView rendered after recording is stopped.");
 
-  yield DetailsView.selectView("waterfall");
-
   yield startRecording(panel);
-  yield busyWait(100);
-  let waterfallRenderedOnWF = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  let waterfallRenderedOnJS = once(JsCallTreeView, EVENTS.WATERFALL_RENDERED);
-
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  yield stopRecording(panel);
-
-  // The waterfall should render by default, and we want to make
-  // sure that the render events don't bleed between detail views
-  // via bug 1173393, so test that's the case after both views have been
-  // created
-  waterfallRenderedOnJS.then(() =>
-    ok(false, "JsCallTreeView should not receive WATERFALL_RENDERED event"));
-  yield waterfallRenderedOnWF;
-
-  yield DetailsView.selectView("js-calltree");
-  yield rendered;
+  yield stopRecording(panel, {
+    expectedViewClass: "JsCallTreeView",
+    expectedViewEvent: "UI_JS_CALL_TREE_RENDERED"
+  });
 
   ok(true, "JsCallTreeView rendered again after recording completed a second time.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-flamegraph-render.js
rename to devtools/client/performance/test/browser_perf-details-render-02-js-flamegraph.js
--- a/devtools/client/performance/test/browser_perf-details-flamegraph-render.js
+++ b/devtools/client/performance/test/browser_perf-details-render-02-js-flamegraph.js
@@ -1,33 +1,40 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the flamegraph view renders content after recording.
+ * Tests that the js flamegraph view renders content after recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  let rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("js-flamegraph");
-  ok(DetailsView.isViewSelected(JsFlameGraphView), "The flamegraph is now selected.");
   yield rendered;
 
   ok(true, "JsFlameGraphView rendered after recording is stopped.");
 
   yield startRecording(panel);
-  yield busyWait(100);
-
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  yield stopRecording(panel);
-  yield rendered;
+  yield stopRecording(panel, {
+    expectedViewClass: "JsFlameGraphView",
+    expectedViewEvent: "UI_JS_FLAMEGRAPH_RENDERED"
+  });
 
   ok(true, "JsFlameGraphView rendered again after recording completed a second time.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-memory-calltree-render.js
rename to devtools/client/performance/test/browser_perf-details-render-03-memory-calltree.js
--- a/devtools/client/performance/test/browser_perf-details-memory-calltree-render.js
+++ b/devtools/client/performance/test/browser_perf-details-render-03-memory-calltree.js
@@ -1,38 +1,44 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the memory call tree view renders content after recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(ALLOCS_URL);
-  let { EVENTS, $$, PerformanceController, DetailsView, MemoryCallTreeView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-  // Enable memory to test.
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
+
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
 
   yield startRecording(panel);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getAllocations().sizes.length);
   yield stopRecording(panel);
 
-  let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
+  let rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   yield DetailsView.selectView("memory-calltree");
-  ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
   yield rendered;
 
   ok(true, "MemoryCallTreeView rendered after recording is stopped.");
 
-  ok($$("#memory-calltree-view .call-tree-item").length, "there are several allocations rendered.");
-
   yield startRecording(panel);
-  yield busyWait(100);
-
-  rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
-  yield stopRecording(panel);
-  yield rendered;
+  yield stopRecording(panel, {
+    expectedViewClass: "MemoryCallTreeView",
+    expectedViewEvent: "UI_MEMORY_CALL_TREE_RENDERED"
+  });
 
   ok(true, "MemoryCallTreeView rendered again after recording completed a second time.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-memory-flamegraph-render.js
rename to devtools/client/performance/test/browser_perf-details-render-04-memory-flamegraph.js
--- a/devtools/client/performance/test/browser_perf-details-memory-flamegraph-render.js
+++ b/devtools/client/performance/test/browser_perf-details-render-04-memory-flamegraph.js
@@ -1,36 +1,44 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the memory flamegraph view renders content after recording.
+ * Tests that the memory call tree view renders content after recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
 
-  // Enable memory to test.
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
+  let rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("memory-flamegraph");
-  ok(DetailsView.isViewSelected(MemoryFlameGraphView), "The flamegraph is now selected.");
   yield rendered;
 
   ok(true, "MemoryFlameGraphView rendered after recording is stopped.");
 
   yield startRecording(panel);
-  yield busyWait(100);
-
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  yield stopRecording(panel);
-  yield rendered;
+  yield stopRecording(panel, {
+    expectedViewClass: "MemoryFlameGraphView",
+    expectedViewEvent: "UI_MEMORY_FLAMEGRAPH_RENDERED"
+  });
 
   ok(true, "MemoryFlameGraphView rendered again after recording completed a second time.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-markers-docload.js
rename to devtools/client/performance/test/browser_perf-docload.js
--- a/devtools/client/performance/test/browser_perf-markers-docload.js
+++ b/devtools/client/performance/test/browser_perf-docload.js
@@ -1,25 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the sidebar is updated with "DOMContentLoaded" and "load" markers.
  */
 
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording, reload } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+
+add_task(function*() {
+  let { panel, target } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { PerformanceController } = panel.panelWin;
 
-  loadFrameScripts();
-
   yield startRecording(panel);
-  ok(true, "Recording has started.");
-
-  evalInDebuggee("document.location.reload()");
+  yield reload(target);
 
   yield waitUntil(() => {
     // Wait until we get the necessary markers.
     let markers = PerformanceController.getCurrentRecording().getMarkers();
     if (!markers.some(m => m.name == "document::DOMContentLoaded") ||
         !markers.some(m => m.name == "document::Load")) {
       return false;
     }
@@ -28,41 +34,10 @@ function* spawnTest() {
       "There should only be one `DOMContentLoaded` marker.");
     ok(markers.filter(m => m.name == "document::Load").length == 1,
       "There should only be one `load` marker.");
 
     return true;
   });
 
   yield stopRecording(panel);
-  ok(true, "Recording has ended.");
-
-  yield teardown(panel);
-  finish();
-}
-
-/**
- * Takes a string `script` and evaluates it directly in the content
- * in potentially a different process.
- */
-function evalInDebuggee (script) {
-  let { generateUUID } = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator);
-  let deferred = Promise.defer();
-
-  if (!mm) {
-    throw new Error("`loadFrameScripts()` must be called when using MessageManager.");
-  }
-
-  let id = generateUUID().toString();
-  mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id });
-  mm.addMessageListener("devtools:test:eval:response", handler);
-
-  function handler ({ data }) {
-    if (id !== data.id) {
-      return;
-    }
-
-    mm.removeMessageListener("devtools:test:eval:response", handler);
-    deferred.resolve(data.value);
-  }
-
-  return deferred.promise;
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-details-waterfall-gc-snap.js
rename to devtools/client/performance/test/browser_perf-gc-snap.js
--- a/devtools/client/performance/test/browser_perf-details-waterfall-gc-snap.js
+++ b/devtools/client/performance/test/browser_perf-gc-snap.js
@@ -14,17 +14,17 @@ function* spawnTest() {
 
   yield startRecording(panel);
   yield idleWait(1000);
   yield stopRecording(panel);
 
   injectGCMarkers(PerformanceController, WaterfallView);
 
   // Select everything
-  let rendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
+  let rendered = WaterfallView.once(EVENTS.UI_WATERFALL_RENDERED);
   OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE });
   yield rendered;
 
   let bars = $$(".waterfall-marker-bar");
   let gcMarkers = PerformanceController.getCurrentRecording().getMarkers();
   ok(gcMarkers.length === 9, "should have 9 GC markers");
   ok(bars.length === 9, "should have 9 GC markers rendered");
 
@@ -36,25 +36,25 @@ function* spawnTest() {
   let targetBar = bars[1];
   info(`Clicking GC Marker of type ${targetMarker.causeName} ${targetMarker.start}:${targetMarker.end}`);
   EventUtils.sendMouseEvent({ type: "mousedown" }, targetBar);
   let showAllocsButton;
   // On slower machines this can not be found immediately?
   yield waitUntil(() => showAllocsButton = $("#waterfall-details .custom-button[type='show-allocations']"));
   ok(showAllocsButton, "GC buttons when allocations are enabled");
 
-  rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
+  rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   EventUtils.sendMouseEvent({ type: "click" }, showAllocsButton);
   yield rendered;
 
   is(OverviewView.getTimeInterval().startTime, 0, "When clicking first GC, should use 0 as start time");
   within(OverviewView.getTimeInterval().endTime, targetMarker.start, EPSILON, "Correct end time range");
 
   let duration = PerformanceController.getCurrentRecording().getDuration();
-  rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   OverviewView.setTimeInterval({ startTime: 0, endTime: duration });
   yield DetailsView.selectView("waterfall");
   yield rendered;
 
   /**
    * Check when there is a previous GC cycle
    */
 
@@ -63,46 +63,46 @@ function* spawnTest() {
   targetBar = bars[4];
 
   info(`Clicking GC Marker of type ${targetMarker.causeName} ${targetMarker.start}:${targetMarker.end}`);
   EventUtils.sendMouseEvent({ type: "mousedown" }, targetBar);
   // On slower machines this can not be found immediately?
   yield waitUntil(() => showAllocsButton = $("#waterfall-details .custom-button[type='show-allocations']"));
   ok(showAllocsButton, "GC buttons when allocations are enabled");
 
-  rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
+  rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   EventUtils.sendMouseEvent({ type: "click" }, showAllocsButton);
   yield rendered;
 
   within(OverviewView.getTimeInterval().startTime, gcMarkers[2].end, EPSILON,
     "selection start range is last marker from previous GC cycle.");
   within(OverviewView.getTimeInterval().endTime, targetMarker.start, EPSILON,
     "selection end range is current GC marker's start time");
 
   /**
    * Now with allocations disabled
    */
 
   // Reselect the entire recording -- due to bug 1196945, the new recording
   // won't reset the selection
   duration = PerformanceController.getCurrentRecording().getDuration();
-  rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   OverviewView.setTimeInterval({ startTime: 0, endTime: duration });
   yield rendered;
 
   Services.prefs.setBoolPref(ALLOCATIONS_PREF, false);
   yield startRecording(panel);
-  rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   yield stopRecording(panel);
   yield rendered;
 
   injectGCMarkers(PerformanceController, WaterfallView);
 
   // Select everything
-  rendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
+  rendered = WaterfallView.once(EVENTS.UI_WATERFALL_RENDERED);
   OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE });
   yield rendered;
 
   ok(true, "WaterfallView rendered after recording is stopped.");
 
   bars = $$(".waterfall-marker-bar");
   gcMarkers = PerformanceController.getCurrentRecording().getMarkers();
 
--- a/devtools/client/performance/test/browser_perf-highlighted.js
+++ b/devtools/client/performance/test/browser_perf-highlighted.js
@@ -1,46 +1,48 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the toolbox tab for performance is highlighted when recording,
  * whether already loaded, or via console.profile with an unloaded performance tools.
  */
 
-function* spawnTest() {
-  let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
-  let front = toolbox.performance;
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+
+add_task(function*() {
+  let { target, toolbox, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let tab = toolbox.doc.getElementById("toolbox-tab-performance");
 
-  let profileStart = once(front, "recording-started");
-  console.profile("rust");
-  yield profileStart;
-
+  yield console.profile("rust");
   yield waitUntil(() => tab.hasAttribute("highlighted"));
 
   ok(tab.hasAttribute("highlighted"),
-    "performance tab is highlighted during recording from console.profile when unloaded");
+    "Performance tab is highlighted during recording from console.profile when unloaded.");
 
-  let profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust");
-  yield profileEnd;
+  yield console.profileEnd("rust");
+  yield waitUntil(() => !tab.hasAttribute("highlighted"));
 
   ok(!tab.hasAttribute("highlighted"),
-    "performance tab is no longer highlighted when console.profile recording finishes");
+    "Performance tab is no longer highlighted when console.profile recording finishes.");
 
-  yield gDevTools.showToolbox(target, "performance");
-  let panel = yield toolbox.getCurrentPanel().open();
-  let { panelWin: { PerformanceController, RecordingsView }} = panel;
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
 
   yield startRecording(panel);
 
   ok(tab.hasAttribute("highlighted"),
-    "performance tab is highlighted during recording while in performance tool");
+    "Performance tab is highlighted during recording while in performance tool.");
 
   yield stopRecording(panel);
 
   ok(!tab.hasAttribute("highlighted"),
-    "performance tab is no longer highlighted when recording finishes");
+    "Performance tab is no longer highlighted when recording finishes.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-01.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
-
-/**
- * Tests that when setting recording features in the UI (like enabling framerate or memory),
- * if the target does not support these features, then the target's support overrides
- * the UI preferences when fetching configuration from a recording.
- */
-
-const WAIT_TIME = 100;
-
-var test = Task.async(function*() {
-  yield testMockMemory();
-  yield testMockMemoryAndTimeline();
-  finish();
-});
-
-// Test mock memory
-function *testMockMemory () {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-  });
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
-  Services.prefs.setBoolPref(FRAMERATE_PREF, true);
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
-  let { EVENTS, $, gFront, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
-
-  yield startRecording(panel, { waitForOverview: false });
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
-  yield stopRecording(panel, { waitForOverview: false });
-
-  ok(gFront.LEGACY_FRONT, "using legacy front");
-
-  let config = PerformanceController.getCurrentRecording().getConfiguration();
-  let {
-    markers, allocations, memory, ticks
-  } = PerformanceController.getCurrentRecording().getAllData();
-
-  ok(typeof config.bufferSize === "number", "sanity check, config options contains `bufferSize`.");
-
-  is(config.withMemory, false,
-    "Recording configuration set by target's support, not by UI prefs [No Memory Actor: withMemory]");
-  is(config.withAllocations, false,
-    "Recording configuration set by target's support, not by UI prefs [No Memory Actor: withAllocations]");
-
-  is(config.withMarkers, true,
-    "Recording configuration set by target's support, not by UI prefs [No Memory Actor: withMarkers]");
-  is(config.withTicks, true,
-    "Recording configuration set by target's support, not by UI prefs [No Memory Actor: withTicks]");
-
-  ok(markers.length > 0, "markers exist.");
-  ok(ticks.length > 0, "ticks exist.");
-  isEmptyArray(memory, "memory");
-  isEmptyArray(allocations.sites, "allocations.sites");
-  isEmptyArray(allocations.timestamps, "allocations.timestamps");
-  isEmptyArray(allocations.frames, "allocations.frames");
-  isEmptyArray(allocations.sizes, "allocations.sizes");
-
-  is(isVisible($("#overview-pane")), true,
-    "overview pane not hidden when server not supporting memory actors, yet UI prefs request them.");
-  is($("#select-waterfall-view").hidden, false,
-    "waterfall view button not hidden when memory mocked, and UI prefs enable them");
-  is($("#select-js-calltree-view").hidden, false,
-    "jscalltree view button not hidden when memory mocked, and UI prefs enable them");
-  is($("#select-js-flamegraph-view").hidden, false,
-    "jsflamegraph view button not hidden when memory mocked, and UI prefs enable them");
-  is($("#select-memory-calltree-view").hidden, true,
-    "memorycalltree view button hidden when memory mocked, and UI prefs enable them");
-  is($("#select-memory-flamegraph-view").hidden, true,
-    "memoryflamegraph view button hidden when memory mocked, and UI prefs enable them");
-
-  yield gFront.destroy();
-  yield teardown(panel);
-}
-
-// Test mock memory and timeline actor
-function *testMockMemoryAndTimeline() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-    TEST_MOCK_TIMELINE_ACTOR: true,
-  });
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
-  Services.prefs.setBoolPref(FRAMERATE_PREF, true);
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
-  let { EVENTS, $, gFront, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
-
-  yield startRecording(panel, { waitForOverview: false });
-  yield busyWait(WAIT_TIME);
-  yield stopRecording(panel, { waitForOverview: false });
-
-  let config = PerformanceController.getCurrentRecording().getConfiguration();
-  let {
-    markers, allocations, memory, ticks
-  } = PerformanceController.getCurrentRecording().getAllData();
-
-  ok(typeof config.bufferSize === "number", "sanity check, config options contains `bufferSize`.");
-
-  is(config.withMemory, false,
-    "Recording configuration set by target's support, not by UI prefs [No Memory/Timeline Actor: withMemory]");
-  is(config.withAllocations, false,
-    "Recording configuration set by target's support, not by UI prefs [No Memory/Timeline Actor: withAllocations]");
-
-  is(config.withMarkers, false,
-    "Recording configuration set by target's support, not by UI prefs [No Memory/Timeline Actor: withMarkers]");
-  is(config.withTicks, false,
-    "Recording configuration set by target's support, not by UI prefs [No Memory/Timeline Actor: withTicks]");
-  isEmptyArray(markers, "markers");
-  isEmptyArray(ticks, "ticks");
-  isEmptyArray(memory, "memory");
-  isEmptyArray(allocations.sites, "allocations.sites");
-  isEmptyArray(allocations.timestamps, "allocations.timestamps");
-  isEmptyArray(allocations.frames, "allocations.frames");
-  isEmptyArray(allocations.sizes, "allocations.sizes");
-
-  is(isVisible($("#overview-pane")), false,
-    "overview pane hidden when server not supporting memory/timeline actors, yet UI prefs request them.");
-  is($("#select-waterfall-view").hidden, true,
-    "waterfall view button hidden when memory/timeline mocked, and UI prefs enable them");
-  is($("#select-js-calltree-view").hidden, false,
-    "jscalltree view button not hidden when memory/timeline mocked, and UI prefs enable them");
-  is($("#select-js-flamegraph-view").hidden, false,
-    "jsflamegraph view button not hidden when memory/timeline mocked, and UI prefs enable them");
-  is($("#select-memory-calltree-view").hidden, true,
-    "memorycalltree view button hidden when memory/timeline mocked, and UI prefs enable them");
-  is($("#select-memory-flamegraph-view").hidden, true,
-    "memoryflamegraph view button hidden when memory/timeline mocked, and UI prefs enable them");
-
-  yield gFront.destroy();
-  yield teardown(panel);
-}
-
-function isEmptyArray (array, name) {
-  ok(Array.isArray(array), `${name} is an array`);
-  is(array.length, 0, `${name} is empty`);
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-02.js
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
-
-/**
- * Tests that the recording model is populated correctly when using timeline
- * and memory actor mocks, and the correct views are shown.
- */
-
-const WAIT_TIME = 1000;
-
-var test = Task.async(function*() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
-    TEST_MOCK_TIMELINE_ACTOR: true,
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-  });
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
-  let { EVENTS, $, gFront: front, PerformanceController, PerformanceView, DetailsView, JsCallTreeView } = panel.panelWin;
-
-  ok(front.LEGACY_FRONT, true, "Using legacy front");
-  is(front.traits.features.withMarkers, false, "traits.features.withMarkers is false.");
-  is(front.traits.features.withTicks, false, "traits.features.withTicks is false.");
-  is(front.traits.features.withMemory, false, "traits.features.withMemory is false.");
-  is(front.traits.features.withAllocations, false, "traits.features.withAllocations is false.");
-
-  yield startRecording(panel, { waitForOverview: false });
-  busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
-  yield stopRecording(panel, { waitForOverview: false });
-
-  let {
-    label, duration, markers, frames, memory, ticks, allocations, profile
-  } = PerformanceController.getCurrentRecording().getAllData();
-
-  is(label, "", "Empty label for mock.");
-  is(typeof duration, "number", "duration is a number");
-  ok(duration > 0, "duration is not 0");
-
-  isEmptyArray(markers, "markers");
-  isEmptyArray(frames, "frames");
-  isEmptyArray(memory, "memory");
-  isEmptyArray(ticks, "ticks");
-  isEmptyArray(allocations.sites, "allocations.sites");
-  isEmptyArray(allocations.timestamps, "allocations.timestamps");
-  isEmptyArray(allocations.frames, "allocations.frames");
-  isEmptyArray(allocations.sizes, "allocations.sizes");
-
-  let sampleCount = 0;
-
-  for (let thread of profile.threads) {
-    info("Checking thread: " + thread.name);
-
-    for (let sample of thread.samples.data) {
-      sampleCount++;
-
-      let stack = getInflatedStackLocations(thread, sample);
-      if (stack[0] != "(root)") {
-        ok(false, "The sample " + stack.toSource() + " doesn't have a root node.");
-      }
-    }
-  }
-
-  ok(sampleCount > 0,
-    "At least some samples have been iterated over, checking for root nodes.");
-
-  is(isVisible($("#overview-pane")), false,
-    "overview pane hidden when timeline mocked.");
-
-  is($("#select-waterfall-view").hidden, true,
-    "waterfall view button hidden when timeline mocked");
-  is($("#select-js-calltree-view").hidden, false,
-    "jscalltree view button not hidden when timeline/memory mocked");
-  is($("#select-js-flamegraph-view").hidden, false,
-    "jsflamegraph view button not hidden when timeline mocked");
-  is($("#select-memory-calltree-view").hidden, true,
-    "memorycalltree view button hidden when memory mocked");
-  is($("#select-memory-flamegraph-view").hidden, true,
-    "memoryflamegraph view button hidden when memory mocked");
-
-  ok(DetailsView.isViewSelected(JsCallTreeView),
-    "JS Call Tree view selected by default when timeline/memory mocked.");
-
-  yield teardown(panel);
-  finish();
-});
-
-function isEmptyArray (array, name) {
-  ok(Array.isArray(array), `${name} is an array`);
-  is(array.length, 0, `${name} is empty`);
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-03.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests that recording notices does not display any buffer
- * status on servers that do not support buffer statuses.
- */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL, void 0, {
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-    TEST_PROFILER_FILTER_STATUS: ["position", "totalSize", "generation"]
-  });
-
-  let { gFront: front, EVENTS, $, PerformanceController, PerformanceView } = panel.panelWin;
-  front.setProfilerStatusInterval(10);
-  yield startRecording(panel);
-
-  front.on("profiler-status", () => ok(false, "profiler-status should not be emitted when not supported"));
-
-  yield busyWait(100);
-  ok(!$("#details-pane-container").getAttribute("buffer-status"),
-    "container does not have [buffer-status] attribute when not supported");
-
-  yield busyWait(100);
-  ok(!$("#details-pane-container").getAttribute("buffer-status"),
-    "container does not have [buffer-status] attribute when not supported");
-
-  yield stopRecording(panel);
-
-  yield teardown(panel);
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-04.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests that the recording model is populated correctly when using timeline
- * and memory actor mocks, and that the correct button/overview displays are shown.
- */
-
-const WAIT_TIME = 1000;
-
-var test = Task.async(function*() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
-    TEST_PERFORMANCE_LEGACY_FRONT: true
-  });
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
-  let { EVENTS, $, gFront: front, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
-
-  ok(front.LEGACY_FRONT, true, "Using legacy front");
-  is(front.traits.features.withMarkers, true, "traits.features.withMarkers is true.");
-  is(front.traits.features.withTicks, true, "traits.features.withTicks is true.");
-  is(front.traits.features.withMemory, false, "traits.features.withMemory is false.");
-  is(front.traits.features.withAllocations, false, "traits.features.withAllocations is false.");
-
-  yield startRecording(panel);
-  yield busyWait(100);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
-  yield stopRecording(panel);
-
-  let {
-    label, duration, allocations, profile
-  } = PerformanceController.getCurrentRecording().getAllData();
-
-  is(label, "", "Empty label for mock.");
-  is(typeof duration, "number", "duration is a number");
-  ok(duration > 0, "duration is not 0");
-
-  isEmptyArray(allocations.sites, "allocations.sites");
-  isEmptyArray(allocations.timestamps, "allocations.timestamps");
-  isEmptyArray(allocations.frames, "allocations.frames");
-  isEmptyArray(allocations.sizes, "allocations.sizes");
-
-  let sampleCount = 0;
-
-  for (let thread of profile.threads) {
-    info("Checking thread: " + thread.name);
-
-    for (let sample of thread.samples.data) {
-      sampleCount++;
-
-      let stack = getInflatedStackLocations(thread, sample);
-      if (stack[0] != "(root)") {
-        ok(false, "The sample " + stack.toSource() + " doesn't have a root node.");
-      }
-    }
-  }
-
-  ok(sampleCount > 0,
-    "At least some samples have been iterated over, checking for root nodes.");
-
-  is($("#overview-pane").hidden, false,
-    "overview pane not hidden when only memory mocked.");
-
-  is($("#select-waterfall-view").hidden, false,
-    "waterfall view button not hidden when memory mocked");
-  is($("#select-js-calltree-view").hidden, false,
-    "jscalltree view button not hidden when memory mocked");
-  is($("#select-js-flamegraph-view").hidden, false,
-    "jsflamegraph view button not hidden when memory mocked");
-  is($("#select-memory-calltree-view").hidden, true,
-    "memorycalltree view button hidden when memory mocked");
-  is($("#select-memory-flamegraph-view").hidden, true,
-    "memoryflamegraph view button hidden when memory mocked");
-
-  ok(DetailsView.isViewSelected(WaterfallView),
-    "Waterfall view selected by default when memory mocked.");
-
-  yield teardown(panel);
-  finish();
-});
-
-function isEmptyArray (array, name) {
-  ok(Array.isArray(array), `${name} is an array`);
-  is(array.length, 0, `${name} is empty`);
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-05.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests that when using an older server (< Fx40) where the profiler actor does not
- * have the `filterable` trait, the samples are filtered by time on the client, rather
- * than the more performant platform code.
- */
-
-const WAIT_TIME = 1000; // ms
-
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL, void 0, {
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-  });
-  let { gFront: front, gTarget: target } = panel.panelWin;
-
-  // Explicitly override the profiler's trait `filterable`
-  front._profiler.traits.filterable = false;
-
-  // Ugly, but we need to also not send the startTime to the server
-  // so we don't filter it both on the server and client
-  let request = target.client.request;
-  target.client.request = (data, res) => {
-    // Copy so we don't destructively change the request object, as we use
-    // the startTime on this object for filtering in the callback
-    let newData = merge({}, data, { startTime: void 0 });
-    return request.call(target.client, newData, res);
-  };
-
-  // Perform the first recording...
-
-  let firstRecording = yield front.startRecording();
-  let firstRecordingStartTime = firstRecording._profilerStartTime;
-  info("Started profiling at: " + firstRecordingStartTime);
-
-  busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
-
-  yield front.stopRecording(firstRecording);
-  info("The first recording is " + firstRecording.getDuration() + "ms long.");
-
-  ok(firstRecording.getDuration() >= WAIT_TIME,
-    "The first recording duration is correct.");
-
-  // Perform the second recording...
-
-  let secondRecording = yield front.startRecording();
-  let secondRecordingStartTime = secondRecording._profilerStartTime;
-  info("Started profiling at: " + secondRecordingStartTime);
-
-  busyWait(WAIT_TIME); // allow the profiler module to sample more cpu activity
-
-  yield front.stopRecording(secondRecording);
-  info("The second recording is " + secondRecording.getDuration() + "ms long.");
-
-  let secondRecordingProfile = secondRecording.getProfile();
-  let secondRecordingSamples = secondRecordingProfile.threads[0].samples.data;
-
-  isnot(secondRecording._profilerStartTime, 0,
-    "The profiling start time should not be 0 on the second recording.");
-  ok(secondRecording.getDuration() >= WAIT_TIME,
-    "The second recording duration is correct.");
-
-  const TIME_SLOT = secondRecordingProfile.threads[0].samples.schema.time;
-  info("Second profile's first sample time: " + secondRecordingSamples[0][TIME_SLOT]);
-  ok(secondRecordingSamples[0][TIME_SLOT] < secondRecordingStartTime,
-    "The second recorded sample times were normalized.");
-  ok(secondRecordingSamples[0][TIME_SLOT] > 0,
-    "The second recorded sample times were normalized correctly.");
-  ok(!secondRecordingSamples.find(e => e[TIME_SLOT] + secondRecordingStartTime <= firstRecording.getDuration()),
-    "There should be no samples from the first recording in the second one, " +
-    "even though the total number of frames did not overflow.");
-
-  target.client.request = request;
-
-  yield teardown(panel);
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-06.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests if the profiler is populated by in-progress console recordings
- * when it is opened with the legacy front.
- */
-
-var WAIT_TIME = 10;
-
-function* spawnTest() {
-  let { target, toolbox, console } = yield initConsole(SIMPLE_URL, { TEST_PERFORMANCE_LEGACY_FRONT: true });
-  let front = toolbox.performance;
-
-  let profileStart = once(front, "recording-started");
-  console.profile("rust");
-  yield profileStart;
-  profileStart = once(front, "recording-started");
-  console.profile("rust2");
-  yield profileStart;
-
-  yield gDevTools.showToolbox(target, "performance");
-  let panel = yield toolbox.getCurrentPanel().open();
-  let { panelWin: { PerformanceController, RecordingsView }} = panel;
-
-  yield waitUntil(() => PerformanceController.getRecordings().length === 2);
-  let recordings = PerformanceController.getRecordings();
-  is(recordings.length, 2, "two recordings found in the performance panel.");
-  is(recordings[0].isConsole(), true, "recording came from console.profile (1).");
-  is(recordings[0].getLabel(), "rust", "correct label in the recording model (1).");
-  is(recordings[0].isRecording(), true, "recording is still recording (1).");
-  is(recordings[1].isConsole(), true, "recording came from console.profile (2).");
-  is(recordings[1].getLabel(), "rust2", "correct label in the recording model (2).");
-  is(recordings[1].isRecording(), true, "recording is still recording (2).");
-
-  is(RecordingsView.selectedItem.attachment, recordings[0],
-    "The first console recording should be selected.");
-
-  let profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust");
-  yield profileEnd;
-  profileEnd = once(front, "recording-stopped");
-  console.profileEnd("rust2");
-  yield profileEnd;
-
-  yield teardown(panel);
-  finish();
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-07.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Test basic functionality of PerformanceFront with mock memory and timeline actors.
- */
-
-var WAIT_TIME = 100;
-
-const { LegacyPerformanceFront } = require("devtools/client/performance/legacy/front");
-
-function* spawnTest() {
-  let tab = yield getTab(SIMPLE_URL);
-  let target = TargetFactory.forTab(tab);
-  yield target.makeRemote();
-
-  merge(target, {
-    TEST_MOCK_TIMELINE_ACTOR: true,
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-  });
-
-  let front = new LegacyPerformanceFront(target);
-  yield front.connect();
-
-  ok(front.LEGACY_FRONT, true, "Using legacy front");
-  front.on("timeline-data", () => ok(false, "There should not be any timeline-data events when mocked"));
-
-  let recording = yield front.startRecording({
-    withTicks: true,
-    withMarkers: true,
-    withMemory: true,
-    withAllocations: true,
-  });
-
-  is(recording.getConfiguration().withMarkers, false, "overrides withMarkers based off of actor support");
-  is(recording.getConfiguration().withTicks, false, "overrides withTicks based off of actor support");
-  is(recording.getConfiguration().withMemory, false, "overrides withMemory based off of actor support");
-  is(recording.getConfiguration().withAllocations, false, "overrides withAllocations based off of actor support");
-
-  yield busyWait(WAIT_TIME);
-
-  yield front.stopRecording(recording);
-
-  ok(typeof recording.getDuration() === "number",
-    "The front.stopRecording() allows recording to get a duration.");
-  ok(recording.getDuration() >= 0, "duration is a positive number");
-  isEmptyArray(recording.getMarkers(), "markers");
-  isEmptyArray(recording.getTicks(), "ticks");
-  isEmptyArray(recording.getMemory(), "memory");
-  isEmptyArray(recording.getAllocations().sites, "allocations.sites");
-  isEmptyArray(recording.getAllocations().timestamps, "allocations.timestamps");
-  isEmptyArray(recording.getAllocations().frames, "allocations.frames");
-  ok(recording.getProfile().threads[0].samples.data.length, "profile data has some samples");
-  checkSystemInfo(recording, "Host");
-  checkSystemInfo(recording, "Client");
-
-  yield front.destroy();
-  gBrowser.removeCurrentTab();
-}
-
-function isEmptyArray (array, name) {
-  ok(Array.isArray(array), `${name} is an array`);
-  ok(array.length === 0, `${name} is empty`);
-}
-
-function getTab (url) {
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-  let loaded = once(gBrowser.selectedBrowser, "load", true);
-
-  content.location = url;
-  return loaded.then(() => {
-    return new Promise(resolve => {
-      let isBlank = url == "about:blank";
-      waitForFocus(() => resolve(tab), content, isBlank);
-    });
-  });
-}
-
-function checkSystemInfo (recording, type) {
-  let data = recording[`get${type}SystemInfo`]();
-  for (let field of ["appid", "apptype", "vendor", "name", "version"]) {
-    ok(data[field], `get${type}SystemInfo() has ${field} property`);
-  }
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-08.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Test basic functionality of PerformanceFront without a mock Timeline actor.
- */
-
-var WAIT_TIME = 100;
-
-const { LegacyPerformanceFront } = require("devtools/client/performance/legacy/front");
-
-function* spawnTest() {
-  let tab = yield getTab(SIMPLE_URL);
-  let target = TargetFactory.forTab(tab);
-  yield target.makeRemote();
-
-  merge(target, {
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-  });
-
-  let front = new LegacyPerformanceFront(target);
-  yield front.connect();
-
-  ok(front.LEGACY_FRONT, true, "Using legacy front");
-
-  let recording = yield front.startRecording({
-    withTicks: true,
-    withMarkers: true,
-    withMemory: true,
-    withAllocations: true,
-  });
-
-  is(recording.getConfiguration().withMarkers, true, "allows withMarkers based off of actor support");
-  is(recording.getConfiguration().withTicks, true, "allows withTicks based off of actor support");
-  is(recording.getConfiguration().withMemory, false, "overrides withMemory based off of actor support");
-  is(recording.getConfiguration().withAllocations, false, "overrides withAllocations based off of actor support");
-
-  yield waitUntil(() => recording.getMarkers().length);
-  yield waitUntil(() => recording.getTicks().length);
-
-  yield front.stopRecording(recording);
-
-  ok(recording.getMarkers().length, "we have several markers");
-  ok(recording.getTicks().length, "we have several ticks");
-
-  ok(typeof recording.getDuration() === "number",
-    "The front.stopRecording() allows recording to get a duration.");
-  ok(recording.getDuration() >= 0, "duration is a positive number");
-  isEmptyArray(recording.getMemory(), "memory");
-  isEmptyArray(recording.getAllocations().sites, "allocations.sites");
-  isEmptyArray(recording.getAllocations().timestamps, "allocations.timestamps");
-  isEmptyArray(recording.getAllocations().frames, "allocations.frames");
-  ok(recording.getProfile().threads[0].samples.data.length, "profile data has some samples");
-
-  yield front.destroy();
-  gBrowser.removeCurrentTab();
-}
-
-function isEmptyArray (array, name) {
-  ok(Array.isArray(array), `${name} is an array`);
-  ok(array.length === 0, `${name} is empty`);
-}
-
-function getTab (url) {
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-  let loaded = once(gBrowser.selectedBrowser, "load", true);
-
-  content.location = url;
-  return loaded.then(() => {
-    return new Promise(resolve => {
-      let isBlank = url == "about:blank";
-      waitForFocus(() => resolve(tab), content, isBlank);
-    });
-  });
-}
deleted file mode 100644
--- a/devtools/client/performance/test/browser_perf-legacy-front-09.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/**
- * Tests that when using an older server (< Fx40) where the profiler actor does not
- * have the `getBufferInfo` method that nothing breaks and RecordingModels have null
- * `getBufferUsage()` values.
- */
-
-const { LegacyPerformanceFront } = require("devtools/client/performance/legacy/front");
-
-function* spawnTest() {
-  let tab = yield getTab(SIMPLE_URL);
-  let target = TargetFactory.forTab(tab);
-  yield target.makeRemote();
-
-  merge(target, {
-    TEST_PROFILER_FILTER_STATUS: ["position", "totalSize", "generation"],
-    TEST_PERFORMANCE_LEGACY_FRONT: true,
-  });
-
-  let front = new LegacyPerformanceFront(target);
-  yield front.connect();
-  front.setProfilerStatusInterval(10);
-
-  front.on("profiler-status", () => ok(false, "profiler-status should not be called when not supported"));
-  let model = yield front.startRecording();
-
-  yield busyWait(100);
-  is(front.getBufferUsageForRecording(model), null, "buffer usage for recording should be null");
-
-  yield front.stopRecording(model);
-  yield front.destroy();
-  gBrowser.removeCurrentTab();
-}
-
-function getTab (url) {
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-  let loaded = once(gBrowser.selectedBrowser, "load", true);
-
-  content.location = url;
-  return loaded.then(() => {
-    return new Promise(resolve => {
-      let isBlank = url == "about:blank";
-      waitForFocus(() => resolve(tab), content, isBlank);
-    });
-  });
-}
--- a/devtools/client/performance/test/browser_perf-loading-01.js
+++ b/devtools/client/performance/test/browser_perf-loading-01.js
@@ -1,52 +1,51 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the recordings view shows the right label while recording, after
  * recording, and once the record has loaded.
  */
 
-var test = Task.async(function*() {
-  // This test seems to take a long time to cleanup.
-  requestLongerTimeout(2);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
-  let { RecordingsView, PerformanceController, PerformanceView,
-        EVENTS, $, L10N } = panel.panelWin;
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
-  info("Start to record");
+  let { EVENTS, L10N, $, PerformanceController, RecordingsView } = panel.panelWin;
+
   yield startRecording(panel);
-  let durationNode = $(".recording-item-duration",
-    RecordingsView.selectedItem.target);
 
-  is(durationNode.getAttribute("value"),
+  let durationLabel = $(".recording-item-duration", RecordingsView.selectedItem.target);
+  is(durationLabel.getAttribute("value"),
     L10N.getStr("recordingsList.recordingLabel"),
     "The duration node should show the 'recording' message while recording");
 
-  info("Stop the recording and wait for the WILL_STOP and STOPPED events");
+  let recordingStopping = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopping" }
+  });
+  let recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopped" }
+  });
+  let everythingStopped = stopRecording(panel);
 
-  let willStop = PerformanceController.once(EVENTS.RECORDING_WILL_STOP);
-  let hasStopped = PerformanceController.once(EVENTS.RECORDING_STOPPED);
-  let stoppingRecording = PerformanceController.stopRecording();
-
-  yield willStop;
-
-  is(durationNode.getAttribute("value"),
+  yield recordingStopping;
+  is(durationLabel.getAttribute("value"),
     L10N.getStr("recordingsList.loadingLabel"),
     "The duration node should show the 'loading' message while stopping");
 
-  yield hasStopped;
-  yield stoppingRecording;
-
-  ok(PerformanceController.getCurrentRecording().isCompleted(), "recording should be completed");
-
-  let duration = RecordingsView.selectedItem.attachment.getDuration().toFixed(0);
-  is(durationNode.getAttribute("value"),
-    L10N.getFormatStr("recordingsList.durationLabel", duration),
+  yield recordingStopped;
+  is(durationLabel.getAttribute("value"),
+    L10N.getFormatStr("recordingsList.durationLabel",
+    RecordingsView.selectedItem.attachment.getDuration().toFixed(0)),
     "The duration node should show the duration after the record has stopped");
 
-  yield PerformanceController.clearRecordings();
-
-  yield teardown(panel);
-  finish();
+  yield everythingStopped;
+  yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-loading-02.js
+++ b/devtools/client/performance/test/browser_perf-loading-02.js
@@ -1,77 +1,81 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
  * Tests that the details view is locked after recording has stopped and before
  * the recording has finished loading.
  * Also test that the details view isn't locked if the recording that is being
  * stopped isn't the active one.
  */
 
-var test = Task.async(function*() {
-  // This test seems to take a long time to cleanup.
-  requestLongerTimeout(2);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { PerformanceController, PerformanceView, RecordingsView,
-        EVENTS, $ } = panel.panelWin;
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
+  let { EVENTS, $, PerformanceController, RecordingsView } = panel.panelWin;
   let detailsContainer = $("#details-pane-container");
   let recordingNotice = $("#recording-notice");
   let loadingNotice = $("#loading-notice");
   let detailsPane = $("#details-pane");
 
-  info("Start to record");
   yield startRecording(panel);
 
   is(detailsContainer.selectedPanel, recordingNotice,
-    "The recording-notice is shown while recording");
+    "The recording-notice is shown while recording.");
 
-  info("Stop the recording and wait for the WILL_STOP and STOPPED events");
-  let willStop = PerformanceController.once(EVENTS.RECORDING_WILL_STOP);
-  let hasStopped = PerformanceController.once(EVENTS.RECORDING_STOPPED);
-  let stoppingRecording = PerformanceController.stopRecording();
+  let recordingStopping = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopping" }
+  });
+  let recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopped" }
+  });
+  let everythingStopped = stopRecording(panel);
 
-  yield willStop;
-
+  yield recordingStopping;
   is(detailsContainer.selectedPanel, loadingNotice,
-    "The loading-notice is shown while the record is stopping");
-
-  yield hasStopped;
-  yield stoppingRecording;
+    "The loading-notice is shown while the record is stopping.");
 
+  yield recordingStopped;
   is(detailsContainer.selectedPanel, detailsPane,
-    "The details panel is shown after the record has stopped");
+    "The details panel is shown after the record has stopped.");
 
-  info("Start to record again");
+  yield everythingStopped;
   yield startRecording(panel);
 
-  info("While the 2nd record is still going, switch to the first one");
-  let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  info("While the 2nd record is still going, switch to the first one.");
+  let recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
-  yield select;
+  yield recordingSelected;
 
-  info("Stop the 2nd recording and wait for the WILL_STOP and STOPPED events");
-  willStop = PerformanceController.once(EVENTS.RECORDING_WILL_STOP);
-  hasStopped = PerformanceController.once(EVENTS.RECORDING_STOPPED);
-  stoppingRecording = PerformanceController.stopRecording();
+  recordingStopping = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopping" }
+  });
+  recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
+    expectedArgs: { "1": "recording-stopped" }
+  });
+  everythingStopped = stopRecording(panel);
 
-  yield willStop;
+  yield recordingStopping;
+  is(detailsContainer.selectedPanel, detailsPane,
+    "The details panel is still shown while the 2nd record is being stopped.");
+  is(RecordingsView.selectedIndex, 0,
+    "The first record is still selected.");
+
+  yield recordingStopped;
 
   is(detailsContainer.selectedPanel, detailsPane,
-    "The details panel is still shown while the 2nd record is being stopped");
-  is(RecordingsView.selectedIndex, 0, "The first record is still selected");
-
-  yield hasStopped;
-  yield stoppingRecording;
+    "The details panel is still shown after the 2nd record has stopped.");
+  is(RecordingsView.selectedIndex, 1,
+    "The second record is now selected.");
 
-  is(detailsContainer.selectedPanel, detailsPane,
-    "The details panel is still shown after the 2nd record has stopped");
-  is(RecordingsView.selectedIndex, 1, "The second record is now selected");
-
-  yield PerformanceController.clearRecordings();
-  yield teardown(panel);
-  finish();
+  yield everythingStopped;
+  yield teardownToolboxAndRemoveTab(panel);
 });
rename from devtools/client/performance/test/browser_perf-marker-details-01.js
rename to devtools/client/performance/test/browser_perf-marker-details.js
rename from devtools/client/performance/test/browser_perf-options-01.js
rename to devtools/client/performance/test/browser_perf-options-01-toggle-throw.js
--- a/devtools/client/performance/test/browser_perf-options-01.js
+++ b/devtools/client/performance/test/browser_perf-options-01-toggle-throw.js
@@ -1,23 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that toggling preferences before there are any recordings does not throw.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { DetailsView, JsCallTreeView } = panel.panelWin;
 
   yield DetailsView.selectView("js-calltree");
 
-  // Manually call the _onPrefChanged function so we can catch an error
+  // Manually call the _onPrefChanged function so we can catch an error.
   try {
     JsCallTreeView._onPrefChanged(null, "invert-call-tree", true);
     ok(true, "Toggling preferences before there are any recordings should not fail.");
   } catch (e) {
     ok(false, "Toggling preferences before there are any recordings should not fail.");
   }
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-options-02.js
rename to devtools/client/performance/test/browser_perf-options-02-toggle-throw-alt.js
--- a/devtools/client/performance/test/browser_perf-options-02.js
+++ b/devtools/client/performance/test/browser_perf-options-02-toggle-throw-alt.js
@@ -1,27 +1,38 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that toggling preferences during a recording does not throw.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { DetailsView, JsCallTreeView } = panel.panelWin;
 
   yield DetailsView.selectView("js-calltree");
-
   yield startRecording(panel);
 
-  // Manually call the _onPrefChanged function so we can catch an error
+  // Manually call the _onPrefChanged function so we can catch an error.
   try {
     JsCallTreeView._onPrefChanged(null, "invert-call-tree", true);
     ok(true, "Toggling preferences during a recording should not fail.");
   } catch (e) {
     ok(false, "Toggling preferences during a recording should not fail.");
   }
 
-  yield stopRecording(panel);
+  yield stopRecording(panel, {
+    expectedViewClass: "JsCallTreeView",
+    expectedViewEvent: "UI_JS_CALL_TREE_RENDERED"
+  });
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-options-03.js
rename to devtools/client/performance/test/browser_perf-options-03-toggle-meta.js
--- a/devtools/client/performance/test/browser_perf-options-03.js
+++ b/devtools/client/performance/test/browser_perf-options-03-toggle-meta.js
@@ -1,27 +1,38 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that toggling meta option prefs change visibility of other options.
  */
 
-Services.prefs.setBoolPref(EXPERIMENTAL_PREF, false);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_EXPERIMENTAL_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+
+add_task(function*() {
+  Services.prefs.setBoolPref(UI_EXPERIMENTAL_PREF, false);
 
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, PerformanceController } = panel.panelWin;
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
+  let { $ } = panel.panelWin;
   let $body = $(".theme-body");
   let $menu = $("#performance-options-menupopup");
 
-  ok(!$body.classList.contains("experimental-enabled"), "body does not have `experimental-enabled` on start");
-  ok(!$menu.classList.contains("experimental-enabled"), "menu does not have `experimental-enabled` on start");
+  ok(!$body.classList.contains("experimental-enabled"),
+    "The body node does not have `experimental-enabled` on start.");
+  ok(!$menu.classList.contains("experimental-enabled"),
+    "The menu popup does not have `experimental-enabled` on start.");
 
-  Services.prefs.setBoolPref(EXPERIMENTAL_PREF, true);
+  Services.prefs.setBoolPref(UI_EXPERIMENTAL_PREF, true);
 
-  ok($body.classList.contains("experimental-enabled"), "body has `experimental-enabled` after toggle");
-  ok($menu.classList.contains("experimental-enabled"), "menu has `experimental-enabled` after toggle");
+  ok($body.classList.contains("experimental-enabled"),
+    "The body node has `experimental-enabled` after toggle.");
+  ok($menu.classList.contains("experimental-enabled"),
+    "The menu popup has `experimental-enabled` after toggle.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-options-enable-framerate.js
rename to devtools/client/performance/test/browser_perf-options-enable-framerate-01.js
--- a/devtools/client/performance/test/browser_perf-options-enable-framerate.js
+++ b/devtools/client/performance/test/browser_perf-options-enable-framerate-01.js
@@ -1,34 +1,52 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
  * Tests that `enable-framerate` toggles the visibility of the fps graph,
  * as well as enabling ticks data on the PerformanceFront.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, $ } = panel.panelWin;
-  Services.prefs.setBoolPref(FRAMERATE_PREF, false);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_FRAMERATE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { isVisible } = require("devtools/client/performance/test/helpers/dom-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, PerformanceController } = panel.panelWin;
+
+  // Disable framerate to test.
+  Services.prefs.setBoolPref(UI_ENABLE_FRAMERATE_PREF, false);
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, false,
     "PerformanceFront started without ticks recording.");
-  ok(!isVisible($("#time-framerate")), "fps graph is hidden when ticks disabled");
+  ok(!isVisible($("#time-framerate")),
+    "The fps graph is hidden when ticks disabled.");
 
-  Services.prefs.setBoolPref(FRAMERATE_PREF, true);
-  ok(!isVisible($("#time-framerate")), "fps graph is still hidden if recording does not contain ticks.");
+  // Re-enable framerate.
+  Services.prefs.setBoolPref(UI_ENABLE_FRAMERATE_PREF, true);
+
+  is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, false,
+    "PerformanceFront still marked without ticks recording.");
+  ok(!isVisible($("#time-framerate")),
+    "The fps graph is still hidden if recording does not contain ticks.");
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  ok(isVisible($("#time-framerate")), "fps graph is not hidden when ticks enabled before recording");
   is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, true,
     "PerformanceFront started with ticks recording.");
+  ok(isVisible($("#time-framerate")),
+    "The fps graph is not hidden when ticks enabled before recording.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/test/browser_perf-options-enable-framerate-02.js
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Tests that toggling `enable-memory` during a recording doesn't change that
+ * recording's state and does not break.
+ */
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_FRAMERATE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, PerformanceController } = panel.panelWin;
+
+  // Test starting without framerate, and stopping with it.
+  Services.prefs.setBoolPref(UI_ENABLE_FRAMERATE_PREF, false);
+  yield startRecording(panel);
+
+  Services.prefs.setBoolPref(UI_ENABLE_FRAMERATE_PREF, true);
+  yield stopRecording(panel);
+
+  is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, false,
+    "The recording finished without tracking framerate.");
+
+  // Test starting with framerate, and stopping without it.
+  yield startRecording(panel);
+
+  Services.prefs.setBoolPref(UI_ENABLE_FRAMERATE_PREF, false);
+  yield stopRecording(panel);
+
+  is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, true,
+    "The recording finished with tracking framerate.");
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-enable-memory-01.js
+++ b/devtools/client/performance/test/browser_perf-options-enable-memory-01.js
@@ -1,38 +1,58 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that `enable-memory` toggles the visibility of the memory graph,
  * as well as enabling memory data on the PerformanceFront.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, $ } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { isVisible } = require("devtools/client/performance/test/helpers/dom-utils");
 
-  Services.prefs.setBoolPref(MEMORY_PREF, false);
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, PerformanceController } = panel.panelWin;
+
+  // Disable memory to test.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, false);
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, false,
     "PerformanceFront started without memory recording.");
   is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
     "PerformanceFront started without allocations recording.");
-  ok(!isVisible($("#memory-overview")), "memory graph is hidden when memory disabled");
+  ok(!isVisible($("#memory-overview")),
+    "The memory graph is hidden when memory disabled.");
 
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+  // Re-enable memory.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
+
+  is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, false,
+    "PerformanceFront still marked without memory recording.");
+  is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
+    "PerformanceFront still marked without allocations recording.");
   ok(!isVisible($("#memory-overview")),
     "memory graph is still hidden after enabling if recording did not start recording memory");
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  ok(isVisible($("#memory-overview")), "memory graph is not hidden when memory enabled before recording");
   is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, true,
     "PerformanceFront started with memory recording.");
   is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
     "PerformanceFront did not record with allocations.");
+  ok(isVisible($("#memory-overview")),
+    "The memory graph is not hidden when memory enabled before recording.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-enable-memory-02.js
+++ b/devtools/client/performance/test/browser_perf-options-enable-memory-02.js
@@ -1,36 +1,47 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that toggling `enable-memory` during a recording doesn't change that
  * recording's state and does not break.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, $ } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, PerformanceController } = panel.panelWin;
 
   // Test starting without memory, and stopping with it.
-  Services.prefs.setBoolPref(MEMORY_PREF, false);
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, false);
   yield startRecording(panel);
 
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
   yield stopRecording(panel);
 
   is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, false,
     "The recording finished without tracking memory.");
   is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
     "The recording finished without tracking allocations.");
 
   // Test starting with memory, and stopping without it.
   yield startRecording(panel);
-  Services.prefs.setBoolPref(MEMORY_PREF, false);
+
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, false);
   yield stopRecording(panel);
 
   is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, true,
     "The recording finished with tracking memory.");
   is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
     "The recording still is not recording allocations.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-flatten-tree-recursion-01.js
+++ b/devtools/client/performance/test/browser_perf-options-flatten-tree-recursion-01.js
@@ -1,59 +1,67 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the js flamegraphs get rerendered when toggling `flatten-tree-recursion`
+ * Tests that the js flamegraphs get rerendered when toggling `flatten-tree-recursion`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_FLATTEN_RECURSION_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, PerformanceController, DetailsView, JsFlameGraphView, FlameGraphUtils } = panel.panelWin;
 
-  Services.prefs.setBoolPref(FLATTEN_PREF, true);
+  Services.prefs.setBoolPref(UI_FLATTEN_RECURSION_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
+  yield stopRecording(panel);
 
-  yield stopRecording(panel);
-  let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  let rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("js-flamegraph");
   yield rendered;
 
   let thread1 = PerformanceController.getCurrentRecording().getProfile().threads[0];
   let rendering1 = FlameGraphUtils._cache.get(thread1);
 
   ok(thread1,
     "The samples were retrieved from the controller.");
   ok(rendering1,
     "The rendering data was cached.");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(FLATTEN_PREF, false);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_FLATTEN_RECURSION_PREF, false);
   yield rendered;
-
   ok(true, "JsFlameGraphView rerendered when toggling flatten-tree-recursion.");
 
   let thread2 = PerformanceController.getCurrentRecording().getProfile().threads[0];
   let rendering2 = FlameGraphUtils._cache.get(thread2);
 
   is(thread1, thread2,
     "The same samples data should be retrieved from the controller (1).");
   isnot(rendering1, rendering2,
     "The rendering data should be different because other options were used (1).");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(FLATTEN_PREF, true);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_FLATTEN_RECURSION_PREF, true);
   yield rendered;
-
   ok(true, "JsFlameGraphView rerendered when toggling back flatten-tree-recursion.");
 
   let thread3 = PerformanceController.getCurrentRecording().getProfile().threads[0];
   let rendering3 = FlameGraphUtils._cache.get(thread3);
 
   is(thread2, thread3,
     "The same samples data should be retrieved from the controller (2).");
   isnot(rendering2, rendering3,
     "The rendering data should be different because other options were used (2).");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-flatten-tree-recursion-02.js
+++ b/devtools/client/performance/test/browser_perf-options-flatten-tree-recursion-02.js
@@ -1,70 +1,78 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the memory flamegraphs get rerendered when toggling `flatten-tree-recursion`
+ * Tests that the memory flamegraphs get rerendered when toggling `flatten-tree-recursion`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_FLATTEN_RECURSION_PREF, UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, PerformanceController, DetailsView, MemoryFlameGraphView, RecordingUtils, FlameGraphUtils } = panel.panelWin;
 
   // Enable memory to test
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
-  Services.prefs.setBoolPref(FLATTEN_PREF, true);
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
+  Services.prefs.setBoolPref(UI_FLATTEN_RECURSION_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
+  yield stopRecording(panel);
 
-  let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  yield stopRecording(panel);
+  let rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("memory-flamegraph");
   yield rendered;
 
   let allocations1 = PerformanceController.getCurrentRecording().getAllocations();
   let thread1 = RecordingUtils.getProfileThreadFromAllocations(allocations1);
   let rendering1 = FlameGraphUtils._cache.get(thread1);
 
   ok(allocations1,
     "The allocations were retrieved from the controller.");
   ok(thread1,
     "The allocations profile was synthesized by the utility funcs.");
   ok(rendering1,
     "The rendering data was cached.");
 
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(FLATTEN_PREF, false);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_FLATTEN_RECURSION_PREF, false);
   yield rendered;
-
   ok(true, "MemoryFlameGraphView rerendered when toggling flatten-tree-recursion.");
 
   let allocations2 = PerformanceController.getCurrentRecording().getAllocations();
   let thread2 = RecordingUtils.getProfileThreadFromAllocations(allocations2);
   let rendering2 = FlameGraphUtils._cache.get(thread2);
 
   is(allocations1, allocations2,
     "The same allocations data should be retrieved from the controller (1).");
   is(thread1, thread2,
     "The same allocations profile should be retrieved from the utility funcs. (1).");
   isnot(rendering1, rendering2,
     "The rendering data should be different because other options were used (1).");
 
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(FLATTEN_PREF, true);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_FLATTEN_RECURSION_PREF, true);
   yield rendered;
-
   ok(true, "MemoryFlameGraphView rerendered when toggling back flatten-tree-recursion.");
 
   let allocations3 = PerformanceController.getCurrentRecording().getAllocations();
   let thread3 = RecordingUtils.getProfileThreadFromAllocations(allocations3);
   let rendering3 = FlameGraphUtils._cache.get(thread3);
 
   is(allocations2, allocations3,
     "The same allocations data should be retrieved from the controller (2).");
   is(thread2, thread3,
     "The same allocations profile should be retrieved from the utility funcs. (2).");
   isnot(rendering2, rendering3,
     "The rendering data should be different because other options were used (2).");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-invert-call-tree-01.js
+++ b/devtools/client/performance/test/browser_perf-options-invert-call-tree-01.js
@@ -1,36 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the js call tree views get rerendered when toggling `invert-call-tree`
+ * Tests that the js call tree views get rerendered when toggling `invert-call-tree`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_INVERT_CALL_TREE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
 
-  Services.prefs.setBoolPref(INVERT_PREF, true);
+  Services.prefs.setBoolPref(UI_INVERT_CALL_TREE_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
-  ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
-  yield rendered;
-
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  Services.prefs.setBoolPref(INVERT_PREF, false);
   yield rendered;
 
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_CALL_TREE_PREF, false);
+  yield rendered;
   ok(true, "JsCallTreeView rerendered when toggling invert-call-tree.");
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  Services.prefs.setBoolPref(INVERT_PREF, true);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_CALL_TREE_PREF, true);
   yield rendered;
-
   ok(true, "JsCallTreeView rerendered when toggling back invert-call-tree.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-invert-call-tree-02.js
+++ b/devtools/client/performance/test/browser_perf-options-invert-call-tree-02.js
@@ -1,38 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the memory call tree views get rerendered when toggling `invert-call-tree`
+ * Tests that the memory call tree views get rerendered when toggling `invert-call-tree`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF, UI_INVERT_CALL_TREE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
 
-  // Enable memory to test
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
-  Services.prefs.setBoolPref(INVERT_PREF, true);
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
+  Services.prefs.setBoolPref(UI_INVERT_CALL_TREE_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
+  let rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
   yield DetailsView.selectView("memory-calltree");
-  ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
-  yield rendered;
-
-  rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
-  Services.prefs.setBoolPref(INVERT_PREF, false);
   yield rendered;
 
+  rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_CALL_TREE_PREF, false);
+  yield rendered;
   ok(true, "MemoryCallTreeView rerendered when toggling invert-call-tree.");
 
-  rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
-  Services.prefs.setBoolPref(INVERT_PREF, true);
+  rendered = once(MemoryCallTreeView, EVENTS.UI_MEMORY_CALL_TREE_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_CALL_TREE_PREF, true);
   yield rendered;
-
   ok(true, "MemoryCallTreeView rerendered when toggling back invert-call-tree.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-invert-flame-graph-01.js
+++ b/devtools/client/performance/test/browser_perf-options-invert-flame-graph-01.js
@@ -1,35 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the js Flamegraphs gets rerendered when toggling `invert-flame-graph`
+ * Tests that the js flamegraphs views get rerendered when toggling `invert-flame-graph`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_INVERT_FLAME_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
 
-  Services.prefs.setBoolPref(INVERT_FLAME_PREF, true);
+  Services.prefs.setBoolPref(UI_INVERT_FLAME_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  let rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("js-flamegraph");
   yield rendered;
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(INVERT_FLAME_PREF, false);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_FLAME_PREF, false);
   yield rendered;
-
-  ok(true, "JsFlameGraphView rerendered when toggling invert-flame-graph.");
+  ok(true, "JsFlameGraphView rerendered when toggling invert-call-tree.");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(INVERT_FLAME_PREF, true);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_FLAME_PREF, true);
   yield rendered;
+  ok(true, "JsFlameGraphView rerendered when toggling back invert-call-tree.");
 
-  ok(true, "JsFlameGraphView rerendered when toggling back invert-flame-graph.");
-
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-invert-flame-graph-02.js
+++ b/devtools/client/performance/test/browser_perf-options-invert-flame-graph-02.js
@@ -1,36 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the memory Flamegraphs gets rerendered when toggling `invert-flame-graph`
+ * Tests that the memory flamegraphs views get rerendered when toggling `invert-flame-graph`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF, UI_INVERT_FLAME_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
 
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
-  Services.prefs.setBoolPref(INVERT_FLAME_PREF, true);
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
+  Services.prefs.setBoolPref(UI_INVERT_FLAME_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
+  let rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("memory-flamegraph");
   yield rendered;
 
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(INVERT_FLAME_PREF, false);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_FLAME_PREF, false);
   yield rendered;
-
-  ok(true, "MemoryFlameGraphView rerendered when toggling invert-flame-graph.");
+  ok(true, "MemoryFlameGraphView rerendered when toggling invert-call-tree.");
 
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(INVERT_FLAME_PREF, true);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_INVERT_FLAME_PREF, true);
   yield rendered;
+  ok(true, "MemoryFlameGraphView rerendered when toggling back invert-call-tree.");
 
-  ok(true, "MemoryFlameGraphView rerendered when toggling back invert-flame-graph.");
-
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-options-allocations.js
rename to devtools/client/performance/test/browser_perf-options-propagate-allocations.js
--- a/devtools/client/performance/test/browser_perf-options-allocations.js
+++ b/devtools/client/performance/test/browser_perf-options-propagate-allocations.js
@@ -1,33 +1,36 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
+"use strict";
 
 /**
- * Tests that setting the `devtools.performance.memory.` prefs propagate to the memory actor.
+ * Tests that setting the `devtools.performance.memory.` prefs propagate to
+ * the memory actor.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, $, gFront } = panel.panelWin;
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { MEMORY_SAMPLE_PROB_PREF, MEMORY_MAX_LOG_LEN_PREF, UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
 
-  let originalProbability = Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF);
-  let originalLogLength = Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF);
+add_task(function*() {
+  let { panel, toolbox } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
   Services.prefs.setCharPref(MEMORY_SAMPLE_PROB_PREF, "0.213");
   Services.prefs.setIntPref(MEMORY_MAX_LOG_LEN_PREF, 777777);
 
   yield startRecording(panel);
-
-  let { probability, maxLogLength } = yield gFront.getConfiguration();
-
+  let { probability, maxLogLength } = yield toolbox.performance.getConfiguration();
   yield stopRecording(panel);
 
-  is(probability, 0.213, "allocations probability option is set on memory actor");
-  is(maxLogLength, 777777, "allocations max log length option is set on memory actor");
+  is(probability, 0.213,
+    "The allocations probability option is set on memory actor.");
+  is(maxLogLength, 777777,
+    "The allocations max log length option is set on memory actor.");
 
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, false);
-  Services.prefs.setCharPref(MEMORY_SAMPLE_PROB_PREF, originalProbability);
-  Services.prefs.setIntPref(MEMORY_MAX_LOG_LEN_PREF, originalLogLength);
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
rename from devtools/client/performance/test/browser_perf-options-profiler.js
rename to devtools/client/performance/test/browser_perf-options-propagate-profiler.js
--- a/devtools/client/performance/test/browser_perf-options-profiler.js
+++ b/devtools/client/performance/test/browser_perf-options-propagate-profiler.js
@@ -1,26 +1,32 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
+"use strict";
 
 /**
- * Tests that setting the `devtools.performance.profiler.` prefs propagate to the profiler actor.
+ * Tests that setting the `devtools.performance.profiler.` prefs propagate
+ * to the profiler actor.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { gFront } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { PROFILER_BUFFER_SIZE_PREF, PROFILER_SAMPLE_RATE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+
+add_task(function*() {
+  let { panel, toolbox } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
 
   Services.prefs.setIntPref(PROFILER_BUFFER_SIZE_PREF, 1000);
   Services.prefs.setIntPref(PROFILER_SAMPLE_RATE_PREF, 2);
 
   yield startRecording(panel);
-
-  let { entries, interval } = yield gFront.getConfiguration();
-
+  let { entries, interval } = yield toolbox.performance.getConfiguration();
   yield stopRecording(panel);
 
   is(entries, 1000, "profiler entries option is set on profiler");
   is(interval, 0.5, "profiler interval option is set on profiler");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-show-idle-blocks-01.js
+++ b/devtools/client/performance/test/browser_perf-options-show-idle-blocks-01.js
@@ -1,37 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that the js flamegraphs get rerendered when toggling `show-idle-blocks`
+ * Tests that the js flamegraphs get rerendered when toggling `show-idle-blocks`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_SHOW_IDLE_BLOCKS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
 
-  Services.prefs.setBoolPref(IDLE_PREF, true);
+  Services.prefs.setBoolPref(UI_SHOW_IDLE_BLOCKS_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  let rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("js-flamegraph");
   yield rendered;
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(IDLE_PREF, false);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_IDLE_BLOCKS_PREF, false);
   yield rendered;
-
   ok(true, "JsFlameGraphView rerendered when toggling show-idle-blocks.");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(IDLE_PREF, true);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_IDLE_BLOCKS_PREF, true);
   yield rendered;
-
   ok(true, "JsFlameGraphView rerendered when toggling back show-idle-blocks.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-show-idle-blocks-02.js
+++ b/devtools/client/performance/test/browser_perf-options-show-idle-blocks-02.js
@@ -1,37 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the memory flamegraphs get rerendered when toggling `show-idle-blocks`
+ * Tests that the memory flamegraphs get rerendered when toggling `show-idle-blocks`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_ALLOCATIONS_PREF, UI_SHOW_IDLE_BLOCKS_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
 
-  // Enable memory to test
-  Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
-  Services.prefs.setBoolPref(IDLE_PREF, true);
+  // Enable allocations to test.
+  Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
+  Services.prefs.setBoolPref(UI_SHOW_IDLE_BLOCKS_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
+  let rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("memory-flamegraph");
   yield rendered;
 
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(IDLE_PREF, false);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_IDLE_BLOCKS_PREF, false);
   yield rendered;
-
   ok(true, "MemoryFlameGraphView rerendered when toggling show-idle-blocks.");
 
-  rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(IDLE_PREF, true);
+  rendered = once(MemoryFlameGraphView, EVENTS.UI_MEMORY_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_IDLE_BLOCKS_PREF, true);
   yield rendered;
-
   ok(true, "MemoryFlameGraphView rerendered when toggling back show-idle-blocks.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-show-jit-optimizations.js
+++ b/devtools/client/performance/test/browser_perf-options-show-jit-optimizations.js
@@ -51,34 +51,34 @@ function* spawnTest() {
   // to ensure the opts view is cleared
   let rendered = once(JsCallTreeView, "focus");
   mousedown(window, $$(".call-tree-item")[2]);
   yield rendered;
   let isHidden = $("#jit-optimizations-view").classList.contains("hidden");
   ok(!isHidden, "opts view should be visible when selecting a frame with opts");
 
   let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   RecordingsView.selectedIndex = 0;
   yield Promise.all([select, rendered]);
 
   isHidden = $("#jit-optimizations-view").classList.contains("hidden");
   ok(isHidden, "opts view is hidden when switching recordings");
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   RecordingsView.selectedIndex = 1;
   yield rendered;
 
   rendered = once(JsCallTreeView, "focus");
   mousedown(window, $$(".call-tree-item")[2]);
   yield rendered;
   isHidden = $("#jit-optimizations-view").classList.contains("hidden");
   ok(!isHidden, "opts view should be visible when selecting a frame with opts");
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   Services.prefs.setBoolPref(JIT_PREF, false);
   yield rendered;
   ok(true, "call tree rerendered when JIT pref changes");
   isHidden = $("#jit-optimizations-view").classList.contains("hidden");
   ok(isHidden, "opts view hidden when toggling off jit pref");
 
   rendered = once(JsCallTreeView, "focus");
   mousedown(window, $$(".call-tree-item")[2]);
@@ -91,17 +91,17 @@ function* spawnTest() {
 
   function *injectAndRenderProfilerData() {
     // Get current recording and inject our mock data
     info("Injecting mock profile data");
     let recording = PerformanceController.getCurrentRecording();
     recording._profile = profilerData;
 
     // Force a rerender
-    let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+    let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
     JsCallTreeView.render(OverviewView.getTimeInterval());
     yield rendered;
   }
 
   function *checkFrame (frameIndex, hasOpts) {
     info(`Checking frame ${frameIndex}`);
     // Click the frame
     let rendered = once(JsCallTreeView, "focus");
--- a/devtools/client/performance/test/browser_perf-options-show-platform-data-01.js
+++ b/devtools/client/performance/test/browser_perf-options-show-platform-data-01.js
@@ -1,35 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that the js call tree views get rerendered when toggling `show-platform-data`
+ * Tests that the js call tree views get rerendered when toggling `show-platform-data`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_SHOW_PLATFORM_DATA_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
 
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  let rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
   yield rendered;
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, false);
   yield rendered;
-  ok(true, "JsCallTreeView rerendered when toggling off show-platform-data.");
+  ok(true, "JsCallTreeView rerendered when toggling show-idle-blocks.");
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, true);
   yield rendered;
-  ok(true, "JsCallTreeView rerendered when toggling on show-platform-data.");
+  ok(true, "JsCallTreeView rerendered when toggling back show-idle-blocks.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-options-show-platform-data-02.js
+++ b/devtools/client/performance/test/browser_perf-options-show-platform-data-02.js
@@ -1,33 +1,43 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that the js flamegraphs get rerendered when toggling `show-platform-data`
+ * Tests that the js flamegraphs views get rerendered when toggling `show-platform-data`.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_SHOW_PLATFORM_DATA_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
 
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(100);
   yield stopRecording(panel);
 
-  let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  let rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("js-flamegraph");
   yield rendered;
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, false);
   yield rendered;
-  ok(true, "JsFlameGraphView rerendered when toggling on show-platform-data.");
+  ok(true, "JsFlameGraphView rerendered when toggling show-idle-blocks.");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  Services.prefs.setBoolPref(UI_SHOW_PLATFORM_DATA_PREF, true);
   yield rendered;
-  ok(true, "JsFlameGraphView rerendered when toggling off show-platform-data.");
+  ok(true, "JsFlameGraphView rerendered when toggling back show-idle-blocks.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-render-01.js
+++ b/devtools/client/performance/test/browser_perf-overview-render-01.js
@@ -1,34 +1,34 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the overview continuously renders content when recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, OverviewView } = panel.panelWin;
 
-  // Enable memory to test all the overview graphs.
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
-
   yield startRecording(panel);
 
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED),
-  ]);
+  // Ensure overview keeps rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED),
-  ]);
+  ok(true, "Overview was rendered while recording.");
 
   yield stopRecording(panel);
-
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-render-02.js
+++ b/devtools/client/performance/test/browser_perf-overview-render-02.js
@@ -1,64 +1,66 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the overview graphs cannot be selected during recording
  * and that they're cleared upon rerecording.
  */
-const TIMES_TO_UPDATE = 2;
-function* spawnTest() {
-  // This test seems to take a long time to cleanup on Ubuntu VMs.
-  requestLongerTimeout(2);
 
-  let { panel } = yield initPerformance(SIMPLE_URL);
+const { Constants } = require("devtools/client/performance/modules/constants");
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, OverviewView } = panel.panelWin;
 
-  // Enable memory to test all the overview graphs.
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+  // Enable memory to test.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
 
   yield startRecording(panel);
 
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED),
-  ]);
+  let framerate = OverviewView.graphs.get("framerate");
+  let markers = OverviewView.graphs.get("timeline");
+  let memory = OverviewView.graphs.get("memory");
 
-  let framerate = OverviewView.graphs.get("framerate");
   ok("selectionEnabled" in framerate,
     "The selection should not be enabled for the framerate overview (1).");
   is(framerate.selectionEnabled, false,
     "The selection should not be enabled for the framerate overview (2).");
   is(framerate.hasSelection(), false,
     "The framerate overview shouldn't have a selection before recording.");
 
-  let markers = OverviewView.graphs.get("timeline");
   ok("selectionEnabled" in markers,
     "The selection should not be enabled for the markers overview (1).");
   is(markers.selectionEnabled, false,
     "The selection should not be enabled for the markers overview (2).");
   is(markers.hasSelection(), false,
     "The markers overview shouldn't have a selection before recording.");
 
-  let memory = OverviewView.graphs.get("memory");
   ok("selectionEnabled" in memory,
     "The selection should not be enabled for the memory overview (1).");
   is(memory.selectionEnabled, false,
     "The selection should not be enabled for the memory overview (2).");
   is(memory.hasSelection(), false,
     "The memory overview shouldn't have a selection before recording.");
 
-  let updated = 0;
-  OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
-
-  ok((yield waitUntil(() => updated > TIMES_TO_UPDATE)),
-    "The overviews were updated several times.");
+  // Ensure overview keeps rendering.
+  yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
+    expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
+  });
 
   ok("selectionEnabled" in framerate,
     "The selection should still not be enabled for the framerate overview (1).");
   is(framerate.selectionEnabled, false,
     "The selection should still not be enabled for the framerate overview (2).");
   is(framerate.hasSelection(), false,
     "The framerate overview still shouldn't have a selection before recording.");
 
@@ -75,18 +77,15 @@ function* spawnTest() {
     "The selection should still not be enabled for the memory overview (2).");
   is(memory.hasSelection(), false,
     "The memory overview still shouldn't have a selection before recording.");
 
   yield stopRecording(panel);
 
   is(framerate.selectionEnabled, true,
     "The selection should now be enabled for the framerate overview.");
-
   is(markers.selectionEnabled, true,
     "The selection should now be enabled for the markers overview.");
-
   is(memory.selectionEnabled, true,
     "The selection should now be enabled for the memory overview.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-render-03.js
+++ b/devtools/client/performance/test/browser_perf-overview-render-03.js
@@ -1,69 +1,76 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the overview graphs share the exact same width and scaling.
  */
-const TIMES_TO_UPDATE = 2;
-function* spawnTest() {
-  // This test seems to take a long time to cleanup on Ubuntu VMs.
-  requestLongerTimeout(2);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { PerformanceController, OverviewView } = panel.panelWin;
+
+  // Enable memory to test.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
+
+  let doChecks = () => {
+    let markers = OverviewView.graphs.get("timeline");
+    let framerate = OverviewView.graphs.get("framerate");
+    let memory = OverviewView.graphs.get("memory");
+
+    ok(markers.width > 0,
+      "The overview's markers graph has a width.");
+    ok(markers.dataScaleX > 0,
+      "The overview's markers graph has a data scale factor.");
 
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
+    ok(memory.width > 0,
+      "The overview's memory graph has a width.");
+    ok(memory.dataDuration > 0,
+      "The overview's memory graph has a data duration.");
+    ok(memory.dataScaleX > 0,
+      "The overview's memory graph has a data scale factor.");
+
+    ok(framerate.width > 0,
+      "The overview's framerate graph has a width.");
+    ok(framerate.dataDuration > 0,
+      "The overview's framerate graph has a data duration.");
+    ok(framerate.dataScaleX > 0,
+      "The overview's framerate graph has a data scale factor.");
 
-  // Enable memory to test all the overview graphs.
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+    is(markers.width, memory.width,
+      "The markers and memory graphs widths are the same.");
+    is(markers.width, framerate.width,
+      "The markers and framerate graphs widths are the same.");
+
+    is(memory.dataDuration, framerate.dataDuration,
+      "The memory and framerate graphs data duration are the same.");
+
+    is(markers.dataScaleX, memory.dataScaleX,
+      "The markers and memory graphs data scale are the same.");
+    is(markers.dataScaleX, framerate.dataScaleX,
+      "The markers and framerate graphs data scale are the same.");
+  };
 
   yield startRecording(panel);
+  doChecks();
 
-  let updated = 0;
-  OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
-
-  yield busyWait(100);
   yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
   yield waitUntil(() => PerformanceController.getCurrentRecording().getMemory().length);
   yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
-  yield waitUntil(() => updated > TIMES_TO_UPDATE);
+  doChecks();
 
   yield stopRecording(panel);
-
-  let markers = OverviewView.graphs.get("timeline");
-  let framerate = OverviewView.graphs.get("framerate");
-  let memory = OverviewView.graphs.get("memory");
-
-  ok(markers.width > 0,
-    "The overview's markers graph has a width.");
-  ok(markers.dataScaleX > 0,
-    "The overview's markers graph has a data scale factor.");
-
-  ok(memory.width > 0,
-    "The overview's memory graph has a width.");
-  ok(memory.dataDuration > 0,
-    "The overview's memory graph has a data duration.");
-  ok(memory.dataScaleX > 0,
-    "The overview's memory graph has a data scale factor.");
+  doChecks();
 
-  ok(framerate.width > 0,
-    "The overview's framerate graph has a width.");
-  ok(framerate.dataDuration > 0,
-    "The overview's framerate graph has a data duration.");
-  ok(framerate.dataScaleX > 0,
-    "The overview's framerate graph has a data scale factor.");
-
-  is(markers.width, memory.width,
-    "The markers and memory graphs widths are the same.");
-  is(markers.width, framerate.width,
-    "The markers and framerate graphs widths are the same.");
-
-  is(memory.dataDuration, framerate.dataDuration,
-    "The memory and framerate graphs data duration are the same.");
-
-  is(markers.dataScaleX, memory.dataScaleX,
-    "The markers and memory graphs data scale are the same.");
-  is(markers.dataScaleX, framerate.dataScaleX,
-    "The markers and framerate graphs data scale are the same.");
-
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-render-04.js
+++ b/devtools/client/performance/test/browser_perf-overview-render-04.js
@@ -1,52 +1,69 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the overview graphs do not render when realtime rendering is off
  * due to lack of e10s.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+const { isVisible } = require("devtools/client/performance/test/helpers/dom-utils");
 
-  let updated = 0;
-  OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
-  OverviewView.OVERVIEW_UPDATE_INTERVAL = 1;
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, EVENTS, PerformanceController, RecordingsView, OverviewView } = panel.panelWin;
+
+  // Enable memory to test.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
 
   // Set realtime rendering off.
   OverviewView.isRealtimeRenderingEnabled = () => false;
 
-  yield startRecording(panel, { waitForOverview: false, waitForStateChange: true });
-  is(isVisible($("#overview-pane")), false, "overview graphs hidden");
-  is(updated, 0, "Overview graphs have still not been updated");
+  let updated = 0;
+  OverviewView.on(EVENTS.UI_OVERVIEW_RENDERED, () => updated++);
+
+  yield startRecording(panel, { skipWaitingForOverview: true });
+
+  is(isVisible($("#overview-pane")), false, "Overview graphs hidden.");
+  is(updated, 0, "Overview graphs have not been updated");
+
   yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
+  yield waitUntil(() => PerformanceController.getCurrentRecording().getMemory().length);
   yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
+  is(isVisible($("#overview-pane")), false, "Overview graphs still hidden.");
   is(updated, 0, "Overview graphs have still not been updated");
 
   yield stopRecording(panel);
 
-  let markers = OverviewView.graphs.get("timeline");
-  let framerate = OverviewView.graphs.get("framerate");
+  is(isVisible($("#overview-pane")), true, "Overview graphs no longer hidden.");
+  is(updated, 1, "Overview graphs rendered upon completion.");
 
-  ok(markers.width > 0,
-    "The overview's markers graph has a width.");
-  ok(framerate.width > 0,
-    "The overview's framerate graph has a width.");
+  yield startRecording(panel, { skipWaitingForOverview: true });
 
-  is(updated, 1, "Overview graphs rendered upon completion.");
-  is(isVisible($("#overview-pane")), true, "overview graphs no longer hidden");
-
-  yield startRecording(panel, { waitForOverview: false, waitForStateChange: true });
-  is(isVisible($("#overview-pane")), false, "overview graphs hidden again when starting new recording");
+  is(isVisible($("#overview-pane")), false, "Overview graphs hidden again when starting new recording.");
+  is(updated, 1, "Overview graphs have not been updated again.");
 
   RecordingsView.selectedIndex = 0;
-  is(isVisible($("#overview-pane")), true, "overview graphs no longer hidden when switching back to complete recording.");
+  is(isVisible($("#overview-pane")), true, "Overview graphs no longer hidden when switching back to complete recording.");
+  is(updated, 1, "Overview graphs have not been updated again.");
+
   RecordingsView.selectedIndex = 1;
-  is(isVisible($("#overview-pane")), false, "overview graphs hidden again when going back to inprogress recording.");
+  is(isVisible($("#overview-pane")), false, "Overview graphs hidden again when going back to inprogress recording.");
+  is(updated, 1, "Overview graphs have not been updated again.");
 
   yield stopRecording(panel);
-  is(isVisible($("#overview-pane")), true, "overview graphs no longer hidden when recording finishes");
 
-  yield teardown(panel);
-  finish();
-}
+  is(isVisible($("#overview-pane")), true, "overview graphs no longer hidden when recording finishes");
+  is(updated, 2, "Overview graphs rendered again upon completion.");
+
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-selection-01.js
+++ b/devtools/client/performance/test/browser_perf-overview-selection-01.js
@@ -1,72 +1,69 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that events are fired from OverviewView from selection manipulation.
+ * Tests that events are fired from selection manipulation.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+const { idleWait } = require("devtools/client/performance/test/helpers/wait-utils");
+const { dragStartCanvasGraph, dragStopCanvasGraph, clickCanvasGraph } = require("devtools/client/performance/test/helpers/input-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
-  let params, _;
 
   yield startRecording(panel);
-
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED)
-  ]);
-
   yield stopRecording(panel);
 
+  let duration = PerformanceController.getCurrentRecording().getDuration();
   let graph = OverviewView.graphs.get("timeline");
-  let MAX = graph.width;
-  let duration = PerformanceController.getCurrentRecording().getDuration();
-  let selection = null;
+
+  // Select the first half of the graph.
+
+  let rangeSelected = once(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED, { spreadArgs: true });
+  dragStartCanvasGraph(graph, { x: 0 });
+  let [_, { startTime, endTime }] = yield rangeSelected;
+  is(endTime, duration, "The selected range is the entire graph, for now.");
 
-  // Throw out events that select everything, as this will occur on the
-  // first click
-  OverviewView.on(EVENTS.OVERVIEW_RANGE_SELECTED, function handler (_, interval) {
-    if (interval.endTime !== duration) {
-      selection = interval;
-      OverviewView.off(handler);
-    }
-  });
+  rangeSelected = once(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED, { spreadArgs: true });
+  dragStopCanvasGraph(graph, { x: graph.width / 2 });
+  [_, { startTime, endTime }] = yield rangeSelected;
+  is(endTime, duration / 2, "The selected range is half of the graph.");
 
-  let results = onceSpread(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
-  // Select the first half of the graph
-  dragStart(graph, 0);
-  dragStop(graph, MAX / 2);
-  yield waitUntil(() => selection);
-  let { startTime, endTime } = selection;
+  is(graph.hasSelection(), true,
+    "A selection exists on the graph.");
+  is(startTime, 0,
+    "The UI_OVERVIEW_RANGE_SELECTED event fired with 0 as a `startTime`.");
+  is(endTime, duration / 2,
+    `The UI_OVERVIEW_RANGE_SELECTED event fired with ${duration / 2} as \`endTime\`.`);
 
   let mapStart = () => 0;
   let mapEnd = () => duration;
   let actual = graph.getMappedSelection({ mapStart, mapEnd });
-  is(actual.min, 0, "graph selection starts at 0");
-  is(actual.max, duration/2, `graph selection ends at ${duration/2}`);
+  is(actual.min, 0, "Graph selection starts at 0.");
+  is(actual.max, duration / 2, `Graph selection ends at ${duration / 2}.`);
 
-  is(graph.hasSelection(), true,
-    "A selection exists on the graph.");
-  is(startTime, 0,
-    "OVERVIEW_RANGE_SELECTED fired with startTime value on click.");
-  is(endTime, duration / 2,
-    "OVERVIEW_RANGE_SELECTED fired with endTime value on click.");
+  // Listen to deselection.
 
-  // Listen to deselection
-  results = onceSpread(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
-  dropSelection(graph);
-  [_, params] = yield results;
+  rangeSelected = once(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED, { spreadArgs: true });
+  clickCanvasGraph(graph, { x: 3 * graph.width / 4 });
+  [_, { startTime, endTime }] = yield rangeSelected;
 
   is(graph.hasSelection(), false,
     "A selection no longer on the graph.");
-  is(params.startTime, 0,
-    "OVERVIEW_RANGE_SELECTED fired with 0 as a startTime.");
-  is(params.endTime, duration,
-    "OVERVIEW_RANGE_SELECTED fired with max duration as endTime");
+  is(startTime, 0,
+    "The UI_OVERVIEW_RANGE_SELECTED event fired with 0 as a `startTime`.");
+  is(endTime, duration,
+    "The UI_OVERVIEW_RANGE_SELECTED event fired with duration as `endTime`.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-selection-02.js
+++ b/devtools/client/performance/test/browser_perf-overview-selection-02.js
@@ -1,79 +1,73 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
  * Tests that the graphs' selection is correctly disabled or enabled.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, OverviewView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
 
-  // Enable memory to test all the overview graphs.
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { OverviewView } = panel.panelWin;
+
+  // Enable memory to test.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
 
   yield startRecording(panel);
 
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED),
-  ]);
-
   let markersOverview = OverviewView.graphs.get("timeline");
-  let memoryOverview = OverviewView.graphs.get("memory");
+  let memoryGraph = OverviewView.graphs.get("memory");
   let framerateGraph = OverviewView.graphs.get("framerate");
 
   ok(markersOverview,
     "The markers graph should have been created now.");
-  ok(memoryOverview,
+  ok(memoryGraph,
     "The memory graph should have been created now.");
   ok(framerateGraph,
     "The framerate graph should have been created now.");
 
+  ok(!markersOverview.selectionEnabled,
+    "Selection shouldn't be enabled when the first recording started (2).");
+  ok(!memoryGraph.selectionEnabled,
+    "Selection shouldn't be enabled when the first recording started (3).");
   ok(!framerateGraph.selectionEnabled,
     "Selection shouldn't be enabled when the first recording started (1).");
-  ok(!markersOverview.selectionEnabled,
-    "Selection shouldn't be enabled when the first recording started (2).");
-  ok(!memoryOverview.selectionEnabled,
-    "Selection shouldn't be enabled when the first recording started (3).");
 
   yield stopRecording(panel);
 
+  ok(markersOverview.selectionEnabled,
+    "Selection should be enabled when the first recording finishes (2).");
+  ok(memoryGraph.selectionEnabled,
+    "Selection should be enabled when the first recording finishes (3).");
   ok(framerateGraph.selectionEnabled,
     "Selection should be enabled when the first recording finishes (1).");
-  ok(markersOverview.selectionEnabled,
-    "Selection should be enabled when the first recording finishes (2).");
-  ok(memoryOverview.selectionEnabled,
-    "Selection should be enabled when the first recording finishes (3).");
 
   yield startRecording(panel);
 
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED),
-  ]);
-
+  ok(!markersOverview.selectionEnabled,
+    "Selection shouldn't be enabled when the second recording started (2).");
+  ok(!memoryGraph.selectionEnabled,
+    "Selection shouldn't be enabled when the second recording started (3).");
   ok(!framerateGraph.selectionEnabled,
     "Selection shouldn't be enabled when the second recording started (1).");
-  ok(!markersOverview.selectionEnabled,
-    "Selection shouldn't be enabled when the second recording started (2).");
-  ok(!memoryOverview.selectionEnabled,
-    "Selection shouldn't be enabled when the second recording started (3).");
 
   yield stopRecording(panel);
 
-  ok(framerateGraph.selectionEnabled,
-    "Selection should be enabled when the first second finishes (1).");
   ok(markersOverview.selectionEnabled,
     "Selection should be enabled when the first second finishes (2).");
-  ok(memoryOverview.selectionEnabled,
+  ok(memoryGraph.selectionEnabled,
     "Selection should be enabled when the first second finishes (3).");
+  ok(framerateGraph.selectionEnabled,
+    "Selection should be enabled when the first second finishes (1).");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-selection-03.js
+++ b/devtools/client/performance/test/browser_perf-overview-selection-03.js
@@ -1,76 +1,82 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the graphs' selections are linked.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { UI_ENABLE_MEMORY_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { times } = require("devtools/client/performance/test/helpers/event-utils");
+const { dragStartCanvasGraph, dragStopCanvasGraph } = require("devtools/client/performance/test/helpers/input-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, OverviewView } = panel.panelWin;
 
-  // Enable memory to test all the overview graphs.
-  Services.prefs.setBoolPref(MEMORY_PREF, true);
+  // Enable memory to test.
+  Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
 
   yield startRecording(panel);
-
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED),
-  ]);
-
   yield stopRecording(panel);
 
+  let markersOverview = OverviewView.graphs.get("timeline");
+  let memoryGraph = OverviewView.graphs.get("memory");
   let framerateGraph = OverviewView.graphs.get("framerate");
-  let markersOverview = OverviewView.graphs.get("timeline");
-  let memoryOverview = OverviewView.graphs.get("memory");
-  let MAX = framerateGraph.width;
+  let width = framerateGraph.width;
 
   // Perform a selection inside the framerate graph.
 
-  let selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
-  dragStart(framerateGraph, 0);
-  dragStop(framerateGraph, MAX / 2);
-  yield selected;
+  let rangeSelected = times(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED, 2);
+  dragStartCanvasGraph(framerateGraph, { x: 0 });
+  dragStopCanvasGraph(framerateGraph, { x: width / 2 });
+  yield rangeSelected;
 
-  is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 2) + "})",
-    "The framerate graph has a correct selection.");
   is(markersOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
     "The markers overview has a correct selection.");
-  is(memoryOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
+  is(memoryGraph.getSelection().toSource(), framerateGraph.getSelection().toSource(),
     "The memory overview has a correct selection.");
+  is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (width / 2) + "})",
+    "The framerate graph has a correct selection.");
 
   // Perform a selection inside the markers overview.
 
-  selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
   markersOverview.dropSelection();
-  dragStart(markersOverview, 0);
-  dragStop(markersOverview, MAX / 4);
-  yield selected;
 
-  is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 4) + "})",
-    "The framerate graph has a correct selection.");
+  rangeSelected = times(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED, 2);
+  dragStartCanvasGraph(markersOverview, { x: 0 });
+  dragStopCanvasGraph(markersOverview, { x: width / 4 });
+  yield rangeSelected;
+
   is(markersOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
     "The markers overview has a correct selection.");
-  is(memoryOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
+  is(memoryGraph.getSelection().toSource(), framerateGraph.getSelection().toSource(),
     "The memory overview has a correct selection.");
+  is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (width / 4) + "})",
+    "The framerate graph has a correct selection.");
 
   // Perform a selection inside the memory overview.
 
-  selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
-  memoryOverview.dropSelection();
-  dragStart(memoryOverview, 0);
-  dragStop(memoryOverview, MAX / 10);
-  yield selected;
+  markersOverview.dropSelection();
 
-  is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (MAX / 10) + "})",
-    "The framerate graph has a correct selection.");
+  rangeSelected = times(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED, 2);
+  dragStartCanvasGraph(memoryGraph, { x: 0 });
+  dragStopCanvasGraph(memoryGraph, { x: width / 10 });
+  yield rangeSelected;
+
   is(markersOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
     "The markers overview has a correct selection.");
-  is(memoryOverview.getSelection().toSource(), framerateGraph.getSelection().toSource(),
+  is(memoryGraph.getSelection().toSource(), framerateGraph.getSelection().toSource(),
     "The memory overview has a correct selection.");
+  is(framerateGraph.getSelection().toSource(), "({start:0, end:" + (width / 10) + "})",
+    "The framerate graph has a correct selection.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-overview-time-interval.js
+++ b/devtools/client/performance/test/browser_perf-overview-time-interval.js
@@ -1,70 +1,73 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the `setTimeInterval` and `getTimeInterval` functions
  * work properly.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, OverviewView } = panel.panelWin;
 
   try {
     OverviewView.setTimeInterval({ starTime: 0, endTime: 1 });
     ok(false, "Setting a time interval shouldn't have worked.");
   } catch (e) {
     ok(true, "Setting a time interval didn't work, as expected.");
   }
 
   try {
     OverviewView.getTimeInterval();
     ok(false, "Getting the time interval shouldn't have worked.");
   } catch (e) {
     ok(true, "Getting the time interval didn't work, as expected.");
   }
 
   yield startRecording(panel);
-
-  yield Promise.all([
-    once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
-    once(OverviewView, EVENTS.OVERVIEW_RENDERED)
-  ]);
-
   yield stopRecording(panel);
 
   // Get/set the time interval and wait for the event propagation.
 
-  let notified = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);
+  let rangeSelected = once(OverviewView, EVENTS.UI_OVERVIEW_RANGE_SELECTED);
   OverviewView.setTimeInterval({ startTime: 10, endTime: 20 });
-  yield notified;
+  yield rangeSelected;
 
   let firstInterval = OverviewView.getTimeInterval();
   info("First interval start time: " + firstInterval.startTime);
   info("First interval end time: " + firstInterval.endTime);
   is(Math.round(firstInterval.startTime), 10,
     "The interval's start time was properly set.");
   is(Math.round(firstInterval.endTime), 20,
     "The interval's end time was properly set.");
 
   // Get/set another time interval and make sure there's no event propagation.
 
   function fail() {
     ok(false, "The selection event should not have propagated.");
   }
 
-  OverviewView.on(EVENTS.OVERVIEW_RANGE_SELECTED, fail);
+  OverviewView.on(EVENTS.UI_OVERVIEW_RANGE_SELECTED, fail);
   OverviewView.setTimeInterval({ startTime: 30, endTime: 40 }, { stopPropagation: true });
-  OverviewView.off(EVENTS.OVERVIEW_RANGE_SELECTED, fail);
+  OverviewView.off(EVENTS.UI_OVERVIEW_RANGE_SELECTED, fail);
 
   let secondInterval = OverviewView.getTimeInterval();
   info("Second interval start time: " + secondInterval.startTime);
   info("Second interval end time: " + secondInterval.endTime);
   is(Math.round(secondInterval.startTime), 30,
     "The interval's start time was properly set again.");
   is(Math.round(secondInterval.endTime), 40,
     "The interval's end time was properly set again.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-private-browsing.js
+++ b/devtools/client/performance/test/browser_perf-private-browsing.js
@@ -1,95 +1,111 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-
-requestLongerTimeout(2);
+"use strict";
 
 /**
- * Tests that disables the frontend when in private browsing mode.
+ * Tests that the frontend is disabled when in private browsing mode.
  */
 
-var gPanelWinTuples = [];
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { addWindow } = require("devtools/client/performance/test/helpers/tab-utils");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-function* spawnTest() {
+let gPanelWinTuples = [];
+
+add_task(function*() {
   yield testNormalWindow();
   yield testPrivateWindow();
   yield testRecordingFailingInWindow(0);
   yield testRecordingFailingInWindow(1);
-  yield teardownPerfInWindow(1);
+  yield teardownPerfInWindow(1, { shouldCloseWindow: true, dontWaitForTabClose: true });
   yield testRecordingSucceedingInWindow(0);
-  yield teardownPerfInWindow(0);
+  yield teardownPerfInWindow(0, { shouldCloseWindow: false });
 
   gPanelWinTuples = null;
-  finish();
+});
+
+function* createPanelInNewWindow(options) {
+  let win = yield addWindow(options);
+  return yield createPanelInWindow(options, win);
 }
 
-function* createPanelInWindow(options) {
-  let win = yield addWindow(options);
-  let tab = yield addTab(SIMPLE_URL, win);
-  let target = TargetFactory.forTab(tab);
-  yield target.makeRemote();
+function* createPanelInWindow(options, win = window) {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: win
+  }, options);
 
-  let toolbox = yield gDevTools.showToolbox(target, "performance");
-  yield toolbox.initPerformance();
-
-  let panel = yield toolbox.getCurrentPanel().open();
   gPanelWinTuples.push({ panel, win });
-
   return { panel, win };
 }
 
 function* testNormalWindow() {
-  let { panel } = yield createPanelInWindow({ private: false });
+  let { panel } = yield createPanelInWindow({
+    private: false
+  });
+
   let { PerformanceView } = panel.panelWin;
 
   is(PerformanceView.getState(), "empty",
     "The initial state of the performance panel view is correct (1).");
 }
 
 function* testPrivateWindow() {
-  let { panel } = yield createPanelInWindow({ private: true });
+  let { panel } = yield createPanelInNewWindow({
+    private: true,
+    // The add-on SDK can't seem to be able to listen to "ready" or "close"
+    // events for private tabs. Don't really absolutely need to though.
+    dontWaitForTabReady: true
+  });
+
   let { PerformanceView } = panel.panelWin;
 
   is(PerformanceView.getState(), "unavailable",
     "The initial state of the performance panel view is correct (2).");
 }
 
 function* testRecordingFailingInWindow(index) {
   let { panel } = gPanelWinTuples[index];
   let { EVENTS, PerformanceController } = panel.panelWin;
 
   let onRecordingStarted = () => {
     ok(false, "Recording should not start while a private window is present.");
   };
 
-  PerformanceController.on(EVENTS.RECORDING_STARTED, onRecordingStarted);
+  PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, onRecordingStarted);
 
-  let whenFailed = once(PerformanceController, EVENTS.NEW_RECORDING_FAILED);
+  let whenFailed = once(PerformanceController, EVENTS.BACKEND_FAILED_AFTER_RECORDING_START);
   PerformanceController.startRecording();
   yield whenFailed;
   ok(true, "Recording has failed.");
 
-  PerformanceController.off(EVENTS.RECORDING_STARTED, onRecordingStarted);
+  PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, onRecordingStarted);
 }
 
 function* testRecordingSucceedingInWindow(index) {
   let { panel } = gPanelWinTuples[index];
   let { EVENTS, PerformanceController } = panel.panelWin;
 
   let onRecordingFailed = () => {
     ok(false, "Recording should start while now private windows are present.");
   };
 
-  PerformanceController.on(EVENTS.NEW_RECORDING_FAILED, onRecordingFailed);
+  PerformanceController.on(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START, onRecordingFailed);
 
   yield startRecording(panel);
   yield stopRecording(panel);
   ok(true, "Recording has succeeded.");
 
-  PerformanceController.off(EVENTS.RECORDING_STARTED, onRecordingFailed);
+  PerformanceController.off(EVENTS.BACKEND_FAILED_AFTER_RECORDING_START, onRecordingFailed);
 }
 
-function* teardownPerfInWindow(index) {
+function* teardownPerfInWindow(index, options) {
   let { panel, win } = gPanelWinTuples[index];
-  yield teardown(panel, win);
-  win.close();
+  yield teardownToolboxAndRemoveTab(panel, options);
+
+  if (options.shouldCloseWindow) {
+    win.close();
+  }
 }
--- a/devtools/client/performance/test/browser_perf-range-changed-render.js
+++ b/devtools/client/performance/test/browser_perf-range-changed-render.js
@@ -1,67 +1,74 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the detail views are rerendered after the range changes.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, PerformanceController, OverviewView, DetailsView } = panel.panelWin;
-  let { WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
 
-  let updateWaterfall = () => updatedWaterfall++;
-  let updateCallTree = () => updatedCallTree++;
-  let updateFlameGraph = () => updatedFlameGraph++;
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { EVENTS, OverviewView, DetailsView, WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
+
   let updatedWaterfall = 0;
   let updatedCallTree = 0;
   let updatedFlameGraph = 0;
-  WaterfallView.on(EVENTS.WATERFALL_RENDERED, updateWaterfall);
-  JsCallTreeView.on(EVENTS.JS_CALL_TREE_RENDERED, updateCallTree);
-  JsFlameGraphView.on(EVENTS.JS_FLAMEGRAPH_RENDERED, updateFlameGraph);
+  let updateWaterfall = () => updatedWaterfall++;
+  let updateCallTree = () => updatedCallTree++;
+  let updateFlameGraph = () => updatedFlameGraph++;
+  WaterfallView.on(EVENTS.UI_WATERFALL_RENDERED, updateWaterfall);
+  JsCallTreeView.on(EVENTS.UI_JS_CALL_TREE_RENDERED, updateCallTree);
+  JsFlameGraphView.on(EVENTS.UI_JS_FLAMEGRAPH_RENDERED, updateFlameGraph);
 
   yield startRecording(panel);
-  yield busyWait(100);
-  yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
   yield stopRecording(panel);
 
-  let rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
-  OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: 10 });
+  let rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
+  OverviewView.emit(EVENTS.UI_OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: 10 });
   yield rendered;
   ok(true, "Waterfall rerenders when a range in the overview graph is selected.");
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
   yield rendered;
   ok(true, "Call tree rerenders after its corresponding pane is shown.");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
   yield DetailsView.selectView("js-flamegraph");
   yield rendered;
   ok(true, "Flamegraph rerenders after its corresponding pane is shown.");
 
-  rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
-  OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED);
+  rendered = once(JsFlameGraphView, EVENTS.UI_JS_FLAMEGRAPH_RENDERED);
+  OverviewView.emit(EVENTS.UI_OVERVIEW_RANGE_SELECTED);
   yield rendered;
   ok(true, "Flamegraph rerenders when a range in the overview graph is removed.");
 
-  rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
+  rendered = once(JsCallTreeView, EVENTS.UI_JS_CALL_TREE_RENDERED);
   yield DetailsView.selectView("js-calltree");
   yield rendered;
   ok(true, "Call tree rerenders after its corresponding pane is shown.");
 
-  rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
+  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   yield DetailsView.selectView("waterfall");
   yield rendered;
   ok(true, "Waterfall rerenders after its corresponding pane is shown.");
 
   is(updatedWaterfall, 3, "WaterfallView rerendered 3 times.");
   is(updatedCallTree, 2, "JsCallTreeView rerendered 2 times.");
   is(updatedFlameGraph, 2, "JsFlameGraphView rerendered 2 times.");
 
-  WaterfallView.off(EVENTS.WATERFALL_RENDERED, updateWaterfall);
-  JsCallTreeView.off(EVENTS.JS_CALL_TREE_RENDERED, updateCallTree);
-  JsFlameGraphView.off(EVENTS.JS_FLAMEGRAPH_RENDERED, updateFlameGraph);
+  WaterfallView.off(EVENTS.UI_WATERFALL_RENDERED, updateWaterfall);
+  JsCallTreeView.off(EVENTS.UI_JS_CALL_TREE_RENDERED, updateCallTree);
+  JsFlameGraphView.off(EVENTS.UI_JS_FLAMEGRAPH_RENDERED, updateFlameGraph);
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-recording-notices-01.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-01.js
@@ -1,36 +1,45 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the recording notice panes are toggled in correct scenarios
  * for initialization and a single recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { EVENTS, $, PerformanceView, RecordingsView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { $, PerformanceView } = panel.panelWin;
 
   let MAIN_CONTAINER = $("#performance-view");
   let EMPTY = $("#empty-notice");
   let CONTENT = $("#performance-view-content");
-  let CONTENT_CONTAINER = $("#details-pane-container");
+  let DETAILS_CONTAINER = $("#details-pane-container");
   let RECORDING = $("#recording-notice");
   let DETAILS = $("#details-pane");
 
-  is(PerformanceView.getState(), "empty", "correct default state");
-  is(MAIN_CONTAINER.selectedPanel, EMPTY, "showing empty panel on load");
+  is(PerformanceView.getState(), "empty", "Correct default state.");
+  is(MAIN_CONTAINER.selectedPanel, EMPTY, "Showing empty panel on load.");
 
   yield startRecording(panel);
 
-  is(PerformanceView.getState(), "recording", "correct state during recording");
-  is(MAIN_CONTAINER.selectedPanel, CONTENT, "showing main view with timeline");
-  is(CONTENT_CONTAINER.selectedPanel, RECORDING, "showing recording panel");
+  is(PerformanceView.getState(), "recording", "Correct state during recording.");
+  is(MAIN_CONTAINER.selectedPanel, CONTENT, "Showing main view with timeline.");
+  is(DETAILS_CONTAINER.selectedPanel, RECORDING, "Showing recording panel.");
 
   yield stopRecording(panel);
 
-  is(PerformanceView.getState(), "recorded", "correct state after recording");
-  is(MAIN_CONTAINER.selectedPanel, CONTENT, "showing main view with timeline");
-  is(CONTENT_CONTAINER.selectedPanel, DETAILS, "showing rendered graphs");
+  is(PerformanceView.getState(), "recorded", "Correct state after recording.");
+  is(MAIN_CONTAINER.selectedPanel, CONTENT, "Showing main view with timeline.");
+  is(DETAILS_CONTAINER.selectedPanel, DETAILS, "Showing rendered graphs.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-recording-notices-02.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-02.js
@@ -1,47 +1,57 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that the recording notice panes are toggled when going between
  * a completed recording and an in-progress recording.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, $, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
 
   let MAIN_CONTAINER = $("#performance-view");
   let CONTENT = $("#performance-view-content");
-  let CONTENT_CONTAINER = $("#details-pane-container");
+  let DETAILS_CONTAINER = $("#details-pane-container");
   let RECORDING = $("#recording-notice");
   let DETAILS = $("#details-pane");
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
 
-  is(PerformanceView.getState(), "recording", "correct state during recording");
-  is(MAIN_CONTAINER.selectedPanel, CONTENT, "showing main view with timeline");
-  is(CONTENT_CONTAINER.selectedPanel, RECORDING, "showing recording panel");
+  is(PerformanceView.getState(), "recording", "Correct state during recording.");
+  is(MAIN_CONTAINER.selectedPanel, CONTENT, "Showing main view with timeline.");
+  is(DETAILS_CONTAINER.selectedPanel, RECORDING, "Showing recording panel.");
 
-  let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
-  yield select;
+  yield selected;
 
-  is(PerformanceView.getState(), "recorded", "correct state during recording but selecting a completed recording");
-  is(MAIN_CONTAINER.selectedPanel, CONTENT, "showing main view with timeline");
-  is(CONTENT_CONTAINER.selectedPanel, DETAILS, "showing recorded panel");
+  is(PerformanceView.getState(), "recorded", "Correct state during recording but selecting a completed recording.");
+  is(MAIN_CONTAINER.selectedPanel, CONTENT, "Showing main view with timeline.");
+  is(DETAILS_CONTAINER.selectedPanel, DETAILS, "Showing recorded panel.");
 
-  select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 1;
-  yield select;
+  yield selected;
 
-  is(PerformanceView.getState(), "recording", "correct state when switching back to recording in progress");
-  is(MAIN_CONTAINER.selectedPanel, CONTENT, "showing main view with timeline");
-  is(CONTENT_CONTAINER.selectedPanel, RECORDING, "showing recording panel");
+  is(PerformanceView.getState(), "recording", "Correct state when switching back to recording in progress.");
+  is(MAIN_CONTAINER.selectedPanel, CONTENT, "Showing main view with timeline.");
+  is(DETAILS_CONTAINER.selectedPanel, RECORDING, "Showing recording panel.");
 
   yield stopRecording(panel);
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-recording-notices-03.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-03.js
@@ -1,77 +1,117 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that recording notices display buffer status when available,
- * and can switch between different recordings with the correct buffer information
- * displayed.
+ * and can switch between different recordings with the correct buffer
+ * information displayed.
  */
-function* spawnTest() {
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { PROFILER_BUFFER_SIZE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { PMM_loadFrameScripts, PMM_stopProfiler, PMM_clearFrameScripts } = require("devtools/client/performance/test/helpers/profiler-mm-utils");
+const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  // Make sure the profiler module is stopped so we can set a new buffer limit.
   PMM_loadFrameScripts(gBrowser);
-  // Keep it large, but still get to 1% relatively quick
+  yield PMM_stopProfiler();
+
+  // Keep the profiler's buffer large, but still get to 1% relatively quick.
   Services.prefs.setIntPref(PROFILER_BUFFER_SIZE_PREF, 1000000);
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+  let { target, console } = yield initConsoleInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { panel } = yield initPerformanceInTab({ tab: target.tab });
   let { gFront, EVENTS, $, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
 
-  // Set a fast profiler-status update interval
+  // Set a fast profiler-status update interval.
   yield gFront.setProfilerStatusInterval(10);
 
+  let DETAILS_CONTAINER = $("#details-pane-container");
+  let NORMAL_BUFFER_STATUS_MESSAGE = $("#recording-notice .buffer-status-message");
+  let CONSOLE_BUFFER_STATUS_MESSAGE = $("#console-recording-notice .buffer-status-message");
+  let gPercent;
+
+  // Start a manual recording.
   yield startRecording(panel);
 
-  let percent = 0;
-  while (percent === 0) {
-    [,percent] = yield onceSpread(PerformanceView, EVENTS.UI_BUFFER_STATUS_UPDATED);
-  }
+  yield waitUntil(function*() {
+    [, gPercent] = yield once(PerformanceView, EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED, { spreadArgs: true });
+    return gPercent > 0;
+  });
+
+  ok(true, "Buffer percentage increased in display (1).");
 
   let bufferUsage = PerformanceController.getBufferUsageForRecording(PerformanceController.getCurrentRecording());
-  is($("#details-pane-container").getAttribute("buffer-status"), "in-progress",
-    "container has [buffer-status=in-progress]");
-  ok($("#recording-notice .buffer-status-message").value.indexOf(percent + "%") !== -1,
-    "buffer status text has correct percentage");
+  either(DETAILS_CONTAINER.getAttribute("buffer-status"), "in-progress", "full",
+    "Container has [buffer-status=in-progress] or [buffer-status=full].");
+  ok(NORMAL_BUFFER_STATUS_MESSAGE.value.indexOf(gPercent + "%") !== -1,
+    "Buffer status text has correct percentage.");
 
-  // Start a console profile
-  yield consoleProfile(panel.panelWin, "rust");
+  // Start a console profile.
+  yield console.profile("rust");
 
-  percent = 0;
-  while (percent <= (Math.floor(bufferUsage * 100))) {
-    [,percent] = yield onceSpread(PerformanceView, EVENTS.UI_BUFFER_STATUS_UPDATED);
-  }
+  yield waitUntil(function*() {
+    [, gPercent] = yield once(PerformanceView, EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED, { spreadArgs: true });
+    return gPercent > Math.floor(bufferUsage * 100);
+  });
 
-  ok(percent > Math.floor(bufferUsage * 100), "buffer percentage increased in display");
+  ok(true, "Buffer percentage increased in display (2).");
+
   bufferUsage = PerformanceController.getBufferUsageForRecording(PerformanceController.getCurrentRecording());
+  either(DETAILS_CONTAINER.getAttribute("buffer-status"), "in-progress", "full",
+    "Container has [buffer-status=in-progress] or [buffer-status=full].");
+  ok(NORMAL_BUFFER_STATUS_MESSAGE.value.indexOf(gPercent + "%") !== -1,
+    "Buffer status text has correct percentage.");
 
-  is($("#details-pane-container").getAttribute("buffer-status"), "in-progress",
-    "container has [buffer-status=in-progress]");
-  ok($("#recording-notice .buffer-status-message").value.indexOf(percent + "%") !== -1,
-    "buffer status text has correct percentage");
-
+  // Select the console recording.
+  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 1;
-  percent = 0;
-  while (percent === 0) {
-    [,percent] = yield onceSpread(PerformanceView, EVENTS.UI_BUFFER_STATUS_UPDATED);
-  }
+  yield selected;
+
+  yield waitUntil(function*() {
+    [, gPercent] = yield once(PerformanceView, EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED, { spreadArgs: true });
+    return gPercent > 0;
+  });
 
-  ok(percent < Math.floor(bufferUsage * 100), "percentage updated for newly selected recording");
-  is($("#details-pane-container").getAttribute("buffer-status"), "in-progress",
-    "container has [buffer-status=in-progress]");
-  ok($("#console-recording-notice .buffer-status-message").value.indexOf(percent + "%") !== -1,
-    "buffer status text has correct percentage for console recording");
+  ok(true, "Percentage updated for newly selected recording.");
+
+  either(DETAILS_CONTAINER.getAttribute("buffer-status"), "in-progress", "full",
+    "Container has [buffer-status=in-progress] or [buffer-status=full].");
+  ok(CONSOLE_BUFFER_STATUS_MESSAGE.value.indexOf(gPercent + "%") !== -1,
+    "Buffer status text has correct percentage for console recording.");
+
+  // Stop the console profile, then select the original manual recording.
+  yield console.profileEnd("rust");
 
-  yield consoleProfileEnd(panel.panelWin, "rust");
+  selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
+  yield selected;
+
+  yield waitUntil(function*() {
+    [, gPercent] = yield once(PerformanceView, EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED, { spreadArgs: true });
+    return gPercent > Math.floor(bufferUsage * 100);
+  });
 
-  percent = 0;
-  while (percent <= (Math.floor(bufferUsage * 100))) {
-    [,percent] = yield onceSpread(PerformanceView, EVENTS.UI_BUFFER_STATUS_UPDATED);
-  }
-  ok(percent > Math.floor(bufferUsage * 100), "percentage increased for original recording");
-  is($("#details-pane-container").getAttribute("buffer-status"), "in-progress",
-    "container has [buffer-status=in-progress]");
-  ok($("#recording-notice .buffer-status-message").value.indexOf(percent + "%") !== -1,
-    "buffer status text has correct percentage");
+  ok(true, "Buffer percentage increased in display (3).");
 
+  either(DETAILS_CONTAINER.getAttribute("buffer-status"), "in-progress", "full",
+    "Container has [buffer-status=in-progress] or [buffer-status=full].");
+  ok(NORMAL_BUFFER_STATUS_MESSAGE.value.indexOf(gPercent + "%") !== -1,
+    "Buffer status text has correct percentage.");
+
+  // Stop the manual recording.
   yield stopRecording(panel);
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+
+  PMM_clearFrameScripts();
+});
--- a/devtools/client/performance/test/browser_perf-recording-notices-04.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-04.js
@@ -1,35 +1,63 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that when a recording overlaps the circular buffer, that
  * a class is assigned to the recording notices.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { PROFILER_BUFFER_SIZE_PREF } = require("devtools/client/performance/test/helpers/prefs");
+const { PMM_loadFrameScripts, PMM_stopProfiler, PMM_clearFrameScripts } = require("devtools/client/performance/test/helpers/profiler-mm-utils");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { waitUntil } = require("devtools/client/performance/test/helpers/wait-utils");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  // Make sure the profiler module is stopped so we can set a new buffer limit.
+  PMM_loadFrameScripts(gBrowser);
+  yield PMM_stopProfiler();
+
+  // Keep the profiler's buffer small, to get to 100% really quickly.
+  Services.prefs.setIntPref(PROFILER_BUFFER_SIZE_PREF, 10000);
+
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { gFront, EVENTS, $, PerformanceController, PerformanceView } = panel.panelWin;
 
-  // Make sure the profiler module is stopped so we can set a new buffer limit
-  PMM_loadFrameScripts(gBrowser);
-  yield PMM_stopProfiler();
-  Services.prefs.setIntPref(PROFILER_BUFFER_SIZE_PREF, 1000);
   // Set a fast profiler-status update interval
   yield gFront.setProfilerStatusInterval(10);
 
+  let DETAILS_CONTAINER = $("#details-pane-container");
+  let NORMAL_BUFFER_STATUS_MESSAGE = $("#recording-notice .buffer-status-message");
+  let gPercent;
+
+  // Start a manual recording.
   yield startRecording(panel);
 
-  let percent = 0;
-  while (percent < 100) {
-    [,percent] = yield onceSpread(PerformanceView, EVENTS.UI_BUFFER_STATUS_UPDATED);
-  }
+  yield waitUntil(function*() {
+    [, gPercent] = yield once(PerformanceView, EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED, { spreadArgs: true });
+    return gPercent == 100;
+  });
+
+  ok(true, "Buffer percentage increased in display.");
 
   let bufferUsage = PerformanceController.getBufferUsageForRecording(PerformanceController.getCurrentRecording());
-  ok(bufferUsage, 1, "Buffer is full for this recording");
-  ok($("#details-pane-container").getAttribute("buffer-status"), "full",
-    "container has [buffer-status=full]");
+  ok(bufferUsage, 1, "Buffer is full for this recording.");
+  ok(DETAILS_CONTAINER.getAttribute("buffer-status"), "full",
+    "Container has [buffer-status=full].");
+  ok(NORMAL_BUFFER_STATUS_MESSAGE.value.indexOf(gPercent + "%") !== -1,
+    "Buffer status text has correct percentage.");
 
+  // Stop the manual recording.
   yield stopRecording(panel);
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+
+  PMM_clearFrameScripts();
+});
--- a/devtools/client/performance/test/browser_perf-recording-notices-05.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-05.js
@@ -1,46 +1,53 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
- * Tests that when a recording overlaps the circular buffer, that
- * a class is assigned to the recording notices.
+ * Tests that the circular buffer notices work when e10s is on/off.
  */
-function* spawnTest() {
-  let { panel } = yield initPerformance(SIMPLE_URL);
-  let { gFront, EVENTS, $, PerformanceController, PerformanceView } = panel.panelWin;
+
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
+  let { gFront, $, PerformanceController } = panel.panelWin;
 
   // Set a fast profiler-status update interval
   yield gFront.setProfilerStatusInterval(10);
 
   let supported = false;
   let enabled = false;
 
   PerformanceController.getMultiprocessStatus = () => {
     return { supported, enabled };
   };
 
   PerformanceController._setMultiprocessAttributes();
   ok($("#performance-view").getAttribute("e10s"), "unsupported",
-    "when e10s is disabled and no option to turn on, container has [e10s=unsupported]");
+    "When e10s is disabled and no option to turn on, container has [e10s=unsupported].");
 
   supported = true;
   enabled = false;
   PerformanceController._setMultiprocessAttributes();
   ok($("#performance-view").getAttribute("e10s"), "disabled",
-    "when e10s is disabled and but is supported, container has [e10s=disabled]");
+    "When e10s is disabled and but is supported, container has [e10s=disabled].");
 
   supported = false;
   enabled = true;
   PerformanceController._setMultiprocessAttributes();
   ok($("#performance-view").getAttribute("e10s"), "",
-    "when e10s is enabled, but not supported, this probably means we no longer have E10S_TESTING_ONLY, and we have no e10s attribute.");
+    "When e10s is enabled, but not supported, this probably means we no longer have E10S_TESTING_ONLY, and we have no e10s attribute.");
 
   supported = true;
   enabled = true;
   PerformanceController._setMultiprocessAttributes();
   ok($("#performance-view").getAttribute("e10s"), "",
-    "when e10s is enabled and supported, there should be no e10s attribute.");
+    "When e10s is enabled and supported, there should be no e10s attribute.");
 
-  yield teardown(panel);
-  finish();
-}
+  yield teardownToolboxAndRemoveTab(panel);
+});
--- a/devtools/client/performance/test/browser_perf-recording-selected-01.js
+++ b/devtools/client/performance/test/browser_perf-recording-selected-01.js
@@ -1,35 +1,44 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler correctly handles multiple recordings and can
  * successfully switch between them.
  */
 
-var test = Task.async(function*() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   is(RecordingsView.itemCount, 2,
     "There should be two recordings visible.");
   is(RecordingsView.selectedIndex, 1,
     "The second recording item should be selected.");
 
-  let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
-  yield select;
+  yield selected;
 
   is(RecordingsView.itemCount, 2,
     "There should still be two recordings visible.");
   is(RecordingsView.selectedIndex, 0,
     "The first recording item should be selected.");
 
-  yield teardown(panel);
-  finish();
+  yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-recording-selected-02.js
+++ b/devtools/client/performance/test/browser_perf-recording-selected-02.js
@@ -1,45 +1,58 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler correctly handles multiple recordings and can
  * successfully switch between them, even when one of them is in progress.
  */
 
-var test = Task.async(function*() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  // This test seems to take a very long time to finish on Linux VMs.
+  requestLongerTimeout(4);
+
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
 
   is(RecordingsView.itemCount, 2,
     "There should be two recordings visible.");
   is(RecordingsView.selectedIndex, 1,
     "The new recording item should be selected.");
 
-  let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
-  yield select;
+  yield selected;
 
   is(RecordingsView.itemCount, 2,
     "There should still be two recordings visible.");
   is(RecordingsView.selectedIndex, 0,
     "The first recording item should be selected now.");
 
-  select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+  selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 1;
-  yield select;
+  yield selected;
 
   is(RecordingsView.itemCount, 2,
     "There should still be two recordings visible.");
   is(RecordingsView.selectedIndex, 1,
     "The second recording item should be selected again.");
 
   yield stopRecording(panel);
 
-  yield teardown(panel);
-  finish();
+  yield teardownToolboxAndRemoveTab(panel);
 });
+
--- a/devtools/client/performance/test/browser_perf-recording-selected-03.js
+++ b/devtools/client/performance/test/browser_perf-recording-selected-03.js
@@ -1,33 +1,43 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests if the profiler UI does not forget that recording is active when
- * selected recording changes. Bug 1060885.
+ * selected recording changes.
  */
 
-var test = Task.async(function*() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
+const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
+const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
+const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { once } = require("devtools/client/performance/test/helpers/event-utils");
+
+add_task(function*() {
+  let { panel } = yield initPerformanceInNewTab({
+    url: SIMPLE_URL,
+    win: window
+  });
+
   let { $, EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
 
   info("Selecting recording #0 and waiting for it to be displayed.");
-  let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
+
+  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   RecordingsView.selectedIndex = 0;
-  yield select;
+  yield selected;
 
   ok($("#main-record-button").hasAttribute("checked"),
     "Button is still checked after selecting another item.");
-
   ok(!$("#main-record-button").hasAttribute("locked"),
     "Button is not locked after selecting another item.");
 
   yield stopRecording(panel);
-  yield teardown(panel);
-  finish();
+
+  yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-recording-selected-04.js
+++ b/devtools/client/performance/test/browser_perf-recording-selected-04.js
@@ -1,45 +1,58 @@
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 /**
  * Tests that all components can get rerendered for a profile when switching.
  */
 
-var test = Task.async(function*() {
-  let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
-  let { $, EVENTS, PerformanceController, DetailsView, DetailsSubview, RecordingsView } = panel.panelWin;
+const { SIMPLE_URL } = require