2

I have the following code but its not working

public static String getHTMLResponse(String url){
   String body = (String) js.executeScript("$.ajax({url:\""+ url + "\", success:function(result){ return result;}});");
    return body;
}

For some reason this is always returning null.

Has anyone tried to get a CURL response from ajax in webdriver? I was doing this in java before but I am getting certificate errors constantly and just want something more reliable.

Thanks ahead of time!

2 Answers 2

3

Ok, so Jason Smiley posted a solution but without an explanation as to what the problem was and how the solution works.

The first problem is that the script passed to executeScript does not return anything, period. What executeScript does is wrap the script you pass to it in function () { ... }. So something of the form $.ajax(...) would be executed as this in the browser:

function () {
    $.ajax(...);
}

This obviously won't return anything in the same way that if the script were 2 + 2 it would not return 4 because it would execute as:

function () {
    2 + 2;
}

The script passed to executeScript would have to be return 2 + 2.

However, here, just adding this return won't fix the problem. There is an additional problem that $.ajax is an asynchronous function. When $.ajax executes, it returns right away. The functions that are passed to it are stored for future execution. If $.ajax returns right away, then the value it returns cannot possibly be the return value of any of the functions that are given to it because these have not executed yet. Conversely, then the functions passed to $.ajax do execute, whatever they give to return cannot be retrieved by your code. The only thing you can do is use the values you care about inside of the function itself or pass it to another function.

The solution is to use executeAsyncScript which is designed for asynchronous execution. This function is just like executeScript but adds an argument which is a callback which should be called when the script has finished executing and it should be called with the value you want executeAsyncScript to return.

Note that it is absolutely not necessary to abandon $.ajax. The following should work:

public static String getHTMLResponse(String url){
    String body = (String) js.executeAsyncScript(
        "var url = arguments[0];" + 
        "var callback = arguments[1];" +
        "$.ajax({url: url, success: callback});", 
        url);
    return body;
}

Note that I've set this code so that url is passed as an argument instead of being concatenated into the script. I find this cleaner than concatenation. In case this needs be explained, arguments is an object automatically made available by the JavaScript virtual machine. It holds the list of arguments given to a function.

Whether $.ajax is used or XMLHttpRequest is used directly the principles are the same.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Louis! I didn't mention this in the ticket, but I actually had a few variations of the OP script. I could tell that nothing was being returned, I guess I didn't know WHY nothing was being returned. For instance, why does "success: callback" work and not "success: return arguments[1]" or "success: function(){return arguments[1]}". Pretty sure one of these didn't compile but I can't remember which lol
1

A front end developer gave me the script!

   public static String getHTMLResponse(String url){
      String body = (String) js.executeAsyncScript(
            "var callback = arguments[arguments.length - 1];" +
                    "var xhr = new XMLHttpRequest();" +
                    "xhr.open('GET', '"+ url + "', true);" +
                    "xhr.onreadystatechange = function() {" +
                    "  if (xhr.readyState == 4) {" +
                    "    callback(xhr.responseText);" +
                    "  }" +
                    "};" +
                    "xhr.send();");
      return body;
  }

1 Comment

Not anymore actually - I had to change it. Will add a new answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.