diff options
Diffstat (limited to '')
-rw-r--r-- | remote/test/browser/runtime/browser_evaluate.js | 506 |
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" + ); +}); |