Protractor and headless Chrome on Docker (with video tutorial)

Parallel test execution and Jenkins are probably the most frequent use cases for headless browser running under Protractor’s control. There are a few options available, and your choice will of course depend on your circumstances. This article is strongly opinionated though and I am quite excited about one of the options in particular. Can you guess which one? ;)

TL;DR

I have prepared a short video tutorial, which shows how to run dockerised Protractor with headless Chrome as a drop in replacement for local installation. The Docker Hub repo webnicer/protractor-headless contains the image.

Running Protractor locally with Chrome is quite cool if you like to see things happening before your very eyes. If you want speed coming from parallel execution though, you will probably have hard time trying to keep up with what’s going on in multiple Chrome windows popping up left, right and center. Moreover, if you want your Jenkins to run Protractor then you probably cannot even have a browser window. So what options do you have? Let’s start with the most obvious one.

PhantomJS? Thanks, but no thanks.

I was really excited when I first heard of PhantomJS some time ago. It is really cool idea, running headless webkit, but when it comes to Protractor tests, PhantomJS is just a bag of trouble. It is even discouraged by the creators of Protractor and for a good reason. Even though it is built on Webkit, it is not the real deal and there differences between PhantomJS and Chrome, which may cost you time. I have experienced Phantom’s moody behaviour myself and I abandoned the idea of PhantomJS as my headless Protractor browser.

External Selenium providers

It is not a lost battle, though. When you abandon PhantomJS you can try an external Selenium provider, like Sauce Labs, which plays nicely with Protractor. It gives you quite a healthy number of browsers to play with, allows parallel execution, gives you screenshots and a video coverage for your tests and so on. The new interface is quite neat and tidy as well.

If you don’t mind spending some money on reasonable testing time per month and if you don’t need speed that much it is perfect. It must be said here that Sauce Labs does not provide you the fastest experience in the Universe, so you will use up all of your 2 hours per month (in the cheapest plan) before you know it. Unless you are a very casual Protractor user, that is.

In my personal opinion, going external is perfect for QA to run all suites in all supported browsers, check for regressions and other qaish business. May not necessarily be such a good idea for development, mainly because of the speed and the cost involved.

Local headless (real) Chrome?

As it turns out, after ruling out PhantomJS and external Selenium providers, we are still left with another good headless option. Think about this: running headlessly real Chrome... And yes, I mean the real deal. Exactly the same Chrome you use every day to browse the web.

I may not make sense at first - if it’s headless it has to be different, right? In fairness it’s not really a headless browser. The trick is to run a real browser in virtual framebuffer X server - xvfb, so that there is no visible window. As you can imagine, you can run any browser available for your system.

Even though the setup is not very complicated, you still need to install some additional packages on the machine which is supposed to run Protractor. I don’t like having messy environments, so I decided to take it one step further and have the whole shebang packed up nicely and ready for instant deployment.

What’s better for that than Docker? The idea was to create a drop in replacement for Protractor protractor installed locally, so that I could run the dockerised version with no real difference from the command line perspective. It did not take too much effort to create protractor-headless Docker image, which can get you started in no time at all.

How to run Protractor with headless Chrome on Docker?

The image description gives all the details you need to run it, as well as explains the command line switches used. Here, let me just show you the essence:

$ docker run -it --rm --net=host -v /dev/shm:/dev/shm -v $(pwd):/protractor webnicer/protractor-headless [protractor options]

Obviously you don't want to type it every time, so you can simply create a script, let’s say protractor.sh, such as this:

#!/bin/bash

docker run -it --rm --net=host -v /dev/shm:/dev/shm -v $(pwd):/protractor webnicer/protractor-headless $@

and then run it like you would run the Protractor installed on the host:

$ protractor.sh [protractor options]

It’s pretty straightforward.

Thanks for reading, I hope you found it useful. Please don’t forget to give a star to my Docker repo!