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/**
|
||||
|
|
|
|||
|
|
@ -7,10 +7,17 @@
|
|||
var EXPORTED_SYMBOLS = ["Connection"];
|
||||
|
||||
const { Log } = ChromeUtils.import("chrome://remote/content/Log.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ var EXPORTED_SYMBOLS = [
|
|||
|
||||
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 { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,14 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["JSONHandler"];
|
||||
|
||||
const {HTTP_404, HTTP_505} = ChromeUtils.import("chrome://remote/content/server/HTTPD.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");
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
var EXPORTED_SYMBOLS = ["RemoteAgent", "RemoteAgentFactory"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.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) {
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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") {
|
||||
if (
|
||||
window.document.readyState == "complete" ||
|
||||
window.document.readyState == "interactive"
|
||||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new EventPromise(window, "DOMContentLoaded", options);
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@
|
|||
|
||||
"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 { 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");
|
||||
|
||||
/**
|
||||
|
|
@ -137,7 +137,9 @@ class TabObserver {
|
|||
}
|
||||
|
||||
window.addEventListener("TabOpen", ({ target }) => this.onTabOpen(target));
|
||||
window.addEventListener("TabClose", ({target}) => this.onTabClose(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 = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,32 +26,40 @@
|
|||
var EXPORTED_SYMBOLS = ["ContextObserver"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.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");
|
||||
}
|
||||
|
||||
|
|
@ -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,7 +6,9 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["Log"];
|
||||
|
||||
const {ContentProcessDomain} = ChromeUtils.import("chrome://remote/content/domains/ContentProcessDomain.jsm");
|
||||
const { ContentProcessDomain } = ChromeUtils.import(
|
||||
"chrome://remote/content/domains/ContentProcessDomain.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
class Log extends ContentProcessDomain {
|
||||
|
|
@ -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";
|
||||
|
||||
|
|
@ -116,11 +117,15 @@ function fromScriptError(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 { 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 { 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,10 +48,12 @@ 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 { 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 { 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");
|
||||
}
|
||||
|
|
@ -336,14 +373,15 @@ class ExecutionContext {
|
|||
|
||||
// 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,
|
||||
|
|
|
|||
|
|
@ -7,13 +7,18 @@
|
|||
var EXPORTED_SYMBOLS = ["Browser"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.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",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
var EXPORTED_SYMBOLS = ["Input"];
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {Domain} = ChromeUtils.import("chrome://remote/content/domains/Domain.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,12 +124,16 @@ 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) {}
|
||||
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,7 +85,9 @@ 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 };
|
||||
}
|
||||
|
|
@ -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 { 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 { 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,7 +294,10 @@ 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);
|
||||
|
|
@ -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,12 +455,16 @@ 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) {}
|
||||
return loadContext;
|
||||
|
|
@ -405,7 +508,11 @@ 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*/);
|
||||
}
|
||||
|
|
@ -425,10 +532,12 @@ 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)
|
||||
}
|
||||
if (response.evicted) {
|
||||
return { base64body: "", evicted: true };
|
||||
}
|
||||
let result = response.body;
|
||||
if (response.encodings && response.encodings.length) {
|
||||
for (const encoding of response.encodings) {
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -11,14 +11,22 @@ 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 { 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();
|
||||
|
|
@ -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) };
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,7 +34,9 @@ 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}`;
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["TabTarget"];
|
||||
|
||||
const {Target} = ChromeUtils.import("chrome://remote/content/targets/Target.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");
|
||||
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.
|
||||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -34,9 +34,19 @@ add_task(async function testCDP() {
|
|||
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();
|
||||
|
|
@ -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,14 +12,16 @@ 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;
|
||||
|
|
@ -30,8 +32,11 @@ add_task(async function() {
|
|||
is(version.product, "Firefox", "Browser.getVersion works");
|
||||
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
is(webSocketDebuggerUrl, targetURL,
|
||||
"Version endpoint refers to the same Main process target");
|
||||
is(
|
||||
webSocketDebuggerUrl,
|
||||
targetURL,
|
||||
"Version endpoint refers to the same Main process target"
|
||||
);
|
||||
|
||||
await RemoteAgent.close();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
// 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);
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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,21 +103,29 @@ 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,
|
||||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ 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 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();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,17 +14,20 @@ add_task(async function() {
|
|||
|
||||
// Connect to the server
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
const client = await CDP({"target": webSocketDebuggerUrl});
|
||||
const client = await CDP({ target: webSocketDebuggerUrl });
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -52,7 +55,11 @@ add_task(async function() {
|
|||
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(
|
||||
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();
|
||||
|
|
@ -61,8 +68,16 @@ add_task(async function() {
|
|||
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ add_task(async function() {
|
|||
|
||||
// Connect to the server
|
||||
const { webSocketDebuggerUrl } = await CDP.Version();
|
||||
const client = await CDP({"target": webSocketDebuggerUrl});
|
||||
const client = await CDP({ target: webSocketDebuggerUrl });
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
const { Target } = client;
|
||||
|
|
@ -42,8 +42,16 @@ add_task(async function() {
|
|||
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");
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
},
|
||||
};
|
||||
|
|
@ -124,10 +128,18 @@ 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" });
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,10 @@ 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();
|
||||
});
|
||||
|
|
@ -54,11 +57,13 @@ add_test(function test_RemoteAgentError_format() {
|
|||
stack: " one\ntwo\nthree ",
|
||||
};
|
||||
equal(format(dog), "DogError: woof");
|
||||
equal(format(dog, {stack: true}),
|
||||
equal(
|
||||
format(dog, { stack: true }),
|
||||
`DogError: woof:
|
||||
one
|
||||
two
|
||||
three`);
|
||||
three`
|
||||
);
|
||||
|
||||
const cat = {
|
||||
name: "CatError",
|
||||
|
|
@ -67,7 +72,8 @@ add_test(function test_RemoteAgentError_format() {
|
|||
cause: dog,
|
||||
};
|
||||
equal(format(cat), "CatError: meow");
|
||||
equal(format(cat, {stack: true}),
|
||||
equal(
|
||||
format(cat, { stack: true }),
|
||||
`CatError: meow:
|
||||
four
|
||||
five
|
||||
|
|
@ -75,15 +81,18 @@ add_test(function test_RemoteAgentError_format() {
|
|||
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,8 +15,7 @@ const connection = {
|
|||
};
|
||||
|
||||
class MockTarget {
|
||||
constructor() {
|
||||
}
|
||||
constructor() {}
|
||||
|
||||
get browsingContext() {
|
||||
return { id: 42 };
|
||||
|
|
|
|||
Loading…
Reference in a new issue