From e8fa9ab01f5ef325008f20844cba51c1b8d18673 Mon Sep 17 00:00:00 2001 From: Jordan Santell Date: Wed, 28 May 2014 11:44:00 -0400 Subject: [PATCH] Bug 1006912 - Fix the web audio dev tools to work after a tab refresh. r=vp --- .../devtools/webaudioeditor/test/browser.ini | 3 + .../test/browser_wa_reset-01.js | 59 +++++++++++++++++++ .../test/browser_wa_reset-02.js | 38 ++++++++++++ .../test/browser_wa_reset-03.js | 49 +++++++++++++++ browser/devtools/webaudioeditor/test/head.js | 10 ++++ .../webaudioeditor-controller.js | 40 ++++++++----- .../webaudioeditor/webaudioeditor-view.js | 25 ++++---- toolkit/devtools/server/actors/webaudio.js | 8 +-- 8 files changed, 200 insertions(+), 32 deletions(-) create mode 100644 browser/devtools/webaudioeditor/test/browser_wa_reset-01.js create mode 100644 browser/devtools/webaudioeditor/test/browser_wa_reset-02.js create mode 100644 browser/devtools/webaudioeditor/test/browser_wa_reset-03.js diff --git a/browser/devtools/webaudioeditor/test/browser.ini b/browser/devtools/webaudioeditor/test/browser.ini index 4fb8915c3f5..3616124e941 100644 --- a/browser/devtools/webaudioeditor/test/browser.ini +++ b/browser/devtools/webaudioeditor/test/browser.ini @@ -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] diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js new file mode 100644 index 00000000000..b5769daeaac --- /dev/null +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js @@ -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(); +} diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js new file mode 100644 index 00000000000..29fe7bbd0ab --- /dev/null +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js @@ -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(); +} diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js new file mode 100644 index 00000000000..2734b9f9137 --- /dev/null +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js @@ -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(); +} diff --git a/browser/devtools/webaudioeditor/test/head.js b/browser/devtools/webaudioeditor/test/head.js index b6569473e53..386ab2ba4cc 100644 --- a/browser/devtools/webaudioeditor/test/head.js +++ b/browser/devtools/webaudioeditor/test/head.js @@ -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 */ diff --git a/browser/devtools/webaudioeditor/webaudioeditor-controller.js b/browser/devtools/webaudioeditor/webaudioeditor-controller.js index d288eeb9cd9..0c5a99ce60c 100644 --- a/browser/devtools/webaudioeditor/webaudioeditor-controller.js +++ b/browser/devtools/webaudioeditor/webaudioeditor-controller.js @@ -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); }, diff --git a/browser/devtools/webaudioeditor/webaudioeditor-view.js b/browser/devtools/webaudioeditor/webaudioeditor-view.js index e89c921032c..123cb3f2d4b 100644 --- a/browser/devtools/webaudioeditor/webaudioeditor-view.js +++ b/browser/devtools/webaudioeditor/webaudioeditor-view.js @@ -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); }, diff --git a/toolkit/devtools/server/actors/webaudio.js b/toolkit/devtools/server/actors/webaudio.js index a2925d9fe12..c0ab8797a37 100644 --- a/toolkit/devtools/server/actors/webaudio.js +++ b/toolkit/devtools/server/actors/webaudio.js @@ -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