Bug 1302062 - Use React on performance recording list; r=jsantell

--HG--
extra : rebase_source : 72db3e85afc693f6ebb2688855b2509bc4f7d6bb
This commit is contained in:
Greg Tatum 2016-09-20 09:47:59 -05:00
parent 548a4d6be0
commit 8cc8c5166b
33 changed files with 541 additions and 268 deletions

View File

@ -8,6 +8,8 @@ DevToolsModules(
'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',

View File

@ -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")
)
)
)
);
}
});

View File

@ -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"));
}
});

View File

@ -27,13 +27,16 @@ Object.defineProperty(this, "EVENTS", {
});
/* 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");

View File

@ -84,7 +84,9 @@
<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 -->

View File

@ -34,11 +34,18 @@ add_task(function* () {
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");

View File

@ -10,6 +10,7 @@
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({
@ -21,7 +22,7 @@ add_task(function* () {
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);
@ -31,9 +32,11 @@ add_task(function* () {
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);

View File

@ -13,6 +13,7 @@ const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab }
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({
@ -24,7 +25,7 @@ add_task(function* () {
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);
@ -37,9 +38,10 @@ add_task(function* () {
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.

View File

@ -11,6 +11,7 @@ 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({
@ -23,7 +24,7 @@ add_task(function* () {
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);
@ -37,9 +38,10 @@ add_task(function* () {
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, {

View File

@ -12,6 +12,7 @@ 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({
@ -20,7 +21,7 @@ add_task(function* () {
});
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
@ -35,9 +36,10 @@ add_task(function* () {
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.

View File

@ -12,6 +12,7 @@ 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({
@ -20,7 +21,7 @@ add_task(function* () {
});
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
@ -35,9 +36,10 @@ add_task(function* () {
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.
@ -70,9 +72,10 @@ add_task(function* () {
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, {

View File

@ -11,6 +11,7 @@ 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({
@ -19,7 +20,7 @@ add_task(function* () {
});
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
@ -30,7 +31,7 @@ add_task(function* () {
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.
@ -52,7 +53,7 @@ add_task(function* () {
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.
@ -69,7 +70,7 @@ add_task(function* () {
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.");
@ -86,7 +87,7 @@ add_task(function* () {
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.");

View File

@ -12,6 +12,7 @@ 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({
@ -20,7 +21,7 @@ add_task(function* () {
});
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
@ -54,11 +55,12 @@ add_task(function* () {
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,
@ -81,9 +83,10 @@ add_task(function* () {
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 " +
@ -97,9 +100,10 @@ add_task(function* () {
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,
@ -122,9 +126,10 @@ add_task(function* () {
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,
@ -141,9 +146,10 @@ add_task(function* () {
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,

View File

@ -13,6 +13,31 @@ const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab }
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.
@ -24,22 +49,27 @@ add_task(function* () {
});
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,
@ -51,9 +81,13 @@ add_task(function* () {
});
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,
@ -65,9 +99,14 @@ add_task(function* () {
});
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,
@ -80,27 +119,48 @@ add_task(function* () {
});
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.");
@ -122,7 +182,12 @@ add_task(function* () {
});
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.");
@ -131,9 +196,15 @@ add_task(function* () {
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.");
@ -142,13 +213,19 @@ add_task(function* () {
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,
@ -161,31 +238,31 @@ add_task(function* () {
});
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.`);
});
}

View File

@ -14,6 +14,7 @@ const { UI_ENABLE_ALLOCATIONS_PREF } = require("devtools/client/performance/test
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({
@ -24,7 +25,6 @@ add_task(function* () {
let {
EVENTS,
$,
RecordingsView,
DetailsView,
WaterfallView,
MemoryCallTreeView,
@ -80,7 +80,7 @@ add_task(function* () {
// 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;
@ -94,7 +94,7 @@ add_task(function* () {
// 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),

View File

@ -11,6 +11,7 @@ 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({
@ -22,7 +23,6 @@ add_task(function* () {
EVENTS,
$,
PerformanceController,
RecordingsView,
WaterfallView
} = panel.panelWin;
@ -84,11 +84,12 @@ add_task(function* () {
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,
@ -103,10 +104,11 @@ add_task(function* () {
"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,
@ -124,7 +126,8 @@ add_task(function* () {
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,

View File

@ -11,6 +11,7 @@ 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({
@ -18,12 +19,11 @@ add_task(function* () {
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");
@ -36,14 +36,15 @@ add_task(function* () {
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;

View File

@ -13,6 +13,7 @@ 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({
@ -20,7 +21,7 @@ add_task(function* () {
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");
@ -52,7 +53,7 @@ add_task(function* () {
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, {
@ -66,14 +67,14 @@ add_task(function* () {
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;

View File

@ -9,13 +9,13 @@ 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] };
@ -58,14 +58,14 @@ function* spawnTest() {
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");

View File

@ -13,6 +13,7 @@ const { initPerformanceInNewTab, teardownToolboxAndRemoveTab } = require("devtoo
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({
@ -20,7 +21,7 @@ add_task(function* () {
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);
@ -53,12 +54,12 @@ add_task(function* () {
"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.");

View File

@ -11,6 +11,7 @@ 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({
@ -23,7 +24,6 @@ add_task(function* () {
$,
PerformanceController,
PerformanceView,
RecordingsView
} = panel.panelWin;
let MAIN_CONTAINER = $("#performance-view");
@ -42,7 +42,7 @@ add_task(function* () {
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",
@ -51,7 +51,7 @@ add_task(function* () {
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",

View File

@ -15,6 +15,7 @@ const { initPerformanceInTab, initConsoleInNewTab, teardownToolboxAndRemoveTab }
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.
@ -36,7 +37,6 @@ add_task(function* () {
$,
PerformanceController,
PerformanceView,
RecordingsView
} = panel.panelWin;
// Set a fast profiler-status update interval.
@ -88,7 +88,7 @@ add_task(function* () {
// Select the console recording.
let selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
RecordingsView.selectedIndex = 1;
setSelectedRecording(panel, 1);
yield selected;
yield waitUntil(function* () {
@ -109,7 +109,7 @@ add_task(function* () {
yield console.profileEnd("rust");
selected = once(PerformanceController, EVENTS.RECORDING_SELECTED);
RecordingsView.selectedIndex = 0;
setSelectedRecording(panel, 0);
yield selected;
yield waitUntil(function* () {

View File

@ -11,6 +11,7 @@ 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({
@ -18,7 +19,7 @@ add_task(function* () {
win: window
});
let { EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
let { EVENTS, PerformanceController } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
@ -26,18 +27,18 @@ add_task(function* () {
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);

View File

@ -11,6 +11,7 @@ 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.
@ -21,38 +22,37 @@ add_task(function* () {
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);
});

View File

@ -12,6 +12,7 @@ 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({
@ -19,7 +20,7 @@ add_task(function* () {
win: window
});
let { $, EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
let { $, EVENTS, PerformanceController } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
@ -29,7 +30,7 @@ add_task(function* () {
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"),

View File

@ -10,6 +10,7 @@ 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({
@ -17,7 +18,7 @@ add_task(function* () {
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);
@ -43,13 +44,13 @@ add_task(function* () {
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.");

View File

@ -10,6 +10,7 @@
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({
@ -18,13 +19,13 @@ add_task(function* () {
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,
@ -33,8 +34,8 @@ add_task(function* () {
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,
@ -42,8 +43,8 @@ add_task(function* () {
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,

View File

@ -11,6 +11,7 @@ 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({
@ -19,13 +20,13 @@ add_task(function* () {
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,
@ -33,8 +34,8 @@ add_task(function* () {
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,
@ -50,8 +51,8 @@ add_task(function* () {
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,
@ -61,8 +62,8 @@ add_task(function* () {
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);
});

View File

@ -12,7 +12,7 @@ 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] };

View File

@ -12,6 +12,7 @@ DevToolsModules(
'panel-utils.js',
'prefs.js',
'profiler-mm-utils.js',
'recording-utils.js',
'synth-utils.js',
'tab-utils.js',
'urls.js',

View File

@ -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;
};

View File

@ -9,13 +9,11 @@
/**
* 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);
@ -23,13 +21,75 @@ var RecordingsView = Heritage.extend(WidgetMethods, {
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);
},
/**
@ -41,56 +101,6 @@ var RecordingsView = Heritage.extend(WidgetMethods, {
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
});
},
/**
@ -112,85 +122,55 @@ var RecordingsView = Heritage.extend(WidgetMethods, {
* 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);
@ -202,8 +182,7 @@ var RecordingsView = Heritage.extend(WidgetMethods, {
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);
}});
},
@ -211,13 +190,11 @@ var RecordingsView = Heritage.extend(WidgetMethods, {
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.

View File

@ -144,33 +144,81 @@
line-height: 0;
}
#recordings-list {
max-width: 300px;
.theme-sidebar {
position: relative;
}
.recording-item {
padding: 4px;
/**
* 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-title {
.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-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;