From 191b35e4b0884ffd92e2cb6fc98413e2f21395d0 Mon Sep 17 00:00:00 2001 From: Nicolas Chevobbe Date: Tue, 18 May 2021 14:16:33 +0000 Subject: [PATCH] Bug 1691576 - [devtools] Update DevTools window title on DOCUMENT_EVENT resource. r=ochameau. Differential Revision: https://phabricator.services.mozilla.com/D104540 --- devtools/client/framework/test/browser.ini | 1 - .../browser_toolbox_window_title_changes.js | 194 ++++++++---------- devtools/client/framework/toolbox.js | 35 ++-- 3 files changed, 105 insertions(+), 125 deletions(-) diff --git a/devtools/client/framework/test/browser.ini b/devtools/client/framework/test/browser.ini index 4e07f04796df..bbca8b0c4ca4 100644 --- a/devtools/client/framework/test/browser.ini +++ b/devtools/client/framework/test/browser.ini @@ -159,7 +159,6 @@ run-if = e10s [browser_toolbox_window_reload_target_force.js] [browser_toolbox_window_shortcuts.js] [browser_toolbox_window_title_changes.js] -skip-if = fission [browser_toolbox_window_title_frame_select.js] fail-if = fission [browser_toolbox_zoom.js] diff --git a/devtools/client/framework/test/browser_toolbox_window_title_changes.js b/devtools/client/framework/test/browser_toolbox_window_title_changes.js index 0bcac7f49ab1..0222159a079b 100644 --- a/devtools/client/framework/test/browser_toolbox_window_title_changes.js +++ b/devtools/client/framework/test/browser_toolbox_window_title_changes.js @@ -5,121 +5,93 @@ requestLongerTimeout(5); var { Toolbox } = require("devtools/client/framework/toolbox"); -function test() { - const URL_1 = "data:text/plain;charset=UTF-8,abcde"; - const URL_2 = "data:text/plain;charset=UTF-8,12345"; - const URL_3 = URL_ROOT + "browser_toolbox_window_title_changes_page.html"; +const NAME_1 = ""; +const NAME_2 = "Toolbox test for title update"; +const NAME_3 = NAME_2; +const NAME_4 = "Toolbox test for another title update"; - const TOOL_ID_1 = "webconsole"; - const TOOL_ID_2 = "jsdebugger"; +const URL_1 = "data:text/plain;charset=UTF-8,abcde"; +const URL_2 = URL_ROOT_ORG + "browser_toolbox_window_title_changes_page.html"; +const URL_3 = URL_ROOT_COM + "browser_toolbox_window_title_changes_page.html"; +const URL_4 = `http://example.com/document-builder.sjs?html=${NAME_4}

Hello`; - const NAME_1 = ""; - const NAME_2 = ""; - const NAME_3 = "Toolbox test for title update"; +add_task(async function test() { + await addTab(URL_1); - let toolbox; - let panel; - - addTab(URL_1).then(async function() { - const tab = gBrowser.selectedTab; - gDevTools - .showToolboxForTab(tab, { hostType: Toolbox.HostType.BOTTOM }) - .then(function(aToolbox) { - toolbox = aToolbox; - }) - .then(() => toolbox.selectTool(TOOL_ID_1)) - - // undock toolbox and check title - .then(() => { - // We have to first switch the host in order to spawn the new top level window - // on which we are going to listen from title change event - return toolbox - .switchHost(Toolbox.HostType.WINDOW) - .then(() => waitForTitleChange(toolbox)); - }) - .then(checkTitle.bind(null, NAME_1, URL_1, "toolbox undocked")) - - // switch to different tool and check title - .then(async () => { - const onTitleChanged = waitForTitleChange(toolbox); - panel = await toolbox.selectTool(TOOL_ID_2); - return onTitleChanged; - }) - .then(checkTitle.bind(null, NAME_1, URL_1, "tool changed")) - - // navigate to different local url and check title - .then(async function() { - const onTitleChanged = waitForTitleChange(toolbox); - const waitForReloaded = panel.once("reloaded"); - await navigateTo(URL_2); - await waitForReloaded; - return onTitleChanged; - }) - .then(checkTitle.bind(null, NAME_2, URL_2, "url changed")) - - // navigate to a real url and check title - .then(async () => { - const onTitleChanged = waitForTitleChange(toolbox); - const waitForReloaded = panel.once("reloaded"); - await navigateTo(URL_3); - await waitForReloaded; - return onTitleChanged; - }) - .then(checkTitle.bind(null, NAME_3, URL_3, "url changed")) - - // destroy toolbox, create new one hosted in a window (with a - // different tool id), and check title - .then(function() { - // Give the tools a chance to handle the navigation event before - // destroying the toolbox. - executeSoon(function() { - toolbox - .destroy() - .then(async function() { - // After destroying the toolbox, open a new one. - return gDevTools.showToolboxForTab(tab, { - hostType: Toolbox.HostType.WINDOW, - }); - }) - .then(function(aToolbox) { - toolbox = aToolbox; - }) - .then(() => { - const onTitleChanged = waitForTitleChange(toolbox); - toolbox.selectTool(TOOL_ID_1); - return onTitleChanged; - }) - .then( - checkTitle.bind( - null, - NAME_3, - URL_3, - "toolbox destroyed and recreated" - ) - ) - - // clean up - .then(() => toolbox.destroy()) - .then(function() { - toolbox = null; - gBrowser.removeCurrentTab(); - Services.prefs.clearUserPref("devtools.toolbox.host"); - Services.prefs.clearUserPref("devtools.toolbox.selectedTool"); - Services.prefs.clearUserPref("devtools.toolbox.sideEnabled"); - finish(); - }); - }); - }); + const tab = gBrowser.selectedTab; + let toolbox = await gDevTools.showToolboxForTab(tab, { + hostType: Toolbox.HostType.BOTTOM, }); + await toolbox.selectTool("webconsole"); + + info("Undock toolbox and check title"); + // We have to first switch the host in order to spawn the new top level window + // on which we are going to listen from title change event + await toolbox.switchHost(Toolbox.HostType.WINDOW); + await checkTitle(NAME_1, URL_1, "toolbox undocked"); + + info("switch to different tool and check title again"); + await toolbox.selectTool("jsdebugger"); + await checkTitle(NAME_1, URL_1, "tool changed"); + + info("navigate to different local url and check title"); + + await navigateTo(URL_2); + info("wait for title change"); + await checkTitle(NAME_2, URL_2, "url changed"); + + info("navigate to a real url and check title"); + await navigateTo(URL_3); + + info("wait for title change"); + await checkTitle(NAME_3, URL_3, "url changed"); + + info("navigate to another page on the same domain"); + await navigateTo(URL_4); + await checkTitle(NAME_4, URL_4, "title changed"); + + info( + "destroy toolbox, create new one hosted in a window (with a different tool id), and check title" + ); + // Give the tools a chance to handle the navigation event before + // destroying the toolbox. + await new Promise(resolve => executeSoon(resolve)); + await toolbox.destroy(); + + // After destroying the toolbox, open a new one. + toolbox = await gDevTools.showToolboxForTab(tab, { + hostType: Toolbox.HostType.WINDOW, + }); + toolbox.selectTool("webconsole"); + await checkTitle(NAME_4, URL_4, "toolbox destroyed and recreated"); + + info("clean up"); + await toolbox.destroy(); + gBrowser.removeCurrentTab(); + Services.prefs.clearUserPref("devtools.toolbox.host"); + Services.prefs.clearUserPref("devtools.toolbox.selectedTool"); + Services.prefs.clearUserPref("devtools.toolbox.sideEnabled"); +}); + +function getExpectedTitle(name, url) { + if (name) { + return `Developer Tools — ${name} — ${url}`; + } + return `Developer Tools — ${url}`; } -function checkTitle(name, url, context) { - const win = Services.wm.getMostRecentWindow("devtools:toolbox"); - let expectedTitle; - if (name) { - expectedTitle = `Developer Tools — ${name} — ${url}`; - } else { - expectedTitle = `Developer Tools — ${url}`; - } - is(win.document.title, expectedTitle, context); +async function checkTitle(name, url, context) { + info("Check title - " + context); + await waitFor( + () => getToolboxWindowTitle() === getExpectedTitle(name, url), + `Didn't get the expected title ("${getExpectedTitle(name, url)}"`, + 200, + 50 + ); + const expectedTitle = getExpectedTitle(name, url); + is(getToolboxWindowTitle(), expectedTitle, context); +} + +function getToolboxWindowTitle() { + return Services.wm.getMostRecentWindow("devtools:toolbox").document.title; } diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index 80f5397c28c8..231b1126761e 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -330,7 +330,6 @@ function Toolbox( this._onResumedState = this._onResumedState.bind(this); this._onTargetAvailable = this._onTargetAvailable.bind(this); this._onTargetDestroyed = this._onTargetDestroyed.bind(this); - this._onNavigate = this._onNavigate.bind(this); this._onResourceAvailable = this._onResourceAvailable.bind(this); this._onResourceUpdated = this._onResourceUpdated.bind(this); @@ -696,7 +695,6 @@ Toolbox.prototype = { // Attach to a new top-level target. // For now, register these event listeners only on the top level target targetFront.on("will-navigate", this._onWillNavigate); - targetFront.on("navigate", this._onNavigate); targetFront.on("frame-update", this._updateFrames); targetFront.on("inspect-object", this._onInspectObject); } @@ -732,7 +730,6 @@ Toolbox.prototype = { if (targetFront.isTopLevel) { this.target.off("inspect-object", this._onInspectObject); this.target.off("will-navigate", this._onWillNavigate); - this.target.off("navigate", this._onNavigate); this.target.off("frame-update", this._updateFrames); } @@ -801,10 +798,10 @@ Toolbox.prototype = { this._onTargetDestroyed ); - // Watch for console API messages, errors and network events in order to populate - // the error count icon in the toolbox. const onResourcesWatched = this.resourceCommand.watchResources( [ + // Watch for console API messages, errors and network events in order to populate + // the error count icon in the toolbox. this.resourceCommand.TYPES.CONSOLE_MESSAGE, this.resourceCommand.TYPES.ERROR_MESSAGE, // Independently of watching network event resources for the error count icon, @@ -813,6 +810,7 @@ Toolbox.prototype = { // for network events across the lifetime of the various panels, so stopping // the resource command from clearing out its cache of network event resources. this.resourceCommand.TYPES.NETWORK_EVENT, + this.resourceCommand.TYPES.DOCUMENT_EVENT, ], { onAvailable: this._onResourceAvailable, @@ -3762,6 +3760,7 @@ Toolbox.prototype = { this.resourceCommand.TYPES.CONSOLE_MESSAGE, this.resourceCommand.TYPES.ERROR_MESSAGE, this.resourceCommand.TYPES.NETWORK_EVENT, + this.resourceCommand.TYPES.DOCUMENT_EVENT, ], { onAvailable: this._onResourceAvailable } ); @@ -4279,14 +4278,6 @@ Toolbox.prototype = { return id; }, - /** - * Fired when the user navigates to another page. - */ - _onNavigate: function() { - this._refreshHostTitle(); - this._setDebugTargetData(); - }, - /** * Sets basic information on the DebugTargetInfo component */ @@ -4325,6 +4316,24 @@ Toolbox.prototype = { errors = 0; } } + + if ( + resource.resourceType === this.resourceCommand.TYPES.DOCUMENT_EVENT && + resource?.targetFront.isTopLevel && + !resource.isFrameSwitching && + // `url` is set on the targetFront when we receive dom-loading, and `title` when + // `dom-interactive` is received. Here we're only updating the window title in + // the "newer" event. + resource.name === "dom-interactive" + ) { + // the targetFront title and url are update on dom-interactive, so delay refreshing + // the host title a bit in order for the event listener in targetCommand to be + // executed. + setTimeout(() => { + this._refreshHostTitle(); + }, 0); + this._setDebugTargetData(); + } } this.setErrorCount(errors);