Selenium on Windows: Docker Revolution

Hi there! During the last two years we in Aerokube team introduced a lot of new stuff for efficient Selenium clusters including:

  • Selenoid — a brand new Selenium protocol implementation using Docker to launch browser
  • Selenoid UI — a standalone UI for Selenoid allowing to efficiently debug running Selenium sessions
  • Ggr — an alternative to Selenium Grid approach of organizing big Selenium cluster
  • GgrUI — a lightweight daemon allowing to use Selenoid UI for the entire cluster behind Ggr
  • A set of maintained and free to use images with Firefox, Chrome, Opera and Android

Today we are going to return back to the problem of the century — how to efficiently run Selenium tests on Windows.

Why

First of all in 2019 Windows is still a leading desktop operating system with 75–80% of the market share and that says it all: you simply can’t ignore testing your web application under Windows.

Then the most popular Windows browsers are Firefox, Chrome, Opera and two Windows built-in browsers: Internet Explorer and Microsoft Edge. While the first three browsers have their Linux versions and thus can be packed to Docker containers, Internet Explorer (IE) and Microsoft Edge are nailed down to Windows. Usually you can’t ignore testing under IE and Edge because approximately 10–12% of users are visiting your product with these browsers.

In big companies, especially in banks and government organizations, there are a lot of legacy web-applications using ActiveX and similar technologies and thus strictly requiring Internet Explorer to work with them.

Finally, even mainstream browsers like Firefox, Chrome or Opera can have differences while comparing their Windows and Linux versions. While in the majority of cases functional testing result in these browsers is exactly the same, a small percent of platform-specific bugs exists. Which is more important — Windows and Linux have different font sets and anti-aliasing algorithms. This can lead to a bit different rendering of the same page on Windows and on Linux and front-end developers should certainly take this into consideration.

So, Windows Selenium testing is important. To better understand our new solution let’s first of all take a look at traditional Selenium approach for Windows browsers.

Traditional Selenium Approach

We have already touched this approach in our previous article about Windows — Selenium on Windows: revisited. It consists of a Selenium-compatible server (for example, Selenoid), a browser version and a web driver binary between them. In idle state only Selenoid is running and waiting for commands. Once a new browser session request arrives — a new web driver binary process is launched. This process then “knows” how to start desired browser and execute Selenium protocol commands using browser internals. Every browser has its own internal architecture and thus requires its own web driver binary. For example, for Internet Explorer we have iedriver developed by Selenium community. For Microsoft Edge - respective webdriver is provided by Microsoft through Windows Updates.

Being so simple traditional approach has a lot of pitfalls. First of all traditionally Windows browsers are usually deployed to long-running (i.e. mutable) virtual machines. That means that from time to time they will run out of memory, will be cluttered by browser temporary files and will suffer from browser process leaks. Then it is impossible to test in different Internet Explorer or Microsoft Edge versions on the same machine — an update automatically removes old version. That’s a shame by in 2019 we still have no way to run more than 1 parallel Microsoft Edge instance per Windows copy. For Internet Explorer this is possible but requires sophisticated techniques like using virtual desktops and running them from different user accounts to provide a reasonable level of isolation between running browser sessions.

All these limitations make Selenium testing far from being efficient and sometimes very expensive. I think most of you already understand that having short-running (i.e. immutable) containers with Windows browsers would dramatically improve testing experience. So let’s build a Docker image with Windows inside!

Running Internet Explorer and Microsoft Edge in Docker container

Every experienced Docker user knows that Docker was initially created as a lightweight isolation technology working under Linux only. Later by introducing its nanoserver Microsoft added support for packaging some command-line Windows applications to Docker containers. Working under Windows only these new containers are still unable to run graphical applications such as browsers. So there is no direct way of packaging Windows browsers to Docker images. But nothing prevents us from running a virtual machine inside Docker container! If you remember my previous article about Android — an Android emulator is a virtual machine using KVM as virtualization technology and open-source QEMU as concrete hypervisor implementation. While in Android case QEMU commands are generated by Google, in Windows case we need to do just the same stuff manually. Let’s do this. We created a step by step guide here:

https://github.com/aerokube/windows-images

Just follow a step by step guide and you will obtain a working Docker image with Windows inside. A short demonstration of working images is shown in the video:

Running containers in parallel

Having a working Docker image with Windows inside we are able to run only one Selenium test. Which is even more annoying — we have to launch this image manually. Let’s fix this by using one of compatible launchers: an open-source Selenoid if you prefer to work with bare Docker or a commercial Moon if you deploy Selenium cluster in Kubernetes. Both tools are using almost identical JSON-based configuration file called browsers.json. To run Windows images we have to specify respective Docker image reference in JSON configuration file.

To use Windows images with Selenoid or Moon minimal configuration file would be:

{
"internet explorer": {
"default": "11",
"versions": {
"11": {
"image": "internet-explorer:11",
"port": "4444",
"path": "/"
}
}
}
}

A possible optimization allowing to reduce disk utilization is to place virtual machine disk file to host machine and mount it to every started container. In that case your configuration file will need one more parameter called volumes:

{
"internet explorer": {
"default": "11",
"versions": {
"11": {
"image": "internet-explorer:11",
"port": "4444",
"path": "/",
"volumes":["/var/lib/selenoid/hdd.img:/hdd.img"]
}
}
}
}

Here we assume that Windows virtual machine disk file is placed to /var/lib/selenoid/hdd.img and image entrypoint script expects it to be present as /hdd.img inside running container.

What about Windows licenses?

This is an important question because contrarily to Linux — Windows is a commercial operating system requiring a paid license. In previous sections you could see that what we are doing is launching a Windows virtual machine inside Docker container. This is why correct solution is to use a special type of Microsoft licenses for virtual machines called VDA (Virtual Desktop Access) licenses. One such license allows to run up to 4 (four) virtual machines. So you have to buy N/4 licenses, where N is a total number of Windows sessions you are expecting to run in parallel.

Limitations

The only important limitation of this approach is also related to the fact that we are launching a virtual machine: your host machine should support virtualization. Under Linux this can be determined by presence of /dev/kvm file or by running kvm-ok command (from cpu-checker package in Ubuntu). Virtualization is usually available on the majority of modern servers and on some types of virtual machines in the cloud with nested virtualization support. If you are already using our Android images on some server - then Windows images should also work.

A short advertising of our new product

You have almost finished reading this article, so you should be interested in efficient Windows testing. We understand that some teams delegate Selenium infrastructure deployment and maintenance to external services. So we created our online Selenium testing platform called Aerokube Browsers. It already supports a wide range of browsers: Firefox, Chrome, Opera, Android emulators and Windows-only browsers: Internet Explorer and Microsoft Edge that work in Docker containers as shown in this article.

Conclusion

In this article I demonstrated an elegant solution allowing to run any number of Windows browser versions in parallel in Docker containers. This allows you to use just the same cool features like live browser screen or video recording in problematic browsers: Internet Explorer and Microsoft Edge. See you soon in next articles!

Still having questions?

Use one of the following ways to ask:

Any More Articles?

Certainly. Take a look at these ones: