Understanding execute async script in Selenium

0
0

I’ve been using selenium (with python bindings and through protractor mostly) for a rather long time and every time I needed to execute a javascript code, I’ve used execute_script() method. For example, for scrolling the page (python):

driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

Or, for infinite scrolling inside an another element (protractor):

var div = element(by.css('div.table-scroll'));
var lastRow
= element(by.css('table#myid tr:last-of-type'));
browser
.executeScript("return arguments[0].offsetTop;", lastRow.getWebElement()).then(function (offset) {
browser
.executeScript('arguments[0].scrollTop = arguments[1];', div.getWebElement(), offset).then(function() {
// assertions
});
});

Or, for getting a dictionary of all element attributes (python):

driver.execute_script('var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;', element)


But, WebDriver API also has execute_async_script() which I haven’t personally used.

What use cases does it cover? When should I use execute_async_script() instead of the regular execute_script()?

The question is selenium-specific, but language-agnostic.

  • You must to post comments
0
0

Here’s the reference to the two APIs (well it’s Javadoc, but the functions are the same), and here’s an excerpt from it that highlights the difference

[executeAsyncScript] Execute an asynchronous piece of JavaScript in
the context of the currently selected frame or window. Unlike
executing synchronous JavaScript, scripts executed with this method
must explicitly signal they are finished by invoking the provided
callback. This callback is always injected into the executed function
as the last argument.

Basically, execSync blocks further actions being performed by the selenium browser, while execAsync does not block and calls on a callback when it’s done.


Since you’ve worked with protractor, I’ll use that as example.
Protractor uses executeAsyncScript in both get and waitForAngular

In waitForAngular, protractor needs to wait until angular announces that all events settled. You can’t use executeScript because that needs to return a value at the end (although I guess you can implement a busy loop that polls angular constantly until it’s done). The way it works is that protractor provides a callback, which Angular calls once all events settled, and that requires executeAsyncScript. Code here

In get, protractor needs to poll the page until the global window.angular is set by Angular. One way to do it is driver.wait(function() {driver.executeScript('return window.angular')}, 5000), but that way protractor would pound at the browser every few ms. Instead, we do this (simplified):

functions.testForAngular = function(attempts, callback) {
var check
= function(n) {
if (window.angular) {
callback
('good');
} else if (n < 1) {
callback
('timedout');
} else {
setTimeout
(function() {check(n - 1);}, 1000);
}
};
check
(attempts);
};

Again, that requires executeAsyncScript because we don’t have a return value immediately. Code here


All in all, use executeAsyncScript when you care about a return value in a calling script, but that return value won’t be available immediately. This is especially necessary if you can’t poll for the result, but must get the result using a callback or promise (which you must translate to callback yourself).

  • You must to post comments
Showing 1 result
Your Answer
Post as a guest by filling out the fields below or if you already have an account.
Name*
E-mail*
Website