mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1750541 - [bidi] Implement basic support for "script.callFunction" command r=webdriver-reviewers,whimboo
Depends on D150245 Differential Revision: https://phabricator.services.mozilla.com/D150822
This commit is contained in:
parent
25cf447901
commit
87ebacdf14
@ -121,6 +121,90 @@ class ScriptModule extends Module {
|
|||||||
* @property {RemoteValue} result
|
* @property {RemoteValue} result
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a provided function with given arguments and scope in the provided
|
||||||
|
* target, which is either a realm or a browsing context.
|
||||||
|
*
|
||||||
|
* @param {Object=} options
|
||||||
|
* @param {Array<RemoteValue>=} arguments
|
||||||
|
* The arguments to pass to the function call. [unsupported]
|
||||||
|
* @param {boolean} awaitPromise
|
||||||
|
* Determines if the command should wait for the return value of the
|
||||||
|
* expression to resolve, if this return value is a Promise.
|
||||||
|
* @param {string} functionDeclaration
|
||||||
|
* The expression to evaluate.
|
||||||
|
* @param {OwnershipModel=} resultOwnership [unsupported]
|
||||||
|
* The ownership model to use for the results of this evaluation.
|
||||||
|
* @param {Object} target
|
||||||
|
* The target for the evaluation, which either matches the definition for
|
||||||
|
* a RealmTarget or for ContextTarget.
|
||||||
|
* @param {RemoteValue=} this
|
||||||
|
* The value of the this keyword for the function call. [unsupported]
|
||||||
|
*
|
||||||
|
* @returns {ScriptEvaluateResult}
|
||||||
|
*
|
||||||
|
* @throws {InvalidArgumentError}
|
||||||
|
* If any of the arguments has not the expected type.
|
||||||
|
* @throws {NoSuchFrameError}
|
||||||
|
* If the target cannot be found.
|
||||||
|
*/
|
||||||
|
async callFunction(options = {}) {
|
||||||
|
const {
|
||||||
|
arguments: commandArguments = null,
|
||||||
|
awaitPromise,
|
||||||
|
functionDeclaration,
|
||||||
|
resultOwnership = OwnershipModel.None,
|
||||||
|
target = {},
|
||||||
|
this: thisParameter = null,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
lazy.assert.string(
|
||||||
|
functionDeclaration,
|
||||||
|
`Expected "functionDeclaration" to be a string, got ${functionDeclaration}`
|
||||||
|
);
|
||||||
|
|
||||||
|
lazy.assert.boolean(
|
||||||
|
awaitPromise,
|
||||||
|
`Expected "awaitPromise" to be a boolean, got ${awaitPromise}`
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#assertResultOwnership(resultOwnership);
|
||||||
|
|
||||||
|
if (commandArguments != null) {
|
||||||
|
lazy.assert.array(
|
||||||
|
commandArguments,
|
||||||
|
`Expected "arguments" to be an array, got ${commandArguments}`
|
||||||
|
);
|
||||||
|
throw new lazy.error.UnsupportedOperationError(
|
||||||
|
`"arguments" parameter is not supported yet`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thisParameter != null) {
|
||||||
|
throw new lazy.error.UnsupportedOperationError(
|
||||||
|
`"this" parameter is not supported yet`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { contextId, realmId, sandbox } = this.#assertTarget(target);
|
||||||
|
const realm = this.#getRealmInfoFromTarget({ contextId, realmId, sandbox });
|
||||||
|
const evaluationResult = await this.messageHandler.forwardCommand({
|
||||||
|
moduleName: "script",
|
||||||
|
commandName: "callFunctionDeclaration",
|
||||||
|
destination: {
|
||||||
|
type: lazy.WindowGlobalMessageHandler.type,
|
||||||
|
id: realm.context.id,
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
awaitPromise,
|
||||||
|
commandArguments,
|
||||||
|
functionDeclaration,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.#buildReturnValue(evaluationResult, realm);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate a provided expression in the provided target, which is either a
|
* Evaluate a provided expression in the provided target, which is either a
|
||||||
* realm or a browsing context.
|
* realm or a browsing context.
|
||||||
@ -162,6 +246,27 @@ class ScriptModule extends Module {
|
|||||||
`Expected "awaitPromise" to be a boolean, got ${awaitPromise}`
|
`Expected "awaitPromise" to be a boolean, got ${awaitPromise}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.#assertResultOwnership(resultOwnership);
|
||||||
|
|
||||||
|
const { contextId, realmId, sandbox } = this.#assertTarget(target);
|
||||||
|
const realm = this.#getRealmInfoFromTarget({ contextId, realmId, sandbox });
|
||||||
|
const evaluationResult = await this.messageHandler.forwardCommand({
|
||||||
|
moduleName: "script",
|
||||||
|
commandName: "evaluateExpression",
|
||||||
|
destination: {
|
||||||
|
type: lazy.WindowGlobalMessageHandler.type,
|
||||||
|
id: realm.context.id,
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
awaitPromise,
|
||||||
|
expression: source,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.#buildReturnValue(evaluationResult, realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#assertResultOwnership(resultOwnership) {
|
||||||
if (![OwnershipModel.None, OwnershipModel.Root].includes(resultOwnership)) {
|
if (![OwnershipModel.None, OwnershipModel.Root].includes(resultOwnership)) {
|
||||||
throw new lazy.error.InvalidArgumentError(
|
throw new lazy.error.InvalidArgumentError(
|
||||||
`Expected "resultOwnership" to be one of ${Object.values(
|
`Expected "resultOwnership" to be one of ${Object.values(
|
||||||
@ -169,7 +274,9 @@ class ScriptModule extends Module {
|
|||||||
)}, got ${resultOwnership}`
|
)}, got ${resultOwnership}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#assertTarget(target) {
|
||||||
lazy.assert.object(
|
lazy.assert.object(
|
||||||
target,
|
target,
|
||||||
`Expected "target" to be an object, got ${target}`
|
`Expected "target" to be an object, got ${target}`
|
||||||
@ -180,6 +287,7 @@ class ScriptModule extends Module {
|
|||||||
realm: realmId = null,
|
realm: realmId = null,
|
||||||
sandbox = null,
|
sandbox = null,
|
||||||
} = target;
|
} = target;
|
||||||
|
|
||||||
if (contextId != null) {
|
if (contextId != null) {
|
||||||
lazy.assert.string(
|
lazy.assert.string(
|
||||||
contextId,
|
contextId,
|
||||||
@ -207,20 +315,10 @@ class ScriptModule extends Module {
|
|||||||
throw new lazy.error.InvalidArgumentError(`No context or realm provided`);
|
throw new lazy.error.InvalidArgumentError(`No context or realm provided`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const realm = this.#getRealmInfoFromTarget({ contextId, realmId, sandbox });
|
return { contextId, realmId, sandbox };
|
||||||
const evaluationResult = await this.messageHandler.forwardCommand({
|
}
|
||||||
moduleName: "script",
|
|
||||||
commandName: "evaluateExpression",
|
|
||||||
destination: {
|
|
||||||
type: lazy.WindowGlobalMessageHandler.type,
|
|
||||||
id: realm.context.id,
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
awaitPromise,
|
|
||||||
expression: source,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
#buildReturnValue(evaluationResult, realm) {
|
||||||
const rv = { realm: realm.realm };
|
const rv = { realm: realm.realm };
|
||||||
switch (evaluationResult.evaluationStatus) {
|
switch (evaluationResult.evaluationStatus) {
|
||||||
// TODO: Compare with EvaluationStatus.Normal after Bug 1774444 is fixed.
|
// TODO: Compare with EvaluationStatus.Normal after Bug 1774444 is fixed.
|
||||||
|
@ -94,48 +94,7 @@ class ScriptModule extends Module {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#toRawObject(maybeDebuggerObject) {
|
async #buildReturnValue(rv, awaitPromise) {
|
||||||
if (maybeDebuggerObject instanceof Debugger.Object) {
|
|
||||||
// Retrieve the referent for the provided Debugger.object.
|
|
||||||
// See https://firefox-source-docs.mozilla.org/devtools-user/debugger-api/debugger.object/index.html
|
|
||||||
const rawObject = maybeDebuggerObject.unsafeDereference();
|
|
||||||
|
|
||||||
// TODO: Getters for Maps and Sets iterators return "Opaque" objects and
|
|
||||||
// are not iterable. RemoteValue.jsm' serializer should handle calling
|
|
||||||
// waiveXrays on Maps/Sets/... and then unwaiveXrays on entries but since
|
|
||||||
// we serialize with maxDepth=1, calling waiveXrays once on the root
|
|
||||||
// object allows to return correctly serialized values.
|
|
||||||
return Cu.waiveXrays(rawObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If maybeDebuggerObject was not a Debugger.Object, it is a primitive value
|
|
||||||
// which can be used as is.
|
|
||||||
return maybeDebuggerObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate a provided expression in the current window global.
|
|
||||||
*
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {boolean} awaitPromise
|
|
||||||
* Determines if the command should wait for the return value of the
|
|
||||||
* expression to resolve, if this return value is a Promise.
|
|
||||||
* @param {string} expression
|
|
||||||
* The expression to evaluate.
|
|
||||||
*
|
|
||||||
* @return {Object}
|
|
||||||
* - evaluationStatus {EvaluationStatus} One of "normal", "throw".
|
|
||||||
* - exceptionDetails {ExceptionDetails=} the details of the exception if
|
|
||||||
* the evaluation status was "throw".
|
|
||||||
* - result {RemoteValue=} the result of the evaluation serialized as a
|
|
||||||
* RemoteValue if the evaluation status was "normal".
|
|
||||||
*/
|
|
||||||
async evaluateExpression(options) {
|
|
||||||
const { awaitPromise, expression } = options;
|
|
||||||
const rv = this.#global.executeInGlobal(expression, {
|
|
||||||
url: this.messageHandler.window.document.baseURI,
|
|
||||||
});
|
|
||||||
|
|
||||||
let evaluationStatus, exception, result, stack;
|
let evaluationStatus, exception, result, stack;
|
||||||
if ("return" in rv) {
|
if ("return" in rv) {
|
||||||
evaluationStatus = EvaluationStatus.Normal;
|
evaluationStatus = EvaluationStatus.Normal;
|
||||||
@ -184,6 +143,78 @@ class ScriptModule extends Module {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#toRawObject(maybeDebuggerObject) {
|
||||||
|
if (maybeDebuggerObject instanceof Debugger.Object) {
|
||||||
|
// Retrieve the referent for the provided Debugger.object.
|
||||||
|
// See https://firefox-source-docs.mozilla.org/devtools-user/debugger-api/debugger.object/index.html
|
||||||
|
const rawObject = maybeDebuggerObject.unsafeDereference();
|
||||||
|
|
||||||
|
// TODO: Getters for Maps and Sets iterators return "Opaque" objects and
|
||||||
|
// are not iterable. RemoteValue.jsm' serializer should handle calling
|
||||||
|
// waiveXrays on Maps/Sets/... and then unwaiveXrays on entries but since
|
||||||
|
// we serialize with maxDepth=1, calling waiveXrays once on the root
|
||||||
|
// object allows to return correctly serialized values.
|
||||||
|
return Cu.waiveXrays(rawObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If maybeDebuggerObject was not a Debugger.Object, it is a primitive value
|
||||||
|
// which can be used as is.
|
||||||
|
return maybeDebuggerObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call a function in the current window global.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {boolean} awaitPromise
|
||||||
|
* Determines if the command should wait for the return value of the
|
||||||
|
* expression to resolve, if this return value is a Promise.
|
||||||
|
* @param {Array<RemoteValue>} commandArguments
|
||||||
|
* The arguments to pass to the function call.
|
||||||
|
* @param {string} functionDeclaration
|
||||||
|
* The body of the function to call.
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* - evaluationStatus {EvaluationStatus} One of "normal", "throw".
|
||||||
|
* - exceptionDetails {ExceptionDetails=} the details of the exception if
|
||||||
|
* the evaluation status was "throw".
|
||||||
|
* - result {RemoteValue=} the result of the evaluation serialized as a
|
||||||
|
* RemoteValue if the evaluation status was "normal".
|
||||||
|
*/
|
||||||
|
async callFunctionDeclaration(options) {
|
||||||
|
const { awaitPromise, functionDeclaration } = options;
|
||||||
|
const rv = this.#global.executeInGlobal(`(${functionDeclaration})()`, {
|
||||||
|
url: this.messageHandler.window.document.baseURI,
|
||||||
|
});
|
||||||
|
return this.#buildReturnValue(rv, awaitPromise);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a provided expression in the current window global.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {boolean} awaitPromise
|
||||||
|
* Determines if the command should wait for the return value of the
|
||||||
|
* expression to resolve, if this return value is a Promise.
|
||||||
|
* @param {string} expression
|
||||||
|
* The expression to evaluate.
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* - evaluationStatus {EvaluationStatus} One of "normal", "throw".
|
||||||
|
* - exceptionDetails {ExceptionDetails=} the details of the exception if
|
||||||
|
* the evaluation status was "throw".
|
||||||
|
* - result {RemoteValue=} the result of the evaluation serialized as a
|
||||||
|
* RemoteValue if the evaluation status was "normal".
|
||||||
|
*/
|
||||||
|
async evaluateExpression(options) {
|
||||||
|
const { awaitPromise, expression } = options;
|
||||||
|
const rv = this.#global.executeInGlobal(expression, {
|
||||||
|
url: this.messageHandler.window.document.baseURI,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.#buildReturnValue(rv, awaitPromise);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const script = ScriptModule;
|
const script = ScriptModule;
|
||||||
|
@ -1,13 +1,7 @@
|
|||||||
[call_function.py]
|
[call_function.py]
|
||||||
[test_exception]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_invalid_function]
|
[test_invalid_function]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_arrow_function]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_arguments]
|
[test_arguments]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
@ -23,14 +17,8 @@
|
|||||||
[test_remote_value_argument]
|
[test_remote_value_argument]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_async_arrow_await_promise[True\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_async_arrow_await_promise[False\]]
|
[test_async_arrow_await_promise[False\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_async_classic_await_promise[True\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_async_classic_await_promise[False\]]
|
[test_async_classic_await_promise[False\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
@ -1,82 +1,7 @@
|
|||||||
[invalid.py]
|
[invalid.py]
|
||||||
[test_params_target_invalid_type[None\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_target_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_target_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_target_invalid_type[target3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_target_invalid_type[target4\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_context_invalid_type[None\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_context_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_context_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_context_invalid_type[context3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_context_invalid_type[context4\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_sandbox_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_sandbox_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_sandbox_invalid_type[sandbox2\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_sandbox_invalid_type[sandbox3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_context_unknown]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_realm_invalid_type[None\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_realm_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_realm_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_realm_invalid_type[realm3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_realm_invalid_type[realm4\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_realm_unknown]
|
[test_params_realm_unknown]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_params_function_declaration_invalid_type[None\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_function_declaration_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_function_declaration_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_function_declaration_invalid_type[function_declaration3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_function_declaration_invalid_type[function_declaration4\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_this_invalid_type[False\]]
|
[test_params_this_invalid_type[False\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
@ -92,18 +17,6 @@
|
|||||||
[test_params_this_invalid_type[this4\]]
|
[test_params_this_invalid_type[this4\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_params_arguments_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_arguments_invalid_type[SOME_STRING\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_arguments_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_arguments_invalid_type[arguments3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_single_argument_invalid_type[False\]]
|
[test_params_single_argument_invalid_type[False\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
@ -118,36 +31,3 @@
|
|||||||
|
|
||||||
[test_params_single_argument_invalid_type[argument4\]]
|
[test_params_single_argument_invalid_type[argument4\]]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[test_params_await_promise_invalid_type[None\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_await_promise_invalid_type[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_await_promise_invalid_type[0\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_await_promise_invalid_type[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_await_promise_invalid_type[await_promise4\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_await_promise_invalid_type[await_promise5\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_result_ownership_invalid_value[False\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_result_ownership_invalid_value[_UNKNOWN_\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_result_ownership_invalid_value[42\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_result_ownership_invalid_value[result_ownership3\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[test_params_result_ownership_invalid_value[result_ownership4\]]
|
|
||||||
expected: FAIL
|
|
||||||
|
Loading…
Reference in New Issue
Block a user