зеркало из https://github.com/mozilla/gecko-dev.git
Bug 964545 Add-on SDK page-mods are now debuggable r=dcamp
This commit is contained in:
Родитель
ed2f101c5e
Коммит
34c7599e4e
|
@ -18,6 +18,7 @@ const { URL } = require('../url');
|
|||
const { sandbox, evaluate, load } = require('../loader/sandbox');
|
||||
const { merge } = require('../util/object');
|
||||
const { getTabForContentWindow } = require('../tabs/utils');
|
||||
const { getInnerId } = require('../window/utils');
|
||||
|
||||
// WeakMap of sandboxes so we can access private values
|
||||
const sandboxes = new WeakMap();
|
||||
|
@ -28,12 +29,13 @@ const sandboxes = new WeakMap();
|
|||
*/
|
||||
let prefix = module.uri.split('sandbox.js')[0];
|
||||
const CONTENT_WORKER_URL = prefix + 'content-worker.js';
|
||||
const metadata = require('@loader/options').metadata;
|
||||
|
||||
// Fetch additional list of domains to authorize access to for each content
|
||||
// script. It is stored in manifest `metadata` field which contains
|
||||
// package.json data. This list is originaly defined by authors in
|
||||
// `permissions` attribute of their package.json addon file.
|
||||
const permissions = require('@loader/options').metadata['permissions'] || {};
|
||||
const permissions = (metadata && metadata['permissions']) || {};
|
||||
const EXPANDED_PRINCIPALS = permissions['cross-domain-content'] || [];
|
||||
|
||||
const JS_VERSION = '1.8';
|
||||
|
@ -128,7 +130,10 @@ const WorkerSandbox = Class({
|
|||
wantXrays: true,
|
||||
wantGlobalProperties: wantGlobalProperties,
|
||||
sameZoneAs: window,
|
||||
metadata: { SDKContentScript: true }
|
||||
metadata: {
|
||||
SDKContentScript: true,
|
||||
'inner-window-id': getInnerId(window)
|
||||
}
|
||||
});
|
||||
model.sandbox = content;
|
||||
|
||||
|
|
|
@ -157,7 +157,10 @@ const WorkerSandbox = EventEmitter.compose({
|
|||
wantXrays: true,
|
||||
wantGlobalProperties: wantGlobalProperties,
|
||||
sameZoneAs: window,
|
||||
metadata: { SDKContentScript: true }
|
||||
metadata: {
|
||||
SDKContentScript: true,
|
||||
'inner-window-id': getInnerId(window)
|
||||
}
|
||||
});
|
||||
// We have to ensure that window.top and window.parent are the exact same
|
||||
// object than window object, i.e. the sandbox global object. But not
|
||||
|
|
|
@ -12,6 +12,12 @@ const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
|
|||
const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
const self = require('sdk/self');
|
||||
const { getTabId, getTabForContentWindow } = require('../tabs/utils');
|
||||
const { getInnerId } = require('../window/utils');
|
||||
|
||||
const { gDevToolsExtensions: {
|
||||
addContentGlobal, removeContentGlobal
|
||||
} } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
|
||||
/**
|
||||
* Make a new sandbox that inherits given `source`'s principals. Source can be
|
||||
|
@ -23,7 +29,16 @@ function sandbox(target, options) {
|
|||
options.metadata.addonID = options.metadata.addonID ?
|
||||
options.metadata.addonID : self.id;
|
||||
|
||||
return Cu.Sandbox(target || systemPrincipal, options);
|
||||
let sandbox = Cu.Sandbox(target || systemPrincipal, options);
|
||||
Cu.setSandboxMetadata(sandbox, options.metadata);
|
||||
let innerWindowID = options.metadata['inner-window-id']
|
||||
if (innerWindowID) {
|
||||
addContentGlobal({
|
||||
global: sandbox,
|
||||
'inner-window-id': innerWindowID
|
||||
});
|
||||
}
|
||||
return sandbox;
|
||||
}
|
||||
exports.sandbox = sandbox;
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Page Mod Debugger Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
unsafeWindow.runDebuggerStatement = function() {
|
||||
window.document.body.setAttribute('style', 'background-color: red');
|
||||
debugger;
|
||||
window.document.body.setAttribute('style', 'background-color: green');
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/* 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 { Cu } = require('chrome');
|
||||
const { PageMod } = require('sdk/page-mod');
|
||||
const tabs = require('sdk/tabs');
|
||||
const promise = require('sdk/core/promise')
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { data } = require('sdk/self');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { DebuggerServer } = Cu.import('resource://gre/modules/devtools/dbg-server.jsm', {});
|
||||
const { DebuggerClient } = Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {});
|
||||
|
||||
let gClient;
|
||||
let ok;
|
||||
let testName = 'testDebugger';
|
||||
let iframeURL = 'data:text/html;charset=utf-8,' + testName;
|
||||
let TAB_URL = 'data:text/html;charset=utf-8,' + encodeURIComponent('<iframe src="' + iframeURL + '" />');
|
||||
TAB_URL = data.url('index.html');
|
||||
let mod;
|
||||
|
||||
exports.testDebugger = function(assert, done) {
|
||||
ok = assert.ok.bind(assert);
|
||||
assert.pass('starting test');
|
||||
set('devtools.debugger.log', true);
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(() => true);
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect((aType, aTraits) => {
|
||||
tabs.open({
|
||||
url: TAB_URL,
|
||||
onLoad: function(tab) {
|
||||
assert.pass('tab loaded');
|
||||
|
||||
attachTabActorForUrl(gClient, TAB_URL).
|
||||
then(_ => { assert.pass('attachTabActorForUrl called'); return _; }).
|
||||
then(attachThread).
|
||||
then(testDebuggerStatement).
|
||||
then(_ => { assert.pass('testDebuggerStatement called') }).
|
||||
then(closeConnection).
|
||||
then(_ => { assert.pass('closeConnection called') }).
|
||||
then(done).
|
||||
then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function attachThread([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Now attach and resume...
|
||||
gClient.request({ to: aResponse.threadActor, type: "attach" }, () => {
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "Pause wasn't called before we've attached.");
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testDebuggerStatement([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
ok(aGrip, 'aGrip existss')
|
||||
|
||||
gClient.addListener("paused", (aEvent, aPacket) => {
|
||||
ok(true, 'there was a pause event');
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "The pause handler was triggered on a debugger statement.");
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
mod = PageMod({
|
||||
include: TAB_URL,
|
||||
attachTo: ['existing', 'top', 'frame'],
|
||||
contentScriptFile: data.url('script.js'),
|
||||
onAttach: function(mod) {
|
||||
ok(true, 'the page-mod was attached to ' + mod.tab.url);
|
||||
|
||||
require('sdk/timers').setTimeout(function() {
|
||||
let debuggee = getMostRecentBrowserWindow().gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
debuggee.runDebuggerStatement();
|
||||
ok(true, 'called runDebuggerStatement');
|
||||
}, 500)
|
||||
}
|
||||
});
|
||||
ok(true, 'PageMod was created');
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
aClient.listTabs(aResponse => {
|
||||
let tabActor = aResponse.tabs.filter(aGrip => aGrip.url == aUrl).pop();
|
||||
deferred.resolve(tabActor);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function attachTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
getTabActorForUrl(aClient, aUrl).then(aGrip => {
|
||||
aClient.attachTab(aGrip.actor, aResponse => {
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function closeConnection() {
|
||||
let deferred = promise.defer();
|
||||
gClient.close(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"id": "test-page-mod-debugger",
|
||||
"author": "Erik Vold"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Page Mod Debugger Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
unsafeWindow.runDebuggerStatement = function() {
|
||||
window.document.body.setAttribute('style', 'background-color: red');
|
||||
debugger;
|
||||
window.document.body.setAttribute('style', 'background-color: green');
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/* 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 { Cu } = require('chrome');
|
||||
const { PageMod } = require('sdk/page-mod');
|
||||
const tabs = require('sdk/tabs');
|
||||
const promise = require('sdk/core/promise')
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { data } = require('sdk/self');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { DebuggerServer } = Cu.import('resource://gre/modules/devtools/dbg-server.jsm', {});
|
||||
const { DebuggerClient } = Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {});
|
||||
|
||||
let gClient;
|
||||
let ok;
|
||||
let testName = 'testDebugger';
|
||||
let iframeURL = 'data:text/html;charset=utf-8,' + testName;
|
||||
let TAB_URL = 'data:text/html;charset=utf-8,' + encodeURIComponent('<iframe src="' + iframeURL + '" />');
|
||||
TAB_URL = data.url('index.html');
|
||||
let mod;
|
||||
|
||||
exports.testDebugger = function(assert, done) {
|
||||
ok = assert.ok.bind(assert);
|
||||
assert.pass('starting test');
|
||||
set('devtools.debugger.log', true);
|
||||
|
||||
mod = PageMod({
|
||||
include: TAB_URL,
|
||||
attachTo: ['existing', 'top', 'frame'],
|
||||
contentScriptFile: data.url('script.js'),
|
||||
});
|
||||
ok(true, 'PageMod was created');
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(() => true);
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect((aType, aTraits) => {
|
||||
tabs.open({
|
||||
url: TAB_URL,
|
||||
onLoad: function(tab) {
|
||||
assert.pass('tab loaded');
|
||||
|
||||
attachTabActorForUrl(gClient, TAB_URL).
|
||||
then(_ => { assert.pass('attachTabActorForUrl called'); return _; }).
|
||||
then(attachThread).
|
||||
then(testDebuggerStatement).
|
||||
then(_ => { assert.pass('testDebuggerStatement called') }).
|
||||
then(closeConnection).
|
||||
then(_ => { assert.pass('closeConnection called') }).
|
||||
then(done).
|
||||
then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function attachThread([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Now attach and resume...
|
||||
gClient.request({ to: aResponse.threadActor, type: "attach" }, () => {
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "Pause wasn't called before we've attached.");
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testDebuggerStatement([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
ok(aGrip, 'aGrip existss')
|
||||
|
||||
gClient.addListener("paused", (aEvent, aPacket) => {
|
||||
ok(true, 'there was a pause event');
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "The pause handler was triggered on a debugger statement.");
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let debuggee = getMostRecentBrowserWindow().gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
debuggee.runDebuggerStatement();
|
||||
ok(true, 'called runDebuggerStatement');
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
aClient.listTabs(aResponse => {
|
||||
let tabActor = aResponse.tabs.filter(aGrip => aGrip.url == aUrl).pop();
|
||||
deferred.resolve(tabActor);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function attachTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
getTabActorForUrl(aClient, aUrl).then(aGrip => {
|
||||
aClient.attachTab(aGrip.actor, aResponse => {
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function closeConnection() {
|
||||
let deferred = promise.defer();
|
||||
gClient.close(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"id": "test-page-mod-debugger",
|
||||
"author": "Erik Vold"
|
||||
}
|
|
@ -9,8 +9,12 @@ const { Loader } = require('sdk/test/loader');
|
|||
const tabs = require("sdk/tabs");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { open, getFrames, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const windowUtils = require('sdk/deprecated/window-utils');
|
||||
const {
|
||||
open,
|
||||
getFrames,
|
||||
getMostRecentBrowserWindow,
|
||||
getInnerId
|
||||
} = require('sdk/window/utils');
|
||||
const { getTabContentWindow, getActiveTab, setTabURL, openTab, closeTab } = require('sdk/tabs/utils');
|
||||
const xulApp = require("sdk/system/xul-app");
|
||||
const { isPrivateBrowsingSupported } = require('sdk/self');
|
||||
|
@ -24,6 +28,8 @@ const { URL } = require("sdk/url");
|
|||
const { waitUntil } = require("sdk/test/utils");
|
||||
const data = require("./fixtures");
|
||||
|
||||
const { gDevToolsExtensions } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
|
||||
const testPageURI = data.url("test.html");
|
||||
|
||||
// The following adds Debugger constructor to the global namespace.
|
||||
|
@ -1060,7 +1066,7 @@ exports.testPageModCssAutomaticDestroy = function(assert, done) {
|
|||
url: "data:text/html;charset=utf-8,<div style='width:200px'>css test</div>",
|
||||
|
||||
onReady: function onReady(tab) {
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let browserWindow = getMostRecentBrowserWindow();
|
||||
let win = getTabContentWindow(getActiveTab(browserWindow));
|
||||
|
||||
let div = win.document.querySelector("div");
|
||||
|
@ -1391,12 +1397,12 @@ exports.testDebugMetadata = function(assert, done) {
|
|||
include: "about:",
|
||||
contentScriptWhen: "start",
|
||||
contentScript: "null;",
|
||||
}],
|
||||
function(win, done) {
|
||||
}], function(win, done) {
|
||||
assert.ok(globalDebuggees.some(function(global) {
|
||||
try {
|
||||
let metadata = Cu.getSandboxMetadata(global.unsafeDereference());
|
||||
return metadata && metadata.addonID && metadata.SDKContentScript;
|
||||
return metadata && metadata.addonID && metadata.SDKContentScript &&
|
||||
metadata['inner-window-id'] == getInnerId(win);
|
||||
} catch(e) {
|
||||
// Some of the globals might not be Sandbox instances and thus
|
||||
// will cause getSandboxMetadata to fail.
|
||||
|
@ -1408,6 +1414,18 @@ exports.testDebugMetadata = function(assert, done) {
|
|||
);
|
||||
};
|
||||
|
||||
exports.testDevToolsExtensionsGetContentGlobals = function(assert, done) {
|
||||
let mods = testPageMod(assert, done, "about:", [{
|
||||
include: "about:",
|
||||
contentScriptWhen: "start",
|
||||
contentScript: "null;",
|
||||
}], function(win, done) {
|
||||
assert.equal(gDevToolsExtensions.getContentGlobals({ 'inner-window-id': getInnerId(win) }).length, 1);
|
||||
done();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.testDetachOnDestroy = function(assert, done) {
|
||||
let tab;
|
||||
const TEST_URL = 'data:text/html;charset=utf-8,detach';
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["gDevToolsExtensions"];
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let globalsCache = {};
|
||||
|
||||
const gDevToolsExtensions = {
|
||||
addContentGlobal: function(options) {
|
||||
if (!options || !options.global || !options['inner-window-id']) {
|
||||
throw Error('Invalid arguments');
|
||||
}
|
||||
let cache = getGlobalCache(options['inner-window-id']);
|
||||
cache.push(options.global);
|
||||
return undefined;
|
||||
},
|
||||
getContentGlobals: function(options) {
|
||||
if (!options || !options['inner-window-id']) {
|
||||
throw Error('Invalid arguments');
|
||||
}
|
||||
return Array.slice(globalsCache[options['inner-window-id']] || []);
|
||||
},
|
||||
removeContentGlobal: function(options) {
|
||||
if (!options || !options.global || !options['inner-window-id']) {
|
||||
throw Error('Invalid arguments');
|
||||
}
|
||||
let cache = getGlobalCache(options['inner-window-id']);
|
||||
let index = cache.indexOf(options.global);
|
||||
cache.splice(index, 1);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
function getGlobalCache(aInnerWindowID) {
|
||||
return globalsCache[aInnerWindowID] = globalsCache[aInnerWindowID] || [];
|
||||
}
|
||||
|
||||
// when the window is destroyed, eliminate the associated globals cache
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
let id = subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data;
|
||||
delete globalsCache[id];
|
||||
}, 'inner-window-destroyed', false);
|
|
@ -3,7 +3,6 @@
|
|||
/* 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";
|
||||
|
||||
let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
|
||||
|
@ -636,22 +635,49 @@ ThreadActor.prototype = {
|
|||
*/
|
||||
globalManager: {
|
||||
findGlobals: function () {
|
||||
const { gDevToolsExtensions: {
|
||||
getContentGlobals
|
||||
} } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
|
||||
this.globalDebugObject = this._addDebuggees(this.global);
|
||||
|
||||
// global may not be a window
|
||||
try {
|
||||
getContentGlobals({
|
||||
'inner-window-id': getInnerId(this.global)
|
||||
}).forEach(this.addDebuggee.bind(this));
|
||||
}
|
||||
catch(e) {}
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object has been
|
||||
* created.
|
||||
* A function that the engine calls when a new global object
|
||||
* (for example a sandbox) has been created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function (aGlobal) {
|
||||
let useGlobal = (aGlobal.hostAnnotations &&
|
||||
aGlobal.hostAnnotations.type == "document" &&
|
||||
aGlobal.hostAnnotations.element === this.global);
|
||||
|
||||
// check if the global is a sdk page-mod sandbox
|
||||
if (!useGlobal) {
|
||||
let metadata = {};
|
||||
let id = "";
|
||||
try {
|
||||
id = getInnerId(this.global);
|
||||
metadata = Cu.getSandboxMetadata(aGlobal.unsafeDereference());
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
useGlobal = (metadata['inner-window-id'] && metadata['inner-window-id'] == id);
|
||||
}
|
||||
|
||||
// Content debugging only cares about new globals in the contant window,
|
||||
// like iframe children.
|
||||
if (aGlobal.hostAnnotations &&
|
||||
aGlobal.hostAnnotations.type == "document" &&
|
||||
aGlobal.hostAnnotations.element === this.global) {
|
||||
if (useGlobal) {
|
||||
this.addDebuggee(aGlobal);
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
|
@ -5325,3 +5351,8 @@ function makeDebuggeeValueIfNeeded(obj, value) {
|
|||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function getInnerId(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
|
||||
};
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
[test_eventemitter_basic.html]
|
||||
[test_devtools_extensions.html]
|
||||
[test_loader_paths.html]
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { gDevToolsExtensions } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const { require } = devtools;
|
||||
const tabs = require('sdk/tabs');
|
||||
const { getMostRecentBrowserWindow, getInnerId } = require('sdk/window/utils');
|
||||
const { PageMod } = require('sdk/page-mod');
|
||||
|
||||
var _tests = [];
|
||||
function addTest(test) {
|
||||
_tests.push(test);
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (_tests.length == 0) {
|
||||
SimpleTest.finish()
|
||||
return;
|
||||
}
|
||||
_tests.shift()();
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
addTest(function () {
|
||||
let TEST_URL = 'data:text/html;charset=utf-8,test';
|
||||
|
||||
let mod = PageMod({
|
||||
include: TEST_URL,
|
||||
contentScriptWhen: 'ready',
|
||||
contentScript: 'null;'
|
||||
});
|
||||
|
||||
tabs.open({
|
||||
url: TEST_URL,
|
||||
onLoad: function(tab) {
|
||||
let id = getInnerId(getMostRecentBrowserWindow().gBrowser.selectedTab.linkedBrowser.contentWindow);
|
||||
|
||||
// getting
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': id
|
||||
}).length, 1, 'found a global for inner-id = ' + id);
|
||||
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
if (id == subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data) {
|
||||
Services.obs.removeObserver(observer, 'inner-window-destroyed');
|
||||
setTimeout(function() {
|
||||
// closing the tab window should have removed the global
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': id
|
||||
}).length, 0, 'did not find a global for inner-id = ' + id);
|
||||
|
||||
mod.destroy();
|
||||
runNextTest();
|
||||
})
|
||||
}
|
||||
}, 'inner-window-destroyed', false);
|
||||
|
||||
tab.close();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
addTest(function testAddRemoveGlobal() {
|
||||
let global = {};
|
||||
let globalDetails = {
|
||||
global: global,
|
||||
'inner-window-id': 5
|
||||
};
|
||||
|
||||
// adding
|
||||
gDevToolsExtensions.addContentGlobal(globalDetails);
|
||||
|
||||
// getting
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': 5
|
||||
}).length, 1, 'found a global for inner-id = 5');
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': 4
|
||||
}).length, 0, 'did not find a global for inner-id = 4');
|
||||
|
||||
// remove
|
||||
gDevToolsExtensions.removeContentGlobal(globalDetails);
|
||||
|
||||
// getting again
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': 5
|
||||
}).length, 0, 'did not find a global for inner-id = 5');
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче