Testing Background Network Requests with Selenium

Amit
travel audience
Published in
5 min readNov 10, 2017

--

Photo by chuttersnap on Unsplash

Few words are required to express the importance of e2e testing for any piece of software, and this definitely holds for frontend UIs. Testing is hard, but it pays back if done properly. Selenium gives you many tools to automatically test your web application on real browsers. One thing it doesn’t provide is the access to the browser’s network activity log. That leaves us with the mere ability to look at the HTML elements and trust that the network activity in the background is working as we’d expected.

First, let’s look at some examples, where it may be useful to be able to track network activity on our end-to-end testing.

Online ads send HTTP requests in the background. If they fail, people are going to lose money.

This website generates revenue by showing ads to users. It works like this: After the ad was rendered, it sends a reports to some server over the internet. This report is saved somewhere and later it will be used to generate a bill for somebody to pay. Eventually it will lead to onlinenews.com getting paid for displaying these ads.

Most websites solve this by using a 3rd party to display ads, so they don’t have to test it themselves. However since travel audience is that third party that display ads, we needed to make sure that it works. Always and with no exceptions.

Another example:

An Optimistic UI sends a network request in the background, while simulating a successful scenario.

Optimistic UI, according to Apollo, “is a pattern that you can use to simulate the results of a mutation and update the UI even before receiving a response from the server”.

In our example, we show Bob that his comment was persisted correctly although we don’t know that yet. Meanwhile, we are sending the actual comment the Bob wrote to the server. Only in case of a failure, we will notify Bob about an error. There are no UI elements to indicate the state of this so we need to somehow be able to test behind the scenes.

The kind of assertions we would like to write

So here’s how I imagined a test could look like:

expect(
browser.getNetworkRequests(postCommentURL)[0].text
).toEqual(bobsText)

This kind of assertion would cover us for both cases described above: the ad reports for billing and Bob’s comment are both network request happening in the background, and we need to test this!

But wait, are you sure Selenium can’t tell you this?

Short answer: no.

Longer answer: there is no API for network requests on Selenium, and as a result, WebDriver and others don’t implement this functionality either. As easy as it is to just open the network tab in a real browser, it seems like an impossible thing to do with automated tests.

Service-Workers to the rescue

Take a moment to follow the pattern above.

First there is Selenium whose job is to load pages, click on HTML elements, query the DOM structure and execute custom Javascript on the page. We can program our test to make Selenium click around the page until the point we want to assert on something.

Then there’s the loader/listener. As the name suggests, it loads a particular Service-Worker and listens to the events it emits. In our case these events are network requests, which the loader/listener will persist into a local object.

Now the the interesting bit: Service-Workers are particularly good at handling HTTP requests that come out of a web page. They can cache, manipulate and do all kinds of things with these network requests, while remaining invisible to the page they’re installed on. For this reason one of the main uses of Service-Workers is to make web sites available offline by caching content.

This ability to access all network activity is exactly the functionality we take advantage of, but instead of caching responses, we tell the Service-Worker to send a message for each HTTP request, and add all the interesting details about the request so that we can later use that in our test assertions.

Using this pattern we can access the text that Bob wrote in his comment, as well as the data delivered to report an online ad was placed on a web-page. All out of our e2e tests, in an automatic and robust manner. Yay!

The small details

The idea brought here, simple as it sounds has quite a few little devils hidden in the implementation details, the main ones are:

  1. ServiceWorker won’t work unless on localhost or https.
  2. Serving and loading a ServiceWorker with Webpack isn’t trivial.
  3. ServiceWorker has a strange API when it comes to loading and activating a new Worker.

For this purpose I’ve prepared a working example on GitHub and configured the tests to run on CircleCI. For the implementation details you might want to clone and try out the following repository:

So out of a desperate need to deliver bug-free software to our clients and users we managed to leverage some modern web APIs and use them creatively to fill the functional gaps into the tools that are currently available to us. If network requests are an important part of your service then you should be trying out this pattern as it will help you and your teammates to sleep better knowing your product works as intended.

Are you using other approaches to test with ServiceWorkers? Do you have any comments or questions? Feel free to leave comments in this article.

--

--