forked from mirrors/gecko-dev
Bug 1561435 - Format remote/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D35925 --HG-- extra : source : b793788d0f38244b33eb59ea36e2c6624dbd12c5
This commit is contained in:
parent
91f67eb25e
commit
991b3c93c6
64 changed files with 1477 additions and 674 deletions
|
|
@ -45,7 +45,6 @@ module.exports = {
|
|||
"overrides": [{
|
||||
"files": [
|
||||
"devtools/**",
|
||||
"remote/**",
|
||||
"security/**",
|
||||
"services/**",
|
||||
"servo/**",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
|
|||
toolkit/components/telemetry/healthreport-prefs.js
|
||||
|
||||
# Ignore all top-level directories for now.
|
||||
remote/**
|
||||
security/**
|
||||
services/**
|
||||
servo/**
|
||||
|
|
|
|||
|
|
@ -6,11 +6,18 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Connection"];
|
||||
|
||||
const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"UUIDGen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator"
|
||||
);
|
||||
|
||||
class Connection {
|
||||
/**
|
||||
|
|
@ -40,8 +47,10 @@ class Connection {
|
|||
registerSession(session) {
|
||||
if (!session.id) {
|
||||
if (this.defaultSession) {
|
||||
throw new Error("Default session is already set on Connection," +
|
||||
"can't register another one.");
|
||||
throw new Error(
|
||||
"Default session is already set on Connection," +
|
||||
"can't register another one."
|
||||
);
|
||||
}
|
||||
this.defaultSession = session;
|
||||
}
|
||||
|
|
@ -58,14 +67,14 @@ class Connection {
|
|||
message: e.message,
|
||||
data: e.stack,
|
||||
};
|
||||
this.send({id, error});
|
||||
this.send({ id, error });
|
||||
}
|
||||
|
||||
deserialize(data) {
|
||||
const id = data.id;
|
||||
const method = data.method;
|
||||
const params = data.params || {};
|
||||
return {id, method, params};
|
||||
return { id, method, params };
|
||||
}
|
||||
|
||||
// transport hooks
|
||||
|
|
@ -73,7 +82,7 @@ class Connection {
|
|||
onPacket(packet) {
|
||||
log.trace(`(connection ${this.id})-> ${JSON.stringify(packet)}`);
|
||||
|
||||
let message = {id: null};
|
||||
let message = { id: null };
|
||||
try {
|
||||
message = this.deserialize(packet);
|
||||
const { sessionId } = packet;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ var EXPORTED_SYMBOLS = [
|
|||
"UnsupportedError",
|
||||
];
|
||||
|
||||
const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
|
||||
|
|
@ -31,15 +33,15 @@ class RemoteAgentError extends Error {
|
|||
|
||||
notify() {
|
||||
Cu.reportError(this);
|
||||
log.error(this.toString({stack: true}));
|
||||
log.error(this.toString({ stack: true }));
|
||||
}
|
||||
|
||||
toString({stack = false} = {}) {
|
||||
return RemoteAgentError.format(this, {stack});
|
||||
toString({ stack = false } = {}) {
|
||||
return RemoteAgentError.format(this, { stack });
|
||||
}
|
||||
|
||||
static format(e, {stack = false} = {}) {
|
||||
return formatError(e, {stack});
|
||||
static format(e, { stack = false } = {}) {
|
||||
return formatError(e, { stack });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -88,7 +90,7 @@ class FatalError extends RemoteAgentError {
|
|||
}
|
||||
|
||||
notify() {
|
||||
log.fatal(this.toString({stack: true}));
|
||||
log.fatal(this.toString({ stack: true }));
|
||||
}
|
||||
|
||||
quit(mode = Ci.nsIAppStartup.eForceQuit) {
|
||||
|
|
@ -110,7 +112,7 @@ class UnknownMethodError extends RemoteAgentError {
|
|||
}
|
||||
}
|
||||
|
||||
function formatError(error, {stack = false} = {}) {
|
||||
function formatError(error, { stack = false } = {}) {
|
||||
const els = [];
|
||||
|
||||
els.push(error.name);
|
||||
|
|
@ -127,7 +129,7 @@ function formatError(error, {stack = false} = {}) {
|
|||
|
||||
if (error.cause) {
|
||||
els.push("\n");
|
||||
els.push("caused by: " + formatError(error.cause, {stack}));
|
||||
els.push("caused by: " + formatError(error.cause, { stack }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["JSONHandler"];
|
||||
|
||||
const {HTTP_404, HTTP_505} = ChromeUtils.import("chrome://remote/content/server/HTTPD.jsm");
|
||||
const {Log} = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const {Protocol} = ChromeUtils.import("chrome://remote/content/Protocol.jsm");
|
||||
const {RemoteAgentError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
|
||||
const { HTTP_404, HTTP_505 } = ChromeUtils.import(
|
||||
"chrome://remote/content/server/HTTPD.jsm"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const { Protocol } = ChromeUtils.import("chrome://remote/content/Protocol.jsm");
|
||||
const { RemoteAgentError } = ChromeUtils.import(
|
||||
"chrome://remote/content/Error.jsm"
|
||||
);
|
||||
|
||||
class JSONHandler {
|
||||
constructor(agent) {
|
||||
|
|
@ -24,12 +28,12 @@ class JSONHandler {
|
|||
getVersion() {
|
||||
const mainProcessTarget = this.agent.targets.getMainProcessTarget();
|
||||
return {
|
||||
"Browser": "Firefox",
|
||||
Browser: "Firefox",
|
||||
"Protocol-Version": "1.0",
|
||||
"User-Agent": "Mozilla",
|
||||
"V8-Version": "1.0",
|
||||
"WebKit-Version": "1.0",
|
||||
"webSocketDebuggerUrl": mainProcessTarget.toJSON().webSocketDebuggerUrl,
|
||||
webSocketDebuggerUrl: mainProcessTarget.toJSON().webSocketDebuggerUrl,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,11 @@ class JSONHandler {
|
|||
|
||||
try {
|
||||
const body = this.routes[request.path]();
|
||||
const payload = JSON.stringify(body, sanitise, Log.verbose ? "\t" : undefined);
|
||||
const payload = JSON.stringify(
|
||||
body,
|
||||
sanitise,
|
||||
Log.verbose ? "\t" : undefined
|
||||
);
|
||||
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Log"];
|
||||
|
||||
const {Log: StdLog} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Log: StdLog } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const LOG_LEVEL = "remote.log.level";
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Observer"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
class Observer {
|
||||
static observe(type, observer) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const RecommendedPreferences = {
|
|||
|
||||
// Prevent various error message on the console
|
||||
// jest-puppeteer asserts that no error message is emitted by the console
|
||||
"browser.contentblocking.features.standard": "-tp,tpPrivate,cookieBehavior0,-cm,-fp",
|
||||
"browser.contentblocking.features.standard":
|
||||
"-tp,tpPrivate,cookieBehavior0,-cm,-fp",
|
||||
"network.cookie.cookieBehavior": 0,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["RemoteAgent", "RemoteAgentFactory"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
FatalError: "chrome://remote/content/Error.jsm",
|
||||
|
|
@ -36,7 +38,9 @@ class RemoteAgentClass {
|
|||
throw new Error("Remote agent is disabled by its preference");
|
||||
}
|
||||
if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
throw new Error("Remote agent can only be instantiated from the parent process");
|
||||
throw new Error(
|
||||
"Remote agent can only be instantiated from the parent process"
|
||||
);
|
||||
}
|
||||
|
||||
if (this.server) {
|
||||
|
|
@ -48,7 +52,7 @@ class RemoteAgentClass {
|
|||
|
||||
this.server.registerPrefixHandler("/json/", new JSONHandler(this));
|
||||
|
||||
this.tabs = new TabObserver({registerExisting: true});
|
||||
this.tabs = new TabObserver({ registerExisting: true });
|
||||
this.tabs.on("open", (eventName, tab) => {
|
||||
this.targets.connect(tab.linkedBrowser);
|
||||
});
|
||||
|
|
@ -78,7 +82,7 @@ class RemoteAgentClass {
|
|||
throw new TypeError(`Expected nsIURI: ${address}`);
|
||||
}
|
||||
|
||||
let {host, port} = address;
|
||||
let { host, port } = address;
|
||||
if (Preferences.get(FORCE_LOCAL) && !LOOPBACKS.includes(host)) {
|
||||
throw new Error("Restricted to loopback devices");
|
||||
}
|
||||
|
|
@ -167,7 +171,9 @@ class RemoteAgentClass {
|
|||
const remoteDebuggingPort = flag("remote-debugging-port");
|
||||
|
||||
if (remoteDebugger && remoteDebuggingPort) {
|
||||
log.fatal("Conflicting flags --remote-debugger and --remote-debugging-port");
|
||||
log.fatal(
|
||||
"Conflicting flags --remote-debugger and --remote-debugging-port"
|
||||
);
|
||||
cmdLine.preventDefault = true;
|
||||
return;
|
||||
}
|
||||
|
|
@ -185,9 +191,14 @@ class RemoteAgentClass {
|
|||
|
||||
let addr;
|
||||
try {
|
||||
addr = NetUtil.newURI(`http://${host || DEFAULT_HOST}:${port || DEFAULT_PORT}/`);
|
||||
addr = NetUtil.newURI(
|
||||
`http://${host || DEFAULT_HOST}:${port || DEFAULT_PORT}/`
|
||||
);
|
||||
} catch (e) {
|
||||
log.fatal(`Expected address syntax [<host>]:<port>: ${remoteDebugger || remoteDebuggingPort}`);
|
||||
log.fatal(
|
||||
`Expected address syntax [<host>]:<port>: ${remoteDebugger ||
|
||||
remoteDebuggingPort}`
|
||||
);
|
||||
cmdLine.preventDefault = true;
|
||||
return;
|
||||
}
|
||||
|
|
@ -200,15 +211,20 @@ class RemoteAgentClass {
|
|||
this.listen(addr);
|
||||
} catch (e) {
|
||||
this.close();
|
||||
throw new FatalError(`Unable to start remote agent on ${addr.spec}: ${e.message}`, e);
|
||||
throw new FatalError(
|
||||
`Unable to start remote agent on ${addr.spec}: ${e.message}`,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
get helpInfo() {
|
||||
return " --remote-debugger [<host>][:<port>]\n" +
|
||||
return (
|
||||
" --remote-debugger [<host>][:<port>]\n" +
|
||||
" --remote-debugging-port <port> Start the Firefox remote agent, which is \n" +
|
||||
" a low-level debugging interface based on the CDP protocol.\n" +
|
||||
" Defaults to listen on localhost:9222.\n";
|
||||
" Defaults to listen on localhost:9222.\n"
|
||||
);
|
||||
}
|
||||
|
||||
// XPCOM
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ var EXPORTED_SYMBOLS = [
|
|||
"MessagePromise",
|
||||
];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* Wait for a single event to be fired on a specific EventListener.
|
||||
|
|
@ -43,34 +43,48 @@ const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
*
|
||||
* @throws {TypeError}
|
||||
*/
|
||||
function EventPromise(listener, type, options = {
|
||||
function EventPromise(
|
||||
listener,
|
||||
type,
|
||||
options = {
|
||||
capture: false,
|
||||
wantsUntrusted: false,
|
||||
mozSystemGroup: false,
|
||||
}) {
|
||||
}
|
||||
) {
|
||||
if (!listener || !("addEventListener" in listener)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
if (typeof type != "string") {
|
||||
throw new TypeError();
|
||||
}
|
||||
if (("capture" in options && typeof options.capture != "boolean") ||
|
||||
("wantsUntrusted" in options && typeof options.wantsUntrusted != "boolean") ||
|
||||
("mozSystemGroup" in options && typeof options.mozSystemGroup != "boolean")) {
|
||||
if (
|
||||
("capture" in options && typeof options.capture != "boolean") ||
|
||||
("wantsUntrusted" in options &&
|
||||
typeof options.wantsUntrusted != "boolean") ||
|
||||
("mozSystemGroup" in options && typeof options.mozSystemGroup != "boolean")
|
||||
) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
options.once = true;
|
||||
|
||||
return new Promise(resolve => {
|
||||
listener.addEventListener(type, event => {
|
||||
listener.addEventListener(
|
||||
type,
|
||||
event => {
|
||||
Services.tm.dispatchToMainThread(() => resolve(event));
|
||||
}, options);
|
||||
},
|
||||
options
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function DOMContentLoadedPromise(window, options = {mozSystemGroup: true}) {
|
||||
if (window.document.readyState == "complete" || window.document.readyState == "interactive") {
|
||||
function DOMContentLoadedPromise(window, options = { mozSystemGroup: true }) {
|
||||
if (
|
||||
window.document.readyState == "complete" ||
|
||||
window.document.readyState == "interactive"
|
||||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new EventPromise(window, "DOMContentLoaded", options);
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"TabManager",
|
||||
"TabObserver",
|
||||
"WindowObserver",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["TabManager", "TabObserver", "WindowObserver"];
|
||||
|
||||
const {DOMContentLoadedPromise} = ChromeUtils.import("chrome://remote/content/Sync.jsm");
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { DOMContentLoadedPromise } = ChromeUtils.import(
|
||||
"chrome://remote/content/Sync.jsm"
|
||||
);
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
/**
|
||||
* The WindowManager provides tooling for application-agnostic
|
||||
|
|
@ -40,7 +40,7 @@ class WindowObserver {
|
|||
* Events will be despatched for the ChromeWindows that exist
|
||||
* at the time the observer is started.
|
||||
*/
|
||||
constructor({registerExisting = false} = {}) {
|
||||
constructor({ registerExisting = false } = {}) {
|
||||
this.registerExisting = registerExisting;
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
|
@ -95,8 +95,8 @@ class TabObserver {
|
|||
* Events will be fired for ChromeWIndows and their respective tabs
|
||||
* at the time when the observer is started.
|
||||
*/
|
||||
constructor({registerExisting = false} = {}) {
|
||||
this.windows = new WindowObserver({registerExisting});
|
||||
constructor({ registerExisting = false } = {}) {
|
||||
this.windows = new WindowObserver({ registerExisting });
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
|
|
@ -136,8 +136,10 @@ class TabObserver {
|
|||
this.onTabOpen(tab);
|
||||
}
|
||||
|
||||
window.addEventListener("TabOpen", ({target}) => this.onTabOpen(target));
|
||||
window.addEventListener("TabClose", ({target}) => this.onTabClose(target));
|
||||
window.addEventListener("TabOpen", ({ target }) => this.onTabOpen(target));
|
||||
window.addEventListener("TabClose", ({ target }) =>
|
||||
this.onTabClose(target)
|
||||
);
|
||||
}
|
||||
|
||||
onWindowClose(window) {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ContentProcessDomain"];
|
||||
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "ContextObserver",
|
||||
"chrome://remote/content/domains/ContextObserver.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ContextObserver",
|
||||
"chrome://remote/content/domains/ContextObserver.jsm"
|
||||
);
|
||||
|
||||
class ContentProcessDomain extends Domain {
|
||||
destructor() {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ContentProcessDomains"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const ContentProcessDomains = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,37 +25,45 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ContextObserver"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
|
||||
class ContextObserver {
|
||||
constructor(chromeEventHandler) {
|
||||
this.chromeEventHandler = chromeEventHandler;
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.chromeEventHandler.addEventListener("DOMWindowCreated", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.addEventListener("DOMWindowCreated", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
|
||||
// Listen for pageshow and pagehide to track pages going in/out to/from the BF Cache
|
||||
this.chromeEventHandler.addEventListener("pageshow", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.addEventListener("pagehide", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.addEventListener("pageshow", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
this.chromeEventHandler.addEventListener("pagehide", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed");
|
||||
}
|
||||
|
||||
destructor() {
|
||||
this.chromeEventHandler.removeEventListener("DOMWindowCreated", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.removeEventListener("pageshow", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.removeEventListener("pagehide", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.removeEventListener("DOMWindowCreated", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
this.chromeEventHandler.removeEventListener("pageshow", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
this.chromeEventHandler.removeEventListener("pagehide", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
}
|
||||
|
||||
handleEvent({type, target, persisted}) {
|
||||
handleEvent({ type, target, persisted }) {
|
||||
const window = target.defaultView;
|
||||
if (window.top != this.chromeEventHandler.ownerGlobal) {
|
||||
// Ignore iframes for now.
|
||||
|
|
@ -99,5 +107,3 @@ class ContextObserver {
|
|||
this.emit("context-destroyed", { id: innerWindowID });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class Domain {
|
|||
}
|
||||
|
||||
function isEventHandler(listener) {
|
||||
return listener &&
|
||||
"onEvent" in listener &&
|
||||
typeof listener.onEvent == "function";
|
||||
return (
|
||||
listener && "onEvent" in listener && typeof listener.onEvent == "function"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Domains"];
|
||||
|
||||
const {UnknownMethodError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const { UnknownMethodError } = ChromeUtils.import(
|
||||
"chrome://remote/content/Error.jsm"
|
||||
);
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Lazy domain instance cache.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ParentProcessDomains"];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const ParentProcessDomains = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["DOM"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
|
||||
class DOM extends ContentProcessDomain {
|
||||
constructor(session) {
|
||||
|
|
@ -48,10 +50,14 @@ class DOM extends ContentProcessDomain {
|
|||
let quads = unsafeObject.getBoxQuads({ relativeTo: this.content.document });
|
||||
quads = quads.map(quad => {
|
||||
return [
|
||||
quad.p1.x, quad.p1.y,
|
||||
quad.p2.x, quad.p2.y,
|
||||
quad.p3.x, quad.p3.y,
|
||||
quad.p4.x, quad.p4.y,
|
||||
quad.p1.x,
|
||||
quad.p1.y,
|
||||
quad.p2.x,
|
||||
quad.p2.y,
|
||||
quad.p3.x,
|
||||
quad.p3.y,
|
||||
quad.p4.x,
|
||||
quad.p4.y,
|
||||
].map(Math.round);
|
||||
});
|
||||
return { quads };
|
||||
|
|
@ -67,7 +73,10 @@ class DOM extends ContentProcessDomain {
|
|||
height: Math.round(bounding.height),
|
||||
};
|
||||
for (const box of ["content", "padding", "border", "margin"]) {
|
||||
const quads = unsafeObject.getBoxQuads({box, relativeTo: this.content.document});
|
||||
const quads = unsafeObject.getBoxQuads({
|
||||
box,
|
||||
relativeTo: this.content.document,
|
||||
});
|
||||
|
||||
// getBoxQuads may return more than one element. In this case we have to compute the bounding box
|
||||
// of all these boxes.
|
||||
|
|
@ -99,10 +108,14 @@ class DOM extends ContentProcessDomain {
|
|||
});
|
||||
|
||||
model[box] = [
|
||||
bounding.p1.x, bounding.p1.y,
|
||||
bounding.p2.x, bounding.p2.y,
|
||||
bounding.p3.x, bounding.p3.y,
|
||||
bounding.p4.x, bounding.p4.y,
|
||||
bounding.p1.x,
|
||||
bounding.p1.y,
|
||||
bounding.p2.x,
|
||||
bounding.p2.y,
|
||||
bounding.p3.x,
|
||||
bounding.p3.y,
|
||||
bounding.p4.x,
|
||||
bounding.p4.y,
|
||||
].map(Math.round);
|
||||
}
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Emulation"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
|
||||
class Emulation extends ContentProcessDomain {
|
||||
// commands
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Input"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
|
||||
class Input extends ContentProcessDomain {}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Log"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
class Log extends ContentProcessDomain {
|
||||
constructor(session) {
|
||||
|
|
@ -57,7 +59,7 @@ class Log extends ContentProcessDomain {
|
|||
entry = fromConsoleAPI(message.wrappedJSObject);
|
||||
}
|
||||
|
||||
this.emit("Log.entryAdded", {entry});
|
||||
this.emit("Log.entryAdded", { entry });
|
||||
}
|
||||
|
||||
// XPCOM
|
||||
|
|
@ -91,12 +93,11 @@ function fromConsoleAPI(message) {
|
|||
// A couple of possible level are defined here:
|
||||
// https://searchfox.org/mozilla-central/rev/00c0d068ece99717bea7475f7dc07e61f7f35984/dom/console/Console.cpp#1086-1100
|
||||
const levels = {
|
||||
"log": "verbose",
|
||||
"info": "info",
|
||||
"warn": "warning",
|
||||
"error": "error",
|
||||
"exception": "error",
|
||||
|
||||
log: "verbose",
|
||||
info: "info",
|
||||
warn: "warning",
|
||||
error: "error",
|
||||
exception: "error",
|
||||
};
|
||||
const level = levels[message.level] || "info";
|
||||
|
||||
|
|
@ -112,15 +113,19 @@ function fromConsoleAPI(message) {
|
|||
}
|
||||
|
||||
function fromScriptError(error) {
|
||||
const {flags, errorMessage, sourceName, lineNumber, stack} = error;
|
||||
const { flags, errorMessage, sourceName, lineNumber, stack } = error;
|
||||
|
||||
// lossy reduction from bitmask to CDP string level
|
||||
let level = "verbose";
|
||||
if ((flags & Ci.nsIScriptError.exceptionFlag) ||
|
||||
(flags & Ci.nsIScriptError.errorFlag)) {
|
||||
if (
|
||||
flags & Ci.nsIScriptError.exceptionFlag ||
|
||||
flags & Ci.nsIScriptError.errorFlag
|
||||
) {
|
||||
level = "error";
|
||||
} else if ((flags & Ci.nsIScriptError.warningFlag) ||
|
||||
(flags & Ci.nsIScriptError.strictFlag)) {
|
||||
} else if (
|
||||
flags & Ci.nsIScriptError.warningFlag ||
|
||||
flags & Ci.nsIScriptError.strictFlag
|
||||
) {
|
||||
level = "warning";
|
||||
} else if (flags & Ci.nsIScriptError.infoFlag) {
|
||||
level = "info";
|
||||
|
|
|
|||
|
|
@ -6,9 +6,13 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Page"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {UnsupportedError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { UnsupportedError } = ChromeUtils.import(
|
||||
"chrome://remote/content/Error.jsm"
|
||||
);
|
||||
|
||||
class Page extends ContentProcessDomain {
|
||||
constructor(session) {
|
||||
|
|
@ -31,10 +35,12 @@ class Page extends ContentProcessDomain {
|
|||
this.enabled = true;
|
||||
this.contextObserver.on("frame-navigated", this.onFrameNavigated);
|
||||
|
||||
this.chromeEventHandler.addEventListener("DOMContentLoaded", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.addEventListener("pageshow", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.addEventListener("DOMContentLoaded", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
this.chromeEventHandler.addEventListener("pageshow", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,15 +48,17 @@ class Page extends ContentProcessDomain {
|
|||
if (this.enabled) {
|
||||
this.contextObserver.off("frame-navigated", this.onFrameNavigated);
|
||||
|
||||
this.chromeEventHandler.removeEventListener("DOMContentLoaded", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.removeEventListener("pageshow", this,
|
||||
{mozSystemGroup: true});
|
||||
this.chromeEventHandler.removeEventListener("DOMContentLoaded", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
this.chromeEventHandler.removeEventListener("pageshow", this, {
|
||||
mozSystemGroup: true,
|
||||
});
|
||||
this.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
async navigate({url, referrer, transitionType, frameId} = {}) {
|
||||
async navigate({ url, referrer, transitionType, frameId } = {}) {
|
||||
if (frameId && frameId != this.content.windowUtils.outerWindowID) {
|
||||
throw new UnsupportedError("frameId not supported");
|
||||
}
|
||||
|
|
@ -108,7 +116,7 @@ class Page extends ContentProcessDomain {
|
|||
});
|
||||
}
|
||||
|
||||
handleEvent({type, target}) {
|
||||
handleEvent({ type, target }) {
|
||||
if (target.defaultView != this.content) {
|
||||
// Ignore iframes for now
|
||||
return;
|
||||
|
|
@ -120,14 +128,14 @@ class Page extends ContentProcessDomain {
|
|||
|
||||
switch (type) {
|
||||
case "DOMContentLoaded":
|
||||
this.emit("Page.domContentEventFired", {timestamp});
|
||||
this.emit("Page.domContentEventFired", { timestamp });
|
||||
break;
|
||||
|
||||
case "pageshow":
|
||||
this.emit("Page.loadEventFired", {timestamp, frameId});
|
||||
this.emit("Page.loadEventFired", { timestamp, frameId });
|
||||
// XXX this should most likely be sent differently
|
||||
this.emit("Page.navigatedWithinDocument", {timestamp, frameId, url});
|
||||
this.emit("Page.frameStoppedLoading", {timestamp, frameId});
|
||||
this.emit("Page.navigatedWithinDocument", { timestamp, frameId, url });
|
||||
this.emit("Page.frameStoppedLoading", { timestamp, frameId });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Performance"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
|
||||
class Performance extends ContentProcessDomain {
|
||||
constructor(session) {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,17 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Runtime"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {ExecutionContext} = ChromeUtils.import("chrome://remote/content/domains/content/runtime/ExecutionContext.jsm");
|
||||
const {addDebuggerToGlobal} = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm", {});
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { ExecutionContext } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/content/runtime/ExecutionContext.jsm"
|
||||
);
|
||||
const { addDebuggerToGlobal } = ChromeUtils.import(
|
||||
"resource://gre/modules/jsdebugger.jsm",
|
||||
{}
|
||||
);
|
||||
|
||||
// Import the `Debugger` constructor in the current scope
|
||||
addDebuggerToGlobal(Cu.getGlobalForObject(this));
|
||||
|
|
@ -63,11 +70,15 @@ class Runtime extends ContentProcessDomain {
|
|||
evaluate(request) {
|
||||
const context = this.contexts.get(request.contextId);
|
||||
if (!context) {
|
||||
throw new Error(`Unable to find execution context with id: ${request.contextId}`);
|
||||
throw new Error(
|
||||
`Unable to find execution context with id: ${request.contextId}`
|
||||
);
|
||||
}
|
||||
if (typeof(request.expression) != "string") {
|
||||
throw new Error(`Expecting 'expression' attribute to be a string. ` +
|
||||
`But was: ${typeof(request.expression)}`);
|
||||
if (typeof request.expression != "string") {
|
||||
throw new Error(
|
||||
`Expecting 'expression' attribute to be a string. ` +
|
||||
`But was: ${typeof request.expression}`
|
||||
);
|
||||
}
|
||||
return context.evaluate(request.expression);
|
||||
}
|
||||
|
|
@ -75,7 +86,7 @@ class Runtime extends ContentProcessDomain {
|
|||
getRemoteObject(objectId) {
|
||||
for (const ctx of this.contexts.values()) {
|
||||
const obj = ctx.getRemoteObject(objectId);
|
||||
if (typeof(obj) != "undefined") {
|
||||
if (typeof obj != "undefined") {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
|
@ -108,33 +119,47 @@ class Runtime extends ContentProcessDomain {
|
|||
}
|
||||
}
|
||||
if (!context) {
|
||||
throw new Error(`Unable to get the context for object with id: ${request.objectId}`);
|
||||
throw new Error(
|
||||
`Unable to get the context for object with id: ${request.objectId}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
context = this.contexts.get(request.executionContextId);
|
||||
if (!context) {
|
||||
throw new Error(`Unable to find execution context with id: ${request.executionContextId}`);
|
||||
throw new Error(
|
||||
`Unable to find execution context with id: ${
|
||||
request.executionContextId
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (typeof(request.functionDeclaration) != "string") {
|
||||
throw new Error("Expect 'functionDeclaration' attribute to be passed and be a string");
|
||||
if (typeof request.functionDeclaration != "string") {
|
||||
throw new Error(
|
||||
"Expect 'functionDeclaration' attribute to be passed and be a string"
|
||||
);
|
||||
}
|
||||
if (request.arguments && !Array.isArray(request.arguments)) {
|
||||
throw new Error("Expect 'arguments' to be an array");
|
||||
}
|
||||
if (request.returnByValue && typeof(request.returnByValue) != "boolean") {
|
||||
if (request.returnByValue && typeof request.returnByValue != "boolean") {
|
||||
throw new Error("Expect 'returnByValue' to be a boolean");
|
||||
}
|
||||
if (request.awaitPromise && typeof(request.awaitPromise) != "boolean") {
|
||||
if (request.awaitPromise && typeof request.awaitPromise != "boolean") {
|
||||
throw new Error("Expect 'awaitPromise' to be a boolean");
|
||||
}
|
||||
return context.callFunctionOn(request.functionDeclaration, request.arguments, request.returnByValue, request.awaitPromise, request.objectId);
|
||||
return context.callFunctionOn(
|
||||
request.functionDeclaration,
|
||||
request.arguments,
|
||||
request.returnByValue,
|
||||
request.awaitPromise,
|
||||
request.objectId
|
||||
);
|
||||
}
|
||||
|
||||
getProperties({ objectId, ownProperties }) {
|
||||
for (const ctx of this.contexts.values()) {
|
||||
const obj = ctx.getRemoteObject(objectId);
|
||||
if (typeof(obj) != "undefined") {
|
||||
if (typeof obj != "undefined") {
|
||||
return ctx.getProperties({ objectId, ownProperties });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Security"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
|
||||
class Security extends ContentProcessDomain {
|
||||
constructor(session) {
|
||||
|
|
|
|||
|
|
@ -6,13 +6,26 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ExecutionContext"];
|
||||
|
||||
const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
|
||||
const TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
|
||||
"Uint32Array", "Int8Array", "Int16Array", "Int32Array",
|
||||
"Float32Array", "Float64Array"];
|
||||
const TYPED_ARRAY_CLASSES = [
|
||||
"Uint8Array",
|
||||
"Uint8ClampedArray",
|
||||
"Uint16Array",
|
||||
"Uint32Array",
|
||||
"Int8Array",
|
||||
"Int16Array",
|
||||
"Int32Array",
|
||||
"Float32Array",
|
||||
"Float64Array",
|
||||
];
|
||||
function uuid() {
|
||||
return uuidGen.generateUUID().toString().slice(1, -1);
|
||||
return uuidGen
|
||||
.generateUUID()
|
||||
.toString()
|
||||
.slice(1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,10 +102,15 @@ class ExecutionContext {
|
|||
* describing the exception by following CDP ExceptionDetails specification.
|
||||
*/
|
||||
_returnError(exception) {
|
||||
if (this._debuggee.executeInGlobalWithBindings("exception instanceof Error",
|
||||
{exception}).return) {
|
||||
const text = this._debuggee.executeInGlobalWithBindings("exception.message",
|
||||
{exception}).return;
|
||||
if (
|
||||
this._debuggee.executeInGlobalWithBindings("exception instanceof Error", {
|
||||
exception,
|
||||
}).return
|
||||
) {
|
||||
const text = this._debuggee.executeInGlobalWithBindings(
|
||||
"exception.message",
|
||||
{ exception }
|
||||
).return;
|
||||
return {
|
||||
exceptionDetails: {
|
||||
text,
|
||||
|
|
@ -108,7 +126,13 @@ class ExecutionContext {
|
|||
};
|
||||
}
|
||||
|
||||
async callFunctionOn(functionDeclaration, callArguments = [], returnByValue = false, awaitPromise = false, objectId = null) {
|
||||
async callFunctionOn(
|
||||
functionDeclaration,
|
||||
callArguments = [],
|
||||
returnByValue = false,
|
||||
awaitPromise = false,
|
||||
objectId = null
|
||||
) {
|
||||
// Map the given objectId to a JS reference.
|
||||
let thisArg = null;
|
||||
if (objectId) {
|
||||
|
|
@ -188,8 +212,12 @@ class ExecutionContext {
|
|||
enumerable: descriptor.enumerable,
|
||||
writable: descriptor.writable,
|
||||
value: this._toRemoteObject(descriptor.value),
|
||||
get: descriptor.get ? this._toRemoteObject(descriptor.get) : undefined,
|
||||
set: descriptor.set ? this._toRemoteObject(descriptor.set) : undefined,
|
||||
get: descriptor.get
|
||||
? this._toRemoteObject(descriptor.get)
|
||||
: undefined,
|
||||
set: descriptor.set
|
||||
? this._toRemoteObject(descriptor.set)
|
||||
: undefined,
|
||||
|
||||
isOwn,
|
||||
});
|
||||
|
|
@ -224,10 +252,13 @@ class ExecutionContext {
|
|||
* The JSON string
|
||||
*/
|
||||
_serialize(obj) {
|
||||
if (typeof(obj) == "undefined") {
|
||||
if (typeof obj == "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
const result = this._debuggee.executeInGlobalWithBindings("JSON.stringify(e)", {e: obj});
|
||||
const result = this._debuggee.executeInGlobalWithBindings(
|
||||
"JSON.stringify(e)",
|
||||
{ e: obj }
|
||||
);
|
||||
if (result.throw) {
|
||||
throw new Error("Object is not serializable");
|
||||
}
|
||||
|
|
@ -247,10 +278,14 @@ class ExecutionContext {
|
|||
}
|
||||
if (arg.unserializableValue) {
|
||||
switch (arg.unserializableValue) {
|
||||
case "Infinity": return Infinity;
|
||||
case "-Infinity": return -Infinity;
|
||||
case "-0": return -0;
|
||||
case "NaN": return NaN;
|
||||
case "Infinity":
|
||||
return Infinity;
|
||||
case "-Infinity":
|
||||
return -Infinity;
|
||||
case "-0":
|
||||
return -0;
|
||||
case "NaN":
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
return this._deserialize(arg.value);
|
||||
|
|
@ -263,8 +298,10 @@ class ExecutionContext {
|
|||
if (typeof obj !== "object") {
|
||||
return obj;
|
||||
}
|
||||
const result = this._debuggee.executeInGlobalWithBindings("JSON.parse(obj)",
|
||||
{obj: JSON.stringify(obj)});
|
||||
const result = this._debuggee.executeInGlobalWithBindings(
|
||||
"JSON.parse(obj)",
|
||||
{ obj: JSON.stringify(obj) }
|
||||
);
|
||||
if (result.throw) {
|
||||
throw new Error("Unable to deserialize object");
|
||||
}
|
||||
|
|
@ -318,7 +355,7 @@ class ExecutionContext {
|
|||
}
|
||||
|
||||
const type = typeof rawObj;
|
||||
return {objectId, type, subtype};
|
||||
return { objectId, type, subtype };
|
||||
}
|
||||
|
||||
// Now, handle all values that Debugger API isn't wrapping into Debugger.API.
|
||||
|
|
@ -331,19 +368,20 @@ class ExecutionContext {
|
|||
if (type == "symbol" || type == "bigint") {
|
||||
const objectId = uuid();
|
||||
this._remoteObjects.set(objectId, debuggerObj);
|
||||
return {objectId, type};
|
||||
return { objectId, type };
|
||||
}
|
||||
|
||||
// A few primitive type can't be serialized and CDP has special case for them
|
||||
let unserializableValue = undefined;
|
||||
if (Object.is(debuggerObj, NaN))
|
||||
if (Object.is(debuggerObj, NaN)) {
|
||||
unserializableValue = "NaN";
|
||||
else if (Object.is(debuggerObj, -0))
|
||||
} else if (Object.is(debuggerObj, -0)) {
|
||||
unserializableValue = "-0";
|
||||
else if (Object.is(debuggerObj, Infinity))
|
||||
} else if (Object.is(debuggerObj, Infinity)) {
|
||||
unserializableValue = "Infinity";
|
||||
else if (Object.is(debuggerObj, -Infinity))
|
||||
} else if (Object.is(debuggerObj, -Infinity)) {
|
||||
unserializableValue = "-Infinity";
|
||||
}
|
||||
if (unserializableValue) {
|
||||
return {
|
||||
unserializableValue,
|
||||
|
|
|
|||
|
|
@ -6,14 +6,19 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Browser"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
|
||||
class Browser extends Domain {
|
||||
getVersion() {
|
||||
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
|
||||
const { userAgent } = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler);
|
||||
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(
|
||||
Ci.nsIGfxInfo
|
||||
);
|
||||
const { userAgent } = Cc[
|
||||
"@mozilla.org/network/protocol;1?name=http"
|
||||
].getService(Ci.nsIHttpProtocolHandler);
|
||||
return {
|
||||
protocolVersion: "1",
|
||||
product: (isHeadless ? "Headless " : "") + "Firefox",
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Input"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
|
||||
class Input extends Domain {
|
||||
// commands
|
||||
|
|
@ -28,12 +30,7 @@ class Input extends Domain {
|
|||
* - windowsVirtualKeyCode
|
||||
*/
|
||||
async dispatchKeyEvent(options) {
|
||||
const {
|
||||
key,
|
||||
modifiers,
|
||||
type,
|
||||
windowsVirtualKeyCode,
|
||||
} = options;
|
||||
const { key, modifiers, type, windowsVirtualKeyCode } = options;
|
||||
|
||||
let domType;
|
||||
if (type == "keyDown" || type == "rawKeyDown") {
|
||||
|
|
@ -54,8 +51,10 @@ class Input extends Domain {
|
|||
|
||||
const EventUtils = this._getEventUtils(browserWindow);
|
||||
const onEvent = new Promise(r => {
|
||||
browserWindow.addEventListener(domType, r,
|
||||
{mozSystemGroup: true, once: true});
|
||||
browserWindow.addEventListener(domType, r, {
|
||||
mozSystemGroup: true,
|
||||
once: true,
|
||||
});
|
||||
});
|
||||
|
||||
if (type == "char") {
|
||||
|
|
@ -65,21 +64,23 @@ class Input extends Domain {
|
|||
} else {
|
||||
// Non printable keys should be prefixed with `KEY_`
|
||||
const eventUtilsKey = key.length == 1 ? key : "KEY_" + key;
|
||||
EventUtils.synthesizeKey(eventUtilsKey, {
|
||||
EventUtils.synthesizeKey(
|
||||
eventUtilsKey,
|
||||
{
|
||||
keyCode: windowsVirtualKeyCode,
|
||||
type: domType,
|
||||
altKey: !!(modifiers & 1),
|
||||
ctrlKey: !!(modifiers & 2),
|
||||
metaKey: !!(modifiers & 4),
|
||||
shiftKey: !!(modifiers & 8),
|
||||
}, browserWindow);
|
||||
},
|
||||
browserWindow
|
||||
);
|
||||
}
|
||||
await onEvent;
|
||||
}
|
||||
|
||||
async dispatchMouseEvent({
|
||||
type, button, x, y, modifiers, clickCount,
|
||||
}) {
|
||||
async dispatchMouseEvent({ type, button, x, y, modifiers, clickCount }) {
|
||||
if (type == "mousePressed") {
|
||||
type = "mousedown";
|
||||
} else if (type == "mouseReleased") {
|
||||
|
|
@ -135,8 +136,10 @@ class Input extends Domain {
|
|||
_EU_Ci: Ci,
|
||||
_EU_Cc: Cc,
|
||||
};
|
||||
Services.scriptloader.loadSubScript("chrome://remote/content/external/EventUtils.js",
|
||||
this._eventUtils);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://remote/content/external/EventUtils.js",
|
||||
this._eventUtils
|
||||
);
|
||||
}
|
||||
return this._eventUtils;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Network"];
|
||||
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const {NetworkObserver} = ChromeUtils.import("chrome://remote/content/domains/parent/network/NetworkObserver.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
const { NetworkObserver } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/parent/network/NetworkObserver.jsm"
|
||||
);
|
||||
|
||||
const LOAD_CAUSE_STRINGS = {
|
||||
[Ci.nsIContentPolicy.TYPE_INVALID]: "Invalid",
|
||||
|
|
@ -120,13 +124,17 @@ function getLoadContext(httpChannel) {
|
|||
let loadContext = null;
|
||||
try {
|
||||
if (httpChannel.notificationCallbacks) {
|
||||
loadContext = httpChannel.notificationCallbacks.getInterface(Ci.nsILoadContext);
|
||||
loadContext = httpChannel.notificationCallbacks.getInterface(
|
||||
Ci.nsILoadContext
|
||||
);
|
||||
}
|
||||
} catch (e) {}
|
||||
try {
|
||||
if (!loadContext && httpChannel.loadGroup) {
|
||||
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
|
||||
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(
|
||||
Ci.nsILoadContext
|
||||
);
|
||||
}
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
return loadContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Page"];
|
||||
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
|
||||
class Page extends Domain {
|
||||
// commands
|
||||
|
|
|
|||
|
|
@ -6,10 +6,18 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Target"];
|
||||
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const {TabManager} = ChromeUtils.import("chrome://remote/content/WindowManager.jsm");
|
||||
const {TabSession} = ChromeUtils.import("chrome://remote/content/sessions/TabSession.jsm");
|
||||
const {ContextualIdentityService} = ChromeUtils.import("resource://gre/modules/ContextualIdentityService.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
const { TabManager } = ChromeUtils.import(
|
||||
"chrome://remote/content/WindowManager.jsm"
|
||||
);
|
||||
const { TabSession } = ChromeUtils.import(
|
||||
"chrome://remote/content/sessions/TabSession.jsm"
|
||||
);
|
||||
const { ContextualIdentityService } = ChromeUtils.import(
|
||||
"resource://gre/modules/ContextualIdentityService.jsm"
|
||||
);
|
||||
|
||||
let sessionIds = 1;
|
||||
let browserContextIds = 1;
|
||||
|
|
@ -29,7 +37,9 @@ class Target extends Domain {
|
|||
}
|
||||
|
||||
createBrowserContext() {
|
||||
const identity = ContextualIdentityService.create("remote-agent-" + (browserContextIds++));
|
||||
const identity = ContextualIdentityService.create(
|
||||
"remote-agent-" + browserContextIds++
|
||||
);
|
||||
return { browserContextId: identity.userContextId };
|
||||
}
|
||||
|
||||
|
|
@ -75,9 +85,11 @@ class Target extends Domain {
|
|||
const tab = TabManager.addTab({ userContextId: browserContextId });
|
||||
const target = await onTarget;
|
||||
if (tab.linkedBrowser != target.browser) {
|
||||
throw new Error("Unexpected tab opened: " + tab.linkedBrowser.currentURI.spec);
|
||||
throw new Error(
|
||||
"Unexpected tab opened: " + tab.linkedBrowser.currentURI.spec
|
||||
);
|
||||
}
|
||||
return {targetId: target.id};
|
||||
return { targetId: target.id };
|
||||
}
|
||||
|
||||
closeTarget({ targetId }) {
|
||||
|
|
@ -93,7 +105,12 @@ class Target extends Domain {
|
|||
return new Error(`Unable to find target with id '${targetId}'`);
|
||||
}
|
||||
|
||||
const session = new TabSession(this.session.connection, target, sessionIds++, this.session);
|
||||
const session = new TabSession(
|
||||
this.session.connection,
|
||||
target,
|
||||
sessionIds++,
|
||||
this.session
|
||||
);
|
||||
this.emit("Target.attachedToTarget", {
|
||||
targetInfo: {
|
||||
type: "page",
|
||||
|
|
|
|||
|
|
@ -4,17 +4,33 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const {CommonUtils} = ChromeUtils.import("resource://services-common/utils.js");
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const { CommonUtils } = ChromeUtils.import(
|
||||
"resource://services-common/utils.js"
|
||||
);
|
||||
|
||||
const Cm = Components.manager;
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream", "setInputStream");
|
||||
const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");
|
||||
const StorageStream = CC("@mozilla.org/storagestream;1", "nsIStorageStream", "init");
|
||||
const BinaryInputStream = CC(
|
||||
"@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream"
|
||||
);
|
||||
const BinaryOutputStream = CC(
|
||||
"@mozilla.org/binaryoutputstream;1",
|
||||
"nsIBinaryOutputStream",
|
||||
"setOutputStream"
|
||||
);
|
||||
const StorageStream = CC(
|
||||
"@mozilla.org/storagestream;1",
|
||||
"nsIStorageStream",
|
||||
"init"
|
||||
);
|
||||
|
||||
// Cap response storage with 100Mb per tracked tab.
|
||||
const MAX_RESPONSE_STORAGE_SIZE = 100 * 1024 * 1024;
|
||||
|
|
@ -36,7 +52,9 @@ class NetworkObserver {
|
|||
constructor() {
|
||||
EventEmitter.decorate(this);
|
||||
this._browserSessionCount = new Map();
|
||||
this._activityDistributor = Cc["@mozilla.org/network/http-activity-distributor;1"].getService(Ci.nsIHttpActivityDistributor);
|
||||
this._activityDistributor = Cc[
|
||||
"@mozilla.org/network/http-activity-distributor;1"
|
||||
].getService(Ci.nsIHttpActivityDistributor);
|
||||
this._activityDistributor.addObserver(this);
|
||||
|
||||
this._redirectMap = new Map();
|
||||
|
|
@ -53,8 +71,19 @@ class NetworkObserver {
|
|||
};
|
||||
// Register self as ChannelEventSink to track redirects.
|
||||
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(SINK_CLASS_ID, SINK_CLASS_DESCRIPTION, SINK_CONTRACT_ID, this._channelSinkFactory);
|
||||
Services.catMan.addCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID, SINK_CONTRACT_ID, false, true);
|
||||
registrar.registerFactory(
|
||||
SINK_CLASS_ID,
|
||||
SINK_CLASS_DESCRIPTION,
|
||||
SINK_CONTRACT_ID,
|
||||
this._channelSinkFactory
|
||||
);
|
||||
Services.catMan.addCategoryEntry(
|
||||
SINK_CATEGORY_NAME,
|
||||
SINK_CONTRACT_ID,
|
||||
SINK_CONTRACT_ID,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
// Request interception state.
|
||||
this._browserSuspendedChannels = new Map();
|
||||
|
|
@ -62,12 +91,24 @@ class NetworkObserver {
|
|||
this._browserResponseStorages = new Map();
|
||||
|
||||
this._onRequest = this._onRequest.bind(this);
|
||||
this._onExamineResponse = this._onResponse.bind(this, false /* fromCache */);
|
||||
this._onExamineResponse = this._onResponse.bind(
|
||||
this,
|
||||
false /* fromCache */
|
||||
);
|
||||
this._onCachedResponse = this._onResponse.bind(this, true /* fromCache */);
|
||||
Services.obs.addObserver(this._onRequest, "http-on-modify-request");
|
||||
Services.obs.addObserver(this._onExamineResponse, "http-on-examine-response");
|
||||
Services.obs.addObserver(this._onCachedResponse, "http-on-examine-cached-response");
|
||||
Services.obs.addObserver(this._onCachedResponse, "http-on-examine-merged-response");
|
||||
Services.obs.addObserver(
|
||||
this._onExamineResponse,
|
||||
"http-on-examine-response"
|
||||
);
|
||||
Services.obs.addObserver(
|
||||
this._onCachedResponse,
|
||||
"http-on-examine-cached-response"
|
||||
);
|
||||
Services.obs.addObserver(
|
||||
this._onCachedResponse,
|
||||
"http-on-examine-merged-response"
|
||||
);
|
||||
}
|
||||
|
||||
setExtraHTTPHeaders(browser, headers) {
|
||||
|
|
@ -111,7 +152,11 @@ class NetworkObserver {
|
|||
}
|
||||
// 2. Set new headers.
|
||||
for (const header of headers) {
|
||||
httpChannel.setRequestHeader(header.name, header.value, false /* merge */);
|
||||
httpChannel.setRequestHeader(
|
||||
header.name,
|
||||
header.value,
|
||||
false /* merge */
|
||||
);
|
||||
}
|
||||
}
|
||||
suspendedChannels.delete(requestId);
|
||||
|
|
@ -150,14 +195,26 @@ class NetworkObserver {
|
|||
}
|
||||
const httpChannel = oldChannel.QueryInterface(Ci.nsIHttpChannel);
|
||||
const loadContext = getLoadContext(httpChannel);
|
||||
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
|
||||
if (
|
||||
!loadContext ||
|
||||
!this._browserSessionCount.has(loadContext.topFrameElement)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this._redirectMap.set(newChannel, oldChannel);
|
||||
}
|
||||
|
||||
observeActivity(channel, activityType, activitySubtype, timestamp, extraSizeData, extraStringData) {
|
||||
if (activityType !== Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION) {
|
||||
observeActivity(
|
||||
channel,
|
||||
activityType,
|
||||
activitySubtype,
|
||||
timestamp,
|
||||
extraSizeData,
|
||||
extraStringData
|
||||
) {
|
||||
if (
|
||||
activityType !== Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (!(channel instanceof Ci.nsIHttpChannel)) {
|
||||
|
|
@ -165,10 +222,16 @@ class NetworkObserver {
|
|||
}
|
||||
const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
const loadContext = getLoadContext(httpChannel);
|
||||
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
|
||||
if (
|
||||
!loadContext ||
|
||||
!this._browserSessionCount.has(loadContext.topFrameElement)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (activitySubtype !== Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE) {
|
||||
if (
|
||||
activitySubtype !==
|
||||
Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.emit("requestfinished", httpChannel, {
|
||||
|
|
@ -182,17 +245,30 @@ class NetworkObserver {
|
|||
}
|
||||
const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
const loadContext = getLoadContext(httpChannel);
|
||||
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
|
||||
if (
|
||||
!loadContext ||
|
||||
!this._browserSessionCount.has(loadContext.topFrameElement)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const extraHeaders = this._extraHTTPHeaders.get(loadContext.topFrameElement);
|
||||
const extraHeaders = this._extraHTTPHeaders.get(
|
||||
loadContext.topFrameElement
|
||||
);
|
||||
if (extraHeaders) {
|
||||
for (const header of extraHeaders) {
|
||||
httpChannel.setRequestHeader(header.name, header.value, false /* merge */);
|
||||
httpChannel.setRequestHeader(
|
||||
header.name,
|
||||
header.value,
|
||||
false /* merge */
|
||||
);
|
||||
}
|
||||
}
|
||||
const causeType = httpChannel.loadInfo ? httpChannel.loadInfo.externalContentPolicyType : Ci.nsIContentPolicy.TYPE_OTHER;
|
||||
const suspendedChannels = this._browserSuspendedChannels.get(loadContext.topFrameElement);
|
||||
const causeType = httpChannel.loadInfo
|
||||
? httpChannel.loadInfo.externalContentPolicyType
|
||||
: Ci.nsIContentPolicy.TYPE_OTHER;
|
||||
const suspendedChannels = this._browserSuspendedChannels.get(
|
||||
loadContext.topFrameElement
|
||||
);
|
||||
if (suspendedChannels) {
|
||||
httpChannel.suspend();
|
||||
suspendedChannels.set(requestId(httpChannel), httpChannel);
|
||||
|
|
@ -218,13 +294,16 @@ class NetworkObserver {
|
|||
|
||||
_onResponse(fromCache, httpChannel, topic) {
|
||||
const loadContext = getLoadContext(httpChannel);
|
||||
if (!loadContext || !this._browserSessionCount.has(loadContext.topFrameElement)) {
|
||||
if (
|
||||
!loadContext ||
|
||||
!this._browserSessionCount.has(loadContext.topFrameElement)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
httpChannel.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
const headers = [];
|
||||
httpChannel.visitResponseHeaders({
|
||||
visitHeader: (name, value) => headers.push({name, value}),
|
||||
visitHeader: (name, value) => headers.push({ name, value }),
|
||||
});
|
||||
|
||||
let remoteIPAddress = undefined;
|
||||
|
|
@ -262,7 +341,13 @@ class NetworkObserver {
|
|||
const value = this._browserSessionCount.get(browser) || 0;
|
||||
this._browserSessionCount.set(browser, value + 1);
|
||||
if (value === 0) {
|
||||
this._browserResponseStorages.set(browser, new ResponseStorage(MAX_RESPONSE_STORAGE_SIZE, MAX_RESPONSE_STORAGE_SIZE / 10));
|
||||
this._browserResponseStorages.set(
|
||||
browser,
|
||||
new ResponseStorage(
|
||||
MAX_RESPONSE_STORAGE_SIZE,
|
||||
MAX_RESPONSE_STORAGE_SIZE / 10
|
||||
)
|
||||
);
|
||||
}
|
||||
return () => this.stopTrackingBrowserNetwork(browser);
|
||||
}
|
||||
|
|
@ -281,11 +366,24 @@ class NetworkObserver {
|
|||
this._activityDistributor.removeObserver(this);
|
||||
const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.unregisterFactory(SINK_CLASS_ID, this._channelSinkFactory);
|
||||
Services.catMan.deleteCategoryEntry(SINK_CATEGORY_NAME, SINK_CONTRACT_ID, false);
|
||||
Services.catMan.deleteCategoryEntry(
|
||||
SINK_CATEGORY_NAME,
|
||||
SINK_CONTRACT_ID,
|
||||
false
|
||||
);
|
||||
Services.obs.removeObserver(this._onRequest, "http-on-modify-request");
|
||||
Services.obs.removeObserver(this._onExamineResponse, "http-on-examine-response");
|
||||
Services.obs.removeObserver(this._onCachedResponse, "http-on-examine-cached-response");
|
||||
Services.obs.removeObserver(this._onCachedResponse, "http-on-examine-merged-response");
|
||||
Services.obs.removeObserver(
|
||||
this._onExamineResponse,
|
||||
"http-on-examine-response"
|
||||
);
|
||||
Services.obs.removeObserver(
|
||||
this._onCachedResponse,
|
||||
"http-on-examine-cached-response"
|
||||
);
|
||||
Services.obs.removeObserver(
|
||||
this._onCachedResponse,
|
||||
"http-on-examine-merged-response"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,8 +433,9 @@ function readRequestPostData(httpChannel) {
|
|||
let text = undefined;
|
||||
try {
|
||||
text = NetUtil.readInputStreamToString(iStream, iStream.available());
|
||||
const converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
const converter = Cc[
|
||||
"@mozilla.org/intl/scriptableunicodeconverter"
|
||||
].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
text = converter.ConvertToUnicode(text);
|
||||
} catch (err) {
|
||||
|
|
@ -356,14 +455,18 @@ function getLoadContext(httpChannel) {
|
|||
let loadContext = null;
|
||||
try {
|
||||
if (httpChannel.notificationCallbacks) {
|
||||
loadContext = httpChannel.notificationCallbacks.getInterface(Ci.nsILoadContext);
|
||||
loadContext = httpChannel.notificationCallbacks.getInterface(
|
||||
Ci.nsILoadContext
|
||||
);
|
||||
}
|
||||
} catch (e) {}
|
||||
try {
|
||||
if (!loadContext && httpChannel.loadGroup) {
|
||||
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
|
||||
loadContext = httpChannel.loadGroup.notificationCallbacks.getInterface(
|
||||
Ci.nsILoadContext
|
||||
);
|
||||
}
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +477,7 @@ function requestId(httpChannel) {
|
|||
function requestHeaders(httpChannel) {
|
||||
const headers = [];
|
||||
httpChannel.visitRequestHeaders({
|
||||
visitHeader: (name, value) => headers.push({name, value}),
|
||||
visitHeader: (name, value) => headers.push({ name, value }),
|
||||
});
|
||||
return headers;
|
||||
}
|
||||
|
|
@ -405,11 +508,15 @@ class ResponseStorage {
|
|||
return;
|
||||
}
|
||||
let encodings = [];
|
||||
if ((httpChannel instanceof Ci.nsIEncodedChannel) && httpChannel.contentEncodings && !httpChannel.applyConversion) {
|
||||
if (
|
||||
httpChannel instanceof Ci.nsIEncodedChannel &&
|
||||
httpChannel.contentEncodings &&
|
||||
!httpChannel.applyConversion
|
||||
) {
|
||||
const encodingHeader = httpChannel.getResponseHeader("Content-Encoding");
|
||||
encodings = encodingHeader.split(/\s*\t*,\s*\t*/);
|
||||
}
|
||||
this._responses.set(requestId(httpChannel), {body, encodings});
|
||||
this._responses.set(requestId(httpChannel), { body, encodings });
|
||||
this._totalSize += body.length;
|
||||
if (this._totalSize > this._maxTotalSize) {
|
||||
for (let [, response] of this._responses) {
|
||||
|
|
@ -425,17 +532,19 @@ class ResponseStorage {
|
|||
|
||||
getBase64EncodedResponse(requestId) {
|
||||
const response = this._responses.get(requestId);
|
||||
if (!response)
|
||||
if (!response) {
|
||||
throw new Error(`Request "${requestId}" is not found`);
|
||||
if (response.evicted)
|
||||
return {base64body: "", evicted: true};
|
||||
}
|
||||
if (response.evicted) {
|
||||
return { base64body: "", evicted: true };
|
||||
}
|
||||
let result = response.body;
|
||||
if (response.encodings && response.encodings.length) {
|
||||
for (const encoding of response.encodings) {
|
||||
result = CommonUtils.convertString(result, encoding, "uncompressed");
|
||||
}
|
||||
}
|
||||
return {base64body: btoa(result)};
|
||||
return { base64body: btoa(result) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -460,7 +569,12 @@ class ResponseBodyListener {
|
|||
this._chunks.push(data);
|
||||
|
||||
oStream.writeBytes(data, aCount);
|
||||
this.originalListener.onDataAvailable(aRequest, sStream.newInputStream(0), aOffset, aCount);
|
||||
this.originalListener.onDataAvailable(
|
||||
aRequest,
|
||||
sStream.newInputStream(0),
|
||||
aOffset,
|
||||
aCount
|
||||
);
|
||||
}
|
||||
|
||||
onStartRequest(aRequest) {
|
||||
|
|
@ -471,25 +585,35 @@ class ResponseBodyListener {
|
|||
this.originalListener.onStopRequest(aRequest, aStatusCode);
|
||||
const body = this._chunks.join("");
|
||||
delete this._chunks;
|
||||
this._networkObserver._onResponseFinished(this._browser, this._httpChannel, body);
|
||||
this._networkObserver._onResponseFinished(
|
||||
this._browser,
|
||||
this._httpChannel,
|
||||
body
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getNetworkErrorStatusText(status) {
|
||||
if (!status)
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
for (const key of Object.keys(Cr)) {
|
||||
if (Cr[key] === status)
|
||||
if (Cr[key] === status) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
// Security module. The following is taken from
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/How_to_check_the_secruity_state_of_an_XMLHTTPRequest_over_SSL
|
||||
if ((status & 0xff0000) === 0x5a0000) {
|
||||
// NSS_SEC errors (happen below the base value because of negative vals)
|
||||
if ((status & 0xffff) < Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)) {
|
||||
if (
|
||||
(status & 0xffff) <
|
||||
Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE)
|
||||
) {
|
||||
// The bases are actually negative, so in our positive numeric space, we
|
||||
// need to subtract the base off our value.
|
||||
const nssErr = Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
|
||||
const nssErr =
|
||||
Math.abs(Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE) - (status & 0xffff);
|
||||
switch (nssErr) {
|
||||
case 11:
|
||||
return "SEC_ERROR_EXPIRED_CERTIFICATE";
|
||||
|
|
@ -511,7 +635,8 @@ function getNetworkErrorStatusText(status) {
|
|||
return "SEC_ERROR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
const sslErr = Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);
|
||||
const sslErr =
|
||||
Math.abs(Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE) - (status & 0xffff);
|
||||
switch (sslErr) {
|
||||
case 3:
|
||||
return "SSL_ERROR_NO_CERTIFICATE";
|
||||
|
|
|
|||
|
|
@ -10,15 +10,23 @@ var EXPORTED_SYMBOLS = ["WebSocketServer"];
|
|||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Stream} = ChromeUtils.import("chrome://remote/content/server/Stream.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Stream } = ChromeUtils.import(
|
||||
"chrome://remote/content/server/Stream.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "WebSocket", () => {
|
||||
return Services.appShell.hiddenDOMWindow.WebSocket;
|
||||
});
|
||||
|
||||
const CryptoHash = CC("@mozilla.org/security/hash;1", "nsICryptoHash", "initWithString");
|
||||
const CryptoHash = CC(
|
||||
"@mozilla.org/security/hash;1",
|
||||
"nsICryptoHash",
|
||||
"initWithString"
|
||||
);
|
||||
const threadManager = Cc["@mozilla.org/thread-manager;1"].getService();
|
||||
|
||||
// limit the header size to put an upper bound on allocated memory
|
||||
|
|
@ -36,7 +44,8 @@ function readLine(input) {
|
|||
return new Promise((resolve, reject) => {
|
||||
let line = "";
|
||||
const wait = () => {
|
||||
input.asyncWait(stream => {
|
||||
input.asyncWait(
|
||||
stream => {
|
||||
try {
|
||||
const amountToRead = HEADER_MAX_LEN - line.length;
|
||||
line += Stream.delimitedRead(input, "\n", amountToRead);
|
||||
|
|
@ -48,14 +57,19 @@ function readLine(input) {
|
|||
|
||||
if (line.length >= HEADER_MAX_LEN) {
|
||||
throw new Error(
|
||||
`Failed to read HTTP header longer than ${HEADER_MAX_LEN} bytes`);
|
||||
`Failed to read HTTP header longer than ${HEADER_MAX_LEN} bytes`
|
||||
);
|
||||
}
|
||||
|
||||
wait();
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
}, 0, 0, threadManager.currentThread);
|
||||
},
|
||||
0,
|
||||
0,
|
||||
threadManager.currentThread
|
||||
);
|
||||
};
|
||||
|
||||
wait();
|
||||
|
|
@ -76,7 +90,8 @@ function writeString(output, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
output.asyncWait(stream => {
|
||||
output.asyncWait(
|
||||
stream => {
|
||||
try {
|
||||
const written = output.write(data, data.length);
|
||||
data = data.slice(written);
|
||||
|
|
@ -84,7 +99,11 @@ function writeString(output, data) {
|
|||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
}, 0, 0, threadManager.currentThread);
|
||||
},
|
||||
0,
|
||||
0,
|
||||
threadManager.currentThread
|
||||
);
|
||||
};
|
||||
|
||||
wait();
|
||||
|
|
@ -120,7 +139,7 @@ const readHttpRequest = async function(input) {
|
|||
}
|
||||
}
|
||||
|
||||
return {requestLine, headers};
|
||||
return { requestLine, headers };
|
||||
};
|
||||
|
||||
/** Write HTTP response (array of strings) to async output stream. */
|
||||
|
|
@ -133,7 +152,7 @@ function writeHttpResponse(output, response) {
|
|||
* Process the WebSocket handshake headers and return the key to be sent in
|
||||
* Sec-WebSocket-Accept response header.
|
||||
*/
|
||||
function processRequest({requestLine, headers}) {
|
||||
function processRequest({ requestLine, headers }) {
|
||||
const method = requestLine.split(" ")[0];
|
||||
if (method !== "GET") {
|
||||
throw new Error("The handshake request must use GET method");
|
||||
|
|
@ -145,19 +164,29 @@ function processRequest({requestLine, headers}) {
|
|||
}
|
||||
|
||||
const connection = headers.get("connection");
|
||||
if (!connection || !connection.split(",").map(t => t.trim()).includes("Upgrade")) {
|
||||
if (
|
||||
!connection ||
|
||||
!connection
|
||||
.split(",")
|
||||
.map(t => t.trim())
|
||||
.includes("Upgrade")
|
||||
) {
|
||||
throw new Error("The handshake request has incorrect Connection header");
|
||||
}
|
||||
|
||||
const version = headers.get("sec-websocket-version");
|
||||
if (!version || version !== "13") {
|
||||
throw new Error("The handshake request must have Sec-WebSocket-Version: 13");
|
||||
throw new Error(
|
||||
"The handshake request must have Sec-WebSocket-Version: 13"
|
||||
);
|
||||
}
|
||||
|
||||
// Compute the accept key
|
||||
const key = headers.get("sec-websocket-key");
|
||||
if (!key) {
|
||||
throw new Error("The handshake request must have a Sec-WebSocket-Key header");
|
||||
throw new Error(
|
||||
"The handshake request must have a Sec-WebSocket-Key header"
|
||||
);
|
||||
}
|
||||
|
||||
return { acceptKey: computeKey(key) };
|
||||
|
|
@ -178,7 +207,7 @@ function computeKey(key) {
|
|||
async function serverHandshake(request, output) {
|
||||
try {
|
||||
// Check and extract info from the request
|
||||
const {acceptKey} = processRequest(request);
|
||||
const { acceptKey } = processRequest(request);
|
||||
|
||||
// Send response headers
|
||||
await writeHttpResponse(output, [
|
||||
|
|
@ -189,7 +218,7 @@ async function serverHandshake(request, output) {
|
|||
]);
|
||||
} catch (error) {
|
||||
// Send error response in case of error
|
||||
await writeHttpResponse(output, [ "HTTP/1.1 400 Bad Request" ]);
|
||||
await writeHttpResponse(output, ["HTTP/1.1 400 Bad Request"]);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -205,7 +234,12 @@ async function createWebSocket(transport, input, output) {
|
|||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const socket = WebSocket.createServerWebSocket(null, [], transportProvider, "");
|
||||
const socket = WebSocket.createServerWebSocket(
|
||||
null,
|
||||
[],
|
||||
transportProvider,
|
||||
""
|
||||
);
|
||||
socket.addEventListener("close", () => {
|
||||
input.close();
|
||||
output.close();
|
||||
|
|
@ -233,7 +267,7 @@ async function upgrade(request, response) {
|
|||
// handle response manually, allowing us to send arbitrary data
|
||||
response._powerSeized = true;
|
||||
|
||||
const {transport, input, output} = response._connection;
|
||||
const { transport, input, output } = response._connection;
|
||||
|
||||
const headers = new Map();
|
||||
for (let [key, values] of Object.entries(request._headers._headers)) {
|
||||
|
|
@ -248,4 +282,4 @@ async function upgrade(request, response) {
|
|||
return createWebSocket(transport, input, output);
|
||||
}
|
||||
|
||||
const WebSocketServer = {accept, upgrade};
|
||||
const WebSocketServer = { accept, upgrade };
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["WebSocketDebuggerTransport"];
|
||||
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
|
||||
function WebSocketDebuggerTransport(socket) {
|
||||
EventEmitter.decorate(this);
|
||||
|
|
@ -72,7 +74,9 @@ WebSocketDebuggerTransport.prototype = {
|
|||
|
||||
onMessage({ data }) {
|
||||
if (typeof data !== "string") {
|
||||
throw new Error("Binary messages are not supported by WebSocket transport");
|
||||
throw new Error(
|
||||
"Binary messages are not supported by WebSocket transport"
|
||||
);
|
||||
}
|
||||
|
||||
const object = JSON.parse(data);
|
||||
|
|
|
|||
|
|
@ -6,9 +6,15 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["ContentProcessSession"];
|
||||
|
||||
const {ContentProcessDomains} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomains.jsm");
|
||||
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
|
||||
const {UnknownMethodError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
|
||||
const { ContentProcessDomains } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomains.jsm"
|
||||
);
|
||||
const { Domains } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domains.jsm"
|
||||
);
|
||||
const { UnknownMethodError } = ChromeUtils.import(
|
||||
"chrome://remote/content/Error.jsm"
|
||||
);
|
||||
|
||||
class ContentProcessSession {
|
||||
constructor(messageManager, browsingContext, content, docShell) {
|
||||
|
|
@ -45,8 +51,8 @@ class ContentProcessSession {
|
|||
|
||||
// nsIMessageListener
|
||||
|
||||
async receiveMessage({name, data}) {
|
||||
const {browsingContextId} = data;
|
||||
async receiveMessage({ name, data }) {
|
||||
const { browsingContextId } = data;
|
||||
|
||||
// We may have more than one tab loaded in the same process,
|
||||
// and debug the two at the same time. We want to ensure not
|
||||
|
|
@ -61,7 +67,7 @@ class ContentProcessSession {
|
|||
switch (name) {
|
||||
case "remote:request":
|
||||
try {
|
||||
const {id, domain, command, params} = data.request;
|
||||
const { id, domain, command, params } = data.request;
|
||||
if (!this.domains.domainSupportsMethod(domain, command)) {
|
||||
throw new UnknownMethodError(domain, command);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Session"];
|
||||
|
||||
const {ParentProcessDomains} = ChromeUtils.import("chrome://remote/content/domains/ParentProcessDomains.jsm");
|
||||
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
|
||||
const {
|
||||
RemoteAgentError,
|
||||
UnknownMethodError,
|
||||
} = ChromeUtils.import("chrome://remote/content/Error.jsm");
|
||||
const { ParentProcessDomains } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ParentProcessDomains.jsm"
|
||||
);
|
||||
const { Domains } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domains.jsm"
|
||||
);
|
||||
const { RemoteAgentError, UnknownMethodError } = ChromeUtils.import(
|
||||
"chrome://remote/content/Error.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* A session represents exactly one client WebSocket connection.
|
||||
|
|
@ -55,7 +58,7 @@ class Session {
|
|||
this.domains.clear();
|
||||
}
|
||||
|
||||
async onMessage({id, method, params}) {
|
||||
async onMessage({ id, method, params }) {
|
||||
try {
|
||||
if (typeof id == "undefined") {
|
||||
throw new TypeError("Message missing 'id' field");
|
||||
|
|
@ -64,7 +67,7 @@ class Session {
|
|||
throw new TypeError("Message missing 'method' field");
|
||||
}
|
||||
|
||||
const {domain, command} = Domains.splitMethod(method);
|
||||
const { domain, command } = Domains.splitMethod(method);
|
||||
await this.execute(id, domain, command, params);
|
||||
} catch (e) {
|
||||
this.onError(id, e);
|
||||
|
|
@ -93,7 +96,7 @@ class Session {
|
|||
id,
|
||||
sessionId: this.id,
|
||||
error: {
|
||||
message: RemoteAgentError.format(error, {stack: true}),
|
||||
message: RemoteAgentError.format(error, { stack: true }),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["TabSession"];
|
||||
|
||||
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
|
||||
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
|
||||
const { Domains } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domains.jsm"
|
||||
);
|
||||
const { Session } = ChromeUtils.import(
|
||||
"chrome://remote/content/sessions/Session.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* A session to communicate with a given tab
|
||||
|
|
@ -36,7 +40,10 @@ class TabSession extends Session {
|
|||
this.mm.addMessageListener("remote:result", this);
|
||||
this.mm.addMessageListener("remote:error", this);
|
||||
|
||||
this.mm.loadFrameScript("chrome://remote/content/sessions/frame-script.js", false);
|
||||
this.mm.loadFrameScript(
|
||||
"chrome://remote/content/sessions/frame-script.js",
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
destructor() {
|
||||
|
|
@ -51,7 +58,7 @@ class TabSession extends Session {
|
|||
this.mm.removeMessageListener("remote:error", this);
|
||||
}
|
||||
|
||||
async onMessage({id, method, params}) {
|
||||
async onMessage({ id, method, params }) {
|
||||
try {
|
||||
if (typeof id == "undefined") {
|
||||
throw new TypeError("Message missing 'id' field");
|
||||
|
|
@ -60,7 +67,7 @@ class TabSession extends Session {
|
|||
throw new TypeError("Message missing 'method' field");
|
||||
}
|
||||
|
||||
const {domain, command} = Domains.splitMethod(method);
|
||||
const { domain, command } = Domains.splitMethod(method);
|
||||
if (this.domains.domainSupportsMethod(domain, command)) {
|
||||
await this.execute(id, domain, command, params);
|
||||
} else {
|
||||
|
|
@ -74,7 +81,7 @@ class TabSession extends Session {
|
|||
executeInChild(id, domain, command, params) {
|
||||
this.mm.sendAsyncMessage("remote:request", {
|
||||
browsingContextId: this.browsingContext.id,
|
||||
request: {id, domain, command, params},
|
||||
request: { id, domain, command, params },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -117,8 +124,8 @@ class TabSession extends Session {
|
|||
|
||||
// nsIMessageListener
|
||||
|
||||
receiveMessage({name, data}) {
|
||||
const {id, result, event, error} = data;
|
||||
receiveMessage({ name, data }) {
|
||||
const { id, result, event, error } = data;
|
||||
|
||||
switch (name) {
|
||||
case "remote:result":
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {ContentProcessSession} =
|
||||
ChromeUtils.import("chrome://remote/content/sessions/ContentProcessSession.jsm");
|
||||
const { ContentProcessSession } = ChromeUtils.import(
|
||||
"chrome://remote/content/sessions/ContentProcessSession.jsm"
|
||||
);
|
||||
|
||||
/* global content, docShell */
|
||||
new ContentProcessSession(this, docShell.browsingContext, content, docShell);
|
||||
|
|
|
|||
|
|
@ -6,11 +6,19 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["MainProcessTarget"];
|
||||
|
||||
const {Target} = ChromeUtils.import("chrome://remote/content/targets/Target.jsm");
|
||||
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
|
||||
const {RemoteAgent} = ChromeUtils.import("chrome://remote/content/RemoteAgent.jsm");
|
||||
const { Target } = ChromeUtils.import(
|
||||
"chrome://remote/content/targets/Target.jsm"
|
||||
);
|
||||
const { Session } = ChromeUtils.import(
|
||||
"chrome://remote/content/sessions/Session.jsm"
|
||||
);
|
||||
const { RemoteAgent } = ChromeUtils.import(
|
||||
"chrome://remote/content/RemoteAgent.jsm"
|
||||
);
|
||||
|
||||
const UUIDGen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
const UUIDGen = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
|
||||
/**
|
||||
* The main process Target.
|
||||
|
|
@ -26,14 +34,16 @@ class MainProcessTarget extends Target {
|
|||
super(targets, Session);
|
||||
|
||||
this.type = "browser";
|
||||
this.id = UUIDGen.generateUUID().toString().slice(1, -1);
|
||||
this.id = UUIDGen.generateUUID()
|
||||
.toString()
|
||||
.slice(1, -1);
|
||||
|
||||
// Define the HTTP path to query this target
|
||||
this.path = `/devtools/browser/${this.id}`;
|
||||
}
|
||||
|
||||
get wsDebuggerURL() {
|
||||
const {host, port} = RemoteAgent;
|
||||
const { host, port } = RemoteAgent;
|
||||
return `ws://${host}:${port}${this.path}`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["TabTarget"];
|
||||
|
||||
const {Target} = ChromeUtils.import("chrome://remote/content/targets/Target.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {TabSession} = ChromeUtils.import("chrome://remote/content/sessions/TabSession.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {RemoteAgent} = ChromeUtils.import("chrome://remote/content/RemoteAgent.jsm");
|
||||
const { Target } = ChromeUtils.import(
|
||||
"chrome://remote/content/targets/Target.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { TabSession } = ChromeUtils.import(
|
||||
"chrome://remote/content/sessions/TabSession.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { RemoteAgent } = ChromeUtils.import(
|
||||
"chrome://remote/content/RemoteAgent.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "Favicons",
|
||||
"@mozilla.org/browser/favicon-service;1", "nsIFaviconService");
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"Favicons",
|
||||
"@mozilla.org/browser/favicon-service;1",
|
||||
"nsIFaviconService"
|
||||
);
|
||||
|
||||
/**
|
||||
* Target for a local tab or a remoted frame.
|
||||
|
|
@ -110,7 +122,7 @@ class TabTarget extends Target {
|
|||
}
|
||||
|
||||
get wsDebuggerURL() {
|
||||
const {host, port} = RemoteAgent;
|
||||
const { host, port } = RemoteAgent;
|
||||
return `ws://${host}:${port}${this.path}`;
|
||||
}
|
||||
|
||||
|
|
@ -147,9 +159,6 @@ class TabTarget extends Target {
|
|||
// XPCOM
|
||||
|
||||
get QueryInterface() {
|
||||
return ChromeUtils.generateQI([
|
||||
Ci.nsIHttpRequestHandler,
|
||||
Ci.nsIObserver,
|
||||
]);
|
||||
return ChromeUtils.generateQI([Ci.nsIHttpRequestHandler, Ci.nsIObserver]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,15 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Target"];
|
||||
|
||||
const {Connection} = ChromeUtils.import("chrome://remote/content/Connection.jsm");
|
||||
const {WebSocketDebuggerTransport} = ChromeUtils.import("chrome://remote/content/server/WebSocketTransport.jsm");
|
||||
const {WebSocketServer} = ChromeUtils.import("chrome://remote/content/server/WebSocket.jsm");
|
||||
const { Connection } = ChromeUtils.import(
|
||||
"chrome://remote/content/Connection.jsm"
|
||||
);
|
||||
const { WebSocketDebuggerTransport } = ChromeUtils.import(
|
||||
"chrome://remote/content/server/WebSocketTransport.jsm"
|
||||
);
|
||||
const { WebSocketServer } = ChromeUtils.import(
|
||||
"chrome://remote/content/server/WebSocket.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Base class for all the Targets.
|
||||
|
|
@ -45,8 +51,6 @@ class Target {
|
|||
// XPCOM
|
||||
|
||||
get QueryInterface() {
|
||||
return ChromeUtils.generateQI([
|
||||
Ci.nsIHttpRequestHandler,
|
||||
]);
|
||||
return ChromeUtils.generateQI([Ci.nsIHttpRequestHandler]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,18 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Targets"];
|
||||
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const {MessagePromise} = ChromeUtils.import("chrome://remote/content/Sync.jsm");
|
||||
const {TabTarget} = ChromeUtils.import("chrome://remote/content/targets/TabTarget.jsm");
|
||||
const {MainProcessTarget} = ChromeUtils.import("chrome://remote/content/targets/MainProcessTarget.jsm");
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
const { MessagePromise } = ChromeUtils.import(
|
||||
"chrome://remote/content/Sync.jsm"
|
||||
);
|
||||
const { TabTarget } = ChromeUtils.import(
|
||||
"chrome://remote/content/targets/TabTarget.jsm"
|
||||
);
|
||||
const { MainProcessTarget } = ChromeUtils.import(
|
||||
"chrome://remote/content/targets/MainProcessTarget.jsm"
|
||||
);
|
||||
|
||||
class Targets {
|
||||
constructor() {
|
||||
|
|
@ -91,7 +99,7 @@ class Targets {
|
|||
return this.mainProcessTarget;
|
||||
}
|
||||
|
||||
* [Symbol.iterator]() {
|
||||
*[Symbol.iterator]() {
|
||||
for (const target of this._targets.values()) {
|
||||
yield target;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,22 +28,32 @@ add_task(async function testCDP() {
|
|||
});
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
const {Browser, Log, Page} = client;
|
||||
const { Browser, Log, Page } = client;
|
||||
ok("Browser" in client, "Browser domain is available");
|
||||
ok("Log" in client, "Log domain is available");
|
||||
ok("Page" in client, "Page domain is available");
|
||||
|
||||
const version = await Browser.getVersion();
|
||||
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
|
||||
is(version.product, isHeadless ? "Headless Firefox" : "Firefox", "Browser.getVersion works and depends on headless mode");
|
||||
is(version.userAgent, window.navigator.userAgent, "Browser.getVersion().userAgent is correct");
|
||||
const { isHeadless } = Cc["@mozilla.org/gfx/info;1"].getService(
|
||||
Ci.nsIGfxInfo
|
||||
);
|
||||
is(
|
||||
version.product,
|
||||
isHeadless ? "Headless Firefox" : "Firefox",
|
||||
"Browser.getVersion works and depends on headless mode"
|
||||
);
|
||||
is(
|
||||
version.userAgent,
|
||||
window.navigator.userAgent,
|
||||
"Browser.getVersion().userAgent is correct"
|
||||
);
|
||||
|
||||
// receive console.log messages and print them
|
||||
Log.enable();
|
||||
ok(true, "Log domain has been enabled");
|
||||
|
||||
Log.entryAdded(({entry}) => {
|
||||
const {timestamp, level, text, args} = entry;
|
||||
Log.entryAdded(({ entry }) => {
|
||||
const { timestamp, level, text, args } = entry;
|
||||
const msg = text || args.join(" ");
|
||||
console.log(`${new Date(timestamp)}\t${level.toUpperCase()}\t${msg}`);
|
||||
});
|
||||
|
|
@ -55,7 +65,10 @@ add_task(async function testCDP() {
|
|||
const frameStoppedLoading = Page.frameStoppedLoading();
|
||||
const navigatedWithinDocument = Page.navigatedWithinDocument();
|
||||
const loadEventFired = Page.loadEventFired();
|
||||
await Page.navigate({url: "data:text/html;charset=utf-8,test-page<script>console.log('foo');</script><script>'</script>"});
|
||||
await Page.navigate({
|
||||
url:
|
||||
"data:text/html;charset=utf-8,test-page<script>console.log('foo');</script><script>'</script>",
|
||||
});
|
||||
ok(true, "A new page has been loaded");
|
||||
|
||||
await loadEventFired;
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ const TEST_URI = "data:text/html;charset=utf-8,<input type=text>";
|
|||
|
||||
// Map of key codes used in this test.
|
||||
const KEYCODES = {
|
||||
"a": 65,
|
||||
"Backspace": 8,
|
||||
"h": 72,
|
||||
"H": 72,
|
||||
"AltLeft": 18,
|
||||
"ArrowLeft": 37,
|
||||
"ArrowRight": 39,
|
||||
a: 65,
|
||||
Backspace: 8,
|
||||
h: 72,
|
||||
H: 72,
|
||||
AltLeft: 18,
|
||||
ArrowLeft: 37,
|
||||
ArrowRight: 39,
|
||||
};
|
||||
|
||||
// Modifier for move forward shortcut is CTRL+RightArrow on Linux/Windows, ALT+RightArrow
|
||||
|
|
@ -72,7 +72,6 @@ add_task(async function() {
|
|||
await sendArrowKey(Input, "ArrowLeft");
|
||||
await checkInputContent("hH’", 2);
|
||||
|
||||
|
||||
info("Write 'a'");
|
||||
await sendTextKey(Input, "a");
|
||||
await checkInputContent("hHa’", 3);
|
||||
|
|
@ -144,15 +143,25 @@ function dispatchKeyEvent(Input, key, type, modifiers = 0) {
|
|||
}
|
||||
|
||||
async function checkInputContent(expectedValue, expectedCaret) {
|
||||
const { value, caret } =
|
||||
await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
const { value, caret } = await ContentTask.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
null,
|
||||
function() {
|
||||
const input = content.document.querySelector("input");
|
||||
return { value: input.value, caret: input.selectionStart };
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
is(value, expectedValue, `The input value is correct ("${value}"="${expectedValue}")`);
|
||||
is(caret, expectedCaret,
|
||||
`The input caret has the correct index ("${caret}"="${expectedCaret}")`);
|
||||
is(
|
||||
value,
|
||||
expectedValue,
|
||||
`The input value is correct ("${value}"="${expectedValue}")`
|
||||
);
|
||||
is(
|
||||
caret,
|
||||
expectedCaret,
|
||||
`The input caret has the correct index ("${caret}"="${expectedCaret}")`
|
||||
);
|
||||
}
|
||||
|
||||
async function sendBackspace(Input, expected) {
|
||||
|
|
@ -182,16 +191,25 @@ async function sendBackspace(Input, expected) {
|
|||
* await waitForInputEvent();
|
||||
*/
|
||||
function addInputEventListener(eventName) {
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, eventName, async (_eventName) => {
|
||||
return ContentTask.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
eventName,
|
||||
async _eventName => {
|
||||
const input = content.document.querySelector("input");
|
||||
this.__onInputEvent =
|
||||
new Promise(r => input.addEventListener(_eventName, r, { once: true }));
|
||||
});
|
||||
this.__onInputEvent = new Promise(r =>
|
||||
input.addEventListener(_eventName, r, { once: true })
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* See documentation for addInputEventListener.
|
||||
*/
|
||||
function waitForInputEvent() {
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, null, () => this.__onInputEvent);
|
||||
return ContentTask.spawn(
|
||||
gBrowser.selectedBrowser,
|
||||
null,
|
||||
() => this.__onInputEvent
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,26 +12,31 @@ add_task(async function() {
|
|||
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
|
||||
|
||||
const { mainProcessTarget } = RemoteAgent.targets;
|
||||
ok(mainProcessTarget,
|
||||
"The main process target is instantiated after the call to `listen`");
|
||||
ok(
|
||||
mainProcessTarget,
|
||||
"The main process target is instantiated after the call to `listen`"
|
||||
);
|
||||
|
||||
const targetURL = mainProcessTarget.wsDebuggerURL;
|
||||
|
||||
const CDP = await getCDP();
|
||||
|
||||
const client = await CDP({"target": targetURL});
|
||||
const client = await CDP({ target: targetURL });
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
const {Browser, Target} = client;
|
||||
const { Browser, Target } = client;
|
||||
ok(Browser, "The main process target exposes Browser domain");
|
||||
ok(Target, "The main process target exposes Target domain");
|
||||
|
||||
const version = await Browser.getVersion();
|
||||
is(version.product, "Firefox", "Browser.getVersion works");
|
||||
|
||||
const {webSocketDebuggerUrl} = await CDP.Version();
|
||||
is(webSocketDebuggerUrl, targetURL,
|
||||
"Version endpoint refers to the same Main process target");
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
is(
|
||||
webSocketDebuggerUrl,
|
||||
targetURL,
|
||||
"Version endpoint refers to the same Main process target"
|
||||
);
|
||||
|
||||
await RemoteAgent.close();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,13 +6,15 @@
|
|||
// Test the Network.requestWillBeSent event
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
const PAGE_URI = "http://example.com/browser/remote/test/browser/doc_network_requestWillBeSent.html";
|
||||
const JS_URI = "http://example.com/browser/remote/test/browser/file_network_requestWillBeSent.js";
|
||||
const PAGE_URI =
|
||||
"http://example.com/browser/remote/test/browser/doc_network_requestWillBeSent.html";
|
||||
const JS_URI =
|
||||
"http://example.com/browser/remote/test/browser/file_network_requestWillBeSent.js";
|
||||
|
||||
add_task(async function() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
|
||||
const {Page, Network} = client;
|
||||
const { Page, Network } = client;
|
||||
|
||||
await Network.enable();
|
||||
ok(true, "Network domain has been enabled");
|
||||
|
|
@ -25,7 +27,11 @@ add_task(async function() {
|
|||
case 1:
|
||||
is(event.request.url, PAGE_URI, "Got the page request");
|
||||
is(event.type, "Document", "The page request has 'Document' type");
|
||||
is(event.requestId, event.loaderId, "The page request has requestId = loaderId (puppeteer assumes that to detect the page start request)");
|
||||
is(
|
||||
event.requestId,
|
||||
event.loaderId,
|
||||
"The page request has requestId = loaderId (puppeteer assumes that to detect the page start request)"
|
||||
);
|
||||
break;
|
||||
case 2:
|
||||
is(event.request.url, JS_URI, "Got the JS request");
|
||||
|
|
|
|||
|
|
@ -11,11 +11,16 @@ add_task(async function testBringToFrontUpdatesSelectedTab() {
|
|||
is(gBrowser.selectedTab, tab, "Selected tab is the target tab");
|
||||
|
||||
info("Open another tab that should become the front tab");
|
||||
const otherTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, OTHER_URI);
|
||||
const otherTab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
OTHER_URI
|
||||
);
|
||||
is(gBrowser.selectedTab, otherTab, "Selected tab is now the new tab");
|
||||
|
||||
const { Page } = client;
|
||||
info("Call Page.bringToFront() and check that the test tab becomes the selected tab");
|
||||
info(
|
||||
"Call Page.bringToFront() and check that the test tab becomes the selected tab"
|
||||
);
|
||||
await Page.bringToFront();
|
||||
is(gBrowser.selectedTab, tab, "Selected tab is the target tab again");
|
||||
is(tab.ownerGlobal, getFocusedNavigator(), "The initial window is focused");
|
||||
|
|
@ -39,9 +44,15 @@ add_task(async function testBringToFrontUpdatesFocusedWindow() {
|
|||
is(otherWindow, getFocusedNavigator(), "The new window is focused");
|
||||
|
||||
const { Page } = client;
|
||||
info("Call Page.bringToFront() and check that the tab window is focused again");
|
||||
info(
|
||||
"Call Page.bringToFront() and check that the tab window is focused again"
|
||||
);
|
||||
await Page.bringToFront();
|
||||
is(tab.ownerGlobal, getFocusedNavigator(), "The initial window is focused again");
|
||||
is(
|
||||
tab.ownerGlobal,
|
||||
getFocusedNavigator(),
|
||||
"The initial window is focused again"
|
||||
);
|
||||
|
||||
await client.close();
|
||||
ok(true, "The client is closed");
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ const promises = new Set();
|
|||
const resolutions = new Map();
|
||||
|
||||
add_task(async function() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
|
||||
const {Page} = client;
|
||||
const { Page } = client;
|
||||
|
||||
// turn on navigation related events, such as DOMContentLoaded et al.
|
||||
await Page.enable();
|
||||
|
|
@ -45,13 +45,17 @@ add_task(async function() {
|
|||
info("Test Page.navigate");
|
||||
recordPromises();
|
||||
|
||||
const url = "http://example.com/browser/remote/test/browser/doc_page_frameNavigated.html";
|
||||
const url =
|
||||
"http://example.com/browser/remote/test/browser/doc_page_frameNavigated.html";
|
||||
const { frameId } = await Page.navigate({ url });
|
||||
ok(true, "A new page has been loaded");
|
||||
|
||||
ok(frameId, "Page.navigate returned a frameId");
|
||||
is(frameId, frameTree.frame.id, "The Page.navigate's frameId is the same than " +
|
||||
"getFrameTree's one");
|
||||
is(
|
||||
frameId,
|
||||
frameTree.frame.id,
|
||||
"The Page.navigate's frameId is the same than " + "getFrameTree's one"
|
||||
);
|
||||
|
||||
await assertNavigationEvents({ url, frameId });
|
||||
|
||||
|
|
@ -68,7 +72,11 @@ add_task(async function() {
|
|||
|
||||
const randomId2 = await getTestTabRandomId();
|
||||
ok(!!randomId2, "Test tab has a valid randomId");
|
||||
isnot(randomId2, randomId1, "Test tab randomId has been updated after reload");
|
||||
isnot(
|
||||
randomId2,
|
||||
randomId1,
|
||||
"Test tab randomId has been updated after reload"
|
||||
);
|
||||
|
||||
info("Test Page.navigate with the same URL still reloads the current page");
|
||||
recordPromises();
|
||||
|
|
@ -80,7 +88,11 @@ add_task(async function() {
|
|||
|
||||
const randomId3 = await getTestTabRandomId();
|
||||
ok(!!randomId3, "Test tab has a valid randomId");
|
||||
isnot(randomId3, randomId2, "Test tab randomId has been updated after reload");
|
||||
isnot(
|
||||
randomId3,
|
||||
randomId2,
|
||||
"Test tab randomId has been updated after reload"
|
||||
);
|
||||
|
||||
await client.close();
|
||||
ok(true, "The client is closed");
|
||||
|
|
@ -102,25 +114,44 @@ async function assertNavigationEvents({ url, frameId }) {
|
|||
"navigatedWithinDocument",
|
||||
"frameStoppedLoading",
|
||||
];
|
||||
Assert.deepEqual([...resolutions.keys()],
|
||||
Assert.deepEqual(
|
||||
[...resolutions.keys()],
|
||||
expectedResolutions,
|
||||
"Received various Page navigation events in the expected order");
|
||||
"Received various Page navigation events in the expected order"
|
||||
);
|
||||
|
||||
// Now assert the data exposed by each of these events
|
||||
const frameNavigated = resolutions.get("frameNavigated");
|
||||
ok(!frameNavigated.frame.parentId, "frameNavigated is for the top level document and" +
|
||||
" has a null parentId");
|
||||
ok(
|
||||
!frameNavigated.frame.parentId,
|
||||
"frameNavigated is for the top level document and" + " has a null parentId"
|
||||
);
|
||||
is(frameNavigated.frame.id, frameId, "frameNavigated id is the right one");
|
||||
is(frameNavigated.frame.name, undefined, "frameNavigated name isn't implemented yet");
|
||||
is(
|
||||
frameNavigated.frame.name,
|
||||
undefined,
|
||||
"frameNavigated name isn't implemented yet"
|
||||
);
|
||||
is(frameNavigated.frame.url, url, "frameNavigated url is the right one");
|
||||
|
||||
const navigatedWithinDocument = resolutions.get("navigatedWithinDocument");
|
||||
is(navigatedWithinDocument.frameId, frameId, "navigatedWithinDocument frameId is " +
|
||||
"the same one");
|
||||
is(navigatedWithinDocument.url, url, "navigatedWithinDocument url is the same one");
|
||||
is(
|
||||
navigatedWithinDocument.frameId,
|
||||
frameId,
|
||||
"navigatedWithinDocument frameId is " + "the same one"
|
||||
);
|
||||
is(
|
||||
navigatedWithinDocument.url,
|
||||
url,
|
||||
"navigatedWithinDocument url is the same one"
|
||||
);
|
||||
|
||||
const frameStoppedLoading = resolutions.get("frameStoppedLoading");
|
||||
is(frameStoppedLoading.frameId, frameId, "frameStoppedLoading frameId is the same one");
|
||||
is(
|
||||
frameStoppedLoading.frameId,
|
||||
frameId,
|
||||
"frameStoppedLoading frameId is the same one"
|
||||
);
|
||||
|
||||
promises.clear();
|
||||
resolutions.clear();
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
|
||||
add_task(async function testCDP() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const {Page, Runtime} = client;
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
const { Page, Runtime } = client;
|
||||
|
||||
const events = [];
|
||||
function assertReceivedEvents(expected, message) {
|
||||
|
|
@ -43,14 +43,21 @@ add_task(async function testCDP() {
|
|||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
ok(!!context.auxData.frameId, "The execution context has a frame id set");
|
||||
|
||||
assertReceivedEvents(["executionContextCreated"], "Received only executionContextCreated event after Runtime.enable call");
|
||||
assertReceivedEvents(
|
||||
["executionContextCreated"],
|
||||
"Received only executionContextCreated event after Runtime.enable call"
|
||||
);
|
||||
|
||||
const { frameTree } = await Page.getFrameTree();
|
||||
ok(!!frameTree.frame, "getFrameTree exposes one frame");
|
||||
is(frameTree.childFrames.length, 0, "getFrameTree reports no child frame");
|
||||
ok(!!frameTree.frame.id, "getFrameTree's frame has an id");
|
||||
is(frameTree.frame.url, TEST_URI, "getFrameTree's frame has the right url");
|
||||
is(frameTree.frame.id, context.auxData.frameId, "getFrameTree and executionContextCreated refers about the same frame Id");
|
||||
is(
|
||||
frameTree.frame.id,
|
||||
context.auxData.frameId,
|
||||
"getFrameTree and executionContextCreated refers about the same frame Id"
|
||||
);
|
||||
|
||||
const onFrameNavigated = Page.frameNavigated();
|
||||
const onExecutionContextDestroyed = Runtime.executionContextDestroyed();
|
||||
|
|
@ -59,33 +66,61 @@ add_task(async function testCDP() {
|
|||
const { frameId } = await Page.navigate({ url });
|
||||
ok(true, "A new page has been loaded");
|
||||
ok(frameId, "Page.navigate returned a frameId");
|
||||
is(frameId, frameTree.frame.id, "The Page.navigate's frameId is the same than " +
|
||||
"getFrameTree's one");
|
||||
is(
|
||||
frameId,
|
||||
frameTree.frame.id,
|
||||
"The Page.navigate's frameId is the same than " + "getFrameTree's one"
|
||||
);
|
||||
|
||||
const frameNavigated = await onFrameNavigated;
|
||||
ok(!frameNavigated.frame.parentId, "frameNavigated is for the top level document and" +
|
||||
" has a null parentId");
|
||||
is(frameNavigated.frame.id, frameId, "frameNavigated id is the same than the one " +
|
||||
"returned by Page.navigate");
|
||||
is(frameNavigated.frame.name, undefined, "frameNavigated name isn't implemented yet");
|
||||
is(frameNavigated.frame.url, url, "frameNavigated url is the same being given to " +
|
||||
"Page.navigate");
|
||||
ok(
|
||||
!frameNavigated.frame.parentId,
|
||||
"frameNavigated is for the top level document and" + " has a null parentId"
|
||||
);
|
||||
is(
|
||||
frameNavigated.frame.id,
|
||||
frameId,
|
||||
"frameNavigated id is the same than the one " + "returned by Page.navigate"
|
||||
);
|
||||
is(
|
||||
frameNavigated.frame.name,
|
||||
undefined,
|
||||
"frameNavigated name isn't implemented yet"
|
||||
);
|
||||
is(
|
||||
frameNavigated.frame.url,
|
||||
url,
|
||||
"frameNavigated url is the same being given to " + "Page.navigate"
|
||||
);
|
||||
|
||||
const { executionContextId } = await onExecutionContextDestroyed;
|
||||
ok(executionContextId, "The destroyed event reports an id");
|
||||
is(executionContextId, context.id, "The destroyed event is for the first reported execution context");
|
||||
is(
|
||||
executionContextId,
|
||||
context.id,
|
||||
"The destroyed event is for the first reported execution context"
|
||||
);
|
||||
|
||||
({ context } = await onExecutionContextCreated2);
|
||||
ok(!!context.id, "The execution context has an id");
|
||||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
is(context.auxData.frameId, frameId, "The execution context frame id is the same " +
|
||||
"the one returned by Page.navigate");
|
||||
is(
|
||||
context.auxData.frameId,
|
||||
frameId,
|
||||
"The execution context frame id is the same " +
|
||||
"the one returned by Page.navigate"
|
||||
);
|
||||
|
||||
isnot(executionContextId, context.id, "The destroyed id is different from the " +
|
||||
"created one");
|
||||
isnot(
|
||||
executionContextId,
|
||||
context.id,
|
||||
"The destroyed id is different from the " + "created one"
|
||||
);
|
||||
|
||||
assertReceivedEvents(["executionContextDestroyed", "frameNavigated", "executionContextCreated"],
|
||||
"Received frameNavigated between the two execution context events during navigation to another URL");
|
||||
assertReceivedEvents(
|
||||
["executionContextDestroyed", "frameNavigated", "executionContextCreated"],
|
||||
"Received frameNavigated between the two execution context events during navigation to another URL"
|
||||
);
|
||||
|
||||
await client.close();
|
||||
ok(true, "The client is closed");
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
|
||||
add_task(async function() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
|
||||
const firstContext = await testRuntimeEnable(client);
|
||||
const contextId = firstContext.id;
|
||||
|
|
@ -43,7 +43,10 @@ async function testRuntimeEnable({ Runtime }) {
|
|||
|
||||
async function testObjectReferences({ Runtime }, contextId) {
|
||||
// First create a JS object remotely via Runtime.evaluate
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 1 })" });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "({ foo: 1 })",
|
||||
});
|
||||
is(result.type, "object", "The type is correct");
|
||||
is(result.subtype, null, "The subtype is null for objects");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
|
@ -57,7 +60,11 @@ async function testObjectReferences({ Runtime }, contextId) {
|
|||
});
|
||||
is(result2.type, "number", "The type is correct");
|
||||
is(result2.subtype, null, "The subtype is null for numbers");
|
||||
is(result2.value, 2, "Updated the existing object and returned the incremented value");
|
||||
is(
|
||||
result2.value,
|
||||
2,
|
||||
"Updated the existing object and returned the incremented value"
|
||||
);
|
||||
|
||||
// Finally, try to pass this JS object and get it back. Ensure that it returns
|
||||
// the same object id. Also increment the attribute again.
|
||||
|
|
@ -83,7 +90,11 @@ async function testObjectReferences({ Runtime }, contextId) {
|
|||
});
|
||||
is(result4.type, "number", "The type is correct");
|
||||
is(result4.subtype, null, "The subtype is null for numbers");
|
||||
is(result4.value, 3, "Updated the existing object and returned the incremented value");
|
||||
is(
|
||||
result4.value,
|
||||
3,
|
||||
"Updated the existing object and returned the incremented value"
|
||||
);
|
||||
}
|
||||
|
||||
async function testExceptions({ Runtime }, executionContextId) {
|
||||
|
|
@ -92,28 +103,36 @@ async function testExceptions({ Runtime }, executionContextId) {
|
|||
executionContextId,
|
||||
functionDeclaration: "doesNotExists()",
|
||||
});
|
||||
is(exceptionDetails.text, "doesNotExists is not defined", "Exception message is passed to the client");
|
||||
is(
|
||||
exceptionDetails.text,
|
||||
"doesNotExists is not defined",
|
||||
"Exception message is passed to the client"
|
||||
);
|
||||
|
||||
// Test error when calling the function
|
||||
({ exceptionDetails } = await Runtime.callFunctionOn({
|
||||
executionContextId,
|
||||
functionDeclaration: "() => doesNotExists()",
|
||||
}));
|
||||
is(exceptionDetails.text, "doesNotExists is not defined", "Exception message is passed to the client");
|
||||
is(
|
||||
exceptionDetails.text,
|
||||
"doesNotExists is not defined",
|
||||
"Exception message is passed to the client"
|
||||
);
|
||||
}
|
||||
|
||||
async function testReturnByValue({ Runtime }, executionContextId) {
|
||||
const values = [
|
||||
42,
|
||||
"42",
|
||||
42.00,
|
||||
42.0,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{ foo: true },
|
||||
{ foo: { bar: 42, str: "str", array: [1, 2, 3] } },
|
||||
[ 42, "42", true ],
|
||||
[ { foo: true } ],
|
||||
[42, "42", true],
|
||||
[{ foo: true }],
|
||||
];
|
||||
for (const value of values) {
|
||||
const { result } = await Runtime.callFunctionOn({
|
||||
|
|
@ -121,7 +140,11 @@ async function testReturnByValue({ Runtime }, executionContextId) {
|
|||
functionDeclaration: "() => (" + JSON.stringify(value) + ")",
|
||||
returnByValue: true,
|
||||
});
|
||||
Assert.deepEqual(result.value, value, "The returned value is the same than the input value");
|
||||
Assert.deepEqual(
|
||||
result.value,
|
||||
value,
|
||||
"The returned value is the same than the input value"
|
||||
);
|
||||
}
|
||||
|
||||
// Test undefined individually as JSON.stringify doesn't return a string
|
||||
|
|
@ -150,7 +173,11 @@ async function testAwaitPromise({ Runtime }, executionContextId) {
|
|||
functionDeclaration: "() => Promise.reject(42)",
|
||||
awaitPromise: true,
|
||||
});
|
||||
is(exceptionDetails.exception.value, 42, "The result is the promise's rejection");
|
||||
is(
|
||||
exceptionDetails.exception.value,
|
||||
42,
|
||||
"The result is the promise's rejection"
|
||||
);
|
||||
|
||||
// Then check delayed promise resolution
|
||||
({ result } = await Runtime.callFunctionOn({
|
||||
|
|
@ -165,10 +192,15 @@ async function testAwaitPromise({ Runtime }, executionContextId) {
|
|||
// And delayed promise rejection
|
||||
({ exceptionDetails } = await Runtime.callFunctionOn({
|
||||
executionContextId,
|
||||
functionDeclaration: "() => new Promise((_,r) => setTimeout(() => r(42), 0))",
|
||||
functionDeclaration:
|
||||
"() => new Promise((_,r) => setTimeout(() => r(42), 0))",
|
||||
awaitPromise: true,
|
||||
}));
|
||||
is(exceptionDetails.exception.value, 42, "The result is the promise's rejection");
|
||||
is(
|
||||
exceptionDetails.exception.value,
|
||||
42,
|
||||
"The result is the promise's rejection"
|
||||
);
|
||||
|
||||
// Finally assert promise resolution without awaitPromise
|
||||
({ result } = await Runtime.callFunctionOn({
|
||||
|
|
@ -195,7 +227,10 @@ async function testAwaitPromise({ Runtime }, executionContextId) {
|
|||
|
||||
async function testObjectId({ Runtime }, contextId) {
|
||||
// First create an object via Runtime.evaluate
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "({ foo: 42 })",
|
||||
});
|
||||
is(result.type, "object", "The type is correct");
|
||||
is(result.subtype, null, "The subtype is null for objects");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
|
@ -208,5 +243,9 @@ async function testObjectId({ Runtime }, contextId) {
|
|||
});
|
||||
is(result2.type, "number", "The type is correct");
|
||||
is(result2.subtype, null, "The subtype is null for numbers");
|
||||
is(result2.value, 42, "We have a good proof that the function was ran against the target object");
|
||||
is(
|
||||
result2.value,
|
||||
42,
|
||||
"We have a good proof that the function was ran against the target object"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,11 @@ add_task(async function() {
|
|||
});
|
||||
}
|
||||
|
||||
for (const fun of [runtimeEvaluate, callFunctionOn, callFunctionOnArguments]) {
|
||||
for (const fun of [
|
||||
runtimeEvaluate,
|
||||
callFunctionOn,
|
||||
callFunctionOnArguments,
|
||||
]) {
|
||||
info("Test " + fun.name);
|
||||
await testPrimitiveTypes(fun);
|
||||
await testUnserializable(fun);
|
||||
|
|
@ -114,8 +118,15 @@ async function testRuntimeEnable({ Runtime }) {
|
|||
}
|
||||
|
||||
async function testEvaluate({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "location.href" });
|
||||
is(result.value, TEST_URI, "Runtime.evaluate works and is against the test page");
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "location.href",
|
||||
});
|
||||
is(
|
||||
result.value,
|
||||
TEST_URI,
|
||||
"Runtime.evaluate works and is against the test page"
|
||||
);
|
||||
}
|
||||
|
||||
async function testEvaluateInvalidContextId({ Runtime }, contextId) {
|
||||
|
|
@ -123,23 +134,40 @@ async function testEvaluateInvalidContextId({ Runtime }, contextId) {
|
|||
await Runtime.evaluate({ contextId: -1, expression: "" });
|
||||
ok(false, "Evaluate shouldn't pass");
|
||||
} catch (e) {
|
||||
ok(e.message.includes("Unable to find execution context with id: -1"),
|
||||
"Throws with the expected error message");
|
||||
ok(
|
||||
e.message.includes("Unable to find execution context with id: -1"),
|
||||
"Throws with the expected error message"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function testCallFunctionOn({ Runtime }, executionContextId) {
|
||||
const { result } = await Runtime.callFunctionOn({ executionContextId, functionDeclaration: "() => location.href" });
|
||||
is(result.value, TEST_URI, "Runtime.callFunctionOn works and is against the test page");
|
||||
const { result } = await Runtime.callFunctionOn({
|
||||
executionContextId,
|
||||
functionDeclaration: "() => location.href",
|
||||
});
|
||||
is(
|
||||
result.value,
|
||||
TEST_URI,
|
||||
"Runtime.callFunctionOn works and is against the test page"
|
||||
);
|
||||
}
|
||||
|
||||
async function testCallFunctionOnInvalidContextId({ Runtime }, executionContextId) {
|
||||
async function testCallFunctionOnInvalidContextId(
|
||||
{ Runtime },
|
||||
executionContextId
|
||||
) {
|
||||
try {
|
||||
await Runtime.callFunctionOn({ executionContextId: -1, functionDeclaration: "" });
|
||||
await Runtime.callFunctionOn({
|
||||
executionContextId: -1,
|
||||
functionDeclaration: "",
|
||||
});
|
||||
ok(false, "callFunctionOn shouldn't pass");
|
||||
} catch (e) {
|
||||
ok(e.message.includes("Unable to find execution context with id: -1"),
|
||||
"Throws with the expected error message");
|
||||
ok(
|
||||
e.message.includes("Unable to find execution context with id: -1"),
|
||||
"Throws with the expected error message"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +176,7 @@ async function testPrimitiveTypes(testFunction) {
|
|||
for (const expression of expressions) {
|
||||
const { result } = await testFunction(JSON.stringify(expression));
|
||||
is(result.value, expression, `Evaluating primitive '${expression}' works`);
|
||||
is(result.type, typeof(expression), `${expression} type is correct`);
|
||||
is(result.type, typeof expression, `${expression} type is correct`);
|
||||
}
|
||||
|
||||
// undefined doesn't work with JSON.stringify, so test it independently
|
||||
|
|
@ -169,7 +197,11 @@ async function testUnserializable(testFunction) {
|
|||
const expressions = ["NaN", "-0", "Infinity", "-Infinity"];
|
||||
for (const expression of expressions) {
|
||||
const { result } = await testFunction(expression);
|
||||
is(result.unserializableValue, expression, `Evaluating unserializable '${expression}' works`);
|
||||
is(
|
||||
result.unserializableValue,
|
||||
expression,
|
||||
`Evaluating unserializable '${expression}' works`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -190,29 +222,48 @@ async function testObjectTypes(testFunction) {
|
|||
{ expression: "new Date()", type: "object", subtype: "date" },
|
||||
{ expression: "document", type: "object", subtype: "node" },
|
||||
{ expression: "document.documentElement", type: "object", subtype: "node" },
|
||||
{ expression: "document.createElement('div')", type: "object", subtype: "node" },
|
||||
{
|
||||
expression: "document.createElement('div')",
|
||||
type: "object",
|
||||
subtype: "node",
|
||||
},
|
||||
];
|
||||
|
||||
for (const { expression, type, subtype } of expressions) {
|
||||
const { result } = await testFunction(expression);
|
||||
is(result.subtype, subtype, `Evaluating '${expression}' has the expected subtype`);
|
||||
is(
|
||||
result.subtype,
|
||||
subtype,
|
||||
`Evaluating '${expression}' has the expected subtype`
|
||||
);
|
||||
is(result.type, type, "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
}
|
||||
}
|
||||
|
||||
async function testThrowError(testFunction) {
|
||||
const { exceptionDetails } = await testFunction("throw new Error('foo')", true);
|
||||
const { exceptionDetails } = await testFunction(
|
||||
"throw new Error('foo')",
|
||||
true
|
||||
);
|
||||
is(exceptionDetails.text, "foo", "Exception message is passed to the client");
|
||||
}
|
||||
|
||||
async function testThrowValue(testFunction) {
|
||||
const { exceptionDetails } = await testFunction("throw 'foo'", true);
|
||||
is(exceptionDetails.exception.type, "string", "Exception type is correct");
|
||||
is(exceptionDetails.exception.value, "foo", "Exception value is passed as a RemoteObject");
|
||||
is(
|
||||
exceptionDetails.exception.value,
|
||||
"foo",
|
||||
"Exception value is passed as a RemoteObject"
|
||||
);
|
||||
}
|
||||
|
||||
async function testJSError(testFunction) {
|
||||
const { exceptionDetails } = await testFunction("doesNotExists()", true);
|
||||
is(exceptionDetails.text, "doesNotExists is not defined", "Exception message is passed to the client");
|
||||
is(
|
||||
exceptionDetails.text,
|
||||
"doesNotExists is not defined",
|
||||
"Exception message is passed to the client"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
|
||||
add_task(async function() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
|
||||
const firstContext = await testRuntimeEnable(client);
|
||||
await testEvaluate(client, firstContext);
|
||||
|
|
@ -42,8 +42,15 @@ async function testRuntimeEnable({ Runtime }) {
|
|||
async function testEvaluate({ Runtime }, previousContext) {
|
||||
const contextId = previousContext.id;
|
||||
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "location.href" });
|
||||
is(result.value, TEST_URI, "Runtime.evaluate works and is against the test page");
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "location.href",
|
||||
});
|
||||
is(
|
||||
result.value,
|
||||
TEST_URI,
|
||||
"Runtime.evaluate works and is against the test page"
|
||||
);
|
||||
}
|
||||
|
||||
async function testNavigate({ Runtime, Page }, previousContext) {
|
||||
|
|
@ -55,20 +62,39 @@ async function testNavigate({ Runtime, Page }, previousContext) {
|
|||
const url = "data:text/html;charset=utf-8,test-page";
|
||||
const { frameId } = await Page.navigate({ url });
|
||||
ok(true, "A new page has been loaded");
|
||||
is(frameId, previousContext.auxData.frameId, "Page.navigate returns the same frameId than executionContextCreated");
|
||||
is(
|
||||
frameId,
|
||||
previousContext.auxData.frameId,
|
||||
"Page.navigate returns the same frameId than executionContextCreated"
|
||||
);
|
||||
|
||||
const { executionContextId } = await executionContextDestroyed;
|
||||
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
|
||||
is(
|
||||
executionContextId,
|
||||
previousContext.id,
|
||||
"The destroyed event reports the previous context id"
|
||||
);
|
||||
|
||||
const { context } = await executionContextCreated;
|
||||
ok(!!context.id, "The execution context has an id");
|
||||
isnot(previousContext.id, context.id, "The new execution context has a different id");
|
||||
isnot(
|
||||
previousContext.id,
|
||||
context.id,
|
||||
"The new execution context has a different id"
|
||||
);
|
||||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
is(context.auxData.frameId, frameId, "The execution context frame id is the same " +
|
||||
"than the one returned by Page.navigate");
|
||||
is(
|
||||
context.auxData.frameId,
|
||||
frameId,
|
||||
"The execution context frame id is the same " +
|
||||
"than the one returned by Page.navigate"
|
||||
);
|
||||
|
||||
isnot(executionContextId, context.id, "The destroyed id is different from the " +
|
||||
"created one");
|
||||
isnot(
|
||||
executionContextId,
|
||||
context.id,
|
||||
"The destroyed id is different from the " + "created one"
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
@ -85,15 +111,34 @@ async function testNavigateBack({ Runtime }, firstContext, previousContext) {
|
|||
gBrowser.selectedBrowser.goBack();
|
||||
|
||||
const { context } = await executionContextCreated;
|
||||
is(context.id, firstContext.id, "The new execution context should be the same than the first one");
|
||||
is(
|
||||
context.id,
|
||||
firstContext.id,
|
||||
"The new execution context should be the same than the first one"
|
||||
);
|
||||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
is(context.auxData.frameId, firstContext.auxData.frameId, "The execution context frame id is always the same");
|
||||
is(
|
||||
context.auxData.frameId,
|
||||
firstContext.auxData.frameId,
|
||||
"The execution context frame id is always the same"
|
||||
);
|
||||
|
||||
const { executionContextId } = await executionContextDestroyed;
|
||||
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
|
||||
is(
|
||||
executionContextId,
|
||||
previousContext.id,
|
||||
"The destroyed event reports the previous context id"
|
||||
);
|
||||
|
||||
const { result } = await Runtime.evaluate({ contextId: context.id, expression: "location.href" });
|
||||
is(result.value, TEST_URI, "Runtime.evaluate works and is against the page we just navigated to");
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId: context.id,
|
||||
expression: "location.href",
|
||||
});
|
||||
is(
|
||||
result.value,
|
||||
TEST_URI,
|
||||
"Runtime.evaluate works and is against the page we just navigated to"
|
||||
);
|
||||
}
|
||||
|
||||
async function testNavigateViaLocation({ Runtime }, previousContext) {
|
||||
|
|
@ -103,19 +148,33 @@ async function testNavigateViaLocation({ Runtime }, previousContext) {
|
|||
const executionContextCreated = Runtime.executionContextCreated();
|
||||
|
||||
const url2 = "data:text/html;charset=utf-8,test-page-2";
|
||||
await Runtime.evaluate({ contextId: previousContext.id, expression: `window.location = '${url2}';` });
|
||||
await Runtime.evaluate({
|
||||
contextId: previousContext.id,
|
||||
expression: `window.location = '${url2}';`,
|
||||
});
|
||||
|
||||
const { executionContextId } = await executionContextDestroyed;
|
||||
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
|
||||
is(
|
||||
executionContextId,
|
||||
previousContext.id,
|
||||
"The destroyed event reports the previous context id"
|
||||
);
|
||||
|
||||
const { context } = await executionContextCreated;
|
||||
ok(!!context.id, "The execution context has an id");
|
||||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
is(context.auxData.frameId, previousContext.auxData.frameId, "The execution context frame id is the same " +
|
||||
"the one returned by Page.navigate");
|
||||
is(
|
||||
context.auxData.frameId,
|
||||
previousContext.auxData.frameId,
|
||||
"The execution context frame id is the same " +
|
||||
"the one returned by Page.navigate"
|
||||
);
|
||||
|
||||
isnot(executionContextId, context.id, "The destroyed id is different from the " +
|
||||
"created one");
|
||||
isnot(
|
||||
executionContextId,
|
||||
context.id,
|
||||
"The destroyed id is different from the " + "created one"
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
@ -129,14 +188,24 @@ async function testReload({ Runtime, Page }, previousContext) {
|
|||
await Page.reload();
|
||||
|
||||
const { executionContextId } = await executionContextDestroyed;
|
||||
is(executionContextId, previousContext.id, "The destroyed event reports the previous context id");
|
||||
is(
|
||||
executionContextId,
|
||||
previousContext.id,
|
||||
"The destroyed event reports the previous context id"
|
||||
);
|
||||
|
||||
const { context } = await executionContextCreated;
|
||||
ok(!!context.id, "The execution context has an id");
|
||||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
is(context.auxData.frameId, previousContext.auxData.frameId, "The execution context " +
|
||||
"frame id is the same one");
|
||||
is(
|
||||
context.auxData.frameId,
|
||||
previousContext.auxData.frameId,
|
||||
"The execution context " + "frame id is the same one"
|
||||
);
|
||||
|
||||
isnot(executionContextId, context.id, "The destroyed id is different from the " +
|
||||
"created one");
|
||||
isnot(
|
||||
executionContextId,
|
||||
context.id,
|
||||
"The destroyed id is different from the " + "created one"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
|
||||
add_task(async function() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
|
||||
const firstContext = await testRuntimeEnable(client);
|
||||
const contextId = firstContext.id;
|
||||
|
|
@ -41,13 +41,23 @@ async function testRuntimeEnable({ Runtime }) {
|
|||
}
|
||||
|
||||
async function testGetOwnSimpleProperties({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ bool: true, fun() {}, int: 1, object: {}, string: 'foo' })" });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "({ bool: true, fun() {}, int: 1, object: {}, string: 'foo' })",
|
||||
});
|
||||
is(result.subtype, null, "JS Object have no subtype");
|
||||
is(result.type, "object", "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
||||
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true });
|
||||
is(result2.length, 5, "ownProperties=true allows to iterate only over direct object properties (i.e. ignore prototype)");
|
||||
const { result: result2 } = await Runtime.getProperties({
|
||||
objectId: result.objectId,
|
||||
ownProperties: true,
|
||||
});
|
||||
is(
|
||||
result2.length,
|
||||
5,
|
||||
"ownProperties=true allows to iterate only over direct object properties (i.e. ignore prototype)"
|
||||
);
|
||||
result2.sort((a, b) => a.name > b.name);
|
||||
is(result2[0].name, "bool");
|
||||
is(result2[0].configurable, true);
|
||||
|
|
@ -91,35 +101,55 @@ async function testGetOwnSimpleProperties({ Runtime }, contextId) {
|
|||
}
|
||||
|
||||
async function testGetPrototypeProperties({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "({ foo: 42 })",
|
||||
});
|
||||
is(result.subtype, null, "JS Object have no subtype");
|
||||
is(result.type, "object", "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
||||
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: false });
|
||||
const { result: result2 } = await Runtime.getProperties({
|
||||
objectId: result.objectId,
|
||||
ownProperties: false,
|
||||
});
|
||||
ok(result2.length > 1, "We have more properties than just the object one");
|
||||
const foo = result2.find(p => p.name == "foo");
|
||||
ok(foo, "The object property is described");
|
||||
ok(foo.isOwn, "and is reported as 'own' property");
|
||||
|
||||
const toString = result2.find(p => p.name == "toString");
|
||||
ok(toString, "Function from Object's prototype are also described like toString");
|
||||
ok(
|
||||
toString,
|
||||
"Function from Object's prototype are also described like toString"
|
||||
);
|
||||
ok(!toString.isOwn, "but are reported as not being an 'own' property");
|
||||
}
|
||||
|
||||
async function testGetGetterSetterProperties({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ get prop() { return this.x; }, set prop(v) { this.x = v; } })" });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression:
|
||||
"({ get prop() { return this.x; }, set prop(v) { this.x = v; } })",
|
||||
});
|
||||
is(result.subtype, null, "JS Object have no subtype");
|
||||
is(result.type, "object", "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
||||
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true });
|
||||
const { result: result2 } = await Runtime.getProperties({
|
||||
objectId: result.objectId,
|
||||
ownProperties: true,
|
||||
});
|
||||
is(result2.length, 1);
|
||||
|
||||
is(result2[0].name, "prop");
|
||||
is(result2[0].configurable, true);
|
||||
is(result2[0].enumerable, true);
|
||||
is(result2[0].writable, undefined, "writable is only set for data properties");
|
||||
is(
|
||||
result2[0].writable,
|
||||
undefined,
|
||||
"writable is only set for data properties"
|
||||
);
|
||||
|
||||
is(result2[0].get.type, "function");
|
||||
ok(!!result2[0].get.objectId);
|
||||
|
|
@ -131,7 +161,10 @@ async function testGetGetterSetterProperties({ Runtime }, contextId) {
|
|||
const { result: result3 } = await Runtime.callFunctionOn({
|
||||
executionContextId: contextId,
|
||||
functionDeclaration: "(set, get) => { set(42); return get(); }",
|
||||
arguments: [{ objectId: result2[0].set.objectId }, { objectId: result2[0].get.objectId }],
|
||||
arguments: [
|
||||
{ objectId: result2[0].set.objectId },
|
||||
{ objectId: result2[0].get.objectId },
|
||||
],
|
||||
});
|
||||
is(result3.type, "number", "The type is correct");
|
||||
is(result3.subtype, null, "The subtype is null for numbers");
|
||||
|
|
@ -139,12 +172,18 @@ async function testGetGetterSetterProperties({ Runtime }, contextId) {
|
|||
}
|
||||
|
||||
async function testGetCustomProperty({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: `const obj = {}; Object.defineProperty(obj, "prop", { value: 42 }); obj` });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: `const obj = {}; Object.defineProperty(obj, "prop", { value: 42 }); obj`,
|
||||
});
|
||||
is(result.subtype, null, "JS Object have no subtype");
|
||||
is(result.type, "object", "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
||||
const { result: result2 } = await Runtime.getProperties({ objectId: result.objectId, ownProperties: true });
|
||||
const { result: result2 } = await Runtime.getProperties({
|
||||
objectId: result.objectId,
|
||||
ownProperties: true,
|
||||
});
|
||||
is(result2.length, 1, "We only get the one object's property");
|
||||
is(result2[0].name, "prop");
|
||||
is(result2[0].configurable, false);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
|
||||
add_task(async function() {
|
||||
const {client} = await setupTestForUri(TEST_URI);
|
||||
const { client } = await setupTestForUri(TEST_URI);
|
||||
|
||||
const firstContext = await testRuntimeEnable(client);
|
||||
const contextId = firstContext.id;
|
||||
|
|
@ -38,7 +38,10 @@ async function testRuntimeEnable({ Runtime }) {
|
|||
}
|
||||
|
||||
async function testObjectRelease({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
|
||||
const { result } = await Runtime.evaluate({
|
||||
contextId,
|
||||
expression: "({ foo: 42 })",
|
||||
});
|
||||
is(result.subtype, null, "JS Object have no subtype");
|
||||
is(result.type, "object", "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
|
@ -71,7 +74,10 @@ async function testObjectRelease({ Runtime }, contextId) {
|
|||
});
|
||||
ok(false, "callFunctionOn with a released object as argument should throw");
|
||||
} catch (e) {
|
||||
ok(e.message.includes("Cannot find object with ID:"), "callFunctionOn throws on released argument");
|
||||
ok(
|
||||
e.message.includes("Cannot find object with ID:"),
|
||||
"callFunctionOn throws on released argument"
|
||||
);
|
||||
}
|
||||
try {
|
||||
await Runtime.callFunctionOn({
|
||||
|
|
@ -80,6 +86,9 @@ async function testObjectRelease({ Runtime }, contextId) {
|
|||
});
|
||||
ok(false, "callFunctionOn with a released object as target should throw");
|
||||
} catch (e) {
|
||||
ok(e.message.includes("Unable to get the context for object with id"), "callFunctionOn throws on released target");
|
||||
ok(
|
||||
e.message.includes("Unable to get the context for object with id"),
|
||||
"callFunctionOn throws on released target"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
add_task(async function() {
|
||||
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
|
||||
const CDP = await getCDP();
|
||||
const {webSocketDebuggerUrl} = await CDP.Version();
|
||||
const client = await CDP({"target": webSocketDebuggerUrl});
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
const client = await CDP({ target: webSocketDebuggerUrl });
|
||||
|
||||
try {
|
||||
await client.send("Hoobaflooba");
|
||||
|
|
|
|||
|
|
@ -24,12 +24,18 @@ add_task(async function() {
|
|||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
|
||||
let targets = await getTargets(CDP);
|
||||
ok(targets.some(target => target.url == TEST_URI), "Found the tab in target list");
|
||||
ok(
|
||||
targets.some(target => target.url == TEST_URI),
|
||||
"Found the tab in target list"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
targets = await getTargets(CDP);
|
||||
ok(!targets.some(target => target.url == TEST_URI), "Tab has been removed from the target list");
|
||||
ok(
|
||||
!targets.some(target => target.url == TEST_URI),
|
||||
"Tab has been removed from the target list"
|
||||
);
|
||||
|
||||
await RemoteAgent.close();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,18 +13,21 @@ add_task(async function() {
|
|||
const CDP = await getCDP();
|
||||
|
||||
// Connect to the server
|
||||
const {webSocketDebuggerUrl} = await CDP.Version();
|
||||
const client = await CDP({"target": webSocketDebuggerUrl});
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
const client = await CDP({ target: webSocketDebuggerUrl });
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
const {Target} = client;
|
||||
const { Target } = client;
|
||||
ok("Target" in client, "Target domain is available");
|
||||
|
||||
const onTargetsCreated = new Promise(resolve => {
|
||||
let gotTabTarget = false, gotMainTarget = false;
|
||||
let gotTabTarget = false,
|
||||
gotMainTarget = false;
|
||||
const unsubscribe = Target.targetCreated(event => {
|
||||
if (event.targetInfo.type == "page" &&
|
||||
event.targetInfo.url == gBrowser.selectedBrowser.currentURI.spec) {
|
||||
if (
|
||||
event.targetInfo.type == "page" &&
|
||||
event.targetInfo.url == gBrowser.selectedBrowser.currentURI.spec
|
||||
) {
|
||||
info("Got the current tab target");
|
||||
gotTabTarget = true;
|
||||
}
|
||||
|
|
@ -48,21 +51,33 @@ add_task(async function() {
|
|||
|
||||
// Create a new target so that the test runs against a fresh new tab
|
||||
const targetCreated = Target.targetCreated();
|
||||
const {targetId} = await Target.createTarget();
|
||||
const { targetId } = await Target.createTarget();
|
||||
ok(true, `Target created: ${targetId}`);
|
||||
ok(!!targetId, "createTarget returns a non-empty target id");
|
||||
const {targetInfo} = await targetCreated;
|
||||
is(targetId, targetInfo.targetId, "createTarget and targetCreated refers to the same target id");
|
||||
const { targetInfo } = await targetCreated;
|
||||
is(
|
||||
targetId,
|
||||
targetInfo.targetId,
|
||||
"createTarget and targetCreated refers to the same target id"
|
||||
);
|
||||
is(targetInfo.type, "page", "The target is a page");
|
||||
|
||||
const attachedToTarget = Target.attachedToTarget();
|
||||
const {sessionId} = await Target.attachToTarget({ targetId });
|
||||
const { sessionId } = await Target.attachToTarget({ targetId });
|
||||
ok(true, "Target attached");
|
||||
|
||||
const attachedEvent = await attachedToTarget;
|
||||
ok(true, "Received Target.attachToTarget event");
|
||||
is(attachedEvent.sessionId, sessionId, "attachedToTarget and attachToTarget returns the same session id");
|
||||
is(attachedEvent.targetInfo.type, "page", "attachedToTarget creates a tab by default");
|
||||
is(
|
||||
attachedEvent.sessionId,
|
||||
sessionId,
|
||||
"attachedToTarget and attachToTarget returns the same session id"
|
||||
);
|
||||
is(
|
||||
attachedEvent.targetInfo.type,
|
||||
"page",
|
||||
"attachedToTarget creates a tab by default"
|
||||
);
|
||||
|
||||
const onResponse = Target.receivedMessageFromTarget();
|
||||
const id = 1;
|
||||
|
|
@ -78,7 +93,10 @@ add_task(async function() {
|
|||
is(response.sessionId, sessionId, "The response is from the same session");
|
||||
const responseMessage = JSON.parse(response.message);
|
||||
is(responseMessage.id, id, "The response is from the same session");
|
||||
ok(!!responseMessage.result.frameId, "received the `frameId` out of `Page.navigate` request");
|
||||
ok(
|
||||
!!responseMessage.result.frameId,
|
||||
"received the `frameId` out of `Page.navigate` request"
|
||||
);
|
||||
|
||||
await client.close();
|
||||
ok(true, "The client is closed");
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ add_task(async function() {
|
|||
const CDP = await getCDP();
|
||||
|
||||
// Connect to the server
|
||||
const {webSocketDebuggerUrl} = await CDP.Version();
|
||||
const client = await CDP({"target": webSocketDebuggerUrl});
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
const client = await CDP({ target: webSocketDebuggerUrl });
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
const {Target} = client;
|
||||
const { Target } = client;
|
||||
ok("Target" in client, "Target domain is available");
|
||||
|
||||
// Wait for all Target.targetCreated event. One for each tab, plus the one
|
||||
|
|
@ -34,16 +34,24 @@ add_task(async function() {
|
|||
Target.setDiscoverTargets({ discover: true });
|
||||
await targetsCreated;
|
||||
|
||||
const {browserContextId} = await Target.createBrowserContext();
|
||||
const { browserContextId } = await Target.createBrowserContext();
|
||||
|
||||
const targetCreated = Target.targetCreated();
|
||||
const {targetId} = await Target.createTarget({ browserContextId });
|
||||
const { targetId } = await Target.createTarget({ browserContextId });
|
||||
ok(true, `Target created: ${targetId}`);
|
||||
ok(!!targetId, "createTarget returns a non-empty target id");
|
||||
|
||||
const {targetInfo} = await targetCreated;
|
||||
is(targetId, targetInfo.targetId, "createTarget and targetCreated refers to the same target id");
|
||||
is(browserContextId, targetInfo.browserContextId, "the created target is reported to be of the same browser context");
|
||||
const { targetInfo } = await targetCreated;
|
||||
is(
|
||||
targetId,
|
||||
targetInfo.targetId,
|
||||
"createTarget and targetCreated refers to the same target id"
|
||||
);
|
||||
is(
|
||||
browserContextId,
|
||||
targetInfo.browserContextId,
|
||||
"the created target is reported to be of the same browser context"
|
||||
);
|
||||
is(targetInfo.type, "page", "The target is a page");
|
||||
|
||||
// Releasing the browser context is going to remove the tab opened when calling createTarget
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ add_task(async function() {
|
|||
info("Create a new tab and wait for the target to be created");
|
||||
const otherTargetCreated = Target.targetCreated();
|
||||
const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URI);
|
||||
const {targetInfo} = await otherTargetCreated;
|
||||
const { targetInfo } = await otherTargetCreated;
|
||||
is(targetInfo.type, "page");
|
||||
|
||||
const onTabClose = BrowserTestUtils.waitForEvent(tab, "TabClose");
|
||||
|
|
|
|||
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {RemoteAgent} = ChromeUtils.import("chrome://remote/content/RemoteAgent.jsm");
|
||||
const {RemoteAgentError} = ChromeUtils.import("chrome://remote/content/Error.jsm");
|
||||
const { RemoteAgent } = ChromeUtils.import(
|
||||
"chrome://remote/content/RemoteAgent.jsm"
|
||||
);
|
||||
const { RemoteAgentError } = ChromeUtils.import(
|
||||
"chrome://remote/content/Error.jsm"
|
||||
);
|
||||
|
||||
/**
|
||||
* Override `add_task` in order to translate chrome-remote-interface exceptions
|
||||
|
|
@ -27,7 +31,8 @@ this.add_task = function(test) {
|
|||
});
|
||||
};
|
||||
|
||||
const CRI_URI = "http://example.com/browser/remote/test/browser/chrome-remote-interface.js";
|
||||
const CRI_URI =
|
||||
"http://example.com/browser/remote/test/browser/chrome-remote-interface.js";
|
||||
|
||||
/**
|
||||
* Create a test document in an invisible window.
|
||||
|
|
@ -59,7 +64,7 @@ async function getCDP() {
|
|||
script.setAttribute("src", CRI_URI);
|
||||
document.documentElement.appendChild(script);
|
||||
await new Promise(resolve => {
|
||||
script.addEventListener("load", resolve, {once: true});
|
||||
script.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
|
||||
const window = document.defaultView.wrappedJSObject;
|
||||
|
|
@ -68,7 +73,7 @@ async function getCDP() {
|
|||
// library in order to do the cross-domain http request, which,
|
||||
// in a regular Web page, is impossible.
|
||||
window.criRequest = (options, callback) => {
|
||||
const {host, port, path} = options;
|
||||
const { host, port, path } = options;
|
||||
const url = `http://${host}:${port}${path}`;
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, true);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
const puppeteer = require("puppeteer");
|
||||
|
||||
console.log("Calling puppeteer.connect");
|
||||
puppeteer.connect({ browserURL: "http://localhost:9000"}).then(async browser => {
|
||||
puppeteer
|
||||
.connect({ browserURL: "http://localhost:9000" })
|
||||
.then(async browser => {
|
||||
console.log("Connect success!");
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
|
@ -21,4 +23,4 @@ puppeteer.connect({ browserURL: "http://localhost:9000"}).then(async browser =>
|
|||
await page.goto("https://www.mozilla.org/");
|
||||
|
||||
return browser.close();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.jsm");
|
||||
const {Domains} = ChromeUtils.import("chrome://remote/content/domains/Domains.jsm");
|
||||
const { Domain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domain.jsm"
|
||||
);
|
||||
const { Domains } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/Domains.jsm"
|
||||
);
|
||||
|
||||
class MockSession {
|
||||
onEvent() {}
|
||||
|
|
@ -20,7 +24,7 @@ add_test(function test_Domains_constructor() {
|
|||
|
||||
add_test(function test_Domains_domainSupportsMethod() {
|
||||
const modules = {
|
||||
"Foo": class extends Domain {
|
||||
Foo: class extends Domain {
|
||||
bar() {}
|
||||
},
|
||||
};
|
||||
|
|
@ -35,7 +39,7 @@ add_test(function test_Domains_domainSupportsMethod() {
|
|||
|
||||
add_test(function test_Domains_get_invalidModule() {
|
||||
Assert.throws(() => {
|
||||
const domains = new Domains(noopSession, {Foo: undefined});
|
||||
const domains = new Domains(noopSession, { Foo: undefined });
|
||||
domains.get("Foo");
|
||||
}, /UnknownMethodError/);
|
||||
|
||||
|
|
@ -44,7 +48,7 @@ add_test(function test_Domains_get_invalidModule() {
|
|||
|
||||
add_test(function test_Domains_get_missingConstructor() {
|
||||
Assert.throws(() => {
|
||||
const domains = new Domains(noopSession, {Foo: {}});
|
||||
const domains = new Domains(noopSession, { Foo: {} });
|
||||
domains.get("Foo");
|
||||
}, /TypeError/);
|
||||
|
||||
|
|
@ -53,7 +57,7 @@ add_test(function test_Domains_get_missingConstructor() {
|
|||
|
||||
add_test(function test_Domain_get_superClassNotDomain() {
|
||||
Assert.throws(() => {
|
||||
const domains = new Domain(noopSession, {Foo: class {}});
|
||||
const domains = new Domain(noopSession, { Foo: class {} });
|
||||
domains.get("Foo");
|
||||
}, /TypeError/);
|
||||
|
||||
|
|
@ -77,7 +81,7 @@ add_test(function test_Domains_get_constructs() {
|
|||
}
|
||||
|
||||
const session = new Session();
|
||||
const domains = new Domains(session, {Foo});
|
||||
const domains = new Domains(session, { Foo });
|
||||
|
||||
const foo = domains.get("Foo");
|
||||
ok(constructed);
|
||||
|
|
@ -92,7 +96,7 @@ add_test(function test_Domains_get_constructs() {
|
|||
|
||||
add_test(function test_Domains_size() {
|
||||
class Foo extends Domain {}
|
||||
const domains = new Domains(noopSession, {Foo});
|
||||
const domains = new Domains(noopSession, { Foo });
|
||||
|
||||
equal(domains.size, 0);
|
||||
domains.get("Foo");
|
||||
|
|
@ -109,7 +113,7 @@ add_test(function test_Domains_clear() {
|
|||
}
|
||||
}
|
||||
|
||||
const domains = new Domains(noopSession, {Foo});
|
||||
const domains = new Domains(noopSession, { Foo });
|
||||
|
||||
equal(domains.size, 0);
|
||||
domains.get("Foo");
|
||||
|
|
@ -124,12 +128,20 @@ add_test(function test_Domains_clear() {
|
|||
|
||||
add_test(function test_Domains_splitMethod() {
|
||||
for (const t of [42, null, true, {}, [], undefined]) {
|
||||
Assert.throws(() => Domains.splitMethod(t), /TypeError/, `${typeof t} throws`);
|
||||
Assert.throws(
|
||||
() => Domains.splitMethod(t),
|
||||
/TypeError/,
|
||||
`${typeof t} throws`
|
||||
);
|
||||
}
|
||||
for (const s of ["", ".", "foo.", ".bar", "foo.bar.baz"]) {
|
||||
Assert.throws(() => Domains.splitMethod(s), /Invalid method format: ".*"/, `"${s}" throws`);
|
||||
Assert.throws(
|
||||
() => Domains.splitMethod(s),
|
||||
/Invalid method format: ".*"/,
|
||||
`"${s}" throws`
|
||||
);
|
||||
}
|
||||
deepEqual(Domains.splitMethod("foo.bar"), {domain: "foo", command: "bar"});
|
||||
deepEqual(Domains.splitMethod("foo.bar"), { domain: "foo", command: "bar" });
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,16 +37,19 @@ add_test(function test_RemoteAgentError_notify() {
|
|||
add_test(function test_RemoteAgentError_toString() {
|
||||
const e = new RemoteAgentError("message");
|
||||
equal(e.toString(), RemoteAgentError.format(e));
|
||||
equal(e.toString({stack: true}), RemoteAgentError.format(e, {stack: true}));
|
||||
equal(
|
||||
e.toString({ stack: true }),
|
||||
RemoteAgentError.format(e, { stack: true })
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_RemoteAgentError_format() {
|
||||
const {format} = RemoteAgentError;
|
||||
const { format } = RemoteAgentError;
|
||||
|
||||
equal(format({name: "HippoError"}), "HippoError");
|
||||
equal(format({name: "HorseError", message: "neigh"}), "HorseError: neigh");
|
||||
equal(format({ name: "HippoError" }), "HippoError");
|
||||
equal(format({ name: "HorseError", message: "neigh" }), "HorseError: neigh");
|
||||
|
||||
const dog = {
|
||||
name: "DogError",
|
||||
|
|
@ -54,11 +57,13 @@ add_test(function test_RemoteAgentError_format() {
|
|||
stack: " one\ntwo\nthree ",
|
||||
};
|
||||
equal(format(dog), "DogError: woof");
|
||||
equal(format(dog, {stack: true}),
|
||||
`DogError: woof:
|
||||
equal(
|
||||
format(dog, { stack: true }),
|
||||
`DogError: woof:
|
||||
one
|
||||
two
|
||||
three`);
|
||||
three`
|
||||
);
|
||||
|
||||
const cat = {
|
||||
name: "CatError",
|
||||
|
|
@ -67,23 +72,27 @@ add_test(function test_RemoteAgentError_format() {
|
|||
cause: dog,
|
||||
};
|
||||
equal(format(cat), "CatError: meow");
|
||||
equal(format(cat, {stack: true}),
|
||||
`CatError: meow:
|
||||
equal(
|
||||
format(cat, { stack: true }),
|
||||
`CatError: meow:
|
||||
four
|
||||
five
|
||||
six
|
||||
caused by: DogError: woof:
|
||||
one
|
||||
two
|
||||
three`);
|
||||
three`
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_RemoteAgentError_fromJSON() {
|
||||
const cdpErr = {message: `TypeError: foo:
|
||||
const cdpErr = {
|
||||
message: `TypeError: foo:
|
||||
bar
|
||||
baz`};
|
||||
baz`,
|
||||
};
|
||||
const err = RemoteAgentError.fromJSON(cdpErr);
|
||||
|
||||
equal(err.message, "TypeError: foo");
|
||||
|
|
@ -101,6 +110,10 @@ add_test(function test_UnsupportedError() {
|
|||
add_test(function test_UnknownMethodError() {
|
||||
ok(new UnknownMethodError() instanceof RemoteAgentError);
|
||||
ok(new UnknownMethodError("domain").message.endsWith("domain"));
|
||||
ok(new UnknownMethodError("domain", "command").message.endsWith("domain.command"));
|
||||
ok(
|
||||
new UnknownMethodError("domain", "command").message.endsWith(
|
||||
"domain.command"
|
||||
)
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Session} = ChromeUtils.import("chrome://remote/content/sessions/Session.jsm");
|
||||
const { Session } = ChromeUtils.import(
|
||||
"chrome://remote/content/sessions/Session.jsm"
|
||||
);
|
||||
|
||||
const connection = {
|
||||
registerSession: () => {},
|
||||
|
|
@ -13,11 +15,10 @@ const connection = {
|
|||
};
|
||||
|
||||
class MockTarget {
|
||||
constructor() {
|
||||
}
|
||||
constructor() {}
|
||||
|
||||
get browsingContext() {
|
||||
return {id: 42};
|
||||
return { id: 42 };
|
||||
}
|
||||
|
||||
get mm() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue