Bug 1006912 - Fix the web audio dev tools to work after a tab refresh. r=vp

This commit is contained in:
Jordan Santell 2014-05-28 11:44:00 -04:00
parent d96a7cbbfa
commit e8fa9ab01f
8 changed files with 200 additions and 32 deletions

View File

@ -18,6 +18,9 @@ support-files =
[browser_webaudio-actor-simple.js]
[browser_wa_first-run.js]
[browser_wa_reset-01.js]
[browser_wa_reset-02.js]
[browser_wa_reset-03.js]
[browser_wa_graph-click.js]
[browser_wa_graph-render-01.js]

View File

@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that reloading a tab will properly listen for the `start-context`
* event and reshow the tools after reloading.
*/
function spawnTest() {
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
let { gFront, $ } = panel.panelWin;
is($("#reload-notice").hidden, false,
"The 'reload this page' notice should initially be visible.");
is($("#waiting-notice").hidden, true,
"The 'waiting for an audio context' notice should initially be hidden.");
is($("#content").hidden, true,
"The tool's content should initially be hidden.");
let navigating = once(target, "will-navigate");
let started = once(gFront, "start-context");
reload(target);
yield navigating;
is($("#reload-notice").hidden, true,
"The 'reload this page' notice should be hidden when navigating.");
is($("#waiting-notice").hidden, false,
"The 'waiting for an audio context' notice should be visible when navigating.");
is($("#content").hidden, true,
"The tool's content should still be hidden.");
yield started;
is($("#reload-notice").hidden, true,
"The 'reload this page' notice should be hidden after context found.");
is($("#waiting-notice").hidden, true,
"The 'waiting for an audio context' notice should be hidden after context found.");
is($("#content").hidden, false,
"The tool's content should not be hidden anymore.");
let navigating = once(target, "will-navigate");
let started = once(gFront, "start-context");
reload(target);
yield Promise.all([navigating, started]);
is($("#reload-notice").hidden, true,
"The 'reload this page' notice should be hidden after context found after reload.");
is($("#waiting-notice").hidden, true,
"The 'waiting for an audio context' notice should be hidden after context found after reload.");
is($("#content").hidden, false,
"The tool's content should reappear without closing and reopening the toolbox.");
yield teardown(panel);
finish();
}

View File

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests reloading a tab with the tools open properly cleans up
* the graph.
*/
function spawnTest() {
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
let { panelWin } = panel;
let { gFront, $ } = panelWin;
reload(target);
let [actors] = yield Promise.all([
get3(gFront, "create-node"),
waitForGraphRendered(panelWin, 3, 2)
]);
let { nodes, edges } = countGraphObjects(panelWin);
ise(nodes, 3, "should only be 3 nodes.");
ise(edges, 2, "should only be 2 edges.");
reload(target);
let [actors] = yield Promise.all([
get3(gFront, "create-node"),
waitForGraphRendered(panelWin, 3, 2)
]);
let { nodes, edges } = countGraphObjects(panelWin);
ise(nodes, 3, "after reload, should only be 3 nodes.");
ise(edges, 2, "after reload, should only be 2 edges.");
yield teardown(panel);
finish();
}

View File

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests reloading a tab with the tools open properly cleans up
* the inspector and selected node.
*/
function spawnTest() {
let [target, debuggee, panel] = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
let { panelWin } = panel;
let { gFront, $, WebAudioInspectorView } = panelWin;
reload(target);
let [actors] = yield Promise.all([
get3(gFront, "create-node"),
waitForGraphRendered(panelWin, 3, 2)
]);
let nodeIds = actors.map(actor => actor.actorID);
yield clickGraphNode(panelWin, nodeIds[1], true);
ok(WebAudioInspectorView.isVisible(), "InspectorView visible after selecting a node.");
is(WebAudioInspectorView.getCurrentNode().id, nodeIds[1], "InspectorView has correct node set.");
/**
* Reload
*/
reload(target);
let [actors] = yield Promise.all([
get3(gFront, "create-node"),
waitForGraphRendered(panelWin, 3, 2)
]);
let nodeIds = actors.map(actor => actor.actorID);
ok(!WebAudioInspectorView.isVisible(), "InspectorView hidden on start.");
ise(WebAudioInspectorView.getCurrentNode(), null,
"InspectorView has no current node set on reset.");
yield clickGraphNode(panelWin, nodeIds[2], true);
ok(WebAudioInspectorView.isVisible(),
"InspectorView visible after selecting a node after a reset.");
is(WebAudioInspectorView.getCurrentNode().id, nodeIds[2], "InspectorView has correct node set upon clicking graph node after a reset.");
yield teardown(panel);
finish();
}

View File

@ -351,6 +351,16 @@ function getGripValue (value) {
}
}
/**
* Counts how many nodes and edges are currently in the graph.
*/
function countGraphObjects (win) {
return {
nodes: win.document.querySelectorAll(".nodes > .audionode").length,
edges: win.document.querySelectorAll(".edgePaths > .edgePath").length
}
}
/**
* List of audio node properties to test against expectations of the AudioNode actor
*/

View File

@ -182,6 +182,18 @@ let WebAudioEditorController = {
gDevTools.off("pref-changed", this._onThemeChange);
},
/**
* Called when page is reloaded to show the reload notice and waiting
* for an audio context notice.
*/
reset: function () {
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
$("#content").hidden = true;
WebAudioGraphView.resetUI();
WebAudioInspectorView.resetUI();
},
/**
* Called when a new audio node is created, or the audio context
* routing changes.
@ -202,22 +214,20 @@ let WebAudioEditorController = {
/**
* Called for each location change in the debugged tab.
*/
_onTabNavigated: function(event) {
_onTabNavigated: Task.async(function* (event) {
switch (event) {
case "will-navigate": {
Task.spawn(function() {
// Make sure the backend is prepared to handle audio contexts.
yield gFront.setup({ reload: false });
// Make sure the backend is prepared to handle audio contexts.
yield gFront.setup({ reload: false });
// Reset UI to show "Waiting for Audio Context..." and clear out
// current UI.
WebAudioGraphView.resetUI();
WebAudioInspectorView.resetUI();
// Reset UI to show "Waiting for Audio Context..." and clear out
// current UI.
this.reset();
// Clear out stored audio nodes
AudioNodes.length = 0;
AudioNodeConnections.clear();
}).then(() => window.emit(EVENTS.UI_RESET));
// Clear out stored audio nodes
AudioNodes.length = 0;
AudioNodeConnections.clear();
window.emit(EVENTS.UI_RESET);
break;
}
case "navigate": {
@ -226,14 +236,16 @@ let WebAudioEditorController = {
break;
}
}
},
}),
/**
* Called after the first audio node is created in an audio context,
* signaling that the audio context is being used.
*/
_onStartContext: function() {
WebAudioGraphView.showContent();
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = true;
$("#content").hidden = false;
window.emit(EVENTS.START_CONTEXT);
},

View File

@ -53,12 +53,14 @@ let WebAudioGraphView = {
this._onGraphNodeClick = this._onGraphNodeClick.bind(this);
this._onThemeChange = this._onThemeChange.bind(this);
this._onNodeSelect = this._onNodeSelect.bind(this);
this._onStartContext = this._onStartContext.bind(this);
this.draw = debounce(this.draw.bind(this), GRAPH_DEBOUNCE_TIMER);
$('#graph-target').addEventListener('click', this._onGraphNodeClick, false);
window.on(EVENTS.THEME_CHANGE, this._onThemeChange);
window.on(EVENTS.UI_INSPECTOR_NODE_SET, this._onNodeSelect);
window.on(EVENTS.START_CONTEXT, this._onStartContext);
},
/**
@ -71,6 +73,7 @@ let WebAudioGraphView = {
$('#graph-target').removeEventListener('click', this._onGraphNodeClick, false);
window.off(EVENTS.THEME_CHANGE, this._onThemeChange);
window.off(EVENTS.UI_INSPECTOR_NODE_SET, this._onNodeSelect);
window.off(EVENTS.START_CONTEXT, this._onStartContext);
},
/**
@ -78,23 +81,9 @@ let WebAudioGraphView = {
* and clears out old content
*/
resetUI: function () {
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
$("#content").hidden = true;
this.resetGraph();
},
/**
* Called once "start-context" is fired, indicating that there is audio context
* activity to view and inspect
*/
showContent: function () {
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = true;
$("#content").hidden = false;
this.draw();
},
/**
* Clears out the rendered graph, called when resetting the SVG elements to draw again,
* or when resetting the entire UI tool
@ -235,6 +224,14 @@ let WebAudioGraphView = {
* Event handlers
*/
/**
* Called once "start-context" is fired, indicating that there is an audio
* context being created to view so render the graph.
*/
_onStartContext: function () {
this.draw();
},
_onNodeSelect: function (eventName, id) {
this.focusNode(id);
},

View File

@ -278,6 +278,10 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
* See ContentObserver and WebAudioInstrumenter for more details.
*/
setup: method(function({ reload }) {
// Used to track when something is happening with the web audio API
// the first time, to ultimately fire `start-context` event
this._firstNodeCreated = false;
if (this._initialized) {
return;
}
@ -293,10 +297,6 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
startRecording: true,
performReload: reload
});
// Used to track when something is happening with the web audio API
// the first time, to ultimately fire `start-context` event
this._firstNodeCreated = false;
}, {
request: { reload: Option(0, "boolean") },
oneway: true