Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Asynchronous Javascript responses from Selenium Webdriver

We have added an asynchronious javascript call to our website. I'm trying to get Selenium Webdriver to wait for a response from the call.

The listener looks like this:

$(document).on("application:subapp:rendered", function(){console.log("foo");});

My webdriver code (python):

driver.set_script_timeout(30)
response =  driver.execute_async_script("$(document).on(\"application:subapp:rendered\", function(){return \"foo\";});"

Next I execute the page should make "foo" return

however this is my response...

TimeoutException: Message: asynchronous script timeout: result was not recei ved in 30 seconds (Session info: chrome=41.0.2272.118) (Driver info: chromedriver=2.11.298604 (75ea2fdb5c87f133a8e1b8da16f6091fb7d532 1e),platform=Windows NT 6.1 SP1 x86_64)

like image 445
user3249517 Avatar asked Apr 08 '15 14:04

user3249517


2 Answers

When you call execute_async_script, Selenium passes as the last argument to the JavaScript code the callback you must call to indicate that the asynchronous code is done executing, if you do not pass arguments after your script when you call execute_async_script, then this will be accessible as arguments[0] in the JavaScript. Whatever value you pass to this callback is what your execute_async_script will return so:

response = driver.execute_async_script("""
    var done = arguments[0];
    $(document).one('application:subapp:rendered', 
        function(){
           done('foo');
    });
""")

In the code above I assign the callback to done. That's just the way I like to do it. Note how the value to which response will be set is set by calling done("foo").

Note also that I'm using .one() rather than .on(). I've discovered that Selenium (at least up to 2.45) does not ever consider an old callback created for execute_async_script to be "obsolete" so if there is any chance that your event can happen again after your JavaScript above has finished executing, then it will call the callback again, and Selenium will honor the call again. If you happen to have another execute_async_script running at that time, then this spurious call will terminate your other execute_async_script call with the return value "foo". I've had that happen in one of my test suites. It led to very bizarre failures.

like image 92
Louis Avatar answered Oct 18 '22 04:10

Louis


Use arguments[0] as a callback:

driver.execute_async_script("""
    $(document).on('application:subapp:rendered', arguments[0]);
""")

See also (should help in understanding):

  • Understanding execute async script in Selenium
like image 38
alecxe Avatar answered Oct 18 '22 06:10

alecxe