summaryrefslogtreecommitdiffstats
path: root/remote/test/browser/runtime/browser_evaluate.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--remote/test/browser/runtime/browser_evaluate.js506
1 files changed, 506 insertions, 0 deletions
diff --git a/remote/test/browser/runtime/browser_evaluate.js b/remote/test/browser/runtime/browser_evaluate.js
new file mode 100644
index 0000000000..61ab7b9dbe
--- /dev/null
+++ b/remote/test/browser/runtime/browser_evaluate.js
@@ -0,0 +1,506 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_DOC = toDataURL("default-test-page");
+
+add_task(async function awaitPromiseInvalidTypes({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ for (const awaitPromise of [null, 1, "foo", [], {}]) {
+ let errorThrown = "";
+ try {
+ await Runtime.evaluate({
+ expression: "",
+ awaitPromise,
+ });
+ } catch (e) {
+ errorThrown = e.message;
+ }
+ ok(errorThrown.includes("awaitPromise: boolean value expected"));
+ }
+});
+
+add_task(async function awaitPromiseResolve({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "Promise.resolve(42)",
+ awaitPromise: true,
+ });
+
+ is(result.type, "number", "The type is correct");
+ is(result.subtype, undefined, "The subtype is undefined for numbers");
+ is(result.value, 42, "The result is the promise's resolution");
+});
+
+add_task(async function awaitPromiseReject({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { exceptionDetails } = await Runtime.evaluate({
+ expression: "Promise.reject(42)",
+ awaitPromise: true,
+ });
+ // TODO: Implement all values for exceptionDetails (bug 1548480)
+ is(
+ exceptionDetails.exception.value,
+ 42,
+ "The result is the promise's rejection"
+ );
+});
+
+add_task(async function awaitPromiseDelayedResolve({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "new Promise(r => setTimeout(() => r(42), 0))",
+ awaitPromise: true,
+ });
+ is(result.type, "number", "The type is correct");
+ is(result.subtype, undefined, "The subtype is undefined for numbers");
+ is(result.value, 42, "The result is the promise's resolution");
+});
+
+add_task(async function awaitPromiseDelayedReject({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { exceptionDetails } = await Runtime.evaluate({
+ expression: "new Promise((_,r) => setTimeout(() => r(42), 0))",
+ awaitPromise: true,
+ });
+ is(
+ exceptionDetails.exception.value,
+ 42,
+ "The result is the promise's rejection"
+ );
+});
+
+add_task(async function awaitPromiseResolveWithoutWait({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "Promise.resolve(42)",
+ awaitPromise: false,
+ });
+
+ is(result.type, "object", "The type is correct");
+ is(result.subtype, "promise", "The subtype is promise");
+ ok(!!result.objectId, "We got the object id for the promise");
+ ok(!result.value, "We do not receive any value");
+});
+
+add_task(async function awaitPromiseDelayedResolveWithoutWait({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "new Promise(r => setTimeout(() => r(42), 0))",
+ awaitPromise: false,
+ });
+
+ is(result.type, "object", "The type is correct");
+ is(result.subtype, "promise", "The subtype is promise");
+ ok(!!result.objectId, "We got the object id for the promise");
+ ok(!result.value, "We do not receive any value");
+});
+
+add_task(async function awaitPromiseRejectWithoutWait({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "Promise.reject(42)",
+ awaitPromise: false,
+ });
+
+ is(result.type, "object", "The type is correct");
+ is(result.subtype, "promise", "The subtype is promise");
+ ok(!!result.objectId, "We got the object id for the promise");
+ ok(!result.exceptionDetails, "We do not receive any exception");
+});
+
+add_task(async function awaitPromiseDelayedRejectWithoutWait({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "new Promise((_,r) => setTimeout(() => r(42), 0))",
+ awaitPromise: false,
+ });
+
+ is(result.type, "object", "The type is correct");
+ is(result.subtype, "promise", "The subtype is promise");
+ ok(!!result.objectId, "We got the object id for the promise");
+ ok(!result.exceptionDetails, "We do not receive any exception");
+});
+
+add_task(async function contextIdInvalidValue({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ let errorThrown = "";
+ try {
+ await Runtime.evaluate({ expression: "", contextId: -1 });
+ } catch (e) {
+ errorThrown = e.message;
+ }
+ ok(errorThrown.includes("Cannot find context with specified id"));
+});
+
+add_task(async function contextIdNotSpecified({ client }) {
+ const { Runtime } = client;
+
+ await loadURL(TEST_DOC);
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({ expression: "location.href" });
+ is(result.value, TEST_DOC, "Works against the current document");
+});
+
+add_task(async function contextIdSpecified({ client }) {
+ const { Runtime } = client;
+
+ await loadURL(TEST_DOC);
+ const { id: contextId } = await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "location.href",
+ contextId,
+ });
+ is(result.value, TEST_DOC, "Works against the targetted document");
+});
+
+add_task(async function returnAsObjectTypes({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const expressions = [
+ { expression: "({foo:true})", type: "object", subtype: undefined },
+ { expression: "Symbol('foo')", type: "symbol", subtype: undefined },
+ { expression: "new Promise(()=>{})", type: "object", subtype: "promise" },
+ { expression: "new Int8Array(8)", type: "object", subtype: "typedarray" },
+ { expression: "new WeakMap()", type: "object", subtype: "weakmap" },
+ { expression: "new WeakSet()", type: "object", subtype: "weakset" },
+ { expression: "new Map()", type: "object", subtype: "map" },
+ { expression: "new Set()", type: "object", subtype: "set" },
+ { expression: "/foo/", type: "object", subtype: "regexp" },
+ { expression: "[1, 2]", type: "object", subtype: "array" },
+ { expression: "new Proxy({}, {})", type: "object", subtype: "proxy" },
+ { expression: "new Date()", type: "object", subtype: "date" },
+ {
+ expression: "document",
+ type: "object",
+ subtype: "node",
+ className: "HTMLDocument",
+ description: "#document",
+ },
+ {
+ expression: `(() => {{
+ const div = document.createElement('div');
+ div.id = "foo";
+ return div;
+ }})()`,
+ type: "object",
+ subtype: "node",
+ className: "HTMLDivElement",
+ description: "div#foo",
+ },
+ ];
+
+ for (const entry of expressions) {
+ const { expression, type, subtype, className, description } = entry;
+
+ const { result } = await Runtime.evaluate({ expression });
+
+ is(result.type, type, "The type is correct");
+ is(result.subtype, subtype, "The subtype is correct");
+ ok(!!result.objectId, "Got an object id");
+ if (className) {
+ is(result.className, className, "The className is correct");
+ }
+ if (description) {
+ is(result.description, description, "The description is correct");
+ }
+ }
+});
+
+add_task(async function returnAsObjectDifferentObjectIds({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const expressions = [{}, "document"];
+ for (const expression of expressions) {
+ const { result: result1 } = await Runtime.evaluate({
+ expression: JSON.stringify(expression),
+ });
+ const { result: result2 } = await Runtime.evaluate({
+ expression: JSON.stringify(expression),
+ });
+ is(
+ result1.objectId,
+ result2.objectId,
+ `Different object ids returned for ${expression}`
+ );
+ }
+});
+
+add_task(async function returnAsObjectPrimitiveTypes({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const expressions = [42, "42", true, 4.2];
+ for (const expression of expressions) {
+ const { result } = await Runtime.evaluate({
+ expression: JSON.stringify(expression),
+ });
+ is(result.value, expression, `Evaluating primitive '${expression}' works`);
+ is(result.type, typeof expression, `${expression} type is correct`);
+ }
+});
+
+add_task(async function returnAsObjectNotSerializable({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const notSerializableNumbers = {
+ number: ["-0", "NaN", "Infinity", "-Infinity"],
+ bigint: ["42n"],
+ };
+
+ for (const type in notSerializableNumbers) {
+ for (const expression of notSerializableNumbers[type]) {
+ const { result } = await Runtime.evaluate({ expression });
+ Assert.deepEqual(
+ result,
+ {
+ type,
+ unserializableValue: expression,
+ description: expression,
+ },
+ `Evaluating unserializable '${expression}' works`
+ );
+ }
+ }
+});
+
+// `null` is special as it has its own subtype, is of type 'object'
+// but is returned as a value, without an `objectId` attribute
+add_task(async function returnAsObjectNull({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "null",
+ });
+ Assert.deepEqual(
+ result,
+ {
+ type: "object",
+ subtype: "null",
+ value: null,
+ },
+ "Null type is correct"
+ );
+});
+
+// undefined doesn't work with JSON.stringify, so test it independently
+add_task(async function returnAsObjectUndefined({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "undefined",
+ });
+ Assert.deepEqual(
+ result,
+ {
+ type: "undefined",
+ },
+ "Undefined type is correct"
+ );
+});
+
+add_task(async function returnByValueInvalidTypes({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ for (const returnByValue of [null, 1, "foo", [], {}]) {
+ let errorThrown = "";
+ try {
+ await Runtime.evaluate({
+ expression: "",
+ returnByValue,
+ });
+ } catch (e) {
+ errorThrown = e.message;
+ }
+ ok(errorThrown.includes("returnByValue: boolean value expected"));
+ }
+});
+
+add_task(async function returnByValue({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const values = [
+ null,
+ 42,
+ 42.0,
+ "42",
+ true,
+ false,
+ { foo: true },
+ { foo: { bar: 42, str: "str", array: [1, 2, 3] } },
+ [42, "42", true],
+ [{ foo: true }],
+ ];
+
+ for (const value of values) {
+ const { result } = await Runtime.evaluate({
+ expression: `(${JSON.stringify(value)})`,
+ returnByValue: true,
+ });
+
+ Assert.deepEqual(
+ result,
+ {
+ type: typeof value,
+ value,
+ description: value != null ? value.toString() : value,
+ },
+ `Returned expected value for ${JSON.stringify(value)}`
+ );
+ }
+});
+
+add_task(async function returnByValueNotSerializable({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const notSerializableNumbers = {
+ number: ["-0", "NaN", "Infinity", "-Infinity"],
+ bigint: ["42n"],
+ };
+
+ for (const type in notSerializableNumbers) {
+ for (const unserializableValue of notSerializableNumbers[type]) {
+ const { result } = await Runtime.evaluate({
+ expression: `(${unserializableValue})`,
+ returnByValue: true,
+ });
+
+ Assert.deepEqual(
+ result,
+ {
+ type,
+ unserializableValue,
+ description: unserializableValue,
+ },
+ `Returned expected value for ${JSON.stringify(unserializableValue)}`
+ );
+ }
+ }
+});
+
+// Test undefined individually as JSON.stringify doesn't return a string
+add_task(async function returnByValueUndefined({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { result } = await Runtime.evaluate({
+ expression: "undefined",
+ returnByValue: true,
+ });
+
+ Assert.deepEqual(
+ result,
+ {
+ type: "undefined",
+ },
+ "Undefined type is correct"
+ );
+});
+
+add_task(async function exceptionDetailsJavascriptError({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { exceptionDetails } = await Runtime.evaluate({
+ expression: "doesNotExists()",
+ });
+
+ Assert.deepEqual(
+ exceptionDetails,
+ {
+ text: "doesNotExists is not defined",
+ },
+ "Javascript error is passed to the client"
+ );
+});
+
+add_task(async function exceptionDetailsThrowError({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { exceptionDetails } = await Runtime.evaluate({
+ expression: "throw new Error('foo')",
+ });
+
+ Assert.deepEqual(
+ exceptionDetails,
+ {
+ text: "foo",
+ },
+ "Exception details are passed to the client"
+ );
+});
+
+add_task(async function exceptionDetailsThrowValue({ client }) {
+ const { Runtime } = client;
+
+ await enableRuntime(client);
+
+ const { exceptionDetails } = await Runtime.evaluate({
+ expression: "throw 'foo'",
+ });
+
+ Assert.deepEqual(
+ exceptionDetails,
+ {
+ exception: {
+ type: "string",
+ value: "foo",
+ },
+ },
+ "Exception details are passed as a RemoteObject"
+ );
+});