Skip to content

Commit

Permalink
Bug 1623581 - [remote] Refactor Runtime.evaluate and Runtime.callFunc…
Browse files Browse the repository at this point in the history
…tionOn browser chrome tests. r=remote-protocol-reviewers,maja_zf

Tests are mixing APIs between each other, which this patch removes.

Also error messages have been adjusted for both methods to
be on par with Chrome.

Differential Revision: https://phabricator.services.mozilla.com/D67840

--HG--
extra : moz-landing-system : lando
  • Loading branch information
whimboo committed Mar 24, 2020
1 parent 9f05df4 commit bc1a519
Show file tree
Hide file tree
Showing 3 changed files with 965 additions and 401 deletions.
162 changes: 112 additions & 50 deletions remote/domains/content/Runtime.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -96,29 +96,6 @@ class Runtime extends ContentProcessDomain {
}
}

evaluate({ expression, contextId = null } = {}) {
let context;
if (contextId) {
context = this.contexts.get(contextId);
if (!context) {
throw new Error(
`Unable to find execution context with id: ${contextId}`
);
}
} else {
context = this._getDefaultContextForWindow();
}

if (typeof expression != "string") {
throw new Error(
`Expecting 'expression' attribute to be a string. ` +
`But was: ${typeof expression}`
);
}

return context.evaluate(expression);
}

releaseObject({ objectId }) {
let context = null;
for (const ctx of this.contexts.values()) {
Expand All @@ -133,53 +110,138 @@ class Runtime extends ContentProcessDomain {
context.releaseObject(objectId);
}

callFunctionOn(request) {
/**
* Calls function with given declaration on the given object.
*
* Object group of the result is inherited from the target object.
*
* @param {Object} options
* @param {string} options.functionDeclaration
* Declaration of the function to call.
* @param {Array.<Object>=} options.arguments
* Call arguments. All call arguments must belong to the same
* JavaScript world as the target object.
* @param {boolean=} options.awaitPromise
* Whether execution should `await` for resulting value
* and return once awaited promise is resolved.
* @param {number=} options.executionContextId
* Specifies execution context which global object will be used
* to call function on. Either executionContextId or objectId
* should be specified.
* @param {string=} options.objectId
* Identifier of the object to call function on.
* Either objectId or executionContextId should be specified.
* @param {boolean=} options.returnByValue
* Whether the result is expected to be a JSON object
* which should be sent by value.
*
* @return {Object.<RemoteObject, ExceptionDetails>}
*/
callFunctionOn(options = {}) {
if (typeof options.functionDeclaration != "string") {
throw new TypeError("functionDeclaration: string value expected");
}
if (
typeof options.arguments != "undefined" &&
!Array.isArray(options.arguments)
) {
throw new TypeError("arguments: array value expected");
}
if (!["undefined", "boolean"].includes(typeof options.awaitPromise)) {
throw new TypeError("awaitPromise: boolean value expected");
}
if (!["undefined", "number"].includes(typeof options.executionContextId)) {
throw new TypeError("executionContextId: number value expected");
}
if (!["undefined", "string"].includes(typeof options.objectId)) {
throw new TypeError("objectId: string value expected");
}
if (!["undefined", "boolean"].includes(typeof options.returnByValue)) {
throw new TypeError("returnByValue: boolean value expected");
}

if (
typeof options.executionContextId == "undefined" &&
typeof options.objectId == "undefined"
) {
throw new Error(
"Either objectId or executionContextId must be specified"
);
}

let context = null;
// When an `objectId` is passed, we want to execute the function of a given object
// So we first have to find its ExecutionContext
if (request.objectId) {
if (options.objectId) {
for (const ctx of this.contexts.values()) {
if (ctx.hasRemoteObject(request.objectId)) {
if (ctx.hasRemoteObject(options.objectId)) {
context = ctx;
break;
}
}
if (!context) {
throw new Error(
`Unable to get the context for object with id: ${request.objectId}`
`Unable to get the context for object with id: ${options.objectId}`
);
}
} else {
context = this.contexts.get(request.executionContextId);
context = this.contexts.get(options.executionContextId);
if (!context) {
throw new Error(
`Unable to find execution context with id: ${request.executionContextId}`
);
throw new Error("Cannot find context with specified id");
}
}
if (typeof request.functionDeclaration != "string") {
throw new Error(
"Expect 'functionDeclaration' attribute to be passed and be a string"
);
}
if (request.arguments && !Array.isArray(request.arguments)) {
throw new Error("Expect 'arguments' to be an array");
}
if (request.returnByValue && typeof request.returnByValue != "boolean") {
throw new Error("Expect 'returnByValue' to be a boolean");
}
if (request.awaitPromise && typeof request.awaitPromise != "boolean") {
throw new Error("Expect 'awaitPromise' to be a boolean");
}

return context.callFunctionOn(
request.functionDeclaration,
request.arguments,
request.returnByValue,
request.awaitPromise,
request.objectId
options.functionDeclaration,
options.arguments,
options.returnByValue,
options.awaitPromise,
options.objectId
);
}

/**
* Evaluate expression on global object.
*
* @param {Object} options
* @param {string} options.expression
* Expression to evaluate.
* @param {boolean=} options.awaitPromise [unsupported]
* Whether execution should `await` for resulting value
* and return once awaited promise is resolved.
* @param {number=} options.contextId
* Specifies in which execution context to perform evaluation.
* If the parameter is omitted the evaluation will be performed
* in the context of the inspected page.
* @param {boolean=} options.returnByValue
* Whether the result is expected to be a JSON object
* that should be sent by value. Defaults to false.
* @param {boolean=} options.userGesture [unsupported]
* Whether execution should be treated as initiated by user in the UI.
*
* @return {Object<RemoteObject, exceptionDetails>}
* The evaluation result, and optionally exception details.
*/
evaluate(options = {}) {
const { expression, contextId } = options;

if (typeof expression != "string") {
throw new Error("expression: string value expected");
}

let context;
if (typeof contextId != "undefined") {
context = this.contexts.get(contextId);
if (!context) {
throw new Error("Cannot find context with specified id");
}
} else {
context = this._getDefaultContextForWindow();
}

return context.evaluate(expression);
}

getProperties({ objectId, ownProperties }) {
for (const ctx of this.contexts.values()) {
const obj = ctx.getRemoteObject(objectId);
Expand Down
Loading

0 comments on commit bc1a519

Please sign in to comment.