mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 1069673 - Add support methods on devtool's Target, r=jryans
This commit is contained in:
parent
2f39e96d72
commit
0ba8932661
@ -109,24 +109,14 @@ exports.TargetFactory = {
|
||||
* The 'version' property allows the developer tools equivalent of browser
|
||||
* detection. Browser detection is evil, however while we don't know what we
|
||||
* will need to detect in the future, it is an easy way to postpone work.
|
||||
* We should be looking to use 'supports()' in place of version where
|
||||
* possible.
|
||||
* We should be looking to use the support features added in bug 1069673
|
||||
* in place of version where possible.
|
||||
*/
|
||||
function getVersion() {
|
||||
// FIXME: return something better
|
||||
return 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* A better way to support feature detection, but we're not yet at a place
|
||||
* where we have the features well enough defined for this to make lots of
|
||||
* sense.
|
||||
*/
|
||||
function supports(feature) {
|
||||
// FIXME: return something better
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* A Target represents something that we can debug. Targets are generally
|
||||
* read-only. Any changes that you wish to make to a target should be done via
|
||||
@ -151,12 +141,6 @@ function supports(feature) {
|
||||
* - hidden: The target is not visible anymore (for TargetTab, another tab is selected)
|
||||
* - visible: The target is visible (for TargetTab, tab is selected)
|
||||
*
|
||||
* Target also supports 2 functions to help allow 2 different versions of
|
||||
* Firefox debug each other. The 'version' property is the equivalent of
|
||||
* browser detection - simple and easy to implement but gets fragile when things
|
||||
* are not quite what they seem. The 'supports' property is the equivalent of
|
||||
* feature detection - harder to setup, but more robust long-term.
|
||||
*
|
||||
* Comparing Targets: 2 instances of a Target object can point at the same
|
||||
* thing, so t1 !== t2 and t1 != t2 even when they represent the same object.
|
||||
* To compare to targets use 't1.equals(t2)'.
|
||||
@ -196,7 +180,109 @@ function TabTarget(tab) {
|
||||
TabTarget.prototype = {
|
||||
_webProgressListener: null,
|
||||
|
||||
supports: supports,
|
||||
/**
|
||||
* Returns a promise for the protocol description from the root actor.
|
||||
* Used internally with `target.actorHasMethod`. Takes advantage of
|
||||
* caching if definition was fetched previously with the corresponding
|
||||
* actor information. Must be a remote target.
|
||||
*
|
||||
* @return {Promise}
|
||||
* {
|
||||
* "category": "actor",
|
||||
* "typeName": "longstractor",
|
||||
* "methods": [{
|
||||
* "name": "substring",
|
||||
* "request": {
|
||||
* "type": "substring",
|
||||
* "start": {
|
||||
* "_arg": 0,
|
||||
* "type": "primitive"
|
||||
* },
|
||||
* "end": {
|
||||
* "_arg": 1,
|
||||
* "type": "primitive"
|
||||
* }
|
||||
* },
|
||||
* "response": {
|
||||
* "substring": {
|
||||
* "_retval": "primitive"
|
||||
* }
|
||||
* }
|
||||
* }],
|
||||
* "events": {}
|
||||
* }
|
||||
*/
|
||||
getActorDescription: function (actorName) {
|
||||
if (!this.client) {
|
||||
throw new Error("TabTarget#getActorDescription() can only be called on remote tabs.");
|
||||
}
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (this._protocolDescription && this._protocolDescription.types[actorName]) {
|
||||
deferred.resolve(this._protocolDescription.types[actorName]);
|
||||
} else {
|
||||
this.client.mainRoot.protocolDescription(description => {
|
||||
this._protocolDescription = description;
|
||||
deferred.resolve(description.types[actorName]);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether or not the specific actor
|
||||
* type exists. Must be a remote target.
|
||||
*
|
||||
* @param {String} actorName
|
||||
* @return {Boolean}
|
||||
*/
|
||||
hasActor: function (actorName) {
|
||||
if (!this.client) {
|
||||
throw new Error("TabTarget#hasActor() can only be called on remote tabs.");
|
||||
}
|
||||
if (this.form) {
|
||||
return !!this.form[actorName + "Actor"];
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Queries the protocol description to see if an actor has
|
||||
* an available method. The actor must already be lazily-loaded,
|
||||
* so this is for use inside of tool. Returns a promise that
|
||||
* resolves to a boolean. Must be a remote target.
|
||||
*
|
||||
* @param {String} actorName
|
||||
* @param {String} methodName
|
||||
* @return {Promise}
|
||||
*/
|
||||
actorHasMethod: function (actorName, methodName) {
|
||||
if (!this.client) {
|
||||
throw new Error("TabTarget#actorHasMethod() can only be called on remote tabs.");
|
||||
}
|
||||
return this.getActorDescription(actorName).then(desc => {
|
||||
if (desc && desc.methods) {
|
||||
return !!desc.methods.find(method => method.name === methodName);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a trait from the root actor.
|
||||
*
|
||||
* @param {String} traitName
|
||||
* @return {Mixed}
|
||||
*/
|
||||
getTrait: function (traitName) {
|
||||
if (!this.client) {
|
||||
throw new Error("TabTarget#getTrait() can only be called on remote tabs.");
|
||||
}
|
||||
return this.client.traits[traitName];
|
||||
},
|
||||
|
||||
get version() { return getVersion(); },
|
||||
|
||||
get tab() {
|
||||
@ -609,7 +695,6 @@ function WindowTarget(window) {
|
||||
}
|
||||
|
||||
WindowTarget.prototype = {
|
||||
supports: supports,
|
||||
get version() { return getVersion(); },
|
||||
|
||||
get window() {
|
||||
|
@ -15,6 +15,7 @@ skip-if = e10s # Bug 1070837 - devtools/framework/toolbox.js |doc| getter not e1
|
||||
[browser_new_activation_workflow.js]
|
||||
[browser_target_events.js]
|
||||
[browser_target_remote.js]
|
||||
[browser_target_support.js]
|
||||
[browser_two_tabs.js]
|
||||
[browser_toolbox_dynamic_registration.js]
|
||||
[browser_toolbox_highlight.js]
|
||||
|
89
browser/devtools/framework/test/browser_target_support.js
Normal file
89
browser/devtools/framework/test/browser_target_support.js
Normal file
@ -0,0 +1,89 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test support methods on Target, such as `hasActor`, `getActorDescription`,
|
||||
// `actorHasMethod` and `getTrait`.
|
||||
|
||||
let { DebuggerServer } =
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let { DebuggerClient } =
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { devtools } =
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let { Task } =
|
||||
Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
let { WebAudioFront } =
|
||||
devtools.require("devtools/server/actors/webaudio");
|
||||
|
||||
function* testTarget (client, target) {
|
||||
yield target.makeRemote();
|
||||
|
||||
ise(target.hasActor("timeline"), true, "target.hasActor() true when actor exists.");
|
||||
ise(target.hasActor("webaudio"), true, "target.hasActor() true when actor exists.");
|
||||
ise(target.hasActor("notreal"), false, "target.hasActor() false when actor does not exist.");
|
||||
// Create a front to ensure the actor is loaded
|
||||
let front = new WebAudioFront(target.client, target.form);
|
||||
|
||||
let desc = yield target.getActorDescription("webaudio");
|
||||
ise(desc.typeName, "webaudio",
|
||||
"target.getActorDescription() returns definition data for corresponding actor");
|
||||
ise(desc.events["start-context"]["type"], "startContext",
|
||||
"target.getActorDescription() returns event data for corresponding actor");
|
||||
|
||||
desc = yield target.getActorDescription("nope");
|
||||
ise(desc, undefined, "target.getActorDescription() returns undefined for non-existing actor");
|
||||
desc = yield target.getActorDescription();
|
||||
ise(desc, undefined, "target.getActorDescription() returns undefined for undefined actor");
|
||||
|
||||
let hasMethod = yield target.actorHasMethod("audionode", "getType");
|
||||
ise(hasMethod, true,
|
||||
"target.actorHasMethod() returns true for existing actor with method");
|
||||
hasMethod = yield target.actorHasMethod("audionode", "nope");
|
||||
ise(hasMethod, false,
|
||||
"target.actorHasMethod() returns false for existing actor with no method");
|
||||
hasMethod = yield target.actorHasMethod("nope", "nope");
|
||||
ise(hasMethod, false,
|
||||
"target.actorHasMethod() returns false for non-existing actor with no method");
|
||||
hasMethod = yield target.actorHasMethod();
|
||||
ise(hasMethod, false,
|
||||
"target.actorHasMethod() returns false for undefined params");
|
||||
|
||||
ise(target.getTrait("customHighlighters")[0], "BoxModelHighlighter",
|
||||
"target.getTrait() returns objects when trait exists");
|
||||
ise(target.getTrait("giddyup"), undefined,
|
||||
"target.getTrait() returns undefined when trait does not exist");
|
||||
|
||||
close(target, client);
|
||||
}
|
||||
|
||||
// Ensure target is closed if client is closed directly
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(function () { return true; });
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
var client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
client.connect(() => {
|
||||
client.listTabs(response => {
|
||||
let options = {
|
||||
form: response,
|
||||
client: client,
|
||||
chrome: true
|
||||
};
|
||||
|
||||
devtools.TargetFactory.forRemoteTab(options).then(Task.async(testTarget).bind(null, client));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function close (target, client) {
|
||||
target.on("close", () => {
|
||||
ok(true, "Target was closed");
|
||||
DebuggerServer.destroy();
|
||||
finish();
|
||||
});
|
||||
client.close();
|
||||
}
|
@ -313,7 +313,7 @@ Tools.timeline = {
|
||||
tooltip: l10n("timeline.tooltip", timelineStrings),
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
return !target.isAddon;
|
||||
return !target.isAddon && target.hasActor("timeline");
|
||||
},
|
||||
|
||||
build: function (iframeWindow, toolbox) {
|
||||
|
@ -193,13 +193,15 @@ let CommandUtils = {
|
||||
* reflects the current debug target
|
||||
*/
|
||||
createEnvironment: function(container, targetProperty='target') {
|
||||
if (container[targetProperty].supports == null) {
|
||||
if (!container[targetProperty].toString ||
|
||||
!/TabTarget/.test(container[targetProperty].toString())) {
|
||||
throw new Error('Missing target');
|
||||
}
|
||||
|
||||
return {
|
||||
get target() {
|
||||
if (container[targetProperty].supports == null) {
|
||||
if (!container[targetProperty].toString ||
|
||||
!/TabTarget/.test(container[targetProperty].toString())) {
|
||||
throw new Error('Removed target');
|
||||
}
|
||||
|
||||
|
@ -5139,6 +5139,20 @@
|
||||
"n_buckets": "1000",
|
||||
"description": "The time (in milliseconds) that it took a 'listTabs' request to go round trip."
|
||||
},
|
||||
"DEVTOOLS_DEBUGGER_RDP_LOCAL_PROTOCOLDESCRIPTION_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "10000",
|
||||
"n_buckets": "1000",
|
||||
"description": "The time (in milliseconds) that it took a 'protocolDescription' request to go round trip."
|
||||
},
|
||||
"DEVTOOLS_DEBUGGER_RDP_REMOTE_PROTOCOLDESCRIPTION_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "10000",
|
||||
"n_buckets": "1000",
|
||||
"description": "The time (in milliseconds) that it took a 'protocolDescription' request to go round trip."
|
||||
},
|
||||
"DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTADDONS_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
@ -1451,6 +1451,15 @@ RootClient.prototype = {
|
||||
listAddons: DebuggerClient.requester({ type: "listAddons" },
|
||||
{ telemetry: "LISTADDONS" }),
|
||||
|
||||
/**
|
||||
* Description of protocol's actors and methods.
|
||||
*
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet.
|
||||
*/
|
||||
protocolDescription: DebuggerClient.requester({ type: "protocolDescription" },
|
||||
{ telemetry: "PROTOCOLDESCRIPTION" }),
|
||||
|
||||
/*
|
||||
* Methods constructed by DebuggerClient.requester require these forwards
|
||||
* on their 'this'.
|
||||
|
Loading…
Reference in New Issue
Block a user