summaryrefslogtreecommitdiffstats
path: root/remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js')
-rw-r--r--remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js845
1 files changed, 845 insertions, 0 deletions
diff --git a/remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js b/remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js
new file mode 100644
index 0000000000..3e72c9c659
--- /dev/null
+++ b/remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js
@@ -0,0 +1,845 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* eslint no-undef: 0 no-unused-vars: 0 */
+
+add_task(async function test_deserializeSharedIdInvalidTypes() {
+ await runTestInContent(() => {
+ for (const invalidType of [false, 42, {}, []]) {
+ info(`Checking type: '${invalidType}'`);
+
+ const serializedValue = {
+ sharedId: invalidType,
+ };
+
+ Assert.throws(
+ () => deserialize(serializedValue, realm, { nodeCache }),
+ /InvalidArgumentError:/,
+ `Got expected error for type ${invalidType}`
+ );
+ }
+ });
+});
+
+add_task(async function test_deserializeSharedIdInvalidValue() {
+ await runTestInContent(() => {
+ const serializedValue = {
+ sharedId: "foo",
+ };
+
+ Assert.throws(
+ () => deserialize(serializedValue, realm, { nodeCache }),
+ /NoSuchNodeError:/,
+ "Got expected error for unknown 'sharedId'"
+ );
+ });
+});
+
+add_task(async function test_deserializeSharedId() {
+ await loadURL(inline("<div>"));
+
+ await runTestInContent(() => {
+ const domEl = content.document.querySelector("div");
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const serializedValue = {
+ sharedId: domElRef,
+ };
+
+ const node = deserialize(serializedValue, realm, { nodeCache });
+
+ Assert.equal(node, domEl);
+ });
+});
+
+add_task(async function test_deserializeSharedIdPrecedenceOverHandle() {
+ await loadURL(inline("<div>"));
+
+ await runTestInContent(() => {
+ const domEl = content.document.querySelector("div");
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const serializedValue = {
+ handle: "foo",
+ sharedId: domElRef,
+ };
+
+ const node = deserialize(serializedValue, realm, { nodeCache });
+
+ Assert.equal(node, domEl);
+ });
+});
+
+add_task(async function test_deserializeSharedIdNoWindowRealm() {
+ await loadURL(inline("<div>"));
+
+ await runTestInContent(() => {
+ const domEl = content.document.querySelector("div");
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const serializedValue = {
+ sharedId: domElRef,
+ };
+
+ Assert.throws(
+ () => deserialize(serializedValue, new Realm(), { nodeCache }),
+ /NoSuchNodeError/,
+ `Got expected error for a non-window realm`
+ );
+ });
+});
+
+// Bug 1819902: Instead of a browsing context check compare the origin
+add_task(async function test_deserializeSharedIdOtherBrowsingContext() {
+ await loadURL(inline("<iframe>"));
+
+ await runTestInContent(() => {
+ const iframeEl = content.document.querySelector("iframe");
+ const domEl = iframeEl.contentWindow.document.createElement("div");
+ iframeEl.contentWindow.document.body.appendChild(domEl);
+
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const serializedValue = {
+ sharedId: domElRef,
+ };
+
+ const node = deserialize(serializedValue, realm, { nodeCache });
+
+ Assert.equal(node, null);
+ });
+});
+
+add_task(async function test_serializeRemoteComplexValues() {
+ await loadURL(inline("<div>"));
+
+ await runTestInContent(() => {
+ const domEl = content.document.querySelector("div");
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const REMOTE_COMPLEX_VALUES = [
+ {
+ value: content.document.querySelector("div"),
+ serialized: {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ },
+ {
+ value: content.document.querySelectorAll("div"),
+ serialized: {
+ type: "nodelist",
+ value: [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ nodeType: 1,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 0,
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ ],
+ },
+ },
+ {
+ value: content.document.getElementsByTagName("div"),
+ serialized: {
+ type: "htmlcollection",
+ value: [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ nodeType: 1,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 0,
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ ],
+ },
+ },
+ ];
+
+ for (const type of REMOTE_COMPLEX_VALUES) {
+ serializeAndAssertRemoteValue(type);
+ }
+ });
+});
+
+add_task(async function test_serializeWindow() {
+ await loadURL(inline("<iframe>"));
+
+ await runTestInContent(() => {
+ const REMOTE_COMPLEX_VALUES = [
+ {
+ value: content,
+ serialized: {
+ type: "window",
+ value: {
+ context: content.browsingContext.browserId.toString(),
+ isTopBrowsingContext: true,
+ },
+ },
+ },
+ {
+ value: content.frames[0],
+ serialized: {
+ type: "window",
+ value: {
+ context: content.frames[0].browsingContext.id.toString(),
+ },
+ },
+ },
+ {
+ value: content.document.querySelector("iframe").contentWindow,
+ serialized: {
+ type: "window",
+ value: {
+ context: content.document
+ .querySelector("iframe")
+ .contentWindow.browsingContext.id.toString(),
+ },
+ },
+ },
+ ];
+
+ for (const type of REMOTE_COMPLEX_VALUES) {
+ serializeAndAssertRemoteValue(type);
+ }
+ });
+});
+
+add_task(async function test_serializeNodeChildren() {
+ await loadURL(inline("<div></div><iframe/>"));
+
+ await runTestInContent(() => {
+ // Add the used elements to the cache so that we know the unique reference.
+ const bodyEl = content.document.body;
+ const domEl = bodyEl.querySelector("div");
+ const iframeEl = bodyEl.querySelector("iframe");
+
+ const bodyElRef = nodeCache.getOrCreateNodeReference(bodyEl, seenNodeIds);
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+ const iframeElRef = nodeCache.getOrCreateNodeReference(
+ iframeEl,
+ seenNodeIds
+ );
+
+ const dataSet = [
+ {
+ node: bodyEl,
+ serializationOptions: {
+ maxDomDepth: null,
+ },
+ serialized: {
+ type: "node",
+ sharedId: bodyElRef,
+ value: {
+ nodeType: 1,
+ localName: "body",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 2,
+ children: [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ nodeType: 1,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 0,
+ children: [],
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ {
+ type: "node",
+ sharedId: iframeElRef,
+ value: {
+ nodeType: 1,
+ localName: "iframe",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 0,
+ children: [],
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ ],
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ },
+ {
+ node: bodyEl,
+ serializationOptions: {
+ maxDomDepth: 0,
+ },
+ serialized: {
+ type: "node",
+ sharedId: bodyElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 2,
+ localName: "body",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ },
+ {
+ node: bodyEl,
+ serializationOptions: {
+ maxDomDepth: 1,
+ },
+ serialized: {
+ type: "node",
+ sharedId: bodyElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 2,
+ children: [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ {
+ type: "node",
+ sharedId: iframeElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "iframe",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ ],
+ localName: "body",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ },
+ {
+ node: domEl,
+ serializationOptions: {
+ maxDomDepth: 0,
+ },
+ serialized: {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ },
+ {
+ node: domEl,
+ serializationOptions: {
+ maxDomDepth: 1,
+ },
+ serialized: {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ children: [],
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ },
+ ];
+
+ for (const { node, serializationOptions, serialized } of dataSet) {
+ const { maxDomDepth } = serializationOptions;
+ info(`Checking '${node.localName}' with maxDomDepth ${maxDomDepth}`);
+
+ const serializationInternalMap = new Map();
+
+ const serializedValue = serialize(
+ node,
+ serializationOptions,
+ "none",
+ serializationInternalMap,
+ realm,
+ { nodeCache, seenNodeIds }
+ );
+
+ Assert.deepEqual(serializedValue, serialized, "Got expected structure");
+ }
+ });
+});
+
+add_task(async function test_serializeNodeEmbeddedWithin() {
+ await loadURL(inline("<div>"));
+
+ await runTestInContent(() => {
+ // Add the used elements to the cache so that we know the unique reference.
+ const bodyEl = content.document.body;
+ const domEl = bodyEl.querySelector("div");
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const dataSet = [
+ {
+ embedder: "array",
+ wrapper: node => [node],
+ serialized: {
+ type: "array",
+ value: [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ ],
+ },
+ },
+ {
+ embedder: "map",
+ wrapper: node => {
+ const map = new Map();
+ map.set(node, "elem");
+ return map;
+ },
+ serialized: {
+ type: "map",
+ value: [
+ [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ {
+ type: "string",
+ value: "elem",
+ },
+ ],
+ ],
+ },
+ },
+ {
+ embedder: "map",
+ wrapper: node => {
+ const map = new Map();
+ map.set("elem", node);
+ return map;
+ },
+ serialized: {
+ type: "map",
+ value: [
+ [
+ "elem",
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ ],
+ ],
+ },
+ },
+ {
+ embedder: "object",
+ wrapper: node => ({ elem: node }),
+ serialized: {
+ type: "object",
+ value: [
+ [
+ "elem",
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ ],
+ ],
+ },
+ },
+ {
+ embedder: "set",
+ wrapper: node => {
+ const set = new Set();
+ set.add(node);
+ return set;
+ },
+ serialized: {
+ type: "set",
+ value: [
+ {
+ type: "node",
+ sharedId: domElRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ localName: "div",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: null,
+ },
+ },
+ ],
+ },
+ },
+ ];
+
+ for (const { embedder, wrapper, serialized } of dataSet) {
+ info(`Checking embedding node within ${embedder}`);
+
+ const serializationInternalMap = new Map();
+
+ const serializedValue = serialize(
+ wrapper(domEl),
+ { maxDomDepth: 0 },
+ "none",
+ serializationInternalMap,
+ realm,
+ { nodeCache }
+ );
+
+ Assert.deepEqual(serializedValue, serialized, "Got expected structure");
+ }
+ });
+});
+
+add_task(async function test_serializeShadowRoot() {
+ await runTestInContent(() => {
+ for (const mode of ["open", "closed"]) {
+ info(`Checking shadow root with mode '${mode}'`);
+ const customElement = content.document.createElement(
+ `${mode}-custom-element`
+ );
+ const insideShadowRootElement = content.document.createElement("input");
+ content.document.body.appendChild(customElement);
+ const shadowRoot = customElement.attachShadow({ mode });
+ shadowRoot.appendChild(insideShadowRootElement);
+
+ // Add the used elements to the cache so that we know the unique reference.
+ const customElementRef = nodeCache.getOrCreateNodeReference(
+ customElement,
+ seenNodeIds
+ );
+ const shadowRootRef = nodeCache.getOrCreateNodeReference(
+ shadowRoot,
+ seenNodeIds
+ );
+ const insideShadowRootElementRef = nodeCache.getOrCreateNodeReference(
+ insideShadowRootElement,
+ seenNodeIds
+ );
+
+ const dataSet = [
+ {
+ node: customElement,
+ serializationOptions: {
+ maxDomDepth: 1,
+ },
+ serialized: {
+ type: "node",
+ sharedId: customElementRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ children: [],
+ localName: `${mode}-custom-element`,
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: {
+ sharedId: shadowRootRef,
+ type: "node",
+ value: {
+ childNodeCount: 1,
+ mode,
+ nodeType: 11,
+ },
+ },
+ },
+ },
+ },
+ {
+ node: customElement,
+ serializationOptions: {
+ includeShadowTree: "open",
+ maxDomDepth: 1,
+ },
+ serialized: {
+ type: "node",
+ sharedId: customElementRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ children: [],
+ localName: `${mode}-custom-element`,
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: {
+ sharedId: shadowRootRef,
+ type: "node",
+ value: {
+ childNodeCount: 1,
+ mode,
+ nodeType: 11,
+ ...(mode === "open"
+ ? {
+ children: [
+ {
+ type: "node",
+ sharedId: insideShadowRootElementRef,
+ value: {
+ nodeType: 1,
+ localName: "input",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 0,
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ ],
+ }
+ : {}),
+ },
+ },
+ },
+ },
+ },
+ {
+ node: customElement,
+ serializationOptions: {
+ includeShadowTree: "all",
+ maxDomDepth: 1,
+ },
+ serialized: {
+ type: "node",
+ sharedId: customElementRef,
+ value: {
+ attributes: {},
+ childNodeCount: 0,
+ children: [],
+ localName: `${mode}-custom-element`,
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ nodeType: 1,
+ shadowRoot: {
+ sharedId: shadowRootRef,
+ type: "node",
+ value: {
+ childNodeCount: 1,
+ mode,
+ nodeType: 11,
+ children: [
+ {
+ type: "node",
+ sharedId: insideShadowRootElementRef,
+ value: {
+ nodeType: 1,
+ localName: "input",
+ namespaceURI: "http://www.w3.org/1999/xhtml",
+ childNodeCount: 0,
+ attributes: {},
+ shadowRoot: null,
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ ];
+
+ for (const { node, serializationOptions, serialized } of dataSet) {
+ const { maxDomDepth, includeShadowTree } = serializationOptions;
+ info(
+ `Checking shadow root with maxDomDepth ${maxDomDepth} and includeShadowTree ${includeShadowTree}`
+ );
+
+ const serializationInternalMap = new Map();
+
+ const serializedValue = serialize(
+ node,
+ serializationOptions,
+ "none",
+ serializationInternalMap,
+ realm,
+ { nodeCache }
+ );
+
+ Assert.deepEqual(serializedValue, serialized, "Got expected structure");
+ }
+ }
+ });
+});
+
+add_task(async function test_serializeNodeSharedId() {
+ await loadURL(inline("<div>"));
+
+ await runTestInContent(() => {
+ const domEl = content.document.querySelector("div");
+
+ // Already add the domEl to the cache so that we know the unique reference.
+ const domElRef = nodeCache.getOrCreateNodeReference(domEl, seenNodeIds);
+
+ const serializedValue = serialize(
+ domEl,
+ { maxDomDepth: 0 },
+ "root",
+ serializationInternalMap,
+ realm,
+ { nodeCache, seenNodeIds }
+ );
+
+ Assert.equal(nodeCache.size, 1, "No additional reference added");
+ Assert.equal(serializedValue.sharedId, domElRef);
+ Assert.notEqual(serializedValue.handle, domElRef);
+ });
+});
+
+function runTestInContent(callback) {
+ return SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [callback.toString()],
+ async callback => {
+ const { NodeCache } = ChromeUtils.importESModule(
+ "chrome://remote/content/shared/webdriver/NodeCache.sys.mjs"
+ );
+ const { Realm, WindowRealm } = ChromeUtils.importESModule(
+ "chrome://remote/content/shared/Realm.sys.mjs"
+ );
+ const { deserialize, serialize, setDefaultSerializationOptions } =
+ ChromeUtils.importESModule(
+ "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs"
+ );
+
+ function assertInternalIds(serializationInternalMap, amount) {
+ const remoteValuesWithInternalIds = Array.from(
+ serializationInternalMap.values()
+ ).filter(remoteValue => !!remoteValue.internalId);
+
+ Assert.equal(
+ remoteValuesWithInternalIds.length,
+ amount,
+ "Got expected amount of internalIds in serializationInternalMap"
+ );
+ }
+
+ const nodeCache = new NodeCache();
+ const seenNodeIds = new Map();
+ const realm = new WindowRealm(content);
+ const serializationInternalMap = new Map();
+
+ function serializeAndAssertRemoteValue(remoteValue) {
+ const { value, serialized } = remoteValue;
+ const serializationOptionsWithDefaults =
+ setDefaultSerializationOptions();
+ const serializationInternalMapWithNone = new Map();
+
+ info(`Checking '${serialized.type}' with none ownershipType`);
+
+ const serializedValue = serialize(
+ value,
+ serializationOptionsWithDefaults,
+ "none",
+ serializationInternalMapWithNone,
+ realm,
+ { nodeCache, seenNodeIds }
+ );
+
+ assertInternalIds(serializationInternalMapWithNone, 0);
+ Assert.deepEqual(serialized, serializedValue, "Got expected structure");
+
+ info(`Checking '${serialized.type}' with root ownershipType`);
+ const serializationInternalMapWithRoot = new Map();
+ const serializedWithRoot = serialize(
+ value,
+ serializationOptionsWithDefaults,
+ "root",
+ serializationInternalMapWithRoot,
+ realm,
+ { nodeCache, seenNodeIds }
+ );
+
+ assertInternalIds(serializationInternalMapWithRoot, 0);
+ Assert.equal(
+ typeof serializedWithRoot.handle,
+ "string",
+ "Got a handle property"
+ );
+ Assert.deepEqual(
+ Object.assign({}, serialized, { handle: serializedWithRoot.handle }),
+ serializedWithRoot,
+ "Got expected structure, plus a generated handle id"
+ );
+ }
+
+ // eslint-disable-next-line no-eval
+ eval(`(${callback})()`);
+ }
+ );
+}