Bug 1302062 - Remove RecordingsView from tests; r?jsantell draft
authorGreg Tatum <tatum.creative@gmail.com>
Tue, 20 Sep 2016 09:50:35 -0500
changeset 415527 4ec9dcba8cfce187869212e71b286cb0264fa93b
parent 415526 129a2027ccd442dd734d38cce40cf800dd4accd9
child 415528 d5cc65dab977017bbe8f2733ef5d3ec3f441bc17
push id29895
push userbmo:gtatum@mozilla.com
push dateTue, 20 Sep 2016 15:20:17 +0000
reviewersjsantell
bugs1302062
milestone52.0a1
Bug 1302062 - Remove RecordingsView from tests; r?jsantell MozReview-Commit-ID: 9UM9empkroH
devtools/client/performance/test/browser_perf-calltree-js-events.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-details-03-without-allocations.js
devtools/client/performance/test/browser_perf-details-04-toolbar-buttons.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-options-show-jit-optimizations.js
devtools/client/performance/test/browser_perf-overview-render-04.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-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-tree-view-11.js
devtools/client/performance/test/helpers/moz.build
devtools/client/performance/test/helpers/recording-utils.js
--- a/devtools/client/performance/test/browser_perf-calltree-js-events.js
+++ b/devtools/client/performance/test/browser_perf-calltree-js-events.js
@@ -29,21 +29,28 @@ add_task(function* () {
   yield rendered;
 
   // 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.UI_JS_CALL_TREE_RENDERED);
 
+  let firstTreeItem = $("#js-calltree-view .call-tree-item");
+
+  // DE-XUL: There are focus issues with XUL. Focus first, then synthesize the clicks
+  // so that keyboard events work correctly.
+  firstTreeItem.focus();
+
   let count = 0;
   let onFocus = () => count++;
   JsCallTreeView.on("focus", onFocus);
 
-  click($("#js-calltree-view .call-tree-item"));
+  click(firstTreeItem);
+
   key("VK_DOWN");
   key("VK_DOWN");
   key("VK_DOWN");
   key("VK_DOWN");
 
   JsCallTreeView.off("focus", onFocus);
   is(count, 4, "Several focus events are fired for the calltree.");
 
--- a/devtools/client/performance/test/browser_perf-console-record-01.js
+++ b/devtools/client/performance/test/browser_perf-console-record-01.js
@@ -5,36 +5,39 @@
 /**
  * Tests if the profiler is populated by console recordings that have finished
  * before it was opened.
  */
 
 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 { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { target, console } = yield initConsoleInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
   yield console.profile("rust");
   yield console.profileEnd("rust");
 
   let { panel } = yield initPerformanceInTab({ tab: target.tab });
-  let { PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
+  let { PerformanceController, WaterfallView } = panel.panelWin;
 
   yield waitUntil(() => PerformanceController.getRecordings().length == 1);
   yield waitUntil(() => WaterfallView.wasRenderedAtLeastOnce);
 
   let recordings = PerformanceController.getRecordings();
   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],
+  const selected = getSelectedRecording(panel);
+
+  is(selected, recordings[0],
     "The profile from console should be selected as it's the only one.");
-  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+  is(selected.getLabel(), "rust",
     "The profile label for the first recording is correct.");
 
   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
@@ -8,43 +8,45 @@
  */
 
 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");
+const { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { target, console } = yield initConsoleInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
   yield console.profile("rust");
   yield console.profile("rust2");
 
   let { panel } = yield initPerformanceInTab({ tab: target.tab });
-  let { EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
+  let { EVENTS, PerformanceController, OverviewView } = 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(RecordingsView.selectedItem.attachment, recordings[0],
+  const selected = getSelectedRecording(panel);
+  is(selected, recordings[0],
     "The first console recording should be selected.");
-  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+  is(selected.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 }
   });
 
   let stopped = waitForRecordingStoppedEvents(panel, {
--- a/devtools/client/performance/test/browser_perf-console-record-03.js
+++ b/devtools/client/performance/test/browser_perf-console-record-03.js
@@ -6,45 +6,47 @@
  * Tests if the profiler is populated by in-progress console recordings, and
  * also console recordings that have finished before it was opened.
  */
 
 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 { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { target, console } = yield initConsoleInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
   yield console.profile("rust");
   yield console.profileEnd("rust");
   yield console.profile("rust2");
 
   let { panel } = yield initPerformanceInTab({ tab: target.tab });
-  let { PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
+  let { PerformanceController, WaterfallView } = panel.panelWin;
 
   yield waitUntil(() => PerformanceController.getRecordings().length == 2);
   yield waitUntil(() => WaterfallView.wasRenderedAtLeastOnce);
 
   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(RecordingsView.selectedItem.attachment, recordings[0],
+  const selected = getSelectedRecording(panel);
+  is(selected, recordings[0],
     "The first console recording should be selected.");
-  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+  is(selected.getLabel(), "rust",
     "The profile label for the first recording is correct.");
 
   let stopped = waitForRecordingStoppedEvents(panel, {
     // only emitted for manual recordings
     skipWaitingForBackendReady: true,
     // only emitted when a finished recording is selected
     skipWaitingForOverview: true,
     skipWaitingForSubview: true,
--- a/devtools/client/performance/test/browser_perf-console-record-04.js
+++ b/devtools/client/performance/test/browser_perf-console-record-04.js
@@ -7,42 +7,44 @@
  * after being opened.
  */
 
 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");
+const { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 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 { EVENTS, PerformanceController, OverviewView } = 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, "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],
+  const selected = getSelectedRecording(panel);
+  is(selected, recordings[0],
     "The profile from console should be selected as it's the only one.");
-  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+  is(selected.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 }
   });
 
   let stopped = waitForRecordingStoppedEvents(panel, {
--- a/devtools/client/performance/test/browser_perf-console-record-05.js
+++ b/devtools/client/performance/test/browser_perf-console-record-05.js
@@ -7,42 +7,44 @@
  * in the recording list.
  */
 
 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");
+const { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 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 { EVENTS, PerformanceController, OverviewView } = 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, "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],
+  let selected = getSelectedRecording(panel);
+  is(selected, recordings[0],
     "The profile from console should be selected as it's the only one.");
-  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+  is(selected.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 }
   });
 
   let stopped = waitForRecordingStoppedEvents(panel, {
@@ -65,19 +67,20 @@ add_task(function* () {
   yield started;
 
   recordings = PerformanceController.getRecordings();
   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],
+  selected = getSelectedRecording(panel);
+  is(selected, recordings[0],
     "The profile from console should still be selected");
-  is(RecordingsView.selectedItem.attachment.getLabel(), "rust",
+  is(selected.getLabel(), "rust",
     "The profile label for the first recording is correct.");
 
   stopped = waitForRecordingStoppedEvents(panel, {
     // only emitted for manual recordings
     skipWaitingForBackendReady: true,
     // only emitted when a finished recording is selected
     skipWaitingForOverview: true,
     skipWaitingForSubview: true,
--- a/devtools/client/performance/test/browser_perf-console-record-06.js
+++ b/devtools/client/performance/test/browser_perf-console-record-06.js
@@ -6,36 +6,37 @@
  * Tests that console recordings can overlap (not completely nested).
  */
 
 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");
+const { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 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 { EVENTS, PerformanceController, OverviewView } = 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(RecordingsView.selectedItem.attachment, recordings[0],
+  is(getSelectedRecording(panel), recordings[0],
     "The first console recording should be selected.");
 
   // Ensure overview is still rendering.
   yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
     expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
   });
 
   started = waitForRecordingStartedEvents(panel, {
@@ -47,49 +48,49 @@ add_task(function* () {
     // 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(RecordingsView.selectedItem.attachment, recordings[0],
+  is(getSelectedRecording(panel), recordings[0],
     "The first console recording should still be selected.");
 
   // Ensure overview is still rendering.
   yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
     expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
   });
 
   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(RecordingsView.selectedItem.attachment, recordings[0],
+  is(getSelectedRecording(panel), recordings[0],
     "The first console recording should still be selected.");
   is(recordings[0].isRecording(), false,
     "The first console recording should no longer be recording.");
 
   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(RecordingsView.selectedItem.attachment, recordings[0],
+  is(getSelectedRecording(panel), 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 teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-console-record-07.js
+++ b/devtools/client/performance/test/browser_perf-console-record-07.js
@@ -7,25 +7,26 @@
  * most recent console recording, and console.profileEnd() with a label that
  * does not match any pending recordings does nothing.
  */
 
 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");
+const { getSelectedRecording } = require("devtools/client/performance/test/helpers/recording-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 { PerformanceController } = panel.panelWin;
 
   let started = waitForRecordingStartedEvents(panel, {
     // only emitted for manual recordings
     skipWaitingForBackendReady: true
   });
   yield console.profile();
   yield started;
 
@@ -49,21 +50,22 @@ add_task(function* () {
     // 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();
+  let selected = getSelectedRecording(panel);
   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],
+  is(selected, recordings[0],
     "The first console recording should be selected.");
 
   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)");
@@ -76,35 +78,37 @@ add_task(function* () {
     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;
 
+  selected = getSelectedRecording(panel);
   recordings = PerformanceController.getRecordings();
   is(recordings.length, 3, "Three recordings found in the performance panel.");
-  is(RecordingsView.selectedItem.attachment, recordings[0],
+  is(selected, recordings[0],
     "The first console recording should still be selected.");
 
   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 the most recent recording should stop " +
     "when calling console.profileEnd with no args.");
 
   info("Trying to `profileEnd` a non-existent console recording.");
   console.profileEnd("fxos");
   yield idleWait(1000);
 
+  selected = getSelectedRecording(panel);
   recordings = PerformanceController.getRecordings();
   is(recordings.length, 3, "Three recordings found in the performance panel.");
-  is(RecordingsView.selectedItem.attachment, recordings[0],
+  is(selected, 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.");
@@ -117,38 +121,40 @@ add_task(function* () {
     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;
 
+  selected = getSelectedRecording(panel);
   recordings = PerformanceController.getRecordings();
   is(recordings.length, 3, "Three recordings found in the performance panel.");
-  is(RecordingsView.selectedItem.attachment, recordings[0],
+  is(selected, 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;
 
+  selected = getSelectedRecording(panel);
   recordings = PerformanceController.getRecordings();
   is(recordings.length, 3, "Three recordings found in the performance panel.");
-  is(RecordingsView.selectedItem.attachment, recordings[0],
+  is(selected, 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)");
--- a/devtools/client/performance/test/browser_perf-details-03-without-allocations.js
+++ b/devtools/client/performance/test/browser_perf-details-03-without-allocations.js
@@ -9,27 +9,27 @@
  * to a default panel instead.
  */
 
 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");
+const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 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']");
@@ -75,31 +75,31 @@ add_task(function* () {
   yield rendered;
 
   ok(DetailsView.isViewSelected(MemoryFlameGraphView),
     "The memory flamegraph view can now be 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;
+  setSelectedRecording(panel, 0);
   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;
+  setSelectedRecording(panel, 1);
   yield rendered;
 
   ok(DetailsView.isViewSelected(WaterfallView),
     "The waterfall view is still selected in the details view.");
 
   is(callBtn.hidden, false,
     "The `memory-calltree` button is shown when recording has memory data.");
   is(flameBtn.hidden, false,
--- a/devtools/client/performance/test/browser_perf-details-04-toolbar-buttons.js
+++ b/devtools/client/performance/test/browser_perf-details-04-toolbar-buttons.js
@@ -6,28 +6,28 @@
  * Tests that the details view hides the toolbar buttons when a recording
  * doesn't exist or is in progress.
  */
 
 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 { setSelectedRecording, getSelectedRecordingIndex } = require("devtools/client/performance/test/helpers/recording-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']");
@@ -79,39 +79,41 @@ add_task(function* () {
     "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 selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
   let rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield selected;
   yield rendered;
 
-  is(RecordingsView.selectedIndex, 0,
+  let selectedIndex = getSelectedRecordingIndex(panel);
+  is(selectedIndex, 0,
     "The first recording was selected again.");
 
   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.");
 
   selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 1;
+  setSelectedRecording(panel, 1);
   yield selected;
 
-  is(RecordingsView.selectedIndex, 1,
+  selectedIndex = getSelectedRecordingIndex(panel);
+  is(selectedIndex, 1,
     "The second recording was selected again.");
 
   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.");
@@ -119,17 +121,18 @@ add_task(function* () {
     "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.");
 
   rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
   yield stopRecording(panel);
   yield rendered;
 
-  is(RecordingsView.selectedIndex, 1,
+  selectedIndex = getSelectedRecordingIndex(panel);
+  is(selectedIndex, 1,
     "The second recording is still selected.");
 
   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.");
--- a/devtools/client/performance/test/browser_perf-loading-01.js
+++ b/devtools/client/performance/test/browser_perf-loading-01.js
@@ -6,46 +6,47 @@
  * Tests that the recordings view shows the right label while recording, after
  * recording, and once the record has loaded.
  */
 
 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 { getSelectedRecording, getDurationLabelText } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPerformanceInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
-  let { EVENTS, L10N, $, PerformanceController, RecordingsView } = panel.panelWin;
+  let { EVENTS, L10N, PerformanceController } = panel.panelWin;
 
   yield startRecording(panel);
 
-  let durationLabel = $(".recording-item-duration", RecordingsView.selectedItem.target);
-  is(durationLabel.getAttribute("value"),
+  is(getDurationLabelText(panel, 0),
     L10N.getStr("recordingsList.recordingLabel"),
     "The duration node should show the 'recording' message while recording");
 
   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 recordingStopping;
-  is(durationLabel.getAttribute("value"),
+  is(getDurationLabelText(panel, 0),
     L10N.getStr("recordingsList.loadingLabel"),
     "The duration node should show the 'loading' message while stopping");
 
   yield recordingStopped;
-  is(durationLabel.getAttribute("value"),
+  const selected = getSelectedRecording(panel);
+  is(getDurationLabelText(panel, 0),
     L10N.getFormatStr("recordingsList.durationLabel",
-    RecordingsView.selectedItem.attachment.getDuration().toFixed(0)),
+    selected.getDuration().toFixed(0)),
     "The duration node should show the duration after the record has stopped");
 
   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
@@ -8,24 +8,25 @@
  * Also test that the details view isn't locked if the recording that is being
  * stopped isn't the active one.
  */
 
 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 { getSelectedRecordingIndex, setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPerformanceInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
-  let { EVENTS, $, PerformanceController, RecordingsView } = panel.panelWin;
+  let { EVENTS, $, PerformanceController } = panel.panelWin;
   let detailsContainer = $("#details-pane-container");
   let recordingNotice = $("#recording-notice");
   let loadingNotice = $("#loading-notice");
   let detailsPane = $("#details-pane");
 
   yield startRecording(panel);
 
   is(detailsContainer.selectedPanel, recordingNotice,
@@ -47,35 +48,35 @@ add_task(function* () {
   is(detailsContainer.selectedPanel, detailsPane,
     "The details panel is shown after the record has stopped.");
 
   yield everythingStopped;
   yield startRecording(panel);
 
   info("While the 2nd record is still going, switch to the first one.");
   let recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield recordingSelected;
 
   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 recordingStopping;
   is(detailsContainer.selectedPanel, detailsPane,
     "The details panel is still shown while the 2nd record is being stopped.");
-  is(RecordingsView.selectedIndex, 0,
+  is(getSelectedRecordingIndex(panel), 0,
     "The first record is still selected.");
 
   yield recordingStopped;
 
   is(detailsContainer.selectedPanel, detailsPane,
     "The details panel is still shown after the 2nd record has stopped.");
-  is(RecordingsView.selectedIndex, 1,
+  is(getSelectedRecordingIndex(panel), 1,
     "The second record is now selected.");
 
   yield everythingStopped;
   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
@@ -4,23 +4,23 @@
 /* eslint-disable */
 // Bug 1235788, increase time out of this test
 requestLongerTimeout(2);
 
 /**
  * Tests that the JIT Optimizations view renders optimization data
  * if on, and displays selected frames on focus.
  */
-
+ const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 Services.prefs.setBoolPref(INVERT_PREF, false);
 
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
   let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
-  let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView, RecordingsView } = panel.panelWin;
+  let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView } = panel.panelWin;
 
   let profilerData = { threads: [gThread] };
 
   is(Services.prefs.getBoolPref(JIT_PREF), false, "record JIT Optimizations pref off by default");
   Services.prefs.setBoolPref(JIT_PREF, true);
   is(Services.prefs.getBoolPref(JIT_PREF), true, "toggle on record JIT Optimizations");
 
   // Make two recordings, so we have one to switch to later, as the
@@ -53,24 +53,24 @@ function* spawnTest() {
   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.UI_JS_CALL_TREE_RENDERED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 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.UI_JS_CALL_TREE_RENDERED);
-  RecordingsView.selectedIndex = 1;
+  setSelectedRecording(panel, 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");
 
--- a/devtools/client/performance/test/browser_perf-overview-render-04.js
+++ b/devtools/client/performance/test/browser_perf-overview-render-04.js
@@ -8,24 +8,25 @@
  */
 
 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");
+const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPerformanceInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
-  let { $, EVENTS, PerformanceController, RecordingsView, OverviewView } = panel.panelWin;
+  let { $, EVENTS, PerformanceController, OverviewView } = panel.panelWin;
 
   // Enable memory to test.
   Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
 
   // Set realtime rendering off.
   OverviewView.isRealtimeRenderingEnabled = () => false;
 
   let updated = 0;
@@ -48,22 +49,22 @@ add_task(function* () {
   is(updated, 1, "Overview graphs rendered upon completion.");
 
   yield startRecording(panel, { skipWaitingForOverview: true });
 
   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;
+  setSelectedRecording(panel, 0);
   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;
+  setSelectedRecording(panel, 1);
   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");
--- a/devtools/client/performance/test/browser_perf-recording-notices-02.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-02.js
@@ -6,29 +6,29 @@
  * Tests that the recording notice panes are toggled when going between
  * a completed recording and an in-progress recording.
  */
 
 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 { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-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 DETAILS_CONTAINER = $("#details-pane-container");
   let RECORDING = $("#recording-notice");
   let DETAILS = $("#details-pane");
 
@@ -37,26 +37,26 @@ add_task(function* () {
 
   yield startRecording(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 selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   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(DETAILS_CONTAINER.selectedPanel, DETAILS, "Showing recorded panel.");
 
   selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 1;
+  setSelectedRecording(panel, 1);
   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(DETAILS_CONTAINER.selectedPanel, RECORDING, "Showing recording panel.");
 
   yield stopRecording(panel);
--- a/devtools/client/performance/test/browser_perf-recording-notices-03.js
+++ b/devtools/client/performance/test/browser_perf-recording-notices-03.js
@@ -10,16 +10,17 @@
 
 const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
 const { PROFILER_BUFFER_SIZE_PREF } = require("devtools/client/performance/test/helpers/prefs");
 const { pmmLoadFrameScripts, pmmStopProfiler, pmmClearFrameScripts } = 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");
+const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   // Make sure the profiler module is stopped so we can set a new buffer limit.
   pmmLoadFrameScripts(gBrowser);
   yield pmmStopProfiler();
 
   // Keep the profiler's buffer large, but still get to 1% relatively quick.
   Services.prefs.setIntPref(PROFILER_BUFFER_SIZE_PREF, 1000000);
@@ -31,17 +32,16 @@ add_task(function* () {
 
   let { panel } = yield initPerformanceInTab({ tab: target.tab });
   let {
     gFront,
     EVENTS,
     $,
     PerformanceController,
     PerformanceView,
-    RecordingsView
   } = panel.panelWin;
 
   // 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 =
@@ -83,17 +83,17 @@ add_task(function* () {
     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.");
 
   // Select the console recording.
   let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 1;
+  setSelectedRecording(panel, 1);
   yield selected;
 
   yield waitUntil(function* () {
     [, gPercent] = yield once(PerformanceView,
                               EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED,
                               { spreadArgs: true });
     return gPercent > 0;
   });
@@ -104,17 +104,17 @@ add_task(function* () {
     "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");
 
   selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield selected;
 
   yield waitUntil(function* () {
     [, gPercent] = yield once(PerformanceView,
                               EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED,
                               { spreadArgs: true });
     return gPercent > Math.floor(bufferUsage * 100);
   });
--- a/devtools/client/performance/test/browser_perf-recording-selected-01.js
+++ b/devtools/client/performance/test/browser_perf-recording-selected-01.js
@@ -6,39 +6,40 @@
  * Tests if the profiler correctly handles multiple recordings and can
  * successfully switch between them.
  */
 
 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 { setSelectedRecording, getRecordingsCount, getSelectedRecordingIndex } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPerformanceInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
-  let { EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
+  let { EVENTS, PerformanceController } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  is(RecordingsView.itemCount, 2,
+  is(getRecordingsCount(panel), 2,
     "There should be two recordings visible.");
-  is(RecordingsView.selectedIndex, 1,
+  is(getSelectedRecordingIndex(panel), 1,
     "The second recording item should be selected.");
 
   let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield selected;
 
-  is(RecordingsView.itemCount, 2,
+  is(getRecordingsCount(panel), 2,
     "There should still be two recordings visible.");
-  is(RecordingsView.selectedIndex, 0,
+  is(getSelectedRecordingIndex(panel), 0,
     "The first recording item should be selected.");
 
   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
@@ -6,53 +6,53 @@
  * Tests if the profiler correctly handles multiple recordings and can
  * successfully switch between them, even when one of them is in progress.
  */
 
 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 { getSelectedRecordingIndex, setSelectedRecording, getRecordingsCount } = require("devtools/client/performance/test/helpers/recording-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;
+  let { EVENTS, PerformanceController } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
 
-  is(RecordingsView.itemCount, 2,
+  is(getRecordingsCount(panel), 2,
     "There should be two recordings visible.");
-  is(RecordingsView.selectedIndex, 1,
+  is(getSelectedRecordingIndex(panel), 1,
     "The new recording item should be selected.");
 
   let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield selected;
 
-  is(RecordingsView.itemCount, 2,
+  is(getRecordingsCount(panel), 2,
     "There should still be two recordings visible.");
-  is(RecordingsView.selectedIndex, 0,
+  is(getSelectedRecordingIndex(panel), 0,
     "The first recording item should be selected now.");
 
   selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 1;
+  setSelectedRecording(panel, 1);
   yield selected;
 
-  is(RecordingsView.itemCount, 2,
+  is(getRecordingsCount(panel), 2,
     "There should still be two recordings visible.");
-  is(RecordingsView.selectedIndex, 1,
+  is(getSelectedRecordingIndex(panel), 1,
     "The second recording item should be selected again.");
 
   yield stopRecording(panel);
 
   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
@@ -7,34 +7,35 @@
  * Tests if the profiler UI does not forget that recording is active when
  * selected recording changes.
  */
 
 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 { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPerformanceInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
-  let { $, EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
+  let { $, EVENTS, PerformanceController } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   yield startRecording(panel);
 
   info("Selecting recording #0 and waiting for it to be displayed.");
 
   let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield selected;
 
   ok($("#main-record-button").classList.contains("checked"),
     "Button is still checked after selecting another item.");
   ok(!$("#main-record-button").hasAttribute("disabled"),
     "Button is not locked after selecting another item.");
 
   yield stopRecording(panel);
--- a/devtools/client/performance/test/browser_perf-recording-selected-04.js
+++ b/devtools/client/performance/test/browser_perf-recording-selected-04.js
@@ -5,24 +5,25 @@
 /**
  * Tests that all components can get rerendered for a profile when switching.
  */
 
 const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
 const { UI_ENABLE_MEMORY_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, waitForAllWidgetsRendered } = require("devtools/client/performance/test/helpers/actions");
+const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPerformanceInNewTab({
     url: SIMPLE_URL,
     win: window
   });
 
-  let { DetailsView, DetailsSubview, RecordingsView } = panel.panelWin;
+  let { DetailsView, DetailsSubview } = panel.panelWin;
 
   // Enable memory to test the memory overview.
   Services.prefs.setBoolPref(UI_ENABLE_MEMORY_PREF, true);
 
   // Enable allocations to test the memory-calltree and memory-flamegraph.
   Services.prefs.setBoolPref(UI_ENABLE_ALLOCATIONS_PREF, true);
 
   yield startRecording(panel);
@@ -38,21 +39,21 @@ add_task(function* () {
   yield DetailsView.selectView("js-flamegraph");
   yield DetailsView.selectView("memory-calltree");
   yield DetailsView.selectView("memory-flamegraph");
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
   let rerender = waitForAllWidgetsRendered(panel);
-  RecordingsView.selectedIndex = 0;
+  setSelectedRecording(panel, 0);
   yield rerender;
 
   ok(true, "All widgets were rendered when selecting the first recording.");
 
   rerender = waitForAllWidgetsRendered(panel);
-  RecordingsView.selectedIndex = 1;
+  setSelectedRecording(panel, 1);
   yield rerender;
 
   ok(true, "All widgets were rendered when selecting the second recording.");
 
   yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-recordings-clear-01.js
+++ b/devtools/client/performance/test/browser_perf-recordings-clear-01.js
@@ -5,49 +5,50 @@
 /**
  * Tests that clearing recordings empties out the recordings list and toggles
  * the empty notice state.
  */
 
 const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
 const { initPanelInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
 const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
+const { getRecordingsCount } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPanelInNewTab({
     tool: "performance",
     url: SIMPLE_URL,
     win: window
   });
 
-  let { PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
+  let { PerformanceController, PerformanceView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  is(RecordingsView.itemCount, 1,
-    "RecordingsView should have one recording.");
+  is(getRecordingsCount(panel), 1,
+    "The recordings list should have one recording.");
   isnot(PerformanceView.getState(), "empty",
     "PerformanceView should not be in an empty state.");
   isnot(PerformanceController.getCurrentRecording(), null,
     "There should be a current recording.");
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  is(RecordingsView.itemCount, 2,
-    "RecordingsView should have two recordings.");
+  is(getRecordingsCount(panel), 2,
+    "The recordings list should have two recordings.");
   isnot(PerformanceView.getState(), "empty",
     "PerformanceView should not be in an empty state.");
   isnot(PerformanceController.getCurrentRecording(), null,
     "There should be a current recording.");
 
   yield PerformanceController.clearRecordings();
 
-  is(RecordingsView.itemCount, 0,
-    "RecordingsView should be empty.");
+  is(getRecordingsCount(panel), 0,
+    "The recordings list should be empty.");
   is(PerformanceView.getState(), "empty",
     "PerformanceView should be in an empty state.");
   is(PerformanceController.getCurrentRecording(), null,
     "There should be no current recording.");
 
   yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-recordings-clear-02.js
+++ b/devtools/client/performance/test/browser_perf-recordings-clear-02.js
@@ -6,63 +6,64 @@
  * Tests that clearing recordings empties out the recordings list and stops
  * a current recording if recording and can continue recording after.
  */
 
 const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
 const { initPanelInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
 const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
 const { times, once } = require("devtools/client/performance/test/helpers/event-utils");
+const { getRecordingsCount } = require("devtools/client/performance/test/helpers/recording-utils");
 
 add_task(function* () {
   let { panel } = yield initPanelInNewTab({
     tool: "performance",
     url: SIMPLE_URL,
     win: window
   });
 
-  let { EVENTS, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
+  let { EVENTS, PerformanceController, PerformanceView } = panel.panelWin;
 
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  is(RecordingsView.itemCount, 1,
-    "RecordingsView should have one recording.");
+  is(getRecordingsCount(panel), 1,
+    "The recordings list should have one recording.");
   isnot(PerformanceView.getState(), "empty",
     "PerformanceView should not be in an empty state.");
   isnot(PerformanceController.getCurrentRecording(), null,
     "There should be a current recording.");
 
   yield startRecording(panel);
 
-  is(RecordingsView.itemCount, 2,
-    "RecordingsView should have two recordings.");
+  is(getRecordingsCount(panel), 2,
+    "The recordings list should have two recordings.");
   isnot(PerformanceView.getState(), "empty",
     "PerformanceView should not be in an empty state.");
   isnot(PerformanceController.getCurrentRecording(), null,
     "There should be a current recording.");
 
   let recordingDeleted = times(PerformanceController, EVENTS.RECORDING_DELETED, 2);
   let recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
     expectedArgs: { "1": "recording-stopped" }
   });
 
   PerformanceController.clearRecordings();
 
   yield recordingDeleted;
   yield recordingStopped;
 
-  is(RecordingsView.itemCount, 0,
-    "RecordingsView should be empty.");
+  is(getRecordingsCount(panel), 0,
+    "The recordings list should be empty.");
   is(PerformanceView.getState(), "empty",
     "PerformanceView should be in an empty state.");
   is(PerformanceController.getCurrentRecording(), null,
     "There should be no current recording.");
 
   // Bug 1169146: Try another recording after clearing mid-recording.
   yield startRecording(panel);
   yield stopRecording(panel);
 
-  is(RecordingsView.itemCount, 1,
-    "RecordingsView should have one recording.");
+  is(getRecordingsCount(panel), 1,
+    "The recordings list should have one recording.");
 
   yield teardownToolboxAndRemoveTab(panel);
 });
--- a/devtools/client/performance/test/browser_perf-tree-view-11.js
+++ b/devtools/client/performance/test/browser_perf-tree-view-11.js
@@ -7,17 +7,17 @@
  * icon is next to the frame with optimizations
  */
 
 var { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
 
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
   let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
-  let { OverviewView, DetailsView, JsCallTreeView, RecordingsView } = panel.panelWin;
+  let { OverviewView, DetailsView, JsCallTreeView } = panel.panelWin;
 
   let profilerData = { threads: [gThread] };
 
   Services.prefs.setBoolPref(JIT_PREF, true);
   Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
   Services.prefs.setBoolPref(INVERT_PREF, false);
 
   // Make two recordings, so we have one to switch to later, as the
--- a/devtools/client/performance/test/helpers/moz.build
+++ b/devtools/client/performance/test/helpers/moz.build
@@ -7,13 +7,14 @@
 DevToolsModules(
     'actions.js',
     'dom-utils.js',
     'event-utils.js',
     'input-utils.js',
     'panel-utils.js',
     'prefs.js',
     'profiler-mm-utils.js',
+    'recording-utils.js',
     'synth-utils.js',
     'tab-utils.js',
     'urls.js',
     'wait-utils.js',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/test/helpers/recording-utils.js
@@ -0,0 +1,54 @@
+/* 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";
+
+/**
+ * These utilities provide a functional interface for accessing the particulars
+ * about the recording's details.
+ */
+
+/**
+ * Access the selected view from the panel's recording list.
+ *
+ * @param {object} panel - The current panel.
+ * @return {object} The recording model.
+ */
+exports.getSelectedRecording = function (panel) {
+  const view = panel.panelWin.RecordingsView;
+  return view.selected;
+};
+
+/**
+ * Set the selected index of the recording via the panel.
+ *
+ * @param {object} panel - The current panel.
+ * @return {number} index
+ */
+exports.setSelectedRecording = function (panel, index) {
+  const view = panel.panelWin.RecordingsView;
+  view.setSelectedByIndex(index);
+  return index;
+};
+
+/**
+ * Access the selected view from the panel's recording list.
+ *
+ * @param {object} panel - The current panel.
+ * @return {number} index
+ */
+exports.getSelectedRecordingIndex = function (panel) {
+  const view = panel.panelWin.RecordingsView;
+  return view.getSelectedIndex();
+};
+
+exports.getDurationLabelText = function (panel, elementIndex) {
+  const { $$ } = panel.panelWin;
+  const elements = $$(".recording-list-item-duration", panel.panelWin.document);
+  return elements[elementIndex].innerHTML;
+};
+
+exports.getRecordingsCount = function (panel) {
+  const { $$ } = panel.panelWin;
+  return $$(".recording-list-item", panel.panelWin.document).length;
+};