/* 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 { ShadowRoot, WebElement, WebFrame, WebReference, WebWindow } = ChromeUtils.importESModule( "chrome://remote/content/marionette/web-reference.sys.mjs" ); const { NodeCache } = ChromeUtils.importESModule( "chrome://remote/content/shared/webdriver/NodeCache.sys.mjs" ); const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; class MockElement { constructor(tagName, attrs = {}) { this.tagName = tagName; this.localName = tagName; this.isConnected = false; this.ownerGlobal = { document: { isActive() { return true; }, }, }; for (let attr in attrs) { this[attr] = attrs[attr]; } } get nodeType() { return 1; } get ELEMENT_NODE() { return 1; } // this is a severely limited CSS selector // that only supports lists of tag names matches(selector) { let tags = selector.split(","); return tags.includes(this.localName); } } class MockXULElement extends MockElement { constructor(tagName, attrs = {}) { super(tagName, attrs); this.namespaceURI = XUL_NS; if (typeof this.ownerDocument == "undefined") { this.ownerDocument = {}; } if (typeof this.ownerDocument.documentElement == "undefined") { this.ownerDocument.documentElement = { namespaceURI: XUL_NS }; } } } const xulEl = new MockXULElement("text"); const domElInPrivilegedDocument = new MockElement("input", { nodePrincipal: { isSystemPrincipal: true }, }); const xulElInPrivilegedDocument = new MockXULElement("text", { nodePrincipal: { isSystemPrincipal: true }, }); function setupTest() { const browser = Services.appShell.createWindowlessBrowser(false); browser.document.body.innerHTML = `
`; const divEl = browser.document.querySelector("div"); const svgEl = browser.document.querySelector("svg"); const textareaEl = browser.document.querySelector("textarea"); const videoEl = browser.document.querySelector("video"); const iframeEl = browser.document.querySelector("iframe"); const childEl = iframeEl.contentDocument.createElement("div"); iframeEl.contentDocument.body.appendChild(childEl); const shadowRoot = videoEl.openOrClosedShadowRoot; return { browser, childEl, divEl, iframeEl, nodeCache: new NodeCache(), shadowRoot, svgEl, textareaEl, videoEl, }; } add_task(function test_WebReference_ctor() { const el = new WebReference("foo"); equal(el.uuid, "foo"); for (let t of [42, true, [], {}, null, undefined]) { Assert.throws(() => new WebReference(t), /to be a string/); } }); add_task(function test_WebReference_from() { const { divEl, iframeEl } = setupTest(); ok(WebReference.from(divEl) instanceof WebElement); ok(WebReference.from(xulEl) instanceof WebElement); ok(WebReference.from(divEl.ownerGlobal) instanceof WebWindow); ok(WebReference.from(iframeEl.contentWindow) instanceof WebFrame); ok(WebReference.from(domElInPrivilegedDocument) instanceof WebElement); ok(WebReference.from(xulElInPrivilegedDocument) instanceof WebElement); Assert.throws(() => WebReference.from({}), /InvalidArgumentError/); }); add_task(function test_WebReference_fromJSON_malformed() { Assert.throws(() => WebReference.fromJSON({}), /InvalidArgumentError/); Assert.throws(() => WebReference.fromJSON(null), /InvalidArgumentError/); }); add_task(function test_WebReference_fromJSON_ShadowRoot() { const { Identifier } = ShadowRoot; const ref = { [Identifier]: "foo" }; const shadowRootEl = WebReference.fromJSON(ref); ok(shadowRootEl instanceof ShadowRoot); equal(shadowRootEl.uuid, "foo"); let identifierPrecedence = { [Identifier]: "identifier-uuid", }; const precedenceShadowRoot = WebReference.fromJSON(identifierPrecedence); ok(precedenceShadowRoot instanceof ShadowRoot); equal(precedenceShadowRoot.uuid, "identifier-uuid"); }); add_task(function test_WebReference_fromJSON_WebElement() { const { Identifier } = WebElement; const ref = { [Identifier]: "foo" }; const webEl = WebReference.fromJSON(ref); ok(webEl instanceof WebElement); equal(webEl.uuid, "foo"); let identifierPrecedence = { [Identifier]: "identifier-uuid", }; const precedenceEl = WebReference.fromJSON(identifierPrecedence); ok(precedenceEl instanceof WebElement); equal(precedenceEl.uuid, "identifier-uuid"); }); add_task(function test_WebReference_fromJSON_WebFrame() { const ref = { [WebFrame.Identifier]: "foo" }; const frame = WebReference.fromJSON(ref); ok(frame instanceof WebFrame); equal(frame.uuid, "foo"); }); add_task(function test_WebReference_fromJSON_WebWindow() { const ref = { [WebWindow.Identifier]: "foo" }; const win = WebReference.fromJSON(ref); ok(win instanceof WebWindow); equal(win.uuid, "foo"); }); add_task(function test_WebReference_is() { const a = new WebReference("a"); const b = new WebReference("b"); ok(a.is(a)); ok(b.is(b)); ok(!a.is(b)); ok(!b.is(a)); ok(!a.is({})); }); add_task(function test_WebReference_isReference() { for (let t of [42, true, "foo", [], {}]) { ok(!WebReference.isReference(t)); } ok(WebReference.isReference({ [WebElement.Identifier]: "foo" })); ok(WebReference.isReference({ [WebWindow.Identifier]: "foo" })); ok(WebReference.isReference({ [WebFrame.Identifier]: "foo" })); }); add_task(function test_ShadowRoot_fromJSON() { const { Identifier } = ShadowRoot; const shadowRoot = ShadowRoot.fromJSON({ [Identifier]: "foo" }); ok(shadowRoot instanceof ShadowRoot); equal(shadowRoot.uuid, "foo"); Assert.throws(() => ShadowRoot.fromJSON({}), /InvalidArgumentError/); }); add_task(function test_ShadowRoot_fromUUID() { const shadowRoot = ShadowRoot.fromUUID("baz"); ok(shadowRoot instanceof ShadowRoot); equal(shadowRoot.uuid, "baz"); Assert.throws(() => ShadowRoot.fromUUID(), /InvalidArgumentError/); }); add_task(function test_ShadowRoot_toJSON() { const { Identifier } = ShadowRoot; const shadowRoot = new ShadowRoot("foo"); const json = shadowRoot.toJSON(); ok(Identifier in json); equal(json[Identifier], "foo"); }); add_task(function test_WebElement_fromJSON() { const { Identifier } = WebElement; const el = WebElement.fromJSON({ [Identifier]: "foo" }); ok(el instanceof WebElement); equal(el.uuid, "foo"); Assert.throws(() => WebElement.fromJSON({}), /InvalidArgumentError/); }); add_task(function test_WebElement_fromUUID() { const domWebEl = WebElement.fromUUID("bar"); ok(domWebEl instanceof WebElement); equal(domWebEl.uuid, "bar"); Assert.throws(() => WebElement.fromUUID(), /InvalidArgumentError/); }); add_task(function test_WebElement_toJSON() { const { Identifier } = WebElement; const el = new WebElement("foo"); const json = el.toJSON(); ok(Identifier in json); equal(json[Identifier], "foo"); }); add_task(function test_WebFrame_fromJSON() { const ref = { [WebFrame.Identifier]: "foo" }; const win = WebFrame.fromJSON(ref); ok(win instanceof WebFrame); equal(win.uuid, "foo"); }); add_task(function test_WebFrame_toJSON() { const frame = new WebFrame("foo"); const json = frame.toJSON(); ok(WebFrame.Identifier in json); equal(json[WebFrame.Identifier], "foo"); }); add_task(function test_WebWindow_fromJSON() { const ref = { [WebWindow.Identifier]: "foo" }; const win = WebWindow.fromJSON(ref); ok(win instanceof WebWindow); equal(win.uuid, "foo"); }); add_task(function test_WebWindow_toJSON() { const win = new WebWindow("foo"); const json = win.toJSON(); ok(WebWindow.Identifier in json); equal(json[WebWindow.Identifier], "foo"); });