зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1356244 - devtools-addon: create low-level DevTools shim for mozilla-central;r=ochameau
MozReview-Commit-ID: KdfomLHgdLY --HG-- extra : rebase_source : 5fff97798bfe3eeac98c8be12cbcfe6e6177afa8 extra : source : 2d422bec07d3a5bab5d83b4c949f27c6e49be261
This commit is contained in:
Родитель
0ce286101c
Коммит
52acc63ebc
|
@ -622,6 +622,10 @@
|
|||
@RESPATH@/browser/chrome/webide.manifest
|
||||
@RESPATH@/browser/@PREF_DIR@/webide-prefs.js
|
||||
|
||||
; [DevTools Shim Files]
|
||||
@RESPATH@/browser/chrome/devtools-shim@JAREXT@
|
||||
@RESPATH@/browser/chrome/devtools-shim.manifest
|
||||
|
||||
; DevTools
|
||||
@RESPATH@/browser/chrome/devtools@JAREXT@
|
||||
@RESPATH@/browser/chrome/devtools.manifest
|
||||
|
|
|
@ -8,6 +8,7 @@ const {Cu} = require("chrome");
|
|||
const Services = require("Services");
|
||||
|
||||
// Load gDevToolsBrowser toolbox lazily as they need gDevTools to be fully initialized
|
||||
loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true);
|
||||
loader.lazyRequireGetter(this, "Toolbox", "devtools/client/framework/toolbox", true);
|
||||
loader.lazyRequireGetter(this, "ToolboxHostManager", "devtools/client/framework/toolbox-host-manager", true);
|
||||
loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
|
||||
|
@ -468,6 +469,18 @@ DevTools.prototype = {
|
|||
return true;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Wrapper on TargetFactory.forTab, constructs a Target for the provided tab.
|
||||
*
|
||||
* @param {XULTab} tab
|
||||
* The tab to use in creating a new target.
|
||||
*
|
||||
* @return {TabTarget} A target object
|
||||
*/
|
||||
getTargetForTab: function (tab) {
|
||||
return TargetFactory.forTab(tab);
|
||||
},
|
||||
|
||||
/**
|
||||
* Either the SDK Loader has been destroyed by the add-on contribution
|
||||
* workflow, or firefox is shutting down.
|
||||
|
|
|
@ -15,6 +15,7 @@ if CONFIG['MOZ_DEVTOOLS'] == 'all':
|
|||
DIRS += [
|
||||
'server',
|
||||
'shared',
|
||||
'shim',
|
||||
]
|
||||
|
||||
# /browser uses DIST_SUBDIR. We opt-in to this treatment when building
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/* 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";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"DevToolsShim",
|
||||
];
|
||||
|
||||
function removeItem(array, callback) {
|
||||
let index = array.findIndex(callback);
|
||||
if (index >= 0) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The DevToolsShim is a part of the DevTools go faster project, which moves the Firefox
|
||||
* DevTools outside of mozilla-central to an add-on. It aims to bridge the gap for
|
||||
* existing mozilla-central code that still needs to interact with DevTools (such as
|
||||
* web-extensions).
|
||||
*
|
||||
* DevToolsShim is a singleton that provides a set of helpers to interact with DevTools,
|
||||
* that work whether the DevTools addon is installed or not. It can be used to start
|
||||
* listening to events, register tools, themes. As soon as a DevTools addon is installed
|
||||
* the DevToolsShim will forward all the requests received until then to the real DevTools
|
||||
* instance.
|
||||
*
|
||||
* DevToolsShim.isInstalled() can also be used to know if DevTools are currently
|
||||
* installed.
|
||||
*/
|
||||
this.DevToolsShim = {
|
||||
gDevTools: null,
|
||||
listeners: [],
|
||||
tools: [],
|
||||
themes: [],
|
||||
|
||||
/**
|
||||
* Check if DevTools are currently installed and available.
|
||||
*
|
||||
* @return {Boolean} true if DevTools are installed.
|
||||
*/
|
||||
isInstalled: function () {
|
||||
return !!this.gDevTools;
|
||||
},
|
||||
|
||||
/**
|
||||
* Register an instance of gDevTools. Should be called by DevTools during startup.
|
||||
*
|
||||
* @param {DevTools} a devtools instance (from client/framework/devtools)
|
||||
*/
|
||||
register: function (gDevTools) {
|
||||
this.gDevTools = gDevTools;
|
||||
this._onDevToolsRegistered();
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregister the current instance of gDevTools. Should be called by DevTools during
|
||||
* shutdown.
|
||||
*/
|
||||
unregister: function () {
|
||||
this.gDevTools = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* The following methods can be called before DevTools are installed:
|
||||
* - on
|
||||
* - off
|
||||
* - registerTool
|
||||
* - unregisterTool
|
||||
* - registerTheme
|
||||
* - unregisterTheme
|
||||
*
|
||||
* If DevTools are not installed when calling the method, DevToolsShim will call the
|
||||
* appropriate method as soon as a gDevTools instance is registered.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This method is used by browser/components/extensions/ext-devtools.js for the events:
|
||||
* - toolbox-created
|
||||
* - toolbox-destroyed
|
||||
*/
|
||||
on: function (event, listener) {
|
||||
if (this.isInstalled()) {
|
||||
this.gDevTools.on(event, listener);
|
||||
} else {
|
||||
this.listeners.push([event, listener]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is currently only used by devtools code, but is kept here for consistency
|
||||
* with on().
|
||||
*/
|
||||
off: function (event, listener) {
|
||||
if (this.isInstalled()) {
|
||||
this.gDevTools.off(event, listener);
|
||||
} else {
|
||||
removeItem(this.listeners, ([e, l]) => e === event && l === listener);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is only used by the addon-sdk and should be removed when Firefox 56 is
|
||||
* no longer supported.
|
||||
*/
|
||||
registerTool: function (tool) {
|
||||
if (this.isInstalled()) {
|
||||
this.gDevTools.registerTool(tool);
|
||||
} else {
|
||||
this.tools.push(tool);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is only used by the addon-sdk and should be removed when Firefox 56 is
|
||||
* no longer supported.
|
||||
*/
|
||||
unregisterTool: function (tool) {
|
||||
if (this.isInstalled()) {
|
||||
this.gDevTools.unregisterTool(tool);
|
||||
} else {
|
||||
removeItem(this.tools, t => t === tool);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is only used by the addon-sdk and should be removed when Firefox 56 is
|
||||
* no longer supported.
|
||||
*/
|
||||
registerTheme: function (theme) {
|
||||
if (this.isInstalled()) {
|
||||
this.gDevTools.registerTheme(theme);
|
||||
} else {
|
||||
this.themes.push(theme);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method is only used by the addon-sdk and should be removed when Firefox 56 is
|
||||
* no longer supported.
|
||||
*/
|
||||
unregisterTheme: function (theme) {
|
||||
if (this.isInstalled()) {
|
||||
this.gDevTools.unregisterTheme(theme);
|
||||
} else {
|
||||
removeItem(this.themes, t => t === theme);
|
||||
}
|
||||
},
|
||||
|
||||
_onDevToolsRegistered: function () {
|
||||
// Register all pending event listeners on the real gDevTools object.
|
||||
for (let [event, listener] of this.listeners) {
|
||||
this.gDevTools.on(event, listener);
|
||||
}
|
||||
|
||||
for (let tool of this.tools) {
|
||||
this.gDevTools.registerTool(tool);
|
||||
}
|
||||
|
||||
for (let theme of this.themes) {
|
||||
this.gDevTools.registerTheme(theme);
|
||||
}
|
||||
|
||||
this.listeners = [];
|
||||
this.tools = [];
|
||||
this.themes = [];
|
||||
},
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
devtools-shim.jar:
|
||||
% content devtools-shim %content/
|
||||
content/DevToolsShim.jsm (DevToolsShim.jsm)
|
|
@ -0,0 +1,3 @@
|
|||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
|
@ -0,0 +1,21 @@
|
|||
// This file was copied from the .eslintrc.xpcshell.js
|
||||
// This new xpcshell test folder should stay in mozilla-central while devtools move to a
|
||||
// GitHub repository, hence the duplication.
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/xpcshell-test"
|
||||
],
|
||||
"rules": {
|
||||
// Allow non-camelcase so that run_test doesn't produce a warning.
|
||||
"camelcase": "off",
|
||||
// Allow using undefined variables so that tests can refer to functions
|
||||
// and variables defined in head.js files, without having to maintain a
|
||||
// list of globals in each .eslintrc file.
|
||||
// Note that bug 1168340 will eventually help auto-registering globals
|
||||
// from head.js files.
|
||||
"no-undef": "off",
|
||||
"block-scoped-var": "off",
|
||||
// Tests can always import anything.
|
||||
"mozilla/reject-some-requires": "off",
|
||||
}
|
||||
};
|
|
@ -0,0 +1,192 @@
|
|||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { DevToolsShim } =
|
||||
Components.utils.import("chrome://devtools-shim/content/DevToolsShim.jsm", {});
|
||||
|
||||
// Test the DevToolsShim
|
||||
|
||||
/**
|
||||
* Create a mocked version of DevTools that records all calls made to methods expected
|
||||
* to be called by DevToolsShim.
|
||||
*/
|
||||
function createMockDevTools() {
|
||||
let methods = [
|
||||
"on",
|
||||
"off",
|
||||
"registerTool",
|
||||
"registerTheme",
|
||||
"unregisterTool",
|
||||
"unregisterTheme",
|
||||
];
|
||||
|
||||
let mock = {
|
||||
callLog: {}
|
||||
};
|
||||
|
||||
for (let method of methods) {
|
||||
// Create a stub for method, that only pushes its arguments in the inner callLog
|
||||
mock[method] = function (...args) {
|
||||
mock.callLog[method].push(args);
|
||||
};
|
||||
mock.callLog[method] = [];
|
||||
}
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given method was called an expected number of times, and finally check the
|
||||
* arguments provided to the last call, if appropriate.
|
||||
*/
|
||||
function checkCalls(mock, method, length, lastArgs) {
|
||||
ok(mock.callLog[method].length === length,
|
||||
"Devtools.on was called the expected number of times");
|
||||
|
||||
// If we don't want to check the last call or if the method was never called, bail out.
|
||||
if (!lastArgs || length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < lastArgs.length; i++) {
|
||||
let expectedArg = lastArgs[i];
|
||||
ok(mock.callLog[method][length - 1][i] === expectedArg,
|
||||
`Devtools.${method} was called with the expected argument (index ${i})`);
|
||||
}
|
||||
}
|
||||
|
||||
function test_register_unregister() {
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
|
||||
DevToolsShim.register(createMockDevTools());
|
||||
ok(DevToolsShim.isInstalled(), "DevTools are installed");
|
||||
|
||||
DevToolsShim.unregister();
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
}
|
||||
|
||||
function test_on_is_forwarded_to_devtools() {
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
|
||||
function cb1() {}
|
||||
function cb2() {}
|
||||
let mock = createMockDevTools();
|
||||
|
||||
DevToolsShim.on("test_event", cb1);
|
||||
DevToolsShim.register(mock);
|
||||
checkCalls(mock, "on", 1, ["test_event", cb1]);
|
||||
|
||||
DevToolsShim.on("other_event", cb2);
|
||||
checkCalls(mock, "on", 2, ["other_event", cb2]);
|
||||
}
|
||||
|
||||
function test_off_called_before_registering_devtools() {
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
|
||||
function cb1() {}
|
||||
let mock = createMockDevTools();
|
||||
|
||||
DevToolsShim.on("test_event", cb1);
|
||||
DevToolsShim.off("test_event", cb1);
|
||||
|
||||
DevToolsShim.register(mock);
|
||||
checkCalls(mock, "on", 0);
|
||||
}
|
||||
|
||||
function test_off_called_before_with_bad_callback() {
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
|
||||
function cb1() {}
|
||||
function cb2() {}
|
||||
let mock = createMockDevTools();
|
||||
|
||||
DevToolsShim.on("test_event", cb1);
|
||||
DevToolsShim.off("test_event", cb2);
|
||||
|
||||
DevToolsShim.register(mock);
|
||||
// on should still be called
|
||||
checkCalls(mock, "on", 1, ["test_event", cb1]);
|
||||
// Calls to off should not be held and forwarded.
|
||||
checkCalls(mock, "off", 0);
|
||||
}
|
||||
|
||||
function test_registering_tool() {
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
|
||||
let tool1 = {};
|
||||
let tool2 = {};
|
||||
let tool3 = {};
|
||||
let mock = createMockDevTools();
|
||||
|
||||
// Pre-register tool1
|
||||
DevToolsShim.registerTool(tool1);
|
||||
|
||||
// Pre-register tool3, but unregister right after
|
||||
DevToolsShim.registerTool(tool3);
|
||||
DevToolsShim.unregisterTool(tool3);
|
||||
|
||||
DevToolsShim.register(mock);
|
||||
checkCalls(mock, "registerTool", 1, [tool1]);
|
||||
|
||||
DevToolsShim.registerTool(tool2);
|
||||
checkCalls(mock, "registerTool", 2, [tool2]);
|
||||
|
||||
DevToolsShim.unregister();
|
||||
|
||||
// Create a new mock and check the tools are not added once again.
|
||||
mock = createMockDevTools();
|
||||
DevToolsShim.register(mock);
|
||||
checkCalls(mock, "registerTool", 0);
|
||||
}
|
||||
|
||||
function test_registering_theme() {
|
||||
ok(!DevToolsShim.isInstalled(), "DevTools are not installed");
|
||||
|
||||
let theme1 = {};
|
||||
let theme2 = {};
|
||||
let theme3 = {};
|
||||
let mock = createMockDevTools();
|
||||
|
||||
// Pre-register theme1
|
||||
DevToolsShim.registerTheme(theme1);
|
||||
|
||||
// Pre-register theme3, but unregister right after
|
||||
DevToolsShim.registerTheme(theme3);
|
||||
DevToolsShim.unregisterTheme(theme3);
|
||||
|
||||
DevToolsShim.register(mock);
|
||||
checkCalls(mock, "registerTheme", 1, [theme1]);
|
||||
|
||||
DevToolsShim.registerTheme(theme2);
|
||||
checkCalls(mock, "registerTheme", 2, [theme2]);
|
||||
|
||||
DevToolsShim.unregister();
|
||||
|
||||
// Create a new mock and check the themes are not added once again.
|
||||
mock = createMockDevTools();
|
||||
DevToolsShim.register(mock);
|
||||
checkCalls(mock, "registerTheme", 0);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
test_register_unregister();
|
||||
DevToolsShim.unregister();
|
||||
|
||||
test_on_is_forwarded_to_devtools();
|
||||
DevToolsShim.unregister();
|
||||
|
||||
test_off_called_before_registering_devtools();
|
||||
DevToolsShim.unregister();
|
||||
|
||||
test_off_called_before_with_bad_callback();
|
||||
DevToolsShim.unregister();
|
||||
|
||||
test_registering_tool();
|
||||
DevToolsShim.unregister();
|
||||
|
||||
test_registering_theme();
|
||||
DevToolsShim.unregister();
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
firefox-appdir = browser
|
||||
skip-if = toolkit == 'android'
|
||||
|
||||
[test_devtools_shim.js]
|
Загрузка…
Ссылка в новой задаче