mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1699493 - [devtools] Migrate WebExtInspectedWindow front to a command. r=nchevobbe,rpl
- implement the new "inspected-window" command - move WebExtensionInspectedWindowFront implement to the command, making the front empty - migrate tests to use the commands instead of front - stop maintaining the current top level target in ExtensionParent.jsm, no longer have to use watchTargets - stop creating a new descriptor on each new target - instead only pull one new dedicated "commands" for WebExt (still in ExtensionParent.jsm) - remove TabDescriptor isDevToolsExtensionContext as we no longer need anything special in the descriptor - remove now unused methods on DevToolsShims (createWebExtensionInspectedWindowFront, createDescriptorForTabForWebExtension) - remove the now unused TabDescriptorFactory.createDescriptorForTab's "forceCreationForWebextension" option, as CommandsFactory.forTab always instantiate a brand new commands - migrate webext to use the command instead of front Differential Revision: https://phabricator.services.mozilla.com/D108994
This commit is contained in:
parent
d48b91e66d
commit
c8f91a99da
@ -15,7 +15,6 @@ module.exports = {
|
||||
browserActionFor: true,
|
||||
clickModifiersFromEvent: true,
|
||||
getContainerForCookieStoreId: true,
|
||||
getInspectedWindowFront: true,
|
||||
getTargetTabIdForToolbox: true,
|
||||
getToolboxEvalOptions: true,
|
||||
isContainerCookieStoreId: true,
|
||||
|
@ -22,11 +22,11 @@ this.devtools_inspectedWindow = class extends ExtensionAPI {
|
||||
devtools: {
|
||||
inspectedWindow: {
|
||||
async eval(expression, options) {
|
||||
const front = await getInspectedWindowFront(context);
|
||||
const toolboxEvalOptions = await getToolboxEvalOptions(context);
|
||||
const evalOptions = Object.assign({}, options, toolboxEvalOptions);
|
||||
|
||||
const evalResult = await front.eval(
|
||||
const commands = await context.getDevToolsCommands();
|
||||
const evalResult = await commands.inspectedWindowCommand.eval(
|
||||
callerInfo,
|
||||
expression,
|
||||
evalOptions
|
||||
@ -39,8 +39,8 @@ this.devtools_inspectedWindow = class extends ExtensionAPI {
|
||||
async reload(options) {
|
||||
const { ignoreCache, userAgent, injectedScript } = options || {};
|
||||
|
||||
const front = await getInspectedWindowFront(context);
|
||||
front.reload(callerInfo, {
|
||||
const commands = await context.getDevToolsCommands();
|
||||
commands.inspectedWindowCommand.reload(callerInfo, {
|
||||
ignoreCache,
|
||||
userAgent,
|
||||
injectedScript,
|
||||
|
@ -571,10 +571,6 @@ const sidebarsById = new Map();
|
||||
|
||||
this.devtools_panels = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
// Lazily retrieved inspectedWindow actor front per child context
|
||||
// (used by Sidebar.setExpression).
|
||||
let waitForInspectedWindowFront;
|
||||
|
||||
// TODO - Bug 1448878: retrieve a more detailed callerInfo object,
|
||||
// like the filename and lineNumber of the actual extension called
|
||||
// in the child process.
|
||||
@ -646,21 +642,14 @@ this.devtools_panels = class extends ExtensionAPI {
|
||||
async setExpression(sidebarId, evalExpression, rootTitle) {
|
||||
const sidebar = sidebarsById.get(sidebarId);
|
||||
|
||||
if (!waitForInspectedWindowFront) {
|
||||
waitForInspectedWindowFront = getInspectedWindowFront(
|
||||
context
|
||||
);
|
||||
}
|
||||
|
||||
const front = await waitForInspectedWindowFront;
|
||||
const toolboxEvalOptions = await getToolboxEvalOptions(context);
|
||||
|
||||
const consoleFront = await context.devToolsToolbox.target.getFront(
|
||||
"console"
|
||||
);
|
||||
const commands = await context.getDevToolsCommands();
|
||||
const target = commands.targetCommand.targetFront;
|
||||
const consoleFront = await target.getFront("console");
|
||||
toolboxEvalOptions.consoleFront = consoleFront;
|
||||
|
||||
const evalResult = await front.eval(
|
||||
const evalResult = await commands.inspectedWindowCommand.eval(
|
||||
callerInfo,
|
||||
evalExpression,
|
||||
toolboxEvalOptions
|
||||
|
@ -54,13 +54,6 @@ global.getTargetTabIdForToolbox = toolbox => {
|
||||
return tabTracker.getId(tab);
|
||||
};
|
||||
|
||||
// Create an InspectedWindowFront instance for a given context (used in devtoools.inspectedWindow.eval
|
||||
// and in sidebar.setExpression API methods).
|
||||
global.getInspectedWindowFront = async function(context) {
|
||||
const target = await context.getCurrentDevToolsTarget();
|
||||
return DevToolsShim.createWebExtensionInspectedWindowFront(target);
|
||||
};
|
||||
|
||||
// Get the WebExtensionInspectedWindowActor eval options (needed to provide the $0 and inspect
|
||||
// binding provided to the evaluated js code).
|
||||
global.getToolboxEvalOptions = async function(context) {
|
||||
|
@ -17,6 +17,12 @@ loader.lazyRequireGetter(
|
||||
"devtools/client/framework/tab-descriptor-factory",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"CommandsFactory",
|
||||
"devtools/shared/commands/commands-factory",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"ToolboxHostManager",
|
||||
@ -706,21 +712,13 @@ DevTools.prototype = {
|
||||
* Compatibility layer for web-extensions. Used by DevToolsShim for
|
||||
* browser/components/extensions/ext-devtools.js
|
||||
*
|
||||
* web-extensions need to use dedicated instances of Target and cannot reuse the
|
||||
* cached instances managed by DevTools target factory.
|
||||
* web-extensions need to use dedicated instances of Commands and cannot reuse the
|
||||
* cached instances managed by DevTools.
|
||||
* Note that is will end up being cached in WebExtension codebase, via
|
||||
* DevToolsExtensionPageContextParent.getDevToolsCommands.
|
||||
*/
|
||||
createDescriptorForTabForWebExtension: function(tab) {
|
||||
return TabDescriptorFactory.createDescriptorForTab(tab, {
|
||||
forceCreationForWebextension: true,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Compatibility layer for web-extensions. Used by DevToolsShim for
|
||||
* browser/components/extensions/ext-devtools-inspectedWindow.js
|
||||
*/
|
||||
createWebExtensionInspectedWindowFront: function(tabTarget) {
|
||||
return tabTarget.getFront("webExtensionInspectedWindow");
|
||||
createCommandsForTabForWebExtension: function(tab) {
|
||||
return CommandsFactory.forTab(tab);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -38,21 +38,10 @@ exports.TabDescriptorFactory = {
|
||||
*
|
||||
* @param {XULTab} tab
|
||||
* The tab to use in creating a new descriptor.
|
||||
* @param {Object} options
|
||||
* - forceCreationForWebextension {Boolean}
|
||||
* Only used from webextension codebase. When set to true, the
|
||||
* factory will always create a new descriptor, even if we already
|
||||
* created one for the provided tab. This descriptor will not be
|
||||
* cached, and will not be returned via subsequent calls to this
|
||||
* method.
|
||||
*
|
||||
* @return {TabDescriptorFront} The tab descriptor for the provided tab.
|
||||
*/
|
||||
async createDescriptorForTab(tab, { forceCreationForWebextension } = {}) {
|
||||
if (forceCreationForWebextension) {
|
||||
return this._createDescriptorForTab(tab);
|
||||
}
|
||||
|
||||
async createDescriptorForTab(tab) {
|
||||
let descriptor = descriptors.get(tab);
|
||||
if (descriptor) {
|
||||
return descriptor;
|
||||
|
@ -17,16 +17,8 @@ async function testTabDescriptorWithURL(url) {
|
||||
info(`Test TabDescriptor against url ${url}\n`);
|
||||
const tab = await addTab(url);
|
||||
|
||||
const descriptorPromises = [];
|
||||
const sharedDescriptor = await TabDescriptorFactory.createDescriptorForTab(
|
||||
tab
|
||||
);
|
||||
descriptorPromises.push(sharedDescriptor);
|
||||
is(
|
||||
sharedDescriptor.localTab,
|
||||
tab,
|
||||
"TabDescriptor's localTab is set correctly"
|
||||
);
|
||||
const descriptor = await TabDescriptorFactory.createDescriptorForTab(tab);
|
||||
is(descriptor.localTab, tab, "TabDescriptor's localTab is set correctly");
|
||||
|
||||
info(
|
||||
"Calling a second time createDescriptorForTab with the same tab, will return the same descriptor"
|
||||
@ -34,58 +26,16 @@ async function testTabDescriptorWithURL(url) {
|
||||
const secondDescriptor = await TabDescriptorFactory.createDescriptorForTab(
|
||||
tab
|
||||
);
|
||||
is(sharedDescriptor, secondDescriptor, "second descriptor is the same");
|
||||
is(descriptor, secondDescriptor, "second descriptor is the same");
|
||||
|
||||
info(
|
||||
"forceCreationForWebextension allows to spawn new descriptor for the same tab"
|
||||
);
|
||||
const webExtDescriptor = await TabDescriptorFactory.createDescriptorForTab(
|
||||
tab,
|
||||
{ forceCreationForWebextension: true }
|
||||
);
|
||||
isnot(
|
||||
sharedDescriptor,
|
||||
webExtDescriptor,
|
||||
"web extension descriptor is a new one"
|
||||
);
|
||||
is(
|
||||
webExtDescriptor.localTab,
|
||||
tab,
|
||||
"web ext descriptor still refers to the same tab"
|
||||
);
|
||||
descriptorPromises.push(webExtDescriptor);
|
||||
|
||||
info("Instantiate many descriptor in parallel");
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const descriptor = TabDescriptorFactory.createDescriptorForTab(tab, {
|
||||
forceCreationForWebextension: true,
|
||||
});
|
||||
descriptorPromises.push(descriptor);
|
||||
}
|
||||
|
||||
info("Wait for all descriptor to be resolved");
|
||||
const descriptors = await Promise.all(descriptorPromises);
|
||||
|
||||
info("Wait for all targets to be created");
|
||||
const targets = await Promise.all(
|
||||
descriptors.map(async descriptor => {
|
||||
return descriptor.getTarget();
|
||||
})
|
||||
);
|
||||
info("Wait for descriptor's target");
|
||||
const target = await descriptor.getTarget();
|
||||
|
||||
info("Call any method to ensure that each target works");
|
||||
await Promise.all(
|
||||
targets.map(async target => {
|
||||
await target.logInPage("foo");
|
||||
})
|
||||
);
|
||||
await target.logInPage("foo");
|
||||
|
||||
info("Destroy all the descriptors");
|
||||
await Promise.all(
|
||||
descriptors.map(async descriptor => {
|
||||
await descriptor.destroy();
|
||||
})
|
||||
);
|
||||
info("Destroy the descriptor");
|
||||
await descriptor.destroy();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
|
@ -13,10 +13,6 @@ const {
|
||||
registerFront,
|
||||
} = require("devtools/shared/protocol");
|
||||
|
||||
const {
|
||||
getAdHocFrontOrPrimitiveGrip,
|
||||
} = require("devtools/client/fronts/object");
|
||||
|
||||
/**
|
||||
* The corresponding Front object for the WebExtensionInspectedWindowActor.
|
||||
*/
|
||||
@ -29,68 +25,6 @@ class WebExtensionInspectedWindowFront extends FrontClassWithSpec(
|
||||
// Attribute name from which to retrieve the actorID out of the target actor's form
|
||||
this.formAttributeName = "webExtensionInspectedWindowActor";
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the provided javascript code in a target window.
|
||||
*
|
||||
* @param {Object} webExtensionCallerInfo - The addonId and the url (the addon base url
|
||||
* or the url of the actual caller filename and lineNumber) used to log useful
|
||||
* debugging information in the produced error logs and eval stack trace.
|
||||
* @param {String} expression - The expression to evaluate.
|
||||
* @param {Object} options - An option object. Check the actor method definition to see
|
||||
* what properties it can hold (minus the `consoleFront` property which is defined
|
||||
* below).
|
||||
* @param {WebConsoleFront} options.consoleFront - An optional webconsole front. When
|
||||
* set, the result will be either a primitive, a LongStringFront or an
|
||||
* ObjectFront, and the WebConsoleActor corresponding to the console front will
|
||||
* be used to generate those, which is needed if we want to handle ObjectFronts
|
||||
* on the client.
|
||||
*/
|
||||
async eval(webExtensionCallerInfo, expression, options = {}) {
|
||||
const { consoleFront } = options;
|
||||
|
||||
if (consoleFront) {
|
||||
options.evalResultAsGrip = true;
|
||||
options.toolboxConsoleActorID = consoleFront.actor;
|
||||
delete options.consoleFront;
|
||||
}
|
||||
|
||||
const response = await super.eval(
|
||||
webExtensionCallerInfo,
|
||||
expression,
|
||||
options
|
||||
);
|
||||
|
||||
// If no consoleFront was provided, we can directly return the response.
|
||||
if (!consoleFront) {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (
|
||||
!response.hasOwnProperty("exceptionInfo") &&
|
||||
!response.hasOwnProperty("valueGrip")
|
||||
) {
|
||||
throw new Error(
|
||||
"Response does not have `exceptionInfo` or `valueGrip` property"
|
||||
);
|
||||
}
|
||||
|
||||
if (response.exceptionInfo) {
|
||||
console.error(
|
||||
response.exceptionInfo.description,
|
||||
...(response.exceptionInfo.details || [])
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
// On the server, the valueGrip is created from the toolbox webconsole actor.
|
||||
// If we want since the ObjectFront connection is inherited from the parent front, we
|
||||
// need to set the console front as the parent front.
|
||||
return getAdHocFrontOrPrimitiveGrip(
|
||||
response.valueGrip,
|
||||
consoleFront || this
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.WebExtensionInspectedWindowFront = WebExtensionInspectedWindowFront;
|
||||
|
@ -44,10 +44,6 @@ class TabDescriptorFront extends DescriptorMixin(
|
||||
// debugging).
|
||||
this._localTab = null;
|
||||
|
||||
// Flipped when creating dedicated tab targets for DevTools WebExtensions.
|
||||
// See toolkit/components/extensions/ExtensionParent.jsm .
|
||||
this.isDevToolsExtensionContext = false;
|
||||
|
||||
this._onTargetDestroyed = this._onTargetDestroyed.bind(this);
|
||||
this._handleTabEvent = this._handleTabEvent.bind(this);
|
||||
}
|
||||
@ -246,11 +242,6 @@ class TabDescriptorFront extends DescriptorMixin(
|
||||
* Process change can go in both ways.
|
||||
*/
|
||||
async _onRemotenessChange() {
|
||||
// The front that was created for DevTools page extension does not have corresponding toolbox.
|
||||
if (this.isDevToolsExtensionContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In a near future, this client side code should be replaced by actor code,
|
||||
// notifying about new tab targets.
|
||||
this.emit("remoteness-change", this._targetFront);
|
||||
|
@ -139,9 +139,7 @@ add_task(async function testSidebarSetObject() {
|
||||
});
|
||||
|
||||
add_task(async function testSidebarSetExpressionResult() {
|
||||
const inspectedWindowFront = await toolbox.target.getFront(
|
||||
"webExtensionInspectedWindow"
|
||||
);
|
||||
const { commands } = toolbox;
|
||||
const sidebar = inspector.getPanel(SIDEBAR_ID);
|
||||
const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID);
|
||||
|
||||
@ -156,7 +154,7 @@ add_task(async function testSidebarSetExpressionResult() {
|
||||
`;
|
||||
|
||||
const consoleFront = await toolbox.target.getFront("console");
|
||||
let evalResult = await inspectedWindowFront.eval(
|
||||
let evalResult = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
expression,
|
||||
{
|
||||
@ -228,7 +226,7 @@ add_task(async function testSidebarSetExpressionResult() {
|
||||
info(
|
||||
"Testing sidebar.setExpressionResult for an expression returning a longstring"
|
||||
);
|
||||
evalResult = await inspectedWindowFront.eval(
|
||||
evalResult = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
`"ab ".repeat(10000)`,
|
||||
{
|
||||
@ -250,23 +248,23 @@ add_task(async function testSidebarSetExpressionResult() {
|
||||
info(
|
||||
"Testing sidebar.setExpressionResult for an expression returning a primitive"
|
||||
);
|
||||
evalResult = await inspectedWindowFront.eval(fakeExtCallerInfo, `1 + 2`, {
|
||||
consoleFront,
|
||||
});
|
||||
evalResult = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
`1 + 2`,
|
||||
{
|
||||
consoleFront,
|
||||
}
|
||||
);
|
||||
sidebar.setExpressionResult(evalResult);
|
||||
const numberEl = await ContentTaskUtils.waitForCondition(
|
||||
() => sidebarPanelContent.querySelector(".objectBox-number"),
|
||||
"Wait for the result number element to be rendered"
|
||||
);
|
||||
is(numberEl.textContent, "3", `The "1 + 2" expression was evaluated as "3"`);
|
||||
|
||||
inspectedWindowFront.destroy();
|
||||
});
|
||||
|
||||
add_task(async function testSidebarDOMNodeHighlighting() {
|
||||
const inspectedWindowFront = await toolbox.target.getFront(
|
||||
"webExtensionInspectedWindow"
|
||||
);
|
||||
const { commands } = toolbox;
|
||||
const sidebar = inspector.getPanel(SIDEBAR_ID);
|
||||
const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID);
|
||||
|
||||
@ -278,7 +276,7 @@ add_task(async function testSidebarDOMNodeHighlighting() {
|
||||
const expression = "({ body: document.body })";
|
||||
|
||||
const consoleFront = await toolbox.target.getFront("console");
|
||||
const evalResult = await inspectedWindowFront.eval(
|
||||
const evalResult = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
expression,
|
||||
{
|
||||
@ -329,8 +327,6 @@ add_task(async function testSidebarDOMNodeHighlighting() {
|
||||
|
||||
await onNodeUnhighlight;
|
||||
info("The node is no longer highlighted");
|
||||
|
||||
inspectedWindowFront.destroy();
|
||||
});
|
||||
|
||||
add_task(async function testSidebarDOMNodeOpenInspector() {
|
||||
@ -387,10 +383,6 @@ add_task(async function testSidebarDOMNodeOpenInspector() {
|
||||
});
|
||||
|
||||
add_task(async function testSidebarSetExtensionPage() {
|
||||
const inspectedWindowFront = await toolbox.target.getFront(
|
||||
"webExtensionInspectedWindow"
|
||||
);
|
||||
|
||||
const sidebar = inspector.getPanel(SIDEBAR_ID);
|
||||
const sidebarPanelContent = inspector.sidebar.getTabPanel(SIDEBAR_ID);
|
||||
|
||||
@ -407,7 +399,6 @@ add_task(async function testSidebarSetExtensionPage() {
|
||||
|
||||
await testSetExtensionPageSidebarPanel(sidebarPanelContent, expectedURL);
|
||||
|
||||
inspectedWindowFront.destroy();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
||||
|
@ -27,7 +27,6 @@ support-files =
|
||||
doc_perf.html
|
||||
error-actor.js
|
||||
grid.html
|
||||
inspectedwindow-reload-target.sjs
|
||||
inspector-isScrollable-data.html
|
||||
inspector-search-data.html
|
||||
inspector-traversal-data.html
|
||||
@ -170,4 +169,3 @@ fail-if = fission
|
||||
[browser_stylesheets_getTextEmpty.js]
|
||||
[browser_stylesheets_nested-iframes.js]
|
||||
[browser_watcher-watchTargets-frames.js]
|
||||
[browser_webextension_inspected_window.js]
|
||||
|
@ -8,6 +8,8 @@
|
||||
// (please try to keep the list alphabetically sorted)
|
||||
/*eslint sort-keys: "error"*/
|
||||
const Commands = {
|
||||
inspectedWindowCommand:
|
||||
"devtools/shared/commands/inspected-window/inspected-window-command",
|
||||
targetCommand: "devtools/shared/commands/target/target-command",
|
||||
targetConfigurationCommand:
|
||||
"devtools/shared/commands/target-configuration/target-configuration-command",
|
||||
|
@ -0,0 +1,106 @@
|
||||
/* 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 {
|
||||
getAdHocFrontOrPrimitiveGrip,
|
||||
// eslint-disable-next-line mozilla/reject-some-requires
|
||||
} = require("devtools/client/fronts/object");
|
||||
|
||||
/**
|
||||
* For now, this class is mostly a wrapper around webExtInspectedWindow actor.
|
||||
*/
|
||||
class InspectedWindowCommand {
|
||||
constructor({ commands }) {
|
||||
this.commands = commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a promise that resolves to the related target actor's front.
|
||||
* The Web Extension inspected window actor.
|
||||
*
|
||||
* @return {Promise<WebExtensionInspectedWindowFront>}
|
||||
*/
|
||||
getFront() {
|
||||
return this.commands.targetCommand.targetFront.getFront(
|
||||
"webExtensionInspectedWindow"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the provided javascript code in a target window.
|
||||
*
|
||||
* @param {Object} webExtensionCallerInfo - The addonId and the url (the addon base url
|
||||
* or the url of the actual caller filename and lineNumber) used to log useful
|
||||
* debugging information in the produced error logs and eval stack trace.
|
||||
* @param {String} expression - The expression to evaluate.
|
||||
* @param {Object} options - An option object. Check the actor method definition to see
|
||||
* what properties it can hold (minus the `consoleFront` property which is defined
|
||||
* below).
|
||||
* @param {WebConsoleFront} options.consoleFront - An optional webconsole front. When
|
||||
* set, the result will be either a primitive, a LongStringFront or an
|
||||
* ObjectFront, and the WebConsoleActor corresponding to the console front will
|
||||
* be used to generate those, which is needed if we want to handle ObjectFronts
|
||||
* on the client.
|
||||
*/
|
||||
async eval(webExtensionCallerInfo, expression, options = {}) {
|
||||
const { consoleFront } = options;
|
||||
|
||||
if (consoleFront) {
|
||||
options.evalResultAsGrip = true;
|
||||
options.toolboxConsoleActorID = consoleFront.actor;
|
||||
delete options.consoleFront;
|
||||
}
|
||||
|
||||
const front = await this.getFront();
|
||||
const response = await front.eval(
|
||||
webExtensionCallerInfo,
|
||||
expression,
|
||||
options
|
||||
);
|
||||
|
||||
// If no consoleFront was provided, we can directly return the response.
|
||||
if (!consoleFront) {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (
|
||||
!response.hasOwnProperty("exceptionInfo") &&
|
||||
!response.hasOwnProperty("valueGrip")
|
||||
) {
|
||||
throw new Error(
|
||||
"Response does not have `exceptionInfo` or `valueGrip` property"
|
||||
);
|
||||
}
|
||||
|
||||
if (response.exceptionInfo) {
|
||||
console.error(
|
||||
response.exceptionInfo.description,
|
||||
...(response.exceptionInfo.details || [])
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
// On the server, the valueGrip is created from the toolbox webconsole actor.
|
||||
// If we want since the ObjectFront connection is inherited from the parent front, we
|
||||
// need to set the console front as the parent front.
|
||||
return getAdHocFrontOrPrimitiveGrip(
|
||||
response.valueGrip,
|
||||
consoleFront || this
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* For more information about the arguments, please have a look at
|
||||
* the actor specification: devtools/shared/specs/addon/webextension-inspected-window.js
|
||||
* or actor: devtools/server/actors/addon/webextension-inspected-window.js
|
||||
*/
|
||||
async reload(callerInfo, options) {
|
||||
const front = await this.getFront();
|
||||
return front.reload(callerInfo, options);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InspectedWindowCommand;
|
10
devtools/shared/commands/inspected-window/moz.build
Normal file
10
devtools/shared/commands/inspected-window/moz.build
Normal file
@ -0,0 +1,10 @@
|
||||
# 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/.
|
||||
|
||||
DevToolsModules(
|
||||
"inspected-window-command.js",
|
||||
)
|
||||
|
||||
if CONFIG["MOZ_BUILD_APP"] != "mobile/android":
|
||||
BROWSER_CHROME_MANIFESTS += ["tests/browser.ini"]
|
@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
// General rule from /.eslintrc.js only accept folders matching **/test*/browser*/
|
||||
// where is this folder doesn't match, so manually apply browser test config
|
||||
module.exports = {
|
||||
extends: ["plugin:mozilla/browser-test"],
|
||||
};
|
11
devtools/shared/commands/inspected-window/tests/browser.ini
Normal file
11
devtools/shared/commands/inspected-window/tests/browser.ini
Normal file
@ -0,0 +1,11 @@
|
||||
[DEFAULT]
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
!/devtools/client/shared/test/shared-head.js
|
||||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
!/devtools/client/shared/test/test-actor.js
|
||||
head.js
|
||||
inspectedwindow-reload-target.sjs
|
||||
|
||||
[browser_webextension_inspected_window.js]
|
@ -3,7 +3,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_RELOAD_URL = `${MAIN_DOMAIN}/inspectedwindow-reload-target.sjs`;
|
||||
const TEST_RELOAD_URL = `${URL_ROOT}/inspectedwindow-reload-target.sjs`;
|
||||
|
||||
async function setup(pageUrl) {
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
@ -23,32 +23,31 @@ async function setup(pageUrl) {
|
||||
addonId: extension.id,
|
||||
};
|
||||
|
||||
const target = await addTabTarget(pageUrl);
|
||||
const tab = await addTab(pageUrl);
|
||||
|
||||
const { client } = target;
|
||||
const webConsoleFront = await target.getFront("console");
|
||||
const inspectedWindowFront = await target.getFront(
|
||||
"webExtensionInspectedWindow"
|
||||
const commands = await CommandsFactory.forTab(tab);
|
||||
await commands.targetCommand.startListening();
|
||||
|
||||
const webConsoleFront = await commands.targetCommand.targetFront.getFront(
|
||||
"console"
|
||||
);
|
||||
|
||||
return {
|
||||
client,
|
||||
target,
|
||||
webConsoleFront,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
};
|
||||
}
|
||||
|
||||
async function teardown({ client, extension }) {
|
||||
await client.close();
|
||||
DevToolsServer.destroy();
|
||||
async function teardown({ commands, extension }) {
|
||||
await commands.destroy();
|
||||
gBrowser.removeCurrentTab();
|
||||
await extension.unload();
|
||||
}
|
||||
|
||||
function waitForNextTabNavigated(target) {
|
||||
function waitForNextTabNavigated(commands) {
|
||||
const target = commands.targetCommand.targetFront;
|
||||
return new Promise(resolve => {
|
||||
target.on("tabNavigated", function tabNavigatedListener(pkt) {
|
||||
if (pkt.state == "stop" && !pkt.isFrameSwitching) {
|
||||
@ -92,14 +91,9 @@ function collectEvalResults() {
|
||||
}
|
||||
|
||||
add_task(async function test_successfull_inspectedWindowEval_result() {
|
||||
const {
|
||||
client,
|
||||
inspectedWindowFront,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
} = await setup(MAIN_DOMAIN);
|
||||
const { commands, extension, fakeExtCallerInfo } = await setup(URL_ROOT);
|
||||
|
||||
const result = await inspectedWindowFront.eval(
|
||||
const result = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"window.location",
|
||||
{}
|
||||
@ -108,7 +102,7 @@ add_task(async function test_successfull_inspectedWindowEval_result() {
|
||||
ok(result.value, "Got a result from inspectedWindow eval");
|
||||
is(
|
||||
result.value.href,
|
||||
MAIN_DOMAIN,
|
||||
URL_ROOT,
|
||||
"Got the expected window.location.href property value"
|
||||
);
|
||||
is(
|
||||
@ -117,22 +111,25 @@ add_task(async function test_successfull_inspectedWindowEval_result() {
|
||||
"Got the expected window.location.protocol property value"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_successfull_inspectedWindowEval_resultAsGrip() {
|
||||
const {
|
||||
client,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
webConsoleFront,
|
||||
} = await setup(MAIN_DOMAIN);
|
||||
} = await setup(URL_ROOT);
|
||||
|
||||
let result = await inspectedWindowFront.eval(fakeExtCallerInfo, "window", {
|
||||
evalResultAsGrip: true,
|
||||
toolboxConsoleActorID: webConsoleFront.actor,
|
||||
});
|
||||
let result = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"window",
|
||||
{
|
||||
evalResultAsGrip: true,
|
||||
toolboxConsoleActorID: webConsoleFront.actor,
|
||||
}
|
||||
);
|
||||
|
||||
ok(result.valueGrip, "Got a result from inspectedWindow eval");
|
||||
ok(result.valueGrip.actor, "Got a object actor as expected");
|
||||
@ -144,9 +141,13 @@ add_task(async function test_successfull_inspectedWindowEval_resultAsGrip() {
|
||||
);
|
||||
|
||||
// Test invalid evalResultAsGrip request.
|
||||
result = await inspectedWindowFront.eval(fakeExtCallerInfo, "window", {
|
||||
evalResultAsGrip: true,
|
||||
});
|
||||
result = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"window",
|
||||
{
|
||||
evalResultAsGrip: true,
|
||||
}
|
||||
);
|
||||
|
||||
ok(
|
||||
!result.value && !result.valueGrip,
|
||||
@ -186,18 +187,13 @@ add_task(async function test_successfull_inspectedWindowEval_resultAsGrip() {
|
||||
"Got the expected content in the error results's details"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_error_inspectedWindowEval_result() {
|
||||
const {
|
||||
client,
|
||||
inspectedWindowFront,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
} = await setup(MAIN_DOMAIN);
|
||||
const { commands, extension, fakeExtCallerInfo } = await setup(URL_ROOT);
|
||||
|
||||
const result = await inspectedWindowFront.eval(
|
||||
const result = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"window",
|
||||
{}
|
||||
@ -232,19 +228,16 @@ add_task(async function test_error_inspectedWindowEval_result() {
|
||||
"Got the expected content in the error results's details"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(
|
||||
async function test_system_principal_denied_error_inspectedWindowEval_result() {
|
||||
const {
|
||||
client,
|
||||
inspectedWindowFront,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
} = await setup("about:addons");
|
||||
const { commands, extension, fakeExtCallerInfo } = await setup(
|
||||
"about:addons"
|
||||
);
|
||||
|
||||
const result = await inspectedWindowFront.eval(
|
||||
const result = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"window",
|
||||
{}
|
||||
@ -276,19 +269,14 @@ add_task(
|
||||
"Got the expected content in the error results's details"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
}
|
||||
);
|
||||
|
||||
add_task(async function test_exception_inspectedWindowEval_result() {
|
||||
const {
|
||||
client,
|
||||
inspectedWindowFront,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
} = await setup(MAIN_DOMAIN);
|
||||
const { commands, extension, fakeExtCallerInfo } = await setup(URL_ROOT);
|
||||
|
||||
const result = await inspectedWindowFront.eval(
|
||||
const result = await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"throw Error('fake eval error');",
|
||||
{}
|
||||
@ -314,25 +302,26 @@ add_task(async function test_exception_inspectedWindowEval_result() {
|
||||
"Got the expected stack trace in the exception message"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_exception_inspectedWindowReload() {
|
||||
const {
|
||||
client,
|
||||
webConsoleFront,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
target,
|
||||
} = await setup(`${TEST_RELOAD_URL}?test=cache`);
|
||||
|
||||
// Test reload with bypassCache=false.
|
||||
|
||||
const waitForNoBypassCacheReload = waitForNextTabNavigated(target);
|
||||
const reloadResult = await inspectedWindowFront.reload(fakeExtCallerInfo, {
|
||||
ignoreCache: false,
|
||||
});
|
||||
const waitForNoBypassCacheReload = waitForNextTabNavigated(commands);
|
||||
const reloadResult = await commands.inspectedWindowCommand.reload(
|
||||
fakeExtCallerInfo,
|
||||
{
|
||||
ignoreCache: false,
|
||||
}
|
||||
);
|
||||
|
||||
ok(
|
||||
!reloadResult,
|
||||
@ -353,8 +342,10 @@ add_task(async function test_exception_inspectedWindowReload() {
|
||||
|
||||
// Test reload with bypassCache=true.
|
||||
|
||||
const waitForForceBypassCacheReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, { ignoreCache: true });
|
||||
const waitForForceBypassCacheReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
|
||||
ignoreCache: true,
|
||||
});
|
||||
|
||||
await waitForForceBypassCacheReload;
|
||||
|
||||
@ -368,23 +359,21 @@ add_task(async function test_exception_inspectedWindowReload() {
|
||||
"Got the expected result with reload forceBypassCache=true"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
|
||||
const {
|
||||
client,
|
||||
webConsoleFront,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
target,
|
||||
} = await setup(`${TEST_RELOAD_URL}?test=user-agent`);
|
||||
|
||||
// Test reload with custom userAgent.
|
||||
|
||||
const waitForCustomUserAgentReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {
|
||||
const waitForCustomUserAgentReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
|
||||
userAgent: "Customized User Agent",
|
||||
});
|
||||
|
||||
@ -402,8 +391,8 @@ add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
|
||||
|
||||
// Test reload with no custom userAgent.
|
||||
|
||||
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
|
||||
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
|
||||
|
||||
await waitForNoCustomUserAgentReload;
|
||||
|
||||
@ -417,23 +406,21 @@ add_task(async function test_exception_inspectedWindowReload_customUserAgent() {
|
||||
"Got the expected result with reload without a customized userAgent"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_exception_inspectedWindowReload_injectedScript() {
|
||||
const {
|
||||
client,
|
||||
webConsoleFront,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
target,
|
||||
} = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`);
|
||||
|
||||
// Test reload with an injectedScript.
|
||||
|
||||
const waitForInjectedScriptReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {
|
||||
const waitForInjectedScriptReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
|
||||
injectedScript: `new ${injectedScript}`,
|
||||
});
|
||||
await waitForInjectedScriptReload;
|
||||
@ -452,8 +439,8 @@ add_task(async function test_exception_inspectedWindowReload_injectedScript() {
|
||||
|
||||
// Test reload without an injectedScript.
|
||||
|
||||
const waitForNoInjectedScriptReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
|
||||
const waitForNoInjectedScriptReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
|
||||
await waitForNoInjectedScriptReload;
|
||||
|
||||
const noInjectedScriptEval = await webConsoleFront.evaluateJSAsync(
|
||||
@ -468,28 +455,26 @@ add_task(async function test_exception_inspectedWindowReload_injectedScript() {
|
||||
"Got the expected result on reload with no injected script"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
|
||||
const {
|
||||
client,
|
||||
webConsoleFront,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
target,
|
||||
} = await setup(`${TEST_RELOAD_URL}?test=user-agent`);
|
||||
|
||||
// Test reload with custom userAgent three times (and then
|
||||
// check that only the first one has affected the page reload.
|
||||
|
||||
const waitForCustomUserAgentReload = waitForNextTabNavigated(target);
|
||||
const waitForCustomUserAgentReload = waitForNextTabNavigated(commands);
|
||||
|
||||
inspectedWindowFront.reload(fakeExtCallerInfo, {
|
||||
commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
|
||||
userAgent: "Customized User Agent 1",
|
||||
});
|
||||
inspectedWindowFront.reload(fakeExtCallerInfo, {
|
||||
commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
|
||||
userAgent: "Customized User Agent 2",
|
||||
});
|
||||
|
||||
@ -507,8 +492,8 @@ add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
|
||||
|
||||
// Test reload with no custom userAgent.
|
||||
|
||||
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
|
||||
const waitForNoCustomUserAgentReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
|
||||
|
||||
await waitForNoCustomUserAgentReload;
|
||||
|
||||
@ -522,23 +507,21 @@ add_task(async function test_exception_inspectedWindowReload_multiple_calls() {
|
||||
"Got the expected result with reload without a customized userAgent"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
add_task(async function test_exception_inspectedWindowReload_stopped() {
|
||||
const {
|
||||
client,
|
||||
webConsoleFront,
|
||||
inspectedWindowFront,
|
||||
commands,
|
||||
extension,
|
||||
fakeExtCallerInfo,
|
||||
target,
|
||||
} = await setup(`${TEST_RELOAD_URL}?test=injected-script&frames=3`);
|
||||
|
||||
// Test reload on a page that calls window.stop() immediately during the page loading
|
||||
|
||||
const waitForPageLoad = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.eval(
|
||||
const waitForPageLoad = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.eval(
|
||||
fakeExtCallerInfo,
|
||||
"window.location += '&stop=windowStop'"
|
||||
);
|
||||
@ -547,8 +530,8 @@ add_task(async function test_exception_inspectedWindowReload_stopped() {
|
||||
await waitForPageLoad;
|
||||
|
||||
info("Starting a reload with an injectedScript");
|
||||
const waitForInjectedScriptReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {
|
||||
const waitForInjectedScriptReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {
|
||||
injectedScript: `new ${injectedScript}`,
|
||||
});
|
||||
await waitForInjectedScriptReload;
|
||||
@ -570,8 +553,8 @@ add_task(async function test_exception_inspectedWindowReload_stopped() {
|
||||
// Reload again with no options.
|
||||
|
||||
info("Reload the tab again without any reload options");
|
||||
const waitForNoInjectedScriptReload = waitForNextTabNavigated(target);
|
||||
await inspectedWindowFront.reload(fakeExtCallerInfo, {});
|
||||
const waitForNoInjectedScriptReload = waitForNextTabNavigated(commands);
|
||||
await commands.inspectedWindowCommand.reload(fakeExtCallerInfo, {});
|
||||
await waitForNoInjectedScriptReload;
|
||||
|
||||
const noInjectedScriptEval = await webConsoleFront.evaluateJSAsync(
|
||||
@ -589,7 +572,7 @@ add_task(async function test_exception_inspectedWindowReload_stopped() {
|
||||
"No injectedScript should have been evaluated during the second reload"
|
||||
);
|
||||
|
||||
await teardown({ client, extension });
|
||||
await teardown({ commands, extension });
|
||||
});
|
||||
|
||||
// TODO: check eval with $0 binding once implemented (Bug 1300590)
|
13
devtools/shared/commands/inspected-window/tests/head.js
Normal file
13
devtools/shared/commands/inspected-window/tests/head.js
Normal file
@ -0,0 +1,13 @@
|
||||
/* 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";
|
||||
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
/* import-globals-from ../../../../client/shared/test/shared-head.js */
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
|
||||
this
|
||||
);
|
@ -3,6 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS += [
|
||||
"inspected-window",
|
||||
"target",
|
||||
"target-configuration",
|
||||
]
|
||||
|
@ -313,8 +313,7 @@ const DevToolsShim = {
|
||||
* therefore DevTools should always be available when they are called.
|
||||
*/
|
||||
const webExtensionsMethods = [
|
||||
"createDescriptorForTabForWebExtension",
|
||||
"createWebExtensionInspectedWindowFront",
|
||||
"createCommandsForTabForWebExtension",
|
||||
"getTheme",
|
||||
"openBrowserConsole",
|
||||
];
|
||||
|
@ -626,13 +626,13 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent {
|
||||
constructor(...params) {
|
||||
super(...params);
|
||||
|
||||
// We want to explicitly set `this._devToolsToolbox` as well to `null` here, but the
|
||||
// toolbox is set during the processing of the parent's constructor, so it is currently
|
||||
// not possible to set.
|
||||
this._currentDevToolsTarget = null;
|
||||
// Set all attributes that are lazily defined to `null` here.
|
||||
//
|
||||
// Note that we can't do that for `this._devToolsToolbox` because it will
|
||||
// be defined when calling our parent constructor and so would override it back to `null`.
|
||||
this._devToolsCommands = null;
|
||||
this._onNavigatedListeners = null;
|
||||
|
||||
this._onTargetAvailable = this._onTargetAvailable.bind(this);
|
||||
this._onResourceAvailable = this._onResourceAvailable.bind(this);
|
||||
}
|
||||
|
||||
@ -671,30 +671,31 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent {
|
||||
}
|
||||
|
||||
/**
|
||||
* The returned target may be destroyed when navigating to another process and so,
|
||||
* should only be used accordingly. That is to say, we can do an immediate action on it,
|
||||
* but not listen to RDP events.
|
||||
* @returns {Promise<TabTarget>}
|
||||
* The current devtools target associated to the context.
|
||||
* The returned "commands" object, exposing modules implemented from devtools/shared/commands.
|
||||
* Each attribute being a static interface to communicate with the server backend.
|
||||
*
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
async getCurrentDevToolsTarget() {
|
||||
if (!this._currentDevToolsTarget) {
|
||||
if (!this._pendingWatchTargetsPromise) {
|
||||
// When _onTargetAvailable is called, it will create a new target,
|
||||
// via DevToolsShim.createDescriptorForTabForWebExtension. If this function
|
||||
// is called multiple times before this._currentDevToolsTarget is populated,
|
||||
// we don't want to create X new, duplicated targets, so we store the Promise
|
||||
// returned by watchTargets, in order to properly wait on subsequent calls.
|
||||
this._pendingWatchTargetsPromise = this.devToolsToolbox.targetList.watchTargets(
|
||||
[this.devToolsToolbox.targetList.TYPES.FRAME],
|
||||
this._onTargetAvailable
|
||||
);
|
||||
}
|
||||
await this._pendingWatchTargetsPromise;
|
||||
this._pendingWatchTargetsPromise = null;
|
||||
async getDevToolsCommands() {
|
||||
// Ensure that we try to instantiate a commands only once,
|
||||
// even if createCommandsForTabForWebExtension is async.
|
||||
if (this._devToolsCommandsPromise) {
|
||||
return this._devToolsCommandsPromise;
|
||||
}
|
||||
if (this._devToolsCommands) {
|
||||
return this._devToolsCommands;
|
||||
}
|
||||
|
||||
return this._currentDevToolsTarget;
|
||||
this._devToolsCommandsPromise = (async () => {
|
||||
const commands = await DevToolsShim.createCommandsForTabForWebExtension(
|
||||
this.devToolsToolbox.descriptorFront.localTab
|
||||
);
|
||||
await commands.targetCommand.startListening();
|
||||
this._devToolsCommands = commands;
|
||||
this._devToolsCommandsPromise = null;
|
||||
return commands;
|
||||
})();
|
||||
return this._devToolsCommandsPromise;
|
||||
}
|
||||
|
||||
unload() {
|
||||
@ -703,11 +704,6 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent {
|
||||
return;
|
||||
}
|
||||
|
||||
this.devToolsToolbox.targetList.unwatchTargets(
|
||||
[this.devToolsToolbox.targetList.TYPES.FRAME],
|
||||
this._onTargetAvailable
|
||||
);
|
||||
|
||||
if (this._onNavigatedListeners) {
|
||||
this.devToolsToolbox.resourceWatcher.unwatchResources(
|
||||
[this.devToolsToolbox.resourceWatcher.TYPES.DOCUMENT_EVENT],
|
||||
@ -715,9 +711,9 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent {
|
||||
);
|
||||
}
|
||||
|
||||
if (this._currentDevToolsTarget) {
|
||||
this._currentDevToolsTarget.destroy();
|
||||
this._currentDevToolsTarget = null;
|
||||
if (this._devToolsCommands) {
|
||||
this._devToolsCommands.destroy();
|
||||
this._devToolsCommands = null;
|
||||
}
|
||||
|
||||
if (this._onNavigatedListeners) {
|
||||
@ -730,25 +726,6 @@ class DevToolsExtensionPageContextParent extends ExtensionPageContextParent {
|
||||
super.unload();
|
||||
}
|
||||
|
||||
async _onTargetAvailable({ targetFront }) {
|
||||
if (!targetFront.isTopLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const descriptorFront = await DevToolsShim.createDescriptorForTabForWebExtension(
|
||||
targetFront.localTab
|
||||
);
|
||||
|
||||
// Update the TabDescriptor `isDevToolsExtensionContext` flag.
|
||||
// This is a duplicated target, attached to no toolbox, DevTools needs to
|
||||
// handle it differently compared to a regular top-level target.
|
||||
descriptorFront.isDevToolsExtensionContext = true;
|
||||
|
||||
this._currentDevToolsTarget = await descriptorFront.getTarget();
|
||||
|
||||
await this._currentDevToolsTarget.attach();
|
||||
}
|
||||
|
||||
async _onResourceAvailable(resources) {
|
||||
for (const resource of resources) {
|
||||
const { targetFront } = resource;
|
||||
|
Loading…
Reference in New Issue
Block a user