--- a/devtools/client/performance/components/moz.build
+++ b/devtools/client/performance/components/moz.build
@@ -3,15 +3,17 @@
# 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/.
DevToolsModules(
'jit-optimizations-item.js',
'jit-optimizations.js',
'recording-button.js',
'recording-controls.js',
+ 'recording-list-item.js',
+ 'recording-list.js',
'waterfall-header.js',
'waterfall-tree-row.js',
'waterfall-tree.js',
'waterfall.js',
)
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/components/recording-list-item.js
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const {DOM, createClass} = require("devtools/client/shared/vendor/react");
+const {div, li, span, button} = DOM;
+const {L10N} = require("devtools/client/performance/modules/global");
+
+module.exports = createClass({
+ displayName: "Recording List Item",
+
+ render() {
+ const {
+ label,
+ duration,
+ onSelect,
+ onSave,
+ isLoading,
+ isSelected,
+ isRecording
+ } = this.props;
+
+ const className = `recording-list-item ${isSelected ? "selected" : ""}`;
+
+ let durationText;
+ if (isLoading) {
+ durationText = L10N.getStr("recordingsList.loadingLabel");
+ } else if (isRecording) {
+ durationText = L10N.getStr("recordingsList.recordingLabel");
+ } else {
+ durationText = L10N.getFormatStr("recordingsList.durationLabel", duration);
+ }
+
+ return (
+ li({ className, onClick: onSelect },
+ div({ className: "recording-list-item-label" },
+ label
+ ),
+ div({ className: "recording-list-item-footer" },
+ span({ className: "recording-list-item-duration" }, durationText),
+ button({ className: "recording-list-item-save", onClick: onSave },
+ L10N.getStr("recordingsList.saveLabel")
+ )
+ )
+ )
+ );
+ }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/components/recording-list.js
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const {DOM, createClass} = require("devtools/client/shared/vendor/react");
+const {L10N} = require("devtools/client/performance/modules/global");
+const {ul, div} = DOM;
+
+module.exports = createClass({
+ displayName: "Recording List",
+
+ render() {
+ const {
+ items,
+ itemComponent: Item,
+ } = this.props;
+
+ return items.length > 0
+ ? ul({ className: "recording-list" }, ...items.map(Item))
+ : div({ className: "recording-list-empty" }, L10N.getStr("noRecordingsText"));
+ }
+});
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -22,23 +22,26 @@ var { gDevTools } = require("devtools/cl
var EVENTS = require("devtools/client/performance/events");
Object.defineProperty(this, "EVENTS", {
value: EVENTS,
enumerable: true,
writable: false
});
/* exported React, ReactDOM, JITOptimizationsView, RecordingControls, RecordingButton,
- Waterfall, Services, promise, EventEmitter, DevToolsUtils, system */
+ RecordingList, RecordingListItem, Services, Waterfall, promise, EventEmitter,
+ DevToolsUtils, system */
var React = require("devtools/client/shared/vendor/react");
var ReactDOM = require("devtools/client/shared/vendor/react-dom");
var Waterfall = React.createFactory(require("devtools/client/performance/components/waterfall"));
var JITOptimizationsView = React.createFactory(require("devtools/client/performance/components/jit-optimizations"));
var RecordingControls = React.createFactory(require("devtools/client/performance/components/recording-controls"));
var RecordingButton = React.createFactory(require("devtools/client/performance/components/recording-button"));
+var RecordingList = React.createFactory(require("devtools/client/performance/components/recording-list"));
+var RecordingListItem = React.createFactory(require("devtools/client/performance/components/recording-list-item"));
var Services = require("Services");
var promise = require("promise");
var EventEmitter = require("devtools/shared/event-emitter");
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
var flags = require("devtools/shared/flags");
var system = require("devtools/shared/system");
--- a/devtools/client/performance/performance.xul
+++ b/devtools/client/performance/performance.xul
@@ -79,17 +79,19 @@
<hbox id="body" class="theme-body performance-tool" flex="1">
<!-- Sidebar: controls and recording list -->
<vbox id="recordings-pane">
<hbox id="recordings-controls">
<html:div id='recording-controls-mount'/>
</hbox>
- <vbox id="recordings-list" class="theme-sidebar" flex="1"/>
+ <vbox id="recordings-list" class="theme-sidebar" flex="1">
+ <html:div id="recording-list-mount"/>
+ </vbox>
</vbox>
<!-- Main panel content -->
<vbox id="performance-pane" flex="1">
<!-- Top toolbar controls -->
<toolbar id="performance-toolbar"
class="devtools-toolbar">
--- 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-console-record-08.js
+++ b/devtools/client/performance/test/browser_perf-console-record-08.js
@@ -8,104 +8,164 @@
*/
const { Constants } = require("devtools/client/performance/modules/constants");
const { SIMPLE_URL } = require("devtools/client/performance/test/helpers/urls");
const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab } = require("devtools/client/performance/test/helpers/panel-utils");
const { startRecording, stopRecording } = require("devtools/client/performance/test/helpers/actions");
const { waitForRecordingStartedEvents, waitForRecordingStoppedEvents } = require("devtools/client/performance/test/helpers/actions");
const { once, times } = require("devtools/client/performance/test/helpers/event-utils");
+const { setSelectedRecording } = require("devtools/client/performance/test/helpers/recording-utils");
+
+/**
+ * The following are bit flag constants that are used to represent the state of a
+ * recording.
+ */
+
+// Represents a manually recorded profile, if a user hit the record button.
+const MANUAL = 0;
+// Represents a recorded profile from console.profile().
+const CONSOLE = 1;
+// Represents a profile that is currently recording.
+const RECORDING = 2;
+// Represents a profile that is currently selected.
+const SELECTED = 4;
+
+/**
+ * Utility function to provide a meaningful inteface for testing that the bits
+ * match for the recording state.
+ * @param {integer} expected - The expected bit values packed in an integer.
+ * @param {integer} actual - The actual bit values packed in an integer.
+ */
+function hasBitFlag(expected, actual) {
+ return !!(expected & actual);
+}
add_task(function* () {
// This test seems to take a very long time to finish on Linux VMs.
requestLongerTimeout(4);
let { target, console } = yield initConsoleInNewTab({
url: SIMPLE_URL,
win: window
});
let { panel } = yield initPerformanceInTab({ tab: target.tab });
- let { EVENTS, PerformanceController, RecordingsView, OverviewView } = panel.panelWin;
+ let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
- info("Starting console.profile()...");
+ info("Recording 1 - Starting console.profile()...");
let started = waitForRecordingStartedEvents(panel, {
// only emitted for manual recordings
skipWaitingForBackendReady: true
});
yield console.profile("rust");
yield started;
- testRecordings(PerformanceController, [C + S + R]);
+ testRecordings(PerformanceController, [
+ CONSOLE + SELECTED + RECORDING
+ ]);
- info("Starting manual recording...");
+ info("Recording 2 - Starting manual recording...");
yield startRecording(panel);
- testRecordings(PerformanceController, [C + R, R + S]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL + RECORDING + SELECTED
+ ]);
- info("Starting console.profile(\"3\")...");
+ 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,
});
yield console.profile("3");
yield started;
- testRecordings(PerformanceController, [C + R, R + S, C + R]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL + RECORDING + SELECTED,
+ CONSOLE + RECORDING
+ ]);
- info("Starting console.profile(\"4\")...");
+ 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,
});
yield console.profile("4");
yield started;
- testRecordings(PerformanceController, [C + R, R + S, C + R, C + R]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL + RECORDING + SELECTED,
+ CONSOLE + RECORDING,
+ CONSOLE + RECORDING
+ ]);
- info("Ending console.profileEnd()...");
+ 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,
});
yield console.profileEnd();
yield stopped;
- testRecordings(PerformanceController, [C + R, R + S, C + R, C]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL + RECORDING + SELECTED,
+ CONSOLE + RECORDING,
+ CONSOLE
+ ]);
- info("Select last recording...");
+ info("Recording 4 - Select last recording...");
let recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
- RecordingsView.selectedIndex = 3;
+ setSelectedRecording(panel, 3);
yield recordingSelected;
- testRecordings(PerformanceController, [C + R, R, C + R, C + S]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL + RECORDING,
+ CONSOLE + RECORDING,
+ CONSOLE + SELECTED
+ ]);
ok(!OverviewView.isRendering(),
"Stop rendering overview when a completed recording is selected.");
- info("Stop manual recording...");
+ info("Recording 2 - Stop manual recording.");
+
yield stopRecording(panel);
- testRecordings(PerformanceController, [C + R, S, C + R, C]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL + SELECTED,
+ CONSOLE + RECORDING,
+ CONSOLE
+ ]);
ok(!OverviewView.isRendering(),
"Stop rendering overview when a completed recording is selected.");
- info("Select first recording...");
+ info("Recording 1 - Select first recording.");
recordingSelected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
- RecordingsView.selectedIndex = 0;
+ setSelectedRecording(panel, 0);
yield recordingSelected;
- testRecordings(PerformanceController, [C + R + S, 0, C + R, C]);
+ 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.
yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
});
@@ -117,75 +177,92 @@ add_task(function* () {
skipWaitingForOverview: true,
skipWaitingForSubview: true,
// the view state won't switch to "recorded" unless the new
// finished recording is selected, which won't happen
skipWaitingForViewState: true,
});
yield console.profileEnd();
yield stopped;
- testRecordings(PerformanceController, [C + R + S, 0, C, C]);
+ 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.
yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
});
- info("Start one more manual recording...");
+ info("Recording 5 - Start one more manual recording.");
yield startRecording(panel);
- testRecordings(PerformanceController, [C + R, 0, C, C, R + S]);
+ 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.
yield times(OverviewView, EVENTS.UI_OVERVIEW_RENDERED, 3, {
expectedArgs: { "1": Constants.FRAMERATE_GRAPH_LOW_RES_INTERVAL }
});
- info("Stop manual recording...");
+ info("Recording 5 - Stop manual recording.");
yield stopRecording(panel);
- testRecordings(PerformanceController, [C + R, 0, C, C, S]);
+ testRecordings(PerformanceController, [
+ CONSOLE + RECORDING,
+ MANUAL,
+ CONSOLE,
+ CONSOLE,
+ MANUAL + SELECTED
+ ]);
ok(!OverviewView.isRendering(),
"Stop rendering overview when a completed recording is selected.");
- info("Ending console.profileEnd()...");
+ 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,
});
yield console.profileEnd();
yield stopped;
- testRecordings(PerformanceController, [C, 0, C, C, S]);
+ testRecordings(PerformanceController, [
+ CONSOLE,
+ MANUAL,
+ CONSOLE,
+ CONSOLE,
+ MANUAL + SELECTED
+ ]);
ok(!OverviewView.isRendering(),
"Stop rendering overview when a completed recording is selected.");
yield teardownToolboxAndRemoveTab(panel);
});
-// is console
-const C = 1;
-// is recording
-const R = 2;
-// is selected
-const S = 4;
-
-function testRecordings(controller, expected) {
+function testRecordings(controller, expectedBitFlags) {
let recordings = controller.getRecordings();
let current = controller.getCurrentRecording();
- is(recordings.length, expected.length, "Expected number of recordings.");
+ is(recordings.length, expectedBitFlags.length, "Expected number of recordings.");
recordings.forEach((recording, i) => {
- ok(recording.isConsole() == !!(expected[i] & C),
+ const expected = expectedBitFlags[i];
+ is(recording.isConsole(), hasBitFlag(expected, CONSOLE),
`Recording ${i + 1} has expected console state.`);
- ok(recording.isRecording() == !!(expected[i] & R),
+ is(recording.isRecording(), hasBitFlag(expected, RECORDING),
`Recording ${i + 1} has expected console state.`);
- ok((recording == current) == !!(expected[i] & S),
+ is((recording == current), hasBitFlag(expected, SELECTED),
`Recording ${i + 1} has expected selected state.`);
});
}
--- 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;
+};
--- a/devtools/client/performance/views/recordings.js
+++ b/devtools/client/performance/views/recordings.js
@@ -4,98 +4,108 @@
/* import-globals-from ../performance-controller.js */
/* import-globals-from ../performance-view.js */
/* globals document, window */
"use strict";
/**
* Functions handling the recordings UI.
*/
-var RecordingsView = Heritage.extend(WidgetMethods, {
+var RecordingsView = {
/**
* Initialization function, called when the tool is started.
*/
initialize: function () {
- this.widget = new SideMenuWidget($("#recordings-list"));
-
this._onSelect = this._onSelect.bind(this);
this._onRecordingStateChange = this._onRecordingStateChange.bind(this);
this._onNewRecording = this._onNewRecording.bind(this);
this._onSaveButtonClick = this._onSaveButtonClick.bind(this);
this._onRecordingDeleted = this._onRecordingDeleted.bind(this);
this._onRecordingExported = this._onRecordingExported.bind(this);
- this.emptyText = L10N.getStr("noRecordingsText");
-
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
PerformanceController.on(EVENTS.RECORDING_ADDED, this._onNewRecording);
PerformanceController.on(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
PerformanceController.on(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
- this.widget.addEventListener("select", this._onSelect, false);
+
+ // DE-XUL: Begin migrating the recording sidebar to React. Temporarily hold state
+ // here.
+ this._listState = {
+ recordings: [],
+ labels: new WeakMap(),
+ selected: null,
+ };
+ this._listMount = PerformanceUtils.createHtmlMount($("#recording-list-mount"));
+ this._renderList();
+ },
+
+ /**
+ * Get the index of the currently selected recording. Only used by tests.
+ * @return {integer} index
+ */
+ getSelectedIndex() {
+ const { recordings, selected } = this._listState;
+ return recordings.indexOf(selected);
+ },
+
+ /**
+ * Set the currently selected recording via its index. Only used by tests.
+ * @param {integer} index
+ */
+ setSelectedByIndex(index) {
+ this._onSelect(this._listState.recordings[index]);
+ this._renderList();
+ },
+
+ /**
+ * DE-XUL: During the migration, this getter will access the selected recording from
+ * the private _listState object so that tests will continue to pass.
+ */
+ get selected() {
+ return this._listState.selected;
+ },
+
+ /**
+ * DE-XUL: During the migration, this getter will access the number of recordings.
+ */
+ get itemCount() {
+ return this._listState.recordings.length;
+ },
+
+ /**
+ * DE-XUL: Render the recording list using React.
+ */
+ _renderList: function () {
+ const {recordings, labels, selected} = this._listState;
+
+ const recordingList = RecordingList({
+ itemComponent: RecordingListItem,
+ items: recordings.map(recording => ({
+ onSelect: () => this._onSelect(recording),
+ onSave: () => this._onSaveButtonClick(recording),
+ isLoading: !recording.isRecording() && !recording.isCompleted(),
+ isRecording: recording.isRecording(),
+ isSelected: recording === selected,
+ duration: recording.getDuration().toFixed(0),
+ label: labels.get(recording),
+ }))
+ });
+
+ ReactDOM.render(recordingList, this._listMount);
},
/**
* Destruction function, called when the tool is closed.
*/
destroy: function () {
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE,
this._onRecordingStateChange);
PerformanceController.off(EVENTS.RECORDING_ADDED, this._onNewRecording);
PerformanceController.off(EVENTS.RECORDING_DELETED, this._onRecordingDeleted);
PerformanceController.off(EVENTS.RECORDING_EXPORTED, this._onRecordingExported);
- this.widget.removeEventListener("select", this._onSelect, false);
- },
-
- /**
- * Adds an empty recording to this container.
- *
- * @param RecordingModel recording
- * A model for the new recording item created.
- */
- addEmptyRecording: function (recording) {
- let titleNode = document.createElement("label");
- titleNode.className = "plain recording-item-title";
- titleNode.setAttribute("crop", "end");
- titleNode.setAttribute("value", recording.getLabel() ||
- L10N.getFormatStr("recordingsList.itemLabel", this.itemCount + 1));
-
- let durationNode = document.createElement("label");
- durationNode.className = "plain recording-item-duration";
- durationNode.setAttribute("value",
- L10N.getStr("recordingsList.recordingLabel"));
-
- let saveNode = document.createElement("label");
- saveNode.className = "plain recording-item-save";
- saveNode.addEventListener("click", this._onSaveButtonClick);
-
- let hspacer = document.createElement("spacer");
- hspacer.setAttribute("flex", "1");
-
- let footerNode = document.createElement("hbox");
- footerNode.className = "recording-item-footer";
- footerNode.appendChild(durationNode);
- footerNode.appendChild(hspacer);
- footerNode.appendChild(saveNode);
-
- let vspacer = document.createElement("spacer");
- vspacer.setAttribute("flex", "1");
-
- let contentsNode = document.createElement("vbox");
- contentsNode.className = "recording-item";
- contentsNode.setAttribute("flex", "1");
- contentsNode.appendChild(titleNode);
- contentsNode.appendChild(vspacer);
- contentsNode.appendChild(footerNode);
-
- // Append a recording item to this container.
- return this.push([contentsNode], {
- // Store the recording model that contains all the data to be
- // rendered in the item.
- attachment: recording
- });
},
/**
* Called when a new recording is stored in the UI. This handles
* when recordings are lazily loaded (like a console.profile occurring
* before the tool is loaded) or imported. In normal manual recording cases,
* this will also be fired.
*/
@@ -107,119 +117,86 @@ var RecordingsView = Heritage.extend(Wid
* Signals that a recording has changed state.
*
* @param string state
* Can be "recording-started", "recording-stopped", "recording-stopping"
* @param RecordingModel recording
* Model of the recording that was started.
*/
_onRecordingStateChange: function (_, state, recording) {
- let recordingItem = this.getItemForPredicate(e => e.attachment === recording);
- if (!recordingItem) {
- recordingItem = this.addEmptyRecording(recording);
+ const { recordings, labels } = this._listState;
+
+ if (!recordings.includes(recording)) {
+ recordings.push(recording);
+ labels.set(recording, recording.getLabel() ||
+ L10N.getFormatStr("recordingsList.itemLabel", recordings.length));
// If this is a manual recording, immediately select it, or
// select a console profile if its the only one
- if (!recording.isConsole() || this.selectedIndex === -1) {
- this.selectedItem = recordingItem;
+ if (!recording.isConsole() || !this._listState.selected) {
+ this._onSelect(recording);
}
}
- recordingItem.isRecording = recording.isRecording();
-
- // This recording is in the process of stopping.
- if (!recording.isRecording() && !recording.isCompleted()) {
- // Mark the corresponding item as loading.
- let durationNode = $(".recording-item-duration", recordingItem.target);
- durationNode.setAttribute("value", L10N.getStr("recordingsList.loadingLabel"));
+ // Determine if the recording needs to be selected.
+ const isCompletedManualRecording = !recording.isConsole() && recording.isCompleted();
+ if (recording.isImported() || isCompletedManualRecording) {
+ this._onSelect(recording);
}
- // Render the recording item with finalized information (timing, etc)
- if (recording.isCompleted() && !recordingItem.finalized) {
- this.finalizeRecording(recordingItem);
- // Select the recording if it was a manual recording only
- if (!recording.isConsole()) {
- this.forceSelect(recordingItem);
- }
- }
-
- // Auto select imported items.
- if (recording.isImported()) {
- this.selectedItem = recordingItem;
- }
+ this._renderList();
},
/**
* Clears out all non-console recordings.
*/
_onRecordingDeleted: function (_, recording) {
- let recordingItem = this.getItemForPredicate(e => e.attachment === recording);
- this.remove(recordingItem);
- },
-
- /**
- * Adds recording data to a recording item in this container.
- *
- * @param Item recordingItem
- * An item inserted via `RecordingsView.addEmptyRecording`.
- */
- finalizeRecording: function (recordingItem) {
- let model = recordingItem.attachment;
- recordingItem.finalized = true;
-
- let saveNode = $(".recording-item-save", recordingItem.target);
- saveNode.setAttribute("value",
- L10N.getStr("recordingsList.saveLabel"));
-
- let durationMillis = model.getDuration().toFixed(0);
- let durationNode = $(".recording-item-duration", recordingItem.target);
- durationNode.setAttribute("value",
- L10N.getFormatStr("recordingsList.durationLabel", durationMillis));
+ const { recordings } = this._listState;
+ const index = recordings.indexOf(recording);
+ if (index === -1) {
+ throw new Error("Attempting to remove a recording that doesn't exist.");
+ }
+ recordings.splice(index, 1);
+ this._renderList();
},
/**
* The select listener for this container.
*/
- _onSelect: Task.async(function* ({ detail: recordingItem }) {
- if (!recordingItem) {
- return;
- }
-
- let model = recordingItem.attachment;
- this.emit(EVENTS.UI_RECORDING_SELECTED, model);
+ _onSelect: Task.async(function* (recording) {
+ this._listState.selected = recording;
+ this.emit(EVENTS.UI_RECORDING_SELECTED, recording);
+ this._renderList();
}),
/**
* The click listener for the "save" button of each item in this container.
*/
- _onSaveButtonClick: function (e) {
+ _onSaveButtonClick: function (recording) {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, L10N.getStr("recordingsList.saveDialogTitle"),
Ci.nsIFilePicker.modeSave);
fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
fp.defaultString = "profile.json";
fp.open({ done: result => {
if (result == Ci.nsIFilePicker.returnCancel) {
return;
}
- let recordingItem = this.getItemForElement(e.target);
- this.emit(EVENTS.UI_EXPORT_RECORDING, recordingItem.attachment, fp.file);
+ this.emit(EVENTS.UI_EXPORT_RECORDING, recording, fp.file);
}});
},
_onRecordingExported: function (_, recording, file) {
if (recording.isConsole()) {
return;
}
- let recordingItem = this.getItemForPredicate(e => e.attachment === recording);
- let titleNode = $(".recording-item-title", recordingItem.target);
- titleNode.setAttribute("value", file.leafName.replace(/\..+$/, ""));
- },
-
- toString: () => "[object RecordingsView]"
-});
+ const name = file.leafName.replace(/\..+$/, "");
+ this._listState.labels.set(recording, name);
+ this._renderList();
+ }
+};
/**
* Convenient way of emitting events from the RecordingsView.
*/
EventEmitter.decorate(RecordingsView);
--- a/devtools/client/themes/performance.css
+++ b/devtools/client/themes/performance.css
@@ -139,43 +139,91 @@
/*
* DE-XUL: The height of the toolbar is not correct without tweaking the line-height.
*/
#recordings-pane .devtools-toolbar {
line-height: 0;
}
-#recordings-list {
- max-width: 300px;
+.theme-sidebar {
+ position: relative;
+}
+
+/**
+ * DE-XUL: This is probably only needed for the html:div inside of a vbox.
+ */
+#recordings-list > div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
+ overflow-x: hidden;
}
-.recording-item {
- padding: 4px;
+.recording-list {
+ width: var(--sidebar-width);
+ min-width: var(--sidebar-width);
+ margin: 0;
+ padding: 0;
+ background-color: var(--theme-sidebar-background);
+ border-inline-end: 1px solid var(--theme-splitter-color);
}
-.recording-item-title {
+.recording-list-item {
+ display: flex;
+ flex-direction: column;
+ color: var(--theme-body-color);
+ border-bottom: 1px solid rgba(128,128,128,0.15);
+ padding: 8px;
+ cursor: default;
+}
+
+.recording-list-item.selected {
+ background-color: var(--theme-selection-background);
+ color: var(--theme-selection-color);
+}
+
+.recording-list-empty {
+ padding: 8px;
+}
+
+.recording-list-item-label {
font-size: 110%;
}
-.recording-item-footer {
+.recording-list-item-footer {
padding-top: 4px;
font-size: 90%;
+ display: flex;
+ justify-content: space-between;
}
-.recording-item-save {
+.recording-list-item-save {
+ background: none;
+ border: none;
text-decoration: underline;
cursor: pointer;
+ font-size: 90%;
+ padding:0;
}
-.recording-item-duration,
-.recording-item-save {
+.recording-list-item-duration,
+.recording-list-item-save {
color: var(--theme-body-color-alt);
}
+.recording-list-item.selected .recording-list-item-duration,
+.recording-list-item.selected .recording-list-item-save {
+ color: var(--theme-body-color-alt);
+ color: var(--theme-selection-color);
+}
+
#recordings-list .selected label {
/* Text inside a selected item should not be custom colored. */
color: inherit !important;
}
/* Recording notices */
.notice-container {