From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- remote/webdriver-bidi/test/browser/browser.toml | 8 + .../test/browser/browser_RemoteValue.js | 1117 ++++++++++++++++++++ .../test/browser/browser_RemoteValueDOM.js | 845 +++++++++++++++ remote/webdriver-bidi/test/browser/head.js | 28 + .../test/xpcshell/test_WebDriverBiDiConnection.js | 25 + remote/webdriver-bidi/test/xpcshell/xpcshell.toml | 3 + 6 files changed, 2026 insertions(+) create mode 100644 remote/webdriver-bidi/test/browser/browser.toml create mode 100644 remote/webdriver-bidi/test/browser/browser_RemoteValue.js create mode 100644 remote/webdriver-bidi/test/browser/browser_RemoteValueDOM.js create mode 100644 remote/webdriver-bidi/test/browser/head.js create mode 100644 remote/webdriver-bidi/test/xpcshell/test_WebDriverBiDiConnection.js create mode 100644 remote/webdriver-bidi/test/xpcshell/xpcshell.toml (limited to 'remote/webdriver-bidi/test') diff --git a/remote/webdriver-bidi/test/browser/browser.toml b/remote/webdriver-bidi/test/browser/browser.toml new file mode 100644 index 0000000000..21e54bf538 --- /dev/null +++ b/remote/webdriver-bidi/test/browser/browser.toml @@ -0,0 +1,8 @@ +[DEFAULT] +tags = "wd" +subsuite = "remote" +support-files = ["head.js"] + +["browser_RemoteValue.js"] + +["browser_RemoteValueDOM.js"] diff --git a/remote/webdriver-bidi/test/browser/browser_RemoteValue.js b/remote/webdriver-bidi/test/browser/browser_RemoteValue.js new file mode 100644 index 0000000000..b95636037b --- /dev/null +++ b/remote/webdriver-bidi/test/browser/browser_RemoteValue.js @@ -0,0 +1,1117 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { Realm } = ChromeUtils.importESModule( + "chrome://remote/content/shared/Realm.sys.mjs" +); +const { deserialize, serialize, setDefaultSerializationOptions, stringify } = + ChromeUtils.importESModule( + "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs" + ); + +const PRIMITIVE_TYPES = [ + { value: undefined, serialized: { type: "undefined" } }, + { value: null, serialized: { type: "null" } }, + { value: "foo", serialized: { type: "string", value: "foo" } }, + { value: Number.NaN, serialized: { type: "number", value: "NaN" } }, + { value: -0, serialized: { type: "number", value: "-0" } }, + { + value: Number.POSITIVE_INFINITY, + serialized: { type: "number", value: "Infinity" }, + }, + { + value: Number.NEGATIVE_INFINITY, + serialized: { type: "number", value: "-Infinity" }, + }, + { value: 42, serialized: { type: "number", value: 42 } }, + { value: false, serialized: { type: "boolean", value: false } }, + { value: 42n, serialized: { type: "bigint", value: "42" } }, +]; + +const REMOTE_SIMPLE_VALUES = [ + { + value: new RegExp(/foo/), + serialized: { + type: "regexp", + value: { + pattern: "foo", + flags: "", + }, + }, + deserializable: true, + }, + { + value: new RegExp(/foo/g), + serialized: { + type: "regexp", + value: { + pattern: "foo", + flags: "g", + }, + }, + deserializable: true, + }, + { + value: new Date(1654004849000), + serialized: { + type: "date", + value: "2022-05-31T13:47:29.000Z", + }, + deserializable: true, + }, +]; + +const REMOTE_COMPLEX_VALUES = [ + { value: Symbol("foo"), serialized: { type: "symbol" } }, + { + value: [1], + serialized: { + type: "array", + value: [{ type: "number", value: 1 }], + }, + }, + { + value: [1], + serializationOptions: { + maxObjectDepth: 0, + }, + serialized: { + type: "array", + }, + }, + { + value: [1, "2", true, new RegExp(/foo/g)], + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "array", + value: [ + { type: "number", value: 1 }, + { type: "string", value: "2" }, + { type: "boolean", value: true }, + { + type: "regexp", + value: { + pattern: "foo", + flags: "g", + }, + }, + ], + }, + deserializable: true, + }, + { + value: [1, [3, "4"]], + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "array", + value: [{ type: "number", value: 1 }, { type: "array" }], + }, + }, + { + value: [1, [3, "4"]], + serializationOptions: { + maxObjectDepth: 2, + }, + serialized: { + type: "array", + value: [ + { type: "number", value: 1 }, + { + type: "array", + value: [ + { type: "number", value: 3 }, + { type: "string", value: "4" }, + ], + }, + ], + }, + deserializable: true, + }, + { + value: new Map(), + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "map", + value: [], + }, + deserializable: true, + }, + { + value: new Map([]), + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "map", + value: [], + }, + deserializable: true, + }, + { + value: new Map([ + [1, 2], + ["2", "3"], + [true, false], + ]), + serialized: { + type: "map", + value: [ + [ + { type: "number", value: 1 }, + { type: "number", value: 2 }, + ], + ["2", { type: "string", value: "3" }], + [ + { type: "boolean", value: true }, + { type: "boolean", value: false }, + ], + ], + }, + }, + { + value: new Map([ + [1, 2], + ["2", "3"], + [true, false], + ]), + serializationOptions: { + maxObjectDepth: 0, + }, + serialized: { + type: "map", + }, + }, + { + value: new Map([ + [1, 2], + ["2", "3"], + [true, false], + ]), + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "map", + value: [ + [ + { type: "number", value: 1 }, + { type: "number", value: 2 }, + ], + ["2", { type: "string", value: "3" }], + [ + { type: "boolean", value: true }, + { type: "boolean", value: false }, + ], + ], + }, + deserializable: true, + }, + { + value: new Set(), + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "set", + value: [], + }, + deserializable: true, + }, + { + value: new Set([]), + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "set", + value: [], + }, + deserializable: true, + }, + { + value: new Set([1, "2", true]), + serialized: { + type: "set", + value: [ + { type: "number", value: 1 }, + { type: "string", value: "2" }, + { type: "boolean", value: true }, + ], + }, + }, + { + value: new Set([1, "2", true]), + serializationOptions: { + maxObjectDepth: 0, + }, + serialized: { + type: "set", + }, + }, + { + value: new Set([1, "2", true]), + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "set", + value: [ + { type: "number", value: 1 }, + { type: "string", value: "2" }, + { type: "boolean", value: true }, + ], + }, + deserializable: true, + }, + { value: new WeakMap([[{}, 1]]), serialized: { type: "weakmap" } }, + { value: new WeakSet([{}]), serialized: { type: "weakset" } }, + { + value: (function* () { + yield "a"; + })(), + serialized: { type: "generator" }, + }, + { + value: (async function* () { + yield await Promise.resolve(1); + })(), + serialized: { type: "generator" }, + }, + { value: new Error("error message"), serialized: { type: "error" } }, + { + value: new SyntaxError("syntax error message"), + serialized: { type: "error" }, + }, + { + value: new TypeError("type error message"), + serialized: { type: "error" }, + }, + { value: new Proxy({}, {}), serialized: { type: "proxy" } }, + { value: new Promise(() => true), serialized: { type: "promise" } }, + { value: new Int8Array(), serialized: { type: "typedarray" } }, + { value: new ArrayBuffer(), serialized: { type: "arraybuffer" } }, + { value: new URL("https://example.com"), serialized: { type: "object" } }, + { value: () => true, serialized: { type: "function" } }, + { value() {}, serialized: { type: "function" } }, + { + value: {}, + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "object", + value: [], + }, + deserializable: true, + }, + { + value: { + 1: 1, + 2: "2", + foo: true, + }, + serialized: { + type: "object", + value: [ + ["1", { type: "number", value: 1 }], + ["2", { type: "string", value: "2" }], + ["foo", { type: "boolean", value: true }], + ], + }, + }, + { + value: { + 1: 1, + 2: "2", + foo: true, + }, + serializationOptions: { + maxObjectDepth: 0, + }, + serialized: { + type: "object", + }, + }, + { + value: { + 1: 1, + 2: "2", + foo: true, + }, + serializationOptions: { + maxObjectDepth: 1, + }, + serialized: { + type: "object", + value: [ + ["1", { type: "number", value: 1 }], + ["2", { type: "string", value: "2" }], + ["foo", { type: "boolean", value: true }], + ], + }, + deserializable: true, + }, + { + value: { + 1: 1, + 2: "2", + 3: { + bar: "foo", + }, + foo: true, + }, + serializationOptions: { + maxObjectDepth: 2, + }, + serialized: { + type: "object", + value: [ + ["1", { type: "number", value: 1 }], + ["2", { type: "string", value: "2" }], + [ + "3", + { + type: "object", + value: [["bar", { type: "string", value: "foo" }]], + }, + ], + ["foo", { type: "boolean", value: true }], + ], + }, + deserializable: true, + }, +]; + +add_task(function test_deserializePrimitiveTypes() { + const realm = new Realm(); + + for (const type of PRIMITIVE_TYPES) { + const { value: expectedValue, serialized } = type; + + info(`Checking '${serialized.type}'`); + const value = deserialize(serialized, realm, {}); + + if (serialized.value == "NaN") { + ok(Number.isNaN(value), `Got expected value for ${serialized}`); + } else { + Assert.strictEqual( + value, + expectedValue, + `Got expected value for ${serialized}` + ); + } + } +}); + +add_task(function test_deserializeDateLocalValue() { + const realm = new Realm(); + + const validaDateStrings = [ + "2009", + "2009-05", + "2009-05-19", + "2022-02-29", + "2009T15:00", + "2009-05T15:00", + "2022-06-31T15:00", + "2009-05-19T15:00", + "2009-05-19T15:00:15", + "2009-05-19T15:00-00:00", + "2009-05-19T15:00:15.452", + "2009-05-19T15:00:15.452Z", + "2009-05-19T15:00:15.452+02:00", + "2009-05-19T15:00:15.452-02:00", + "-271821-04-20T00:00:00Z", + "+000000-01-01T00:00:00Z", + ]; + for (const dateString of validaDateStrings) { + info(`Checking '${dateString}'`); + const value = deserialize({ type: "date", value: dateString }, realm, {}); + + Assert.equal( + value.getTime(), + new Date(dateString).getTime(), + `Got expected value for ${dateString}` + ); + } +}); + +add_task(function test_deserializeLocalValues() { + const realm = new Realm(); + + for (const type of REMOTE_SIMPLE_VALUES.concat(REMOTE_COMPLEX_VALUES)) { + const { value: expectedValue, serialized, deserializable } = type; + + // Skip non deserializable cases + if (!deserializable) { + continue; + } + + info(`Checking '${serialized.type}'`); + const value = deserialize(serialized, realm, {}); + assertLocalValue(serialized.type, value, expectedValue); + } +}); + +add_task(async function test_deserializeLocalValuesInWindowRealm() { + for (const type of REMOTE_SIMPLE_VALUES.concat(REMOTE_COMPLEX_VALUES)) { + const { value: expectedValue, serialized, deserializable } = type; + + // Skip non deserializable cases + if (!deserializable) { + continue; + } + + const value = await deserializeInWindowRealm(serialized); + assertLocalValue(serialized.type, value, expectedValue); + } +}); + +add_task(async function test_deserializeChannel() { + const realm = new Realm(); + const channel = { + type: "channel", + value: { channel: "channel_name" }, + }; + const deserializationOptions = { + emitScriptMessage: (realm, channelProperties, message) => message, + }; + + info(`Checking 'channel'`); + const value = deserialize(channel, realm, deserializationOptions, {}); + Assert.equal( + Object.prototype.toString.call(value), + "[object Function]", + "Got expected type Function" + ); + Assert.equal(value("foo"), "foo", "Got expected result"); +}); + +add_task(function test_deserializeLocalValuesByHandle() { + // Create two realms, realm1 will be used to serialize values, while realm2 + // will be used as a reference empty realm without any object reference. + const realm1 = new Realm(); + const realm2 = new Realm(); + + for (const type of REMOTE_SIMPLE_VALUES.concat(REMOTE_COMPLEX_VALUES)) { + const { value: expectedValue, serialized } = type; + + // No need to skip non-deserializable cases here. + + info(`Checking '${serialized.type}'`); + // Serialize the value once to get a handle. + const serializedValue = serialize( + expectedValue, + { maxObjectDepth: 0 }, + "root", + new Map(), + realm1, + {} + ); + + // Create a remote reference containing only the handle. + // `deserialize` should not need any other property. + const remoteReference = { handle: serializedValue.handle }; + + // Check that the remote reference can be deserialized in realm1. + const value = deserialize(remoteReference, realm1, {}); + assertLocalValue(serialized.type, value, expectedValue); + + Assert.throws( + () => deserialize(remoteReference, realm2, {}), + /NoSuchHandleError:/, + `Got expected error when using the wrong realm for deserialize` + ); + + realm1.removeObjectHandle(serializedValue.handle); + Assert.throws( + () => deserialize(remoteReference, realm1, {}), + /NoSuchHandleError:/, + `Got expected error when after deleting the object handle` + ); + } +}); + +add_task(function test_deserializeHandleInvalidTypes() { + const realm = new Realm(); + + for (const invalidType of [false, 42, {}, []]) { + info(`Checking type: '${invalidType}'`); + + Assert.throws( + () => deserialize({ type: "object", handle: invalidType }, realm, {}), + /InvalidArgumentError:/, + `Got expected error for type ${invalidType}` + ); + } +}); + +add_task(function test_deserializePrimitiveTypesInvalidValues() { + const realm = new Realm(); + + const invalidValues = [ + { type: "bigint", values: [undefined, null, false, "foo", [], {}] }, + { type: "boolean", values: [undefined, null, 42, "foo", [], {}] }, + { + type: "number", + values: [undefined, null, false, "43", [], {}], + }, + { type: "string", values: [undefined, null, false, 42, [], {}] }, + ]; + + for (const invalidValue of invalidValues) { + const { type, values } = invalidValue; + + for (const value of values) { + info(`Checking '${type}' with value ${value}`); + + Assert.throws( + () => deserialize({ type, value }, realm, {}), + /InvalidArgument/, + `Got expected error for type ${type} and value ${value}` + ); + } + } +}); + +add_task(function test_deserializeDateLocalValueInvalidValues() { + const realm = new Realm(); + + const invalidaDateStrings = [ + "10", + "20009", + "+20009", + "2009-", + "2009-0", + "2009-15", + "2009-02-1", + "2009-02-50", + "15:00", + "T15:00", + "9-05-19T15:00", + "2009-5-19T15:00", + "2009-05-1T15:00", + "2009-02-10T15", + "2009-05-19T15:", + "2009-05-19T1:00", + "2009-05-19T10:1", + "2009-05-19T60:00", + "2009-05-19T15:70", + "2009-05-19T15:00.25", + "2009-05-19+10:00", + "2009-05-19Z", + "2009-05-19 15:00", + "2009-05-19t15:00Z", + "2009-05-19T15:00z", + "2009-05-19T15:00+01", + "2009-05-19T10:10+1:00", + "2009-05-19T10:10+01:1", + "2009-05-19T15:00+75:00", + "2009-05-19T15:00+02:80", + "02009-05-19T15:00", + ]; + for (const dateString of invalidaDateStrings) { + info(`Checking '${dateString}'`); + + Assert.throws( + () => deserialize({ type: "date", value: dateString }, realm, {}), + /InvalidArgumentError:/, + `Got expected error for date string: ${dateString}` + ); + } +}); + +add_task(function test_deserializeLocalValuesInvalidType() { + const realm = new Realm(); + + const invalidTypes = [undefined, null, false, 42, {}]; + + for (const invalidType of invalidTypes) { + info(`Checking type: '${invalidType}'`); + + Assert.throws( + () => deserialize({ type: invalidType }, realm, {}), + /InvalidArgumentError:/, + `Got expected error for type ${invalidType}` + ); + + Assert.throws( + () => + deserialize( + { + type: "array", + value: [{ type: invalidType }], + }, + realm, + {} + ), + /InvalidArgumentError:/, + `Got expected error for nested type ${invalidType}` + ); + } +}); + +add_task(function test_deserializeLocalValuesInvalidValues() { + const realm = new Realm(); + + const invalidValues = [ + { type: "array", values: [undefined, null, false, 42, "foo", {}] }, + { + type: "regexp", + values: [ + undefined, + null, + false, + "foo", + 42, + [], + {}, + { pattern: null }, + { pattern: 1 }, + { pattern: true }, + { pattern: "foo", flags: null }, + { pattern: "foo", flags: 1 }, + { pattern: "foo", flags: false }, + { pattern: "foo", flags: "foo" }, + ], + }, + { + type: "date", + values: [ + undefined, + null, + false, + "foo", + "05 October 2011 14:48 UTC", + "Tue Jun 14 2022 10:46:50 GMT+0200!", + 42, + [], + {}, + ], + }, + { + type: "map", + values: [ + undefined, + null, + false, + "foo", + 42, + ["1"], + [[]], + [["1"]], + [{ 1: "2" }], + {}, + ], + }, + { + type: "set", + values: [undefined, null, false, "foo", 42, {}], + }, + { + type: "object", + values: [ + undefined, + null, + false, + "foo", + 42, + {}, + ["1"], + [[]], + [["1"]], + [{ 1: "2" }], + [ + [ + { type: "number", value: "1" }, + { type: "number", value: "2" }, + ], + ], + [ + [ + { type: "object", value: [] }, + { type: "number", value: "1" }, + ], + ], + [ + [ + { + type: "regexp", + value: { + pattern: "foo", + }, + }, + { type: "number", value: "1" }, + ], + ], + ], + }, + ]; + + for (const invalidValue of invalidValues) { + const { type, values } = invalidValue; + + for (const value of values) { + info(`Checking '${type}' with value ${value}`); + + Assert.throws( + () => deserialize({ type, value }, realm, {}), + /InvalidArgumentError:/, + `Got expected error for type ${type} and value ${value}` + ); + } + } +}); + +add_task(function test_serializePrimitiveTypes() { + const realm = new Realm(); + + for (const type of PRIMITIVE_TYPES) { + const { value, serialized } = type; + const defaultSerializationOptions = setDefaultSerializationOptions(); + + const serializationInternalMap = new Map(); + const serializedValue = serialize( + value, + defaultSerializationOptions, + "none", + serializationInternalMap, + realm, + {} + ); + assertInternalIds(serializationInternalMap, 0); + Assert.deepEqual(serialized, serializedValue, "Got expected structure"); + + // For primitive values, the serialization with ownershipType=root should + // be exactly identical to the one with ownershipType=none. + const serializationInternalMapWithRoot = new Map(); + const serializedWithRoot = serialize( + value, + defaultSerializationOptions, + "root", + serializationInternalMapWithRoot, + realm, + {} + ); + assertInternalIds(serializationInternalMapWithRoot, 0); + Assert.deepEqual(serialized, serializedWithRoot, "Got expected structure"); + } +}); + +add_task(function test_serializeRemoteSimpleValues() { + const realm = new Realm(); + + for (const type of REMOTE_SIMPLE_VALUES) { + const { value, serialized } = type; + const defaultSerializationOptions = setDefaultSerializationOptions(); + + info(`Checking '${serialized.type}' with none ownershipType`); + const serializationInternalMapWithNone = new Map(); + const serializedValue = serialize( + value, + defaultSerializationOptions, + "none", + serializationInternalMapWithNone, + realm, + {} + ); + + 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, + defaultSerializationOptions, + "root", + serializationInternalMapWithRoot, + realm, + {} + ); + + 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" + ); + } +}); + +add_task(function test_serializeRemoteComplexValues() { + for (const type of REMOTE_COMPLEX_VALUES) { + const { value, serialized, serializationOptions } = type; + const serializationOptionsWithDefaults = + setDefaultSerializationOptions(serializationOptions); + + info(`Checking '${serialized.type}' with none ownershipType`); + const realm = new Realm(); + const serializationInternalMapWithNone = new Map(); + + const serializedValue = serialize( + value, + serializationOptionsWithDefaults, + "none", + serializationInternalMapWithNone, + realm, + {} + ); + + 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, + {} + ); + + 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" + ); + } +}); + +add_task(function test_serializeWithSerializationInternalMap() { + const dataSet = [ + { + data: [1], + serializedData: [{ type: "number", value: 1 }], + type: "array", + }, + { + data: new Map([[true, false]]), + serializedData: [ + [ + { type: "boolean", value: true }, + { type: "boolean", value: false }, + ], + ], + type: "map", + }, + { + data: new Set(["foo"]), + serializedData: [{ type: "string", value: "foo" }], + type: "set", + }, + { + data: { foo: "bar" }, + serializedData: [["foo", { type: "string", value: "bar" }]], + type: "object", + }, + ]; + const realm = new Realm(); + + for (const { type, data, serializedData } of dataSet) { + info(`Checking '${type}' with serializationInternalMap`); + + const serializationInternalMap = new Map(); + const value = [ + data, + data, + [data], + new Set([data]), + new Map([["bar", data]]), + { bar: data }, + ]; + + const serializedValue = serialize( + value, + { maxObjectDepth: 2 }, + "none", + serializationInternalMap, + realm, + {} + ); + + assertInternalIds(serializationInternalMap, 1); + + const internalId = serializationInternalMap.get(data).internalId; + + const serialized = { + type: "array", + value: [ + { + type, + value: serializedData, + internalId, + }, + { + type, + internalId, + }, + { + type: "array", + value: [{ type, internalId }], + }, + { + type: "set", + value: [{ type, internalId }], + }, + { + type: "map", + value: [["bar", { type, internalId }]], + }, + { + type: "object", + value: [["bar", { type, internalId }]], + }, + ], + }; + + Assert.deepEqual(serialized, serializedValue, "Got expected structure"); + } +}); + +add_task(function test_serializeMultipleValuesWithSerializationInternalMap() { + const realm = new Realm(); + const serializationInternalMap = new Map(); + const obj1 = { foo: "bar" }; + const obj2 = [1, 2]; + const value = [obj1, obj2, obj1, obj2]; + + serialize( + value, + { maxObjectDepth: 2 }, + "none", + serializationInternalMap, + realm, + {} + ); + + assertInternalIds(serializationInternalMap, 2); + + const internalId1 = serializationInternalMap.get(obj1).internalId; + const internalId2 = serializationInternalMap.get(obj2).internalId; + + Assert.notEqual( + internalId1, + internalId2, + "Internal ids for different object are also different" + ); +}); + +add_task(function test_stringify() { + const STRINGIFY_TEST_CASES = [ + [undefined, "undefined"], + [null, "null"], + ["foobar", "foobar"], + ["2", "2"], + [-0, "0"], + [Infinity, "Infinity"], + [-Infinity, "-Infinity"], + [3, "3"], + [1.4, "1.4"], + [true, "true"], + [42n, "42"], + [{ toString: () => "bar" }, "bar", "toString: () => 'bar'"], + [{ toString: () => 4 }, "[object Object]", "toString: () => 4"], + [{ toString: undefined }, "[object Object]", "toString: undefined"], + [{ toString: null }, "[object Object]", "toString: null"], + [ + { + toString: () => { + throw new Error("toString error"); + }, + }, + "[object Object]", + "toString: () => { throw new Error('toString error'); }", + ], + ]; + + for (const [value, expectedString, description] of STRINGIFY_TEST_CASES) { + info(`Checking '${description || value}'`); + const stringifiedValue = stringify(value); + + Assert.strictEqual(expectedString, stringifiedValue, "Got expected string"); + } +}); + +function assertLocalValue(type, value, expectedValue) { + let formattedValue = value; + let formattedExpectedValue = expectedValue; + + // Format certain types for easier assertion + if (type == "map") { + Assert.equal( + Object.prototype.toString.call(expectedValue), + "[object Map]", + "Got expected type Map" + ); + + formattedValue = Array.from(value.values()); + formattedExpectedValue = Array.from(expectedValue.values()); + } else if (type == "set") { + Assert.equal( + Object.prototype.toString.call(expectedValue), + "[object Set]", + "Got expected type Set" + ); + + formattedValue = Array.from(value); + formattedExpectedValue = Array.from(expectedValue); + } + + Assert.deepEqual( + formattedValue, + formattedExpectedValue, + "Got expected structure" + ); +} + +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" + ); +} + +function deserializeInWindowRealm(serialized) { + return SpecialPowers.spawn( + gBrowser.selectedBrowser, + [serialized], + async _serialized => { + const { WindowRealm } = ChromeUtils.importESModule( + "chrome://remote/content/shared/Realm.sys.mjs" + ); + const { deserialize } = ChromeUtils.importESModule( + "chrome://remote/content/webdriver-bidi/RemoteValue.sys.mjs" + ); + const realm = new WindowRealm(content); + info(`Checking '${_serialized.type}'`); + return deserialize(_serialized, realm, {}); + } + ); +} 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("
")); + + 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("
")); + + 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("
")); + + 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("