Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move execute and executeAsync to document ns. #3807

Merged
merged 2 commits into from
Jul 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/api/client-commands/_base-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,30 @@ module.exports = class ClientCommand {
fullPromiseResolve: this.resolvesWithFullResultObject
});
}

/*!
* Helper function for execute and execute_async
*
* @param {string} method
* @param {string|function} script
* @param {Array} args
* @param {function} callback
* @private
*/
executeScriptHandler(method, script, args, callback) {
let fn;

if (script.originalTarget) {
script = script.originalTarget;
}

if (typeof script === 'function') {
fn = 'var passedArgs = Array.prototype.slice.call(arguments,0); return (' +
script.toString() + ').apply(window, passedArgs);';
} else {
fn = script;
}

return this.transportActions[method](fn, args, callback);
}
};
88 changes: 88 additions & 0 deletions lib/api/client-commands/document/execute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const ClientCommand = require('../_base-command.js');
const {isFunction} = require('../../../utils');

/**
* Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. The executed script is assumed to be synchronous.
* The script argument defines the script to execute in the form of a function body. The value returned by that function will be returned to the client.
*
* The function will be invoked with the provided args array and the values may be accessed via the arguments object in the order specified.
*
* Under the hood, if the `body` param is a function it is converted to a string with `function.toString()`. Any references to your current scope are ignored.
*
* To ensure cross-browser compatibility, the specified function should not be in ES6 format (i.e. `() => {}`). If the execution of the function fails, the first argument of the callback contains error information.
*
* @example
* describe('execute script', function() {
* it('executes a script in browser', function(browser) {
* browser.executeScript(function(imageData) {
* // resize operation
* return true;
* }, [imageData], function(result) {
* // whatever is returned by the script passed above will be available
* // as result.value
* console.log(result.value); // true
* });
*
* // scroll to the bottom of the page.
* browser.executeScript('window.scrollTo(0,document.body.scrollHeight);');
* });
*
* it('executes a script with ES6 async/await', async function(browser) {
* const result = await browser
* .document.executeScript(function(imageData) {
* // resize operation
* return true;
* }, [imageData]);
*
* console.log(result); // true
* });
* });
*
* @method document.executeScript
* @syntax .execute(body, [args], [callback])
* @syntax .executeScript(body, [args], [callback])
* @syntax .document.execute(body, [args], [callback])
* @syntax .document.executeScript(body, [args], [callback])
* @param {string|function} body The function body to be injected.
* @param {Array} args An array of arguments which will be passed to the function.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @returns {*} The script result.
* @see document.executeAsyncScript
* @link /#executing-script
* @api protocol.document
*/
class ExecuteScript extends ClientCommand {
static get namespacedAliases() {
return ['document.executeScript', 'execute', 'executeScript'];
}

static get isTraceable() {
return true;
}

performAction(callback) {
const {script, scriptArgs} = this;

this.executeScriptHandler('executeScript', script, scriptArgs, callback);
}

command(script, args, callback) {
if (!script) {
throw new Error('First argument passed to .executeScript() must be defined.');
}

if (arguments.length === 1) {
args = [];
} else if (arguments.length === 2 && isFunction(arguments[1])) {
callback = arguments[2];
args = [];
}

this.script = script;
this.scriptArgs = args;

return super.command(callback);
}
};

module.exports = ExecuteScript;
87 changes: 87 additions & 0 deletions lib/api/client-commands/document/executeAsync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const ClientCommand = require('../_base-command.js');
const {isFunction} = require('../../../utils');

/**
* Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame. The executed script is assumed to be asynchronous.
*
* The function to be injected receives the `done` callback as argument which needs to be called when the asynchronous operation finishes. The value passed to the `done` callback is returned to the client.
* Additional arguments for the injected function may be passed as a non-empty array which will be passed before the `done` callback.
*
* Asynchronous script commands may not span page loads. If an unload event is fired while waiting for the script result, an error will be returned.
*
* @example
* describe('execute async script', function() {
* it('executes async script in browser', function(browser) {
* browser.executeAsyncScript(function(done) {
* setTimeout(function() {
* done(true);
* }, 500);
* }, function(result) {
* // whatever is passed to the `done` callback in the script above
* // will be available as result.value
* console.log(result.value); // true
* });
* });
*
* it('executes a script with ES6 async/await', async function(browser) {
* const result = await browser
* .document.executeAsync(function(arg1, arg2, done) {
* setTimeout(function() {
* done(arg1);
* }, 500);
* }, [arg1, arg2]);
*
* // whatever is passed to the `done` callback in the script above
* // will be returned by the command when used with `await`.
* console.log(result); // arg1
* });
* });
*
* @method document.executeAsyncScript
* @syntax .executeAsync(body, [args], [callback])
* @syntax .executeAsyncScript(body, [args], [callback])
* @syntax .document.executeAsync(body, [args], [callback])
* @syntax .document.executeAsyncScript(body, [args], [callback])
* @param {string|function} body The function body to be injected.
* @param {Array} args An array of arguments which will be passed to the function.
* @param {function} [callback] Optional callback function to be called when the command finishes.
* @returns {*} The script result.
* @see document.executeScript
* @link /#execute-async-script
* @api protocol.document
*/
class ExecuteAsyncScript extends ClientCommand {
static get namespacedAliases() {
return ['document.executeAsyncScript', 'executeAsync', 'executeAsyncScript'];
}

static get isTraceable() {
return true;
}

performAction(callback) {
const {script, scriptArgs} = this;

this.executeScriptHandler('executeAsyncScript', script, scriptArgs, callback);
}

command(script, args, callback) {
if (!script) {
throw new Error('First argument passed to .executeAsyncScript() must be defined.');
}

if (arguments.length === 1) {
args = [];
} else if (arguments.length === 2 && isFunction(arguments[1])) {
callback = arguments[2];
args = [];
}

this.script = script;
this.scriptArgs = args;

return super.command(callback);
}
};

module.exports = ExecuteAsyncScript;
35 changes: 1 addition & 34 deletions lib/api/protocol/_base-action.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ module.exports = class ProtocolAction {
}

if (parentElement) {
let elementResponse = await this.elementLocator.findElement({element: parentElement});
const elementResponse = await this.elementLocator.findElement({element: parentElement});
if (!elementResponse.value) {
return {
value: null,
Expand All @@ -160,39 +160,6 @@ module.exports = class ProtocolAction {
return this.elementLocator.executeProtocolAction({id, element, transportAction, commandName});
}

/*!
* Helper function for execute and execute_async
*
* @param {string} path
* @param {string|function} script
* @param {Array} args
* @param {function} callback
* @private
*/
executeScriptHandler(method, script, args, callback) {
let fn;

if (script.originalTarget) {
script = script.originalTarget;
}

if (isFunction(script)) {
fn = 'var passedArgs = Array.prototype.slice.call(arguments,0); return (' +
script.toString() + ').apply(window, passedArgs);';
} else {
fn = script;
}

if (arguments.length === 2) {
args = [];
} else if (arguments.length === 3 && isFunction(arguments[2])) {
callback = arguments[2];
args = [];
}

return this.transportActions[method](fn, args, callback);
}

/*!
* Helper function for mouseButton actions
*
Expand Down
44 changes: 0 additions & 44 deletions lib/api/protocol/execute.js

This file was deleted.

51 changes: 0 additions & 51 deletions lib/api/protocol/executeAsyncScript.js

This file was deleted.

2 changes: 1 addition & 1 deletion lib/transport/selenium-webdriver/method-mappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ module.exports = class MethodMappings {
};
},

async executeScriptAsync(fn, args) {
async executeAsyncScript(fn, args) {
const value = await this.executeFn(fn, 'executeAsyncScript', args);

return {
Expand Down
8 changes: 4 additions & 4 deletions test/lib/fakedriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,23 +172,23 @@ const createGenericCommandMocks = function(assertion) {
return;
},

executeScript(script, args) {
executeScript(script, ...args) {
assertion({
command: 'executeScript',
script,
args
});

return args;
return null;
},
executeAsyncScript(script, args) {
executeAsyncScript(script, ...args) {
assertion({
command: 'executeAsyncScript',
script,
args
});

return args;
return null;
},
takeScreenshot() {
assertion({
Expand Down
Loading