forked from mirrors/gecko-dev
506 lines
13 KiB
JavaScript
506 lines
13 KiB
JavaScript
/* 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"
|
|
);
|
|
});
|