Selenium and JavaScript Asynchronous Calls

I am completely new to Selenium and JavaScript-callback functions and I have a big problem that I cannot solve on my own. I need the specified variable using JavaScript. If I open the page with GoogleChrome and use the console to enter my JavaScript code, I can get the variable using something like this:

1. var myId;
2. getSomeIdStuffInfo("somestuff",function(docId)(myId = docId));
3. return myId;

      

If I enter these lines step by step, I can easily get the correct myId value. But of course, if I execute three lines as quickly as possible, I get null as the return value, because the callback is not complete when I return myId. SOOOO .. if i use selenium like this:

JavascriptExecutor js = (JavascriptExecutor) driver; 
    String docInfoVal = (String) js.executeScript("" +
            "var myId; " +
            "getCurrentDocumentInfo(\"somestuff\"," +
                "function(docId) {" +
                    "myId = docId;" +
                "}" +
            ");" +
            "return myId;");

      

I am getting null as result. So ... for some reason I need to "wait" for the callback function until I return myId. Should I use executeAsyncScript and how? I've been sitting on it for hours and trying different things, but I just can't seem to find the answer.

Thanks in advance for your help!

+3


source to share


2 answers


For asynchronous code, you should use executeAsyncScript

:

JavascriptExecutor js = (JavascriptExecutor) driver; 
String docInfoVal = (String) js.executeAsyncScript("" +
        "var done = arguments[0]; " +
        "getCurrentDocumentInfo(\"somestuff\"," +
            "function(docId) {" +
                "done(docId);" +
            "}" +
        ");");

      

A script called with executeAsyncScript

will have a callback added to the list of arguments passed to it. Since you are not passing arguments to your script, it arguments[0]

contains a callback. Your code should call this callback when it works. The value you give the callback is the return value executeAsyncScript

.

In the above code, I wrote the call done

by placing it in an anonymous function, but the code could be written more concisely:



JavascriptExecutor js = (JavascriptExecutor) driver; 
String docInfoVal = (String) js.executeAsyncScript("" +
        "var done = arguments[0]; " +
        "getCurrentDocumentInfo(\"somestuff\", done);");

      

Or even:

JavascriptExecutor js = (JavascriptExecutor) driver; 
String docInfoVal = (String) js.executeAsyncScript(
        "getCurrentDocumentInfo('somestuff', arguments[0]);");

      

+4


source


Although it's pretty much the same as @Louis. You need to be installed in advance setScriptTimeout

to pass the script.

The default timeout for a script to be executed is 0ms. In most cases, including the examples below, you need to set the scriptWebDriver.Timeouts.setScriptTimeout (long, java.util.concurrent.TimeUnit) timeout in advance to a value large enough.



Below is an example for which I wait 10 seconds to return a string

  driver.manage().timeouts().setScriptTimeout(20, TimeUnit.SECONDS);//important

    JavascriptExecutor executor = (JavascriptExecutor) driver;
    String val = (String) executor.executeAsyncScript(""
            + "var done=arguments[0]; "
            + "setTimeout(function() {"
            + "   done('tada');"
            + "  }, 10000);");

    System.out.println(val);

      

+2


source







All Articles