add_task(async function() {
  const { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window
  });

  const { $, 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;
  OverviewView.on(EVENTS.UI_OVERVIEW_RENDERED, () => updated++);

  await startRecording(panel, { skipWaitingForOverview: true });

  is(isVisible($("#overview-pane")), false, "Overview graphs hidden.");
  is(updated, 0, "Overview graphs have not been updated");

  await waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
  await waitUntil(() => PerformanceController.getCurrentRecording().getMemory().length);
  await waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
  is(isVisible($("#overview-pane")), false, "Overview graphs still hidden.");
  is(updated, 0, "Overview graphs have still not been updated");

  await stopRecording(panel);

  is(isVisible($("#overview-pane")), true, "Overview graphs no longer hidden.");
  is(updated, 1, "Overview graphs rendered upon completion.");

  await 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.");

  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.");

  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.");

  await stopRecording(panel);

  is(isVisible($("#overview-pane")), true,
     "overview graphs no longer hidden when recording finishes");
  is(updated, 2, "Overview graphs rendered again upon completion.");

  await teardownToolboxAndRemoveTab(panel);
});
add_task(async function() {
  const { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window,
  });

  const {
    EVENTS,
    $,
    PerformanceController,
    PerformanceView,
  } = panel.panelWin;

  const MAIN_CONTAINER = $("#performance-view");
  const CONTENT = $("#performance-view-content");
  const DETAILS_CONTAINER = $("#details-pane-container");
  const RECORDING = $("#recording-notice");
  const DETAILS = $("#details-pane");

  await startRecording(panel);
  await stopRecording(panel);

  await 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);
  setSelectedRecording(panel, 0);
  await 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);
  setSelectedRecording(panel, 1);
  await 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.");

  await stopRecording(panel);

  await teardownToolboxAndRemoveTab(panel);
});
add_task(async function() {
  const { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window,
  });

  const { EVENTS, PerformanceController } = panel.panelWin;

  await startRecording(panel);
  await stopRecording(panel);

  await startRecording(panel);
  await stopRecording(panel);

  is(getRecordingsCount(panel), 2,
    "There should be two recordings visible.");
  is(getSelectedRecordingIndex(panel), 1,
    "The second recording item should be selected.");

  const selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 0);
  await selected;

  is(getRecordingsCount(panel), 2,
    "There should still be two recordings visible.");
  is(getSelectedRecordingIndex(panel), 0,
    "The first recording item should be selected.");

  await teardownToolboxAndRemoveTab(panel);
});
add_task(async function() {
  let { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window
  });

  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);

  await startRecording(panel);
  await stopRecording(panel);

  // Ållow widgets to be updated while hidden, to make testing easier.
  DetailsSubview.canUpdateWhileHidden = true;

  // Cycle through all the views to initialize them. The waterfall is shown
  // by default, but all the other views are created lazily, so won't emit
  // any events.
  await DetailsView.selectView("js-calltree");
  await DetailsView.selectView("js-flamegraph");
  await DetailsView.selectView("memory-calltree");
  await DetailsView.selectView("memory-flamegraph");

  await startRecording(panel);
  await stopRecording(panel);

  let rerender = waitForAllWidgetsRendered(panel);
  setSelectedRecording(panel, 0);
  await rerender;

  ok(true, "All widgets were rendered when selecting the first recording.");

  rerender = waitForAllWidgetsRendered(panel);
  setSelectedRecording(panel, 1);
  await rerender;

  ok(true, "All widgets were rendered when selecting the second recording.");

  await teardownToolboxAndRemoveTab(panel);
});
add_task(async function() {
  // This test seems to take a very long time to finish on Linux VMs.
  requestLongerTimeout(4);

  const { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window
  });

  const { EVENTS, PerformanceController } = panel.panelWin;

  await startRecording(panel);
  await stopRecording(panel);

  await startRecording(panel);

  is(getRecordingsCount(panel), 2,
    "There should be two recordings visible.");
  is(getSelectedRecordingIndex(panel), 1,
    "The new recording item should be selected.");

  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 0);
  await selected;

  is(getRecordingsCount(panel), 2,
    "There should still be two recordings visible.");
  is(getSelectedRecordingIndex(panel), 0,
    "The first recording item should be selected now.");

  selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 1);
  await selected;

  is(getRecordingsCount(panel), 2,
    "There should still be two recordings visible.");
  is(getSelectedRecordingIndex(panel), 1,
    "The second recording item should be selected again.");

  await stopRecording(panel);

  await teardownToolboxAndRemoveTab(panel);
});
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);

  let { target, console } = yield initConsoleInNewTab({
    url: SIMPLE_URL,
    win: window
  });

  let { panel } = yield initPerformanceInTab({ tab: target.tab });
  let {
    gFront,
    EVENTS,
    $,
    PerformanceController,
    PerformanceView,
  } = 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 =
    $("#console-recording-notice .buffer-status-message");
  let gPercent;

  // Start a manual recording.
  yield startRecording(panel);

  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());
  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.includes(gPercent + "%"),
    "Buffer status text has correct percentage.");

  // Start a console profile.
  yield console.profile("rust");

  yield waitUntil(function* () {
    [, gPercent] = yield once(PerformanceView,
                              EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED,
                              { spreadArgs: true });
    return gPercent > Math.floor(bufferUsage * 100);
  });

  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.includes(gPercent + "%"),
    "Buffer status text has correct percentage.");

  // Select the console recording.
  let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 1);
  yield selected;

  yield waitUntil(function* () {
    [, gPercent] = yield once(PerformanceView,
                              EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED,
                              { spreadArgs: true });
    return gPercent > 0;
  });

  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.includes(gPercent + "%"),
    "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);
  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);
  });

  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.includes(gPercent + "%"),
    "Buffer status text has correct percentage.");

  // Stop the manual recording.
  yield stopRecording(panel);

  yield teardownToolboxAndRemoveTab(panel);

  pmmClearFrameScripts();
});
add_task(async function() {
  const { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window,
  });

  const { EVENTS, $, PerformanceController } = panel.panelWin;
  const detailsContainer = $("#details-pane-container");
  const recordingNotice = $("#recording-notice");
  const loadingNotice = $("#loading-notice");
  const detailsPane = $("#details-pane");

  await startRecording(panel);

  is(detailsContainer.selectedPanel, recordingNotice,
    "The recording-notice is shown while recording.");

  let recordingStopping = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
    expectedArgs: ["recording-stopping"],
  });
  let recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
    expectedArgs: ["recording-stopped"],
  });
  let everythingStopped = stopRecording(panel);

  await recordingStopping;
  is(detailsContainer.selectedPanel, loadingNotice,
    "The loading-notice is shown while the record is stopping.");

  await recordingStopped;
  is(detailsContainer.selectedPanel, detailsPane,
    "The details panel is shown after the record has stopped.");

  await everythingStopped;
  await startRecording(panel);

  info("While the 2nd record is still going, switch to the first one.");
  const recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 0);
  await recordingSelected;

  recordingStopping = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
    expectedArgs: ["recording-stopping"],
  });
  recordingStopped = once(PerformanceController, EVENTS.RECORDING_STATE_CHANGE, {
    expectedArgs: ["recording-stopped"],
  });
  everythingStopped = stopRecording(panel);

  await recordingStopping;
  is(detailsContainer.selectedPanel, detailsPane,
    "The details panel is still shown while the 2nd record is being stopped.");
  is(getSelectedRecordingIndex(panel), 0,
    "The first record is still selected.");

  await recordingStopped;

  is(detailsContainer.selectedPanel, detailsPane,
    "The details panel is still shown after the 2nd record has stopped.");
  is(getSelectedRecordingIndex(panel), 1,
    "The second record is now selected.");

  await everythingStopped;
  await teardownToolboxAndRemoveTab(panel);
});
add_task(async function() {
  const { panel } = await initPerformanceInNewTab({
    url: SIMPLE_URL,
    win: window,
  });

  const {
    EVENTS,
    $,
    PerformanceController,
    WaterfallView,
  } = panel.panelWin;

  const waterfallBtn = $("toolbarbutton[data-view='waterfall']");
  const jsFlameBtn = $("toolbarbutton[data-view='js-flamegraph']");
  const jsCallBtn = $("toolbarbutton[data-view='js-calltree']");
  const memFlameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
  const memCallBtn = $("toolbarbutton[data-view='memory-calltree']");

  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.");

  await startRecording(panel);

  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.");

  await stopRecording(panel);

  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.");

  await startRecording(panel);

  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 selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  let rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
  setSelectedRecording(panel, 0);
  await selected;
  await rendered;

  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);
  setSelectedRecording(panel, 1);
  await selected;

  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.");
  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.");

  rendered = once(WaterfallView, EVENTS.UI_WATERFALL_RENDERED);
  await stopRecording(panel);
  await rendered;

  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.");
  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.");

  await teardownToolboxAndRemoveTab(panel);
});
add_task(async function() {
  // This test seems to take a very long time to finish on Linux VMs.
  requestLongerTimeout(4);

  const { target, console } = await initConsoleInNewTab({
    url: SIMPLE_URL,
    win: window
  });

  const { panel } = await initPerformanceInTab({ tab: target.tab });
  const { EVENTS, PerformanceController, OverviewView } = panel.panelWin;

  info("Recording 1 - Starting console.profile()...");
  let started = waitForRecordingStartedEvents(panel, {
    // only emitted for manual recordings
    skipWaitingForBackendReady: true
  });
  await console.profile("rust");
  await started;
  testRecordings(PerformanceController, [
    CONSOLE + SELECTED + RECORDING
  ]);

  info("Recording 2 - Starting manual recording...");
  await startRecording(panel);
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL + RECORDING + SELECTED
  ]);

  info("Recording 3 - Starting console.profile(\"3\")...");
  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,
  });
  await console.profile("3");
  await started;
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL + RECORDING + SELECTED,
    CONSOLE + RECORDING
  ]);

  info("Recording 4 - 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,
  });
  await console.profile("4");
  await started;
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL + RECORDING + SELECTED,
    CONSOLE + RECORDING,
    CONSOLE + RECORDING
  ]);

  info("Recording 4 - Ending console.profileEnd()...");
  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,
  });
  await console.profileEnd();
  await stopped;
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL + RECORDING + SELECTED,
    CONSOLE + RECORDING,
    CONSOLE
  ]);

  info("Recording 4 - Select last recording...");
  let recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 3);
  await recordingSelected;
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL + RECORDING,
    CONSOLE + RECORDING,
    CONSOLE + SELECTED
  ]);
  ok(!OverviewView.isRendering(),
    "Stop rendering overview when a completed recording is selected.");

  info("Recording 2 - Stop manual recording.");

  await stopRecording(panel);
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL + SELECTED,
    CONSOLE + RECORDING,
    CONSOLE
  ]);
  ok(!OverviewView.isRendering(),
    "Stop rendering overview when a completed recording is selected.");

  info("Recording 1 - Select first recording.");
  recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
  setSelectedRecording(panel, 0);
  await recordingSelected;
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING + SELECTED,
    MANUAL,
    CONSOLE + RECORDING,
    CONSOLE
  ]);
  ok(OverviewView.isRendering(),
    "Should be rendering overview a recording in progress is selected.");

  // Ensure overview is still rendering.
  await times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
    expectedArgs: [Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL]
  });

  info("Ending console.profileEnd()...");
  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,
  });
  await console.profileEnd();
  await stopped;
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING + SELECTED,
    MANUAL,
    CONSOLE,
    CONSOLE
  ]);
  ok(OverviewView.isRendering(),
    "Should be rendering overview a recording in progress is selected.");

  // Ensure overview is still rendering.
  await times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
    expectedArgs: [Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL]
  });

  info("Recording 5 - Start one more manual recording.");
  await startRecording(panel);
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL,
    CONSOLE,
    CONSOLE,
    MANUAL + RECORDING + SELECTED
  ]);
  ok(OverviewView.isRendering(),
    "Should be rendering overview a recording in progress is selected.");

  // Ensure overview is still rendering.
  await times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
    expectedArgs: [Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL]
  });

  info("Recording 5 - Stop manual recording.");
  await stopRecording(panel);
  testRecordings(PerformanceController, [
    CONSOLE + RECORDING,
    MANUAL,
    CONSOLE,
    CONSOLE,
    MANUAL + SELECTED
  ]);
  ok(!OverviewView.isRendering(),
  "Stop rendering overview when a completed recording is selected.");

  info("Recording 1 - Ending console.profileEnd()...");
  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,
  });
  await console.profileEnd();
  await stopped;
  testRecordings(PerformanceController, [
    CONSOLE,
    MANUAL,
    CONSOLE,
    CONSOLE,
    MANUAL + SELECTED
  ]);
  ok(!OverviewView.isRendering(),
    "Stop rendering overview when a completed recording is selected.");

  await teardownToolboxAndRemoveTab(panel);
});