no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / remote / marionette / web-reference.sys.mjs
blob5d2d510265b34fb1e914eb1f731b4d7b3eecdad3
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const lazy = {};
7 ChromeUtils.defineESModuleGetters(lazy, {
8   assert: "chrome://remote/content/shared/webdriver/Assert.sys.mjs",
9   dom: "chrome://remote/content/shared/DOM.sys.mjs",
10   error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
11   generateUUID: "chrome://remote/content/shared/UUID.sys.mjs",
12   pprint: "chrome://remote/content/shared/Format.sys.mjs",
13 });
15 /**
16  * A web reference is an abstraction used to identify an element when
17  * it is transported via the protocol, between remote- and local ends.
18  *
19  * In Marionette this abstraction can represent DOM elements,
20  * WindowProxies, and XUL elements.
21  */
22 export class WebReference {
23   /**
24    * @param {string} uuid
25    *     Identifier that must be unique across all browsing contexts
26    *     for the contract to be upheld.
27    */
28   constructor(uuid) {
29     this.uuid = lazy.assert.string(uuid);
30   }
32   /**
33    * Performs an equality check between this web element and
34    * <var>other</var>.
35    *
36    * @param {WebReference} other
37    *     Web element to compare with this.
38    *
39    * @returns {boolean}
40    *     True if this and <var>other</var> are the same.  False
41    *     otherwise.
42    */
43   is(other) {
44     return other instanceof WebReference && this.uuid === other.uuid;
45   }
47   toString() {
48     return `[object ${this.constructor.name} uuid=${this.uuid}]`;
49   }
51   /**
52    * Returns a new {@link WebReference} reference for a DOM or XUL element,
53    * <code>WindowProxy</code>, or <code>ShadowRoot</code>.
54    *
55    * @param {(Element|ShadowRoot|WindowProxy|MockXULElement)} node
56    *     Node to construct a web element reference for.
57    * @param {string=} uuid
58    *     Optional unique identifier of the WebReference if already known.
59    *     If not defined a new unique identifier will be created.
60    *
61    * @returns {WebReference}
62    *     Web reference for <var>node</var>.
63    *
64    * @throws {InvalidArgumentError}
65    *     If <var>node</var> is neither a <code>WindowProxy</code>,
66    *     DOM or XUL element, or <code>ShadowRoot</code>.
67    */
68   static from(node, uuid) {
69     if (uuid === undefined) {
70       uuid = lazy.generateUUID();
71     }
73     if (lazy.dom.isShadowRoot(node) && !lazy.dom.isInPrivilegedDocument(node)) {
74       // When we support Chrome Shadowroots we will need to
75       // do a check here of shadowroot.host being in a privileged document
76       // See Bug 1743541
77       return new ShadowRoot(uuid);
78     } else if (lazy.dom.isElement(node)) {
79       return new WebElement(uuid);
80     } else if (lazy.dom.isDOMWindow(node)) {
81       if (node.parent === node) {
82         return new WebWindow(uuid);
83       }
84       return new WebFrame(uuid);
85     }
87     throw new lazy.error.InvalidArgumentError(
88       "Expected DOM window/element " + lazy.pprint`or XUL element, got: ${node}`
89     );
90   }
92   /**
93    * Unmarshals a JSON Object to one of {@link ShadowRoot}, {@link WebElement},
94    * {@link WebFrame}, or {@link WebWindow}.
95    *
96    * @param {Object<string, string>} json
97    *     Web reference, which is supposed to be a JSON Object
98    *     where the key is one of the {@link WebReference} concrete
99    *     classes' UUID identifiers.
100    *
101    * @returns {WebReference}
102    *     Web reference for the JSON object.
103    *
104    * @throws {InvalidArgumentError}
105    *     If <var>json</var> is not a web reference.
106    */
107   static fromJSON(json) {
108     lazy.assert.object(json);
109     if (json instanceof WebReference) {
110       return json;
111     }
112     let keys = Object.keys(json);
114     for (let key of keys) {
115       switch (key) {
116         case ShadowRoot.Identifier:
117           return ShadowRoot.fromJSON(json);
119         case WebElement.Identifier:
120           return WebElement.fromJSON(json);
122         case WebFrame.Identifier:
123           return WebFrame.fromJSON(json);
125         case WebWindow.Identifier:
126           return WebWindow.fromJSON(json);
127       }
128     }
130     throw new lazy.error.InvalidArgumentError(
131       lazy.pprint`Expected web reference, got: ${json}`
132     );
133   }
135   /**
136    * Checks if <var>obj<var> is a {@link WebReference} reference.
137    *
138    * @param {Object<string, string>} obj
139    *     Object that represents a {@link WebReference}.
140    *
141    * @returns {boolean}
142    *     True if <var>obj</var> is a {@link WebReference}, false otherwise.
143    */
144   static isReference(obj) {
145     if (Object.prototype.toString.call(obj) != "[object Object]") {
146       return false;
147     }
149     if (
150       ShadowRoot.Identifier in obj ||
151       WebElement.Identifier in obj ||
152       WebFrame.Identifier in obj ||
153       WebWindow.Identifier in obj
154     ) {
155       return true;
156     }
157     return false;
158   }
162  * Shadow Root elements are represented as shadow root references when they are
163  * transported over the wire protocol
164  */
165 export class ShadowRoot extends WebReference {
166   toJSON() {
167     return { [ShadowRoot.Identifier]: this.uuid };
168   }
170   static fromJSON(json) {
171     const { Identifier } = ShadowRoot;
173     if (!(Identifier in json)) {
174       throw new lazy.error.InvalidArgumentError(
175         lazy.pprint`Expected shadow root reference, got: ${json}`
176       );
177     }
179     let uuid = json[Identifier];
180     return new ShadowRoot(uuid);
181   }
183   /**
184    * Constructs a {@link ShadowRoot} from a string <var>uuid</var>.
185    *
186    * This whole function is a workaround for the fact that clients
187    * to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
188    * Objects instead of shadow root representations.
189    *
190    * @param {string} uuid
191    *     UUID to be associated with the web reference.
192    *
193    * @returns {ShadowRoot}
194    *     The shadow root reference.
195    *
196    * @throws {InvalidArgumentError}
197    *     If <var>uuid</var> is not a string.
198    */
199   static fromUUID(uuid) {
200     lazy.assert.string(uuid);
202     return new ShadowRoot(uuid);
203   }
206 ShadowRoot.Identifier = "shadow-6066-11e4-a52e-4f735466cecf";
209  * DOM elements are represented as web elements when they are
210  * transported over the wire protocol.
211  */
212 export class WebElement extends WebReference {
213   toJSON() {
214     return { [WebElement.Identifier]: this.uuid };
215   }
217   static fromJSON(json) {
218     const { Identifier } = WebElement;
220     if (!(Identifier in json)) {
221       throw new lazy.error.InvalidArgumentError(
222         lazy.pprint`Expected web element reference, got: ${json}`
223       );
224     }
226     let uuid = json[Identifier];
227     return new WebElement(uuid);
228   }
230   /**
231    * Constructs a {@link WebElement} from a string <var>uuid</var>.
232    *
233    * This whole function is a workaround for the fact that clients
234    * to Marionette occasionally pass <code>{id: <uuid>}</code> JSON
235    * Objects instead of web element representations.
236    *
237    * @param {string} uuid
238    *     UUID to be associated with the web reference.
239    *
240    * @returns {WebElement}
241    *     The web element reference.
242    *
243    * @throws {InvalidArgumentError}
244    *     If <var>uuid</var> is not a string.
245    */
246   static fromUUID(uuid) {
247     return new WebElement(uuid);
248   }
251 WebElement.Identifier = "element-6066-11e4-a52e-4f735466cecf";
254  * Nested browsing contexts, such as the <code>WindowProxy</code>
255  * associated with <tt>&lt;frame&gt;</tt> and <tt>&lt;iframe&gt;</tt>,
256  * are represented as web frames over the wire protocol.
257  */
258 export class WebFrame extends WebReference {
259   toJSON() {
260     return { [WebFrame.Identifier]: this.uuid };
261   }
263   static fromJSON(json) {
264     if (!(WebFrame.Identifier in json)) {
265       throw new lazy.error.InvalidArgumentError(
266         lazy.pprint`Expected web frame reference, got: ${json}`
267       );
268     }
269     let uuid = json[WebFrame.Identifier];
270     return new WebFrame(uuid);
271   }
274 WebFrame.Identifier = "frame-075b-4da1-b6ba-e579c2d3230a";
277  * Top-level browsing contexts, such as <code>WindowProxy</code>
278  * whose <code>opener</code> is null, are represented as web windows
279  * over the wire protocol.
280  */
281 export class WebWindow extends WebReference {
282   toJSON() {
283     return { [WebWindow.Identifier]: this.uuid };
284   }
286   static fromJSON(json) {
287     if (!(WebWindow.Identifier in json)) {
288       throw new lazy.error.InvalidArgumentError(
289         lazy.pprint`Expected web window reference, got: ${json}`
290       );
291     }
292     let uuid = json[WebWindow.Identifier];
293     return new WebWindow(uuid);
294   }
297 WebWindow.Identifier = "window-fcc6-11e5-b4f8-330a88ab9d7f";