Test server response headers with Selenium and BrowserMob-Proxy in Java automated tests

Despite Selenium is normally used in pure UI testing, sometimes the nature of the test implies more complicated analysis rather than just check if proper element has taken proper state under certain circumstances. For example one may need to test if server response contains certain HTTP header (e.g. you may need to verify proper Content Encoding that is declared by your server).

Selenium itself does not support such kind of checks, however with the help of BrowserMob-Proxy tool you can implement scenarios like that. This is what we’re going to talk about here in the post.

Example description: Verify server response header value in your Selenium automated test

We’re going to create a test that opens a web page and tests that server declares UTF-8 as content encoding charset. To do that we will parse the value of Content-Type header that is returned with the responses from the server. Here are few things to consider before we start:

  1. We’ll need to configure our browser to use proxy server

  2. We’ll need to configure our proxy to store headers which we’re going to test

  3. When we call a page using web browser it also fetches the resources which are used by that page (images, scripts, CSS, etc.), so that our single page call results in several HTTP requests.

Do not forget to add BrowserMob-Proxy dependency to your project or add appropriate jar to your class path.

<dependency>
    <groupId>net.lightbody.bmp</groupId>
    <artifactId>browsermob-core</artifactId>
    <version>2.1.5</version>
    <scope>test</scope>
</dependency>

Here I also assume that you do know how to configure your WebDriver to use the proxy. If not, you can find more examples in my other posts by clicking this hashtag: #browsermob-proxy.

Implementation details

Assuming that browser can initiate multiple calls to the server for a single page we’ll be storing headers for all the URLs fetched by the browser. The following data structure perfectly fits our needs:

Map<String, Map<String,String>>

Basically we’ll have a map that would associate another map (of header name to header value) with each of requested URL generated by the page. Let’s see our implementation plan:

  1. Implement method that would return required header value from our data structure

  2. Implement the method that would parse content encoding from Content-Type header and test if it is equal to the excepted value

  3. Implement proxy listener that would be populating our data structure basing on the HTTP responses

  4. Develop short test

Retrieving header value from data structure

Taking into account the fact above we implement the method that would take described type of collection, URL for which we’re going to verify the response header and the required header name. The method will return the value for header matching specified criteria.

private String getHeaderValue(Map<String, Map<String,String>> allHeaders,
                              String headerName,
                              String url){
    if(!allHeaders.containsKey(url)){
        throw new NoSuchElementException("Headers for requested URL have not been found...");
    }
    return allHeaders.get(url).get(headerName);
}

Implement content encoding check

Below is the simplified algorithm that verifies content encoding declared by the server. It covers only one possible representation of charset property (property goes last, separated by leading whitespace and has its value not quoted).

If you need to cover all possible ways content encoding can be represented with, please refer to the corresponding specification.

So, the method logic would be:

private boolean testContentEncoding(String contentTypeValue, String expectedCharset){
    return contentTypeValue.toLowerCase().endsWith(" charset=" + expectedCharset.toLowerCase());
}

Implement proxy listener

Below you can find the rest of implementation which is basically a pseudo-test that outputs verification result to the console. The code starts from that we configure our proxy to listen to the responses coming from the HTTP server. With BrowserMob-Proxy you can listen to requests and responses using so called "filters". It the implementation below the filter just takes the response, fetches the URL of what has been requested and fills up the data structure with the header values for given URL:

@Test
public void testHeaders(){

    Map<String, Map<String, String>> urlToHeaders = new HashMap<>();

    browserMobProxy.addResponseFilter((response, contents, messageInfo) -> {
        Map<String, String> headers = new HashMap<>();
        for(Map.Entry<String, String> httpHeader: response.headers()){
            headers.put(httpHeader.getKey(), httpHeader.getValue());
        }
        urlToHeaders.put(messageInfo.getOriginalUrl(), headers);
    });

    driver.get("https://google.com");

    System.out.println(
        testContentEncoding(
            getHeaderValue(
                urlToHeaders,
                "Content-Type",
                "https://google.com/"),
            "UTF-8")
    );
}

It is worth mentioning is that if you would like to add more pages to the test, you will need to do urlToHeaders.clear() before each new check.

This seems to be it. We learned how to extract header information from the responses returned by your application under test. We also now know what we should to pay attention to and how we can implement such scenarios with Selenium. I really appreciate your feedback so feel free to share your questions and thoughts with me using this form.