mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
a55c556aad
Differential Revision: https://phabricator.services.mozilla.com/D219511
307 lines
8.5 KiB
JavaScript
307 lines
8.5 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
|
|
dom: "chrome://remote/content/shared/DOM.sys.mjs",
|
|
error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
|
|
generateUUID: "chrome://remote/content/shared/UUID.sys.mjs",
|
|
pprint: "chrome://remote/content/shared/Format.sys.mjs",
|
|
});
|
|
|
|
/**
|
|
* A web reference is an abstraction used to identify an element when
|
|
* it is transported via the protocol, between remote- and local ends.
|
|
*
|
|
* In Marionette this abstraction can represent DOM elements,
|
|
* WindowProxies, and XUL elements.
|
|
*/
|
|
export class WebReference {
|
|
/**
|
|
* @param {string} uuid
|
|
* Identifier that must be unique across all browsing contexts
|
|
* for the contract to be upheld.
|
|
*/
|
|
constructor(uuid) {
|
|
this.uuid = lazy.assert.string(
|
|
uuid,
|
|
lazy.pprint`Expected "uuid" to be a string, got ${uuid}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Performs an equality check between this web element and
|
|
* <var>other</var>.
|
|
*
|
|
* @param {WebReference} other
|
|
* Web element to compare with this.
|
|
*
|
|
* @returns {boolean}
|
|
* True if this and <var>other</var> are the same. False
|
|
* otherwise.
|
|
*/
|
|
is(other) {
|
|
return other instanceof WebReference && this.uuid === other.uuid;
|
|
}
|
|
|
|
toString() {
|
|
return `[object ${this.constructor.name} uuid=${this.uuid}]`;
|
|
}
|
|
|
|
/**
|
|
* Returns a new {@link WebReference} reference for a DOM or XUL element,
|
|
* <code>WindowProxy</code>, or <code>ShadowRoot</code>.
|
|
*
|
|
* @param {(Element|ShadowRoot|WindowProxy|MockXULElement)} node
|
|
* Node to construct a web element reference for.
|
|
* @param {string=} uuid
|
|
* Optional unique identifier of the WebReference if already known.
|
|
* If not defined a new unique identifier will be created.
|
|
*
|
|
* @returns {WebReference}
|
|
* Web reference for <var>node</var>.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>node</var> is neither a <code>WindowProxy</code>,
|
|
* DOM or XUL element, or <code>ShadowRoot</code>.
|
|
*/
|
|
static from(node, uuid) {
|
|
if (uuid === undefined) {
|
|
uuid = lazy.generateUUID();
|
|
}
|
|
|
|
if (lazy.dom.isShadowRoot(node) && !lazy.dom.isInPrivilegedDocument(node)) {
|
|
// When we support Chrome Shadowroots we will need to
|
|
// do a check here of shadowroot.host being in a privileged document
|
|
// See Bug 1743541
|
|
return new ShadowRoot(uuid);
|
|
} else if (lazy.dom.isElement(node)) {
|
|
return new WebElement(uuid);
|
|
} else if (lazy.dom.isDOMWindow(node)) {
|
|
if (node.parent === node) {
|
|
return new WebWindow(uuid);
|
|
}
|
|
return new WebFrame(uuid);
|
|
}
|
|
|
|
throw new lazy.error.InvalidArgumentError(
|
|
"Expected DOM window/element " + lazy.pprint`or XUL element, got: ${node}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Unmarshals a JSON Object to one of {@link ShadowRoot}, {@link WebElement},
|
|
* {@link WebFrame}, or {@link WebWindow}.
|
|
*
|
|
* @param {Record<string, string>} json
|
|
* Web reference, which is supposed to be a JSON Object
|
|
* where the key is one of the {@link WebReference} concrete
|
|
* classes' UUID identifiers.
|
|
*
|
|
* @returns {WebReference}
|
|
* Web reference for the JSON object.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>json</var> is not a web reference.
|
|
*/
|
|
static fromJSON(json) {
|
|
lazy.assert.object(
|
|
json,
|
|
lazy.pprint`Expected web reference to be an object, got ${json}`
|
|
);
|
|
if (json instanceof WebReference) {
|
|
return json;
|
|
}
|
|
let keys = Object.keys(json);
|
|
|
|
for (let key of keys) {
|
|
switch (key) {
|
|
case ShadowRoot.Identifier:
|
|
return ShadowRoot.fromJSON(json);
|
|
|
|
case WebElement.Identifier:
|
|
return WebElement.fromJSON(json);
|
|
|
|
case WebFrame.Identifier:
|
|
return WebFrame.fromJSON(json);
|
|
|
|
case WebWindow.Identifier:
|
|
return WebWindow.fromJSON(json);
|
|
}
|
|
}
|
|
|
|
throw new lazy.error.InvalidArgumentError(
|
|
lazy.pprint`Expected web reference, got: ${json}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Checks if <var>obj<var> is a {@link WebReference} reference.
|
|
*
|
|
* @param {Record<string, string>} obj
|
|
* Object that represents a {@link WebReference}.
|
|
*
|
|
* @returns {boolean}
|
|
* True if <var>obj</var> is a {@link WebReference}, false otherwise.
|
|
*/
|
|
static isReference(obj) {
|
|
if (Object.prototype.toString.call(obj) != "[object Object]") {
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
ShadowRoot.Identifier in obj ||
|
|
WebElement.Identifier in obj ||
|
|
WebFrame.Identifier in obj ||
|
|
WebWindow.Identifier in obj
|
|
) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shadow Root elements are represented as shadow root references when they are
|
|
* transported over the wire protocol
|
|
*/
|
|
export class ShadowRoot extends WebReference {
|
|
toJSON() {
|
|
return { [ShadowRoot.Identifier]: this.uuid };
|
|
}
|
|
|
|
static fromJSON(json) {
|
|
const { Identifier } = ShadowRoot;
|
|
|
|
if (!(Identifier in json)) {
|
|
throw new lazy.error.InvalidArgumentError(
|
|
lazy.pprint`Expected shadow root reference, got: ${json}`
|
|
);
|
|
}
|
|
|
|
let uuid = json[Identifier];
|
|
return new ShadowRoot(uuid);
|
|
}
|
|
|
|
/**
|
|
* Constructs a {@link ShadowRoot} from a string <var>uuid</var>.
|
|
*
|
|
* This whole function is a workaround for the fact that clients
|
|
* to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
|
|
* Objects instead of shadow root representations.
|
|
*
|
|
* @param {string} uuid
|
|
* UUID to be associated with the web reference.
|
|
*
|
|
* @returns {ShadowRoot}
|
|
* The shadow root reference.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>uuid</var> is not a string.
|
|
*/
|
|
static fromUUID(uuid) {
|
|
lazy.assert.string(
|
|
uuid,
|
|
lazy.pprint`Expected "uuid" to be a string, got: ${uuid}`
|
|
);
|
|
|
|
return new ShadowRoot(uuid);
|
|
}
|
|
}
|
|
|
|
ShadowRoot.Identifier = "shadow-6066-11e4-a52e-4f735466cecf";
|
|
|
|
/**
|
|
* DOM elements are represented as web elements when they are
|
|
* transported over the wire protocol.
|
|
*/
|
|
export class WebElement extends WebReference {
|
|
toJSON() {
|
|
return { [WebElement.Identifier]: this.uuid };
|
|
}
|
|
|
|
static fromJSON(json) {
|
|
const { Identifier } = WebElement;
|
|
|
|
if (!(Identifier in json)) {
|
|
throw new lazy.error.InvalidArgumentError(
|
|
lazy.pprint`Expected web element reference, got: ${json}`
|
|
);
|
|
}
|
|
|
|
let uuid = json[Identifier];
|
|
return new WebElement(uuid);
|
|
}
|
|
|
|
/**
|
|
* Constructs a {@link WebElement} from a string <var>uuid</var>.
|
|
*
|
|
* This whole function is a workaround for the fact that clients
|
|
* to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
|
|
* Objects instead of web element representations.
|
|
*
|
|
* @param {string} uuid
|
|
* UUID to be associated with the web reference.
|
|
*
|
|
* @returns {WebElement}
|
|
* The web element reference.
|
|
*
|
|
* @throws {InvalidArgumentError}
|
|
* If <var>uuid</var> is not a string.
|
|
*/
|
|
static fromUUID(uuid) {
|
|
return new WebElement(uuid);
|
|
}
|
|
}
|
|
|
|
WebElement.Identifier = "element-6066-11e4-a52e-4f735466cecf";
|
|
|
|
/**
|
|
* Nested browsing contexts, such as the <code>WindowProxy</code>
|
|
* associated with <tt><frame></tt> and <tt><iframe></tt>,
|
|
* are represented as web frames over the wire protocol.
|
|
*/
|
|
export class WebFrame extends WebReference {
|
|
toJSON() {
|
|
return { [WebFrame.Identifier]: this.uuid };
|
|
}
|
|
|
|
static fromJSON(json) {
|
|
if (!(WebFrame.Identifier in json)) {
|
|
throw new lazy.error.InvalidArgumentError(
|
|
lazy.pprint`Expected web frame reference, got: ${json}`
|
|
);
|
|
}
|
|
let uuid = json[WebFrame.Identifier];
|
|
return new WebFrame(uuid);
|
|
}
|
|
}
|
|
|
|
WebFrame.Identifier = "frame-075b-4da1-b6ba-e579c2d3230a";
|
|
|
|
/**
|
|
* Top-level browsing contexts, such as <code>WindowProxy</code>
|
|
* whose <code>opener</code> is null, are represented as web windows
|
|
* over the wire protocol.
|
|
*/
|
|
export class WebWindow extends WebReference {
|
|
toJSON() {
|
|
return { [WebWindow.Identifier]: this.uuid };
|
|
}
|
|
|
|
static fromJSON(json) {
|
|
if (!(WebWindow.Identifier in json)) {
|
|
throw new lazy.error.InvalidArgumentError(
|
|
lazy.pprint`Expected web window reference, got: ${json}`
|
|
);
|
|
}
|
|
let uuid = json[WebWindow.Identifier];
|
|
return new WebWindow(uuid);
|
|
}
|
|
}
|
|
|
|
WebWindow.Identifier = "window-fcc6-11e5-b4f8-330a88ab9d7f";
|