How to get Ajax response in HTML Unit (it renders the HTML of the web page)

ajax, htmlunit, jquery, json, testing

Solution

I had a similar problem and found a solution using the HtmlUnit FAQ page:

You can subclass HttpWebConnection and override getResponse() as:

   new WebConnectionWrapper(webClient) {

       public WebResponse getResponse(WebRequest request) throws IOException {
           WebResponse response = super.getResponse(request);
           if (request.getUrl().toExternalForm().contains("my_url")) {
               String content = response.getContentAsString("UTF-8");

               //change content

               WebResponseData data = new WebResponseData(content.getBytes("UTF-8"),
                       response.getStatusCode(), response.getStatusMessage(), >response.getResponseHeaders());
               response = new WebResponse(data, request, response.getLoadTime());
           }
           return response;
       }
   };

What this means is that we can wrap our webClient object, intercept any request and response we need, extract them or make changes.

I made an inner class which extends WebConnectionWrapper, and has one field which is JSON I need:

private class JsonResponseWebWrapper extends WebConnectionWrapper{

    public JsonResponseWebWrapper(WebClient webClient){
        super(webClient);           
    }
    
    String jsonResponse;
    
    @Override
    public WebResponse getResponse(WebRequest request) throws IOException {;
        WebResponse response = super.getResponse(request);
        //extract JSON from response
        jsonResponse = response.getContentAsString();
        return response;
    }

    public String getJsonResponse() {
        return jsonResponse;
    }
};

This way we will intercept every single response. But first we need to wrap the webClient. I did this just before requesting JSON response, so I didn't have to add conditions to my wrapper:

JsonResponseWebWrapper jrww = new JsonResponseWebWrapper(webClient);
page = button.click();
String rawJSON = jrww.getJsonResponse();

And after that you can parse it using your favorite JSON parser. Hope this helps!

Problem

I have a web application that returns JSON when I make AJAX requests to the server for CRUD operations. The reason of this is because I use jQuery to handle the data without refreshing the page (MVC), so if I create a new entry in the system, the server will return a response which have the created entry in JSON format. jQuery manages the data received and renders the entry on a list (with the previously created entries). Now I am testing it with HTML Unit, but if I try ``` WebResponse response = page.getWebResponse() ``` I get 200 status and message "OK". But I was expecting the JSON data of the entry I created. And if I try ``` page.asText() ``` I get the HTML of the current page (with the entry already in the list, but not the data I want). It is a similar issue than this one, that had no response: Json ajax call returning response 200 ok PD: The jQuery form has two fields, one is a text input for the name and another is a select for the car settings. I pass to this function a list of settings to select. The name is autogenerated with a timestamp and a static int seed. This is the code that I am using: ``` public void create(List<Settings> settings) throws FailingHttpStatusCodeException, MalformedURLException, IOException { page = webClient.getPage("localhost:8080/cars/list"); int elementsCount = getEntitiesCount(); creationSeed = elementsCount+1; HtmlAnchor anchor = (HtmlAnchor) page.getFirstByXPath("//a[@class='action-createCar']"); page = (HtmlPage) anchor.click(); HtmlForm form = page.getFirstByXPath("//form[@class='CarsForm']"); form = page.getForms().get(0); HtmlTextInput nameField = form.getInputByName("CarsForm-name"); nameField.setText("Test " + creationSeed + " - " + new Date().getTime()); HtmlSelect columnSelectList = (HtmlSelect) form.getSelectByName("CarsForm-settings"); if (settings != null && settings.size() > 0) for (Settings setting : settings) { HtmlOption htmlOption = columnSelectList.getOptionByValue(setting.name()); htmlOption.setSelected(true); } //looking for the button to submit the form HtmlDivision buttonSet = page.getFirstByXPath("//div[@class='ui-dialog-buttonset']"); HtmlButton okButton = (HtmlButton) buttonSet.getFirstElementChild(); page = okButton.click(); assertEquals(elementsCount + 1, getEntitiesCount()); //Here is where I want to get the server response to check the data which is returned by the server //And neither page.getWebResponse() or page.asText() contains it } ``` }

Original source