0 votes
1 view
in Devops and Agile by (14.9k points)

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 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()?

1 Answer

0 votes
by (42.1k points)

When it involves checking conditions on the browser side, all checks you'll be able to perform with execute_async_script are often performed with execute_script.

Even if what you are checking is asynchronous.

I know because once upon a time there was a bug with execute_async_script that created my tests fail if the script came results too quickly.

As far as I can tell, the bug is gone now since I've been using execute_async_script but for quite long before, I used execute_script for tasks where execute_async_script would have

been more natural.

For instance, performing a check that requires loading a module with RequireJS to perform the check:

 driver.execute_script("""

// Reset in case it's been used already.

window.__selenium_test_check =

undefined

;

require(["foo"], function (foo) );

""")

result = driver.wait(lambda driver:

driver.execute_script("return window.__selenium_test_check;"))

The require call is asynchronous. The problem with this though, besides leaking a variable into the global space, is that it multiplies the network requests. Each execute_script call is a network request.

The wait method works by polling: it runs the test till the returned value is true.

This means one network request per check that wait performs (in the code above).

 

When you test locally it's not an enormous deal. If you've got to go through the network because you're having the browsers provisioned by a service like Sauce Labs,  each network request slows down your test suite.

So using execute_async_script not solely permits writing a test that appears to be a lot of natural (call a callback, as we ordinarily do with asynchronous code, rather than leak into the global space) but it also helps the performance of your tests.

result = driver.execute_async_script("""

var done = arguments[0];

require(["foo"], function (foo) );

""")

The way I see it now is that if a test is going to look into the asynchronous code on the browser side to get a result, I use execute_async_script.

If it's going to do one thing for which there's no asynchronous method offered, I use execute_script.

...