How To Run Selenium Tests In Docker ?
Tags: java, selenium, docker, testing
Published: 2021-05-17 08:39:03

Automation testing and Continuous Integration (CI) are integral parts of the development and test activity. Selenium test automation is one such approach that helps in the end-to-end testing of the web product. The not-so-preferred way of performing tests using the [Selenium framework](https://www.lambdatest.com/selenium?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu) involves installing the required web browser and its corresponding browser drivers. In this blog, we deep dive into how to run Selenium tests in Docker in order to accelerate the Selenium test automation activity.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image36.gif)

## Introduction to Docker

When it comes to Selenium automation testing, it is important that a test run in one execution environment does not hinder the execution of tests run in another test environment (s). Hence, automation tests should be run in isolation, and Docker helps in realizing this ‘essential’ requirement.

Running Selenium tests in Docker containers helps in performing code reviews (at a faster pace), thereby realizing better quality code, attaining high test coverage, and developing an awesome-quality product. Docker provides the flexibility to execute tests in containers or isolate the tests in development and deployment. There are umpteen reasons to use Selenium with Docker for web application testing.

### What is Docker ?

Docker is an open-source containerization platform that makes it easy to create, deploy, and run applications in a secure manner using containers. Docker provides virtualization at the Operating System (OS) level. All the software parts in Docker are organized in Containers.

By default, Dockers come with the strongest isolation capabilities, and the applications run safely and securely in the relevant containers. Also, Docker runs as a discrete process on the host machine. Along with the flexibility to run Docker on local machines that run Windows, Mac, or Linux, it can also be run on cloud infrastructure like AWS, Azure, etc.

#### **Docker Images**

Essentially, the Docker image contains everything that is required for running the application as a container. Docker image includes the following:

- Code
- Libraries
- Runtime variables
- System Tools
- Settings
- Configuration files
- Environment variables, and more

The corresponding image can be deployed to any Docker environment as a Docker Container and can further facilitate running Selenium tests in Docker containers.

#### **Containers in Docker**

Container in Docker is a stand unit of software that packages the code and all the required dependencies so that the application can run more quickly and reliably from one computing environment to another.

As the Docker container image is a standalone, lightweight, executable software package, it is easy to install and run the relevant software (and services) using the same. To run the container, you do not need to boot up the guest operating system.

The installed Docker containers can also be shared with different users so that they can quickly get started with the actual work using the Container image. Containerized software, which is available for Windows and Linux-based applications, is agnostic of the underlying infrastructure. Many open-source serverless frameworks also leverage the advantages offered by the Docker container technology.

#### **Container Vs. Virtual Machines**

Containerization is often compared to Virtual Machines, but there is a glaring difference between both of them.

![Virtual Machines](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Virtual-Machines-1024x500.png)


Docker runs on the host operating system (e.g., Windows, Linux, etc.), and Docker containers contain the dependencies like libraries, configuration files, etc. This also includes the application itself. Docker Containers are light-weights since they do not contain any guest operating system. Shown below is a Docker container that consists of the Selenium Hub and Firefox & Chrome nodes.

![Chrome nodes](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Chrome-nodes.png)

On the other hand, virtual machines have their own guest operating system and run a Hypervisor that is primarily responsible for running VMs. Docker also has a Hyper-V backend, but it is recommended to use WSL (Windows Subsystem for Linux) for better performance. Since VMs have their own guest OS, the size of a VM is much bigger and requires more resources to run the VM.

## How to install and setup the Docker on Windows

Before running Selenium tests in Docker containers, we need to install and setup Docker on Windows. The pre-requisite step to run a Selenium test in a Docker container is installing Docker on the host machine. In our case, we would be installing Docker on a Windows machine. First, you have to download the Docker [Desktop for Windows](https://hub.docker.com/editions/community/docker-ce-desktop-windows/) – the community version of Docker for Microsoft Windows.

Docker desktop for Windows 10 is a native Windows application that provides an easy-to-use development environment for building, running, and shipping dockerized apps. It supports both Linux and Windows-based containers. In our demo, we would make use of the Linux-based containers.

Double-clicking on the ‘Docker for Windows Installer’ runs the installer. Installation is pretty straightforward.

![Docker for Windows](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Docker-for-Windows.png)

Docker for Windows requires the WSL 2 (Windows Subsystem for Linux) support. Select the necessary options for enabling Hyper-V Windows Features and Installing required Windows components for WSL 2.

![Docker for Windows](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Docker-for-Window.png)

You get the following message once the installation is successful.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image1-2.png)

### Common Issues and Solutions when installing Docker on Windows 10

Prior to running Selenium tests in Docker containers, you might encounter some issues related to enabling Hyper-V and data execution protection in the BIOS when starting the Docker.

- Hyper-V and Data Execution Protection

![Hyper-V and Data Execution](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Hyper-V-and-Data-Execution.png)

The support for hardware-assisted virtualization should be first enabled in the BIOS. The set of steps would vary from one manufacturer to another but entering the BIOS and enabling Virtualization should do the trick for you. After rebooting the system, open the Performance Tab in the Task Manager, and you would see that Virtualization is enabled in the machine.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/FileView.png)

Depending on the machine configuration, you can run either of the two commands on the terminal (as an Administrator) to enable Hyper-V support and data execution protection on the host machine:

```
dism.exe /Online /Enable-Feature:Microsoft-Hyper-V /All
```

```
bcdedit /set hypervisorlaunchtype auto
```

Restart the system to apply the changes. In certain cases, you would be required to enable Hyper-V from the ‘Windows Feature.’ For doing the same, navigate to ‘Control Panel’ 🡪 ‘Programs and Features’ 🡪 ‘Turn Windows features On or Off’ and enable the items – Hyper-V and Windows Hypervisor Platform.

![Windows Feature](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Windows-Feature.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image5-3.png)

Restart the machine so that changes take effect. Now the Docker instance should start successfully if WSL 2 is installed on the host machine.

* WSL 2 is not installed 

Though we have enabled Hyper-V on the host machine, it is recommended to use WSL 2 with Docker instead of Hyper-V. WSL 2 provides better performance than the Hyper-V backend. In case you have enabled WSL 2 support in Docker settings, but WSL 2 is not installed on the machine, you would witness the “WSL 2 is not installed” error.

![WSL 2 is not installed](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/WSL-2-is-not-installed.png)

Enable the option ‘Windows Subsystem for Linux’ in the Windows feature section in Control.

![Windows Subsystem](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Windows-Subsystem.png)

As stated in the WSL installation guide for Windows 10, first, we have to enable the Windows Subsystem for Linux. This can be done by running the following command on the terminal (as an Administrator):

```
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
```

Before installing WSL 2, you might need the Virtual Machine feature (which is an optional step).

```
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
```

Download the [WSL2 Linux kernel update package for the x64 machine](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi) and install it on the host machine. Set WSL 2 as the default version using the command:

```
wsl --set-default-version 2
```

Restart the machine for the changes to take effect. With this, you are all set to use the Docker Desktop with WSL 2 backend. In the Docker Desktop settings, enable the option ‘Use the WSL 2 based engine’ so that WSL 2 is used instead of Hyper-V backend.

![Docker Desktop](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Docker-Desktop-1024x371.png)

Run the command docker –version to check whether Docker is installed and the instance has started running:

![docker –version](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/docker-–version.png)

## Why use Selenium with Docker for web application testing

In this tutorial on how to run Selenium tests in Docker, we will see some of the major benefits that make Selenium with Docker an ideal combination for web app testing:

- **Scalable and Reliable**

In a normal Selenium Grid setup, the configuration involves hosting multiple VMs (Virtual Machines) as ‘Nodes’ and connecting the ‘Nodes’ to a single ‘Hub.’ When setting up the Selenium Grid, you have to download the Selenium Server jar (with Selenium 3) and run the same on the machine used to set up the Grid. Apart from this, the browsers and their respective browser drivers should be available on VMs (or Machines) that act as Selenium Nodes.

This approach is neither scalable nor reliable, as the infrastructure would require continuous maintenance and up-gradation to ensure that it is usable from a test point of view. Also, running Selenium Grid adds to unnecessary computing overhead.

Docker images that are used for [cross browser testing](https://www.lambdatest.com/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu) with Selenium contain several nodes in a single image. Also, Docker images share certain system resources, thereby leading to less resource utilization when compared to virtual machines.

- **Test locally hosted sites**

Docker containers have options to access local development sites. In case you are using Windows or Linux, using the option –host when running the Docker containers helps in testing locally hosted sites.

- **Less overhead of installations**

When using Selenium with Docker, there is no need to install the necessary browsers and browser drivers on the host machine. Overall, it is significantly quicker to get started with Selenium web [automation testing](https://www.lambdatest.com/learning-hub/automation-testing?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu) using pre-made Docker containers than installing & setting up the Selenium Grid. You can term it as ‘minimal installation and maximum benefits’!

A range of Docker images (with Selenium) on the Docker Hub can be used by running a few commands on the terminal. Some of these images on the Docker Hub were developed and maintained by Selenium HQ.

Here is a broad category of images that are available on the Docker Hub and used for web automation testing:

1. **Standalone:** Standalone images (of Chrome, Firefox, etc.) that can be run on the Selenium server. These images should be run on different ports (e.g., 4444, 4445, etc.) else it would result in port conflicts.
2. **Hub:** The role played by the Selenium Hub with Docker is the same as that of the normal Selenium Grid. In Docker terms, the Hub is a cloud-based service that lets you create images and test them.
3. **Node:** Akin to the Nodes in the Selenium terminology, Node containers can be started along with the Hub image. For example, Firefox and Chrome node containers can be started with the Selenium Hub image.

Above all, the Base image is used for building your own images. Later in the blog, we would demonstrate how to run selenium tests in Docker using a standalone container and a grid of containers.

- **Improved Security**

Docker is secure and portable, and the Dockers containers run in an isolated environment. Selenium tests can be executed in a much more secure manner with the Docker container when compared to the local Selenium Grid.

For improved scalability, Selenium tests on Docker can be:

- **Lesser chances of discrepancies**

The installed Docker container can be shared with other users, and the behavior remains unchanged irrespective of the underlying environment. For example, tests conducted on a Widows container would work seamlessly on a Linux-based container.

Hence, all the team 

members could make use of the same container, irrespective of the operating system in use.

- **No more Selenium Crash worries**

If you are a local Selenium Grid, there is a high probability of witnessing a Selenium crash. It could be annoying, and the only solution is restarting the Grid so that the required nodes can connect to the Grid.

With the Docker container, you can leave the crash worries at bay since it is just about discarding the old instance and spinning up a new Selenium instance when needed. Stopping and Starting the same Docker container (consisting of the Selenium Hub and Nodes) is fairly easy and takes only a few seconds to set things up for Selenium web automation testing.

- **Docker with Selenium 4**

[Selenium 4](https://www.lambdatest.com/blog/selenium4-w3c-webdriver-protocol/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu), which is still under the Alpha stage, has gained significant attention from the Selenium community and users alike. Apart from massive improvements like WebDriver W3C protocol, the introduction of relative locators, improved Selenium Grid, and useful Selenium IDE, Selenium 4 comes with Docker support.

[Docker images for Selenium 4](https://github.com/SeleniumHQ/docker-selenium) Grid Server let you start the standalone container with Chrome/Firefox/Opera. For setting up and configuring Hub and Nodes, Selenium 4 provides a number of ways to run the Docker images and create a network of Hub & Nodes.

![Docker images for Selenium 4](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Docker-images-for-Selenium-4.jpg)

To summarize, Docker Selenium manages the tasks related to Selenium web automation testing with relative ease in comparison to the traditional Selenium Grid setup.

## Creating Selenium Test in Docker

Now that the Docker is configured successfully, we look at how to run Selenium tests in Docker. Like a normal Selenium Grid, the configuration of Selenium Grid with Docker involves installing the Selenium Hub and the required Browser Node(s) in the container.

There are different ways in which Selenium tests can be run using the Selenium Docker container. Selenium can be run on a standalone (or single) Docker container or on a Grid consisting of multiple containers.

**Test Scenarios**

The same test scenarios are used for the demonstration of Selenium test automation with Docker. The tests are executed in parallel at the ‘Methods’ level.

**Test group – 1 [Test Group – “Search”]**

**Test Scenario – 1 (Browser: Chrome)**

1. Go to Google.
2. Search for ‘LambdaTest.’
3. Click on the first test result.
4. Assert if the page title does not match the expected title.

**Test Scenario – 2 (Browser: Chrome)**

1. Go to Bing.
2. Search for ‘LambdaTest Blog.’
3. Click on the first test result.
4. Assert if the page title does not match the expected title.

**Test group – 2 [Test Group – “ToDo”]**

**Test Scenario – 1 (Browser: Firefox)**

1. Go to https://lambdatest.github.io/sample-todo-app/
2. Mark the first two items (li1 and li2) as Done.
3. Add a new item, ‘Happy Testing at LambdaTest,’ to the ToDo list.
4. Assert if the new item is not added to the list.

**Test Scenario – 2 (Browser: Firefox)**

1. Go to https://lambdatest.github.io/sample-todo-app/
2. Mark the first three items (li1, li2, and li3) as Done 

When running the tests using Selenium Docker, you have the following options:

- Use a single (or standalone) container to launch the cross browser tests.
- Use a Grid of Containers to launch the cross browser tests.
- Use Zalenium – a scalable and flexible Container-based Selenium Grid that provides features like video recording, live preview, dashboard, and more. You can leverage the offerings of Zalenium to run Selenium tests on a cloud-based Selenium Grid provided by [LambdaTest](https://www.lambdatest.com/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu).

We look at each of these approaches in more detail in the subsequent sections.

### Running Selenium in a Standalone Container

In this “how to run Selenium tests in Docker” guide, we use a single container for launching all the tests. To get started, we have to first pull the required images from the [Docker Hub](https://hub.docker.com/). As we want to perform the tests on Chrome and Firefox browsers, we download the Chrome and Firefox Container images.

Run the below commands on the Terminal (Command Prompt or PowerShell) as an Administrator:

| Image | Command |
| --- | --- |
| Standalone Chrome | docker pull selenium/standalone-chrome |
| Standalone Firefox | docker pull selenium/standalone-firefox |

Running the docker pull commands for standalone-chrome and standalone-firefox downloads the latest version of the Chrome and Firefox container images.

**Standalone Chrome (Latest)**

```
docker pull selenium/standalone-chrome
```

![Standalone Chrome](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Standalone-Chrome.png)

**Standalone Firefox (Latest)**

```
docker pull selenium/standalone-firefox
```

![Standalone Firefox](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Standalone-Firefox.png)

You can also download a specific version of the container image by navigating to Docker Hub and searching for the required image. For example, the command docker pull selenium/standalone-chrome:87.0 will download version 87.0 of the Chrome Container.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image21-1024x483.png)

Once the images are downloaded, run the command docker images to verify whether the download was successful. As seen below, we see that the latest versions of Chrome and Firefox containers are available for use:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image13-2.png)

The default port that connects to the WebDriver is 4444, and the Chrome and Firefox Containers will be exposed to port 4444. Since we want to run the Selenium tests against Chrome and Firefox browsers, we use port 4445 for the Chrome Container and 4446 for the Firefox Container.

Run the container exposed on port number **4445** to connect to the Chrome WebDriver:

```
docker run -d -p 4445:4444 -v /dev/shm:/dev/shm selenium/standalone-chrome
```

Run the container exposed on port number **4446** to connect to the Firefox WebDriver:

 
```
docker run -d -p 4446:4444 -v /dev/shm:/dev/shm selenium/standalone-firefox
```

As seen in the screenshot below, the Chrome and Firefox docker containers are started successfully:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image16.png)

Running the docker ps command on the Windows PowerShell shows that the Chrome and Firefox Docker containers are ready for use:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image14-2.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image17.png)

Now we have to configure the RemoteWebDriver’s URL:

**Chrome Container**

```
public static String remote_url_chrome = "http://localhost:4445/wd/hub";
ChromeOptions options = new ChromeOptions();
driver.set(new RemoteWebDriver(new URL(remote_url_chrome), options));
```

**Firefox Container**

```
public static String remote_url_firefox = "http://localhost:4446/wd/hub";
FirefoxOptions options = new FirefoxOptions();
driver.set(new RemoteWebDriver(new URL(remote_url_firefox), options));
```

Now that we have touched upon the essentials of starting the individual Docker containers for Chrome and Firefox let’s look at the complete implementation.

**Implementation**

```java
package org.testnggroup;
 
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.safari.SafariOptions;
 
public class Helper {
    protected static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<>();
    public static String remote_url_chrome = "http://localhost:4445/wd/hub";
    public static String remote_url_firefox = "http://localhost:4446/wd/hub";
 
    public void setupThread(String browserName) throws MalformedURLException
    {
        if(browserName.equalsIgnoreCase("chrome"))
        {
            System.out.println("Inside Chrome");
            ChromeOptions options = new ChromeOptions();
            driver.set(new RemoteWebDriver(new URL(remote_url_chrome), options));
        }
        else if (browserName.equalsIgnoreCase("firefox"))
        {
            System.out.println("Inside Firefox");
            FirefoxOptions options = new FirefoxOptions();
            driver.set(new RemoteWebDriver(new URL(remote_url_firefox), options));
        }
    }
 
    public WebDriver getDriver()
    {
        return driver.get();
    }
 
    public void tearDownDriver()
    {
        getDriver().quit();
    }
}
```

Based on the parameter ‘environment’ passed from testng.xml, the test is run either on Chrome or Firefox browser.

Since the Chrome Container is on `http://localhost:4445/wd/hub`, a Remote WebDriver instance with remote URL set to Chrome Container is used for running the tests on Chrome.

```
public static String remote_url_chrome = "http://localhost:4445/wd/hub";
 
public void setupThread(String browserName) throws MalformedURLException
{
   if(browserName.equalsIgnoreCase("chrome"))
   {
      ChromeOptions options = new ChromeOptions();
      driver.set(new RemoteWebDriver(new URL(remote_url_chrome), options));
   }
   ......................
   ......................
}
```

Since the Firefox Container is on `http://localhost:4446/wd/hub`, a Remote WebDriver instance with remote URL set to Firefox Container is used for running the tests on Firefox.

```
public static String remote_url_chrome = "http://localhost:4445/wd/hub";
 
public void setupThread(String browserName) throws MalformedURLException
{
   ......................
   ......................
 	
   else if (browserName.equalsIgnoreCase("firefox"))
   {
      FirefoxOptions options = new FirefoxOptions();
      driver.set(new RemoteWebDriver(new URL(remote_url_firefox), options));
   }
```

```java
package org.testnggroup;
 
import org.openqa.selenium.*;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.IExecutionListener;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import java.io.Console;
import java.net.MalformedURLException;
import java.net.URL;
 
public class TestNG_SearchGroup extends Helper implements IExecutionListener
{
    public static String status = "passed";
 
    @Override
    public void onExecutionStart()
    {
        System.out.println("onExecutionStart");
    }
 
    @Test(priority = 1, groups = {"Search"})
    @Parameters({"environment"})
    public void test_GoogleSearch(String environment) throws InterruptedException, MalformedURLException
    {
        String search_string =" LambdaTest";
        String exp_title = "Most Powerful Cross Browser Testing Tool Online | LambdaTest";
 
        if (environment.equalsIgnoreCase("local"))
        {
            setupThread("chrome");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://www.google.com");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
 
        try {
            /* Enter the search term in the Google Search Box */
            WebElement search_box = webdriver.findElement(By.xpath("//input[@name='q']"));
            search_box.sendKeys(search_string);
 
            search_box.submit();
            Thread.sleep(3000);
 
            /* Click on the first result which will open up the LambdaTest homepage */
            WebElement lt_link = webdriver.findElement(By.xpath("//span[.='LambdaTest: Most Powerful Cross Browser Testing Tool Online']"));
            lt_link.click();
            Thread.sleep(5000);
 
            String curr_window_title = webdriver.getTitle();
            Assert.assertEquals(curr_window_title, exp_title);
            status = "passed";
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        if (getDriver() != null)
        {
            tearDownDriver();
        }
    }
 
    @Test(priority = 2, groups = {"Search"})
    @Parameters({"environment"})
    public void test_BingSearch(String environment) throws InterruptedException, MalformedURLException {
        String search_string ="LambdaTest Blog";
        String exp_title = "LambdaTest | A Cross Browser Testing Blog";
 
        if (environment.equalsIgnoreCase("local"))
        {
            setupThread("Chrome");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://www.bing.com");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
 
        try {
            /* Enter the search term in the Google Search Box */
            WebElement search_box = webdriver.findElement(By.xpath("//input[@id='sb_form_q']"));
            search_box.sendKeys(search_string + Keys.ENTER);
            Thread.sleep(3000);
 
            /* Click on the first result which will open up the LambdaTest homepage */
            WebElement lt_link = webdriver.findElement(By.xpath("//a[.='LambdaTest | A Cross Browser Testing Blog']"));
            lt_link.click();
            Thread.sleep(5000);
 
            String curr_window_title = webdriver.getTitle();
            Assert.assertEquals(curr_window_title, exp_title);
            status = "passed";
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        if (getDriver() != null)
        {
            tearDownDriver();
        }
    }
 
    @Override
    public void onExecutionFinish()
    {
        System.out.println("onExecutionFinish");
    }
}
```

```java
package org.testnggroup;
 
import org.openqa.selenium.*;
import org.testng.IExecutionListener;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
 
public class TestNG_ToDoGroup extends Helper implements IExecutionListener {
    public static String status = "passed";
 
    @Override
    public void onExecutionStart()
    {
        System.out.println("onExecutionStart");
    }
 
    @Test(priority = 1, groups = {"ToDo"})
    @Parameters({"environment"})
    public void test_Selenium4_ToDoApp_Test1(String environment) throws InterruptedException, MalformedURLException
    {
        if (environment.equalsIgnoreCase("local"))
        {
            setupThread("Firefox");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://lambdatest.github.io/sample-todo-app/");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
        Thread.sleep(5000);
 
        try
        {
            /* Let's mark done first two items in the list. */
            webdriver.findElement(By.name("li1")).click();
            webdriver.findElement(By.name("li2")).click();
 
            /* Let's add an item in the list. */
            webdriver.findElement(By.id("sampletodotext")).sendKeys("Happy Testing at LambdaTest");
            webdriver.findElement(By.id("addbutton")).click();
 
            /* Let's check that the item we added is added in the list. */
            String enteredText = webdriver.findElement(By.xpath("/html/body/div/div/div/ul/li[6]/span")).getText();
            if (enteredText.equals("Happy Testing at LambdaTest")) {
                System.out.println("Demonstration is complete");
                status = "passed";
            }
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        if (getDriver() != null)
        {
            tearDownDriver();
        }
    }
 
    @Test(priority = 2, groups = {"ToDo"})
    @Parameters({"environment"})
    public void test_Selenium4_ToDoApp_Test2(String environment) throws InterruptedException, MalformedURLException {
        if (environment.equalsIgnoreCase("local"))
        {
            setupThread("Firefox");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://lambdatest.github.io/sample-todo-app/");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
        Thread.sleep(5000);
 
        try
        {
            /* Let's mark done first three items in the list. */
            webdriver.findElement(By.name("li1")).click();
            webdriver.findElement(By.name("li2")).click();
            webdriver.findElement(By.name("li3")).click();
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        status = "passed";
        if (getDriver() != null)
        {
            tearDownDriver();
        }
    }
 
    @Override
    public void onExecutionFinish()
    {
        System.out.println("onExecutionFinish");
    }
}
```

```java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestNG Group Test" thread-count="4" parallel="methods">
    <!-- Tested in the Chrome instance -->
    <parameter name="environment" value="local"/>
    <test name="Search" verbose="2" preserve-order="true" enabled="true">
        <groups>
            <run>
                <include name = "Search"></include>
            </run>
        </groups>
        <classes>
            <class name="org.testnggroup.TestNG_SearchGroup"></class>
        </classes>
    </test>
 
    <!-- Tested in the Firefox instance -->
    <parameter name="environment" value="local"/>
    <test name="ToDoApp" verbose="2" preserve-order="true" enabled="true">
        <groups>
            <run>
                <include name = "ToDo"></include>
            </run>
        </groups>
        <classes>
            <class name="org.testnggroup.TestNG_ToDoGroup"></class>
        </classes>
    </test>
</suite>
```

**Execution**

With this, we are all set to run the tests in the respective containers. As seen in the container screenshot, two instances of the Chrome browser (or Chrome Driver) were instantiated on the Chrome Docker container (running on port number 4445)

![Chrome Docker](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Chrome-Docker-1024x517.png)

Similarly, two instances of the Firefox browser (or GeckoDriver) were instantiated on the Firefox Docker container (running on port number 4446)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image45-1024x522.png)

The tests are executed in a headless fashion since we have not installed the Docker images that do not have VNC preinstalled. As seen below, the tests are executed successfully:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image24-1024x190.png)

To view what is happening inside the Container, we would need to download the [standalone-chrome-debug](https://hub.docker.com/r/selenium/standalone-chrome-debug) and [standalone-firefox-debug](https://hub.docker.com/r/selenium/standalone-firefox-debug) images that have VNC preinstalled in them. The major downside of performing tests in a standalone container is low scalability. Hence, running Selenium in a standalone (or single) container is only suited for small projects.

### Running Selenium in a Grid of Containers  

The problem of scalability posed by the first option can be fixed by running Selenium in a Grid of containers. In large projects, you would want Selenium web automation tests to be conducted in parallel on different browser and OS combinations. This is where a Grid of different containers can be used for accelerating the cross browser testing activity.

With this approach, you can get a number of instances of different browsers (and browser versions). For example, you could have ‘X instances of Chrome v83.0, ‘y’ instances of Chrome v76.0, ‘Z instances of Firefox 68.0, and so on. Tests can be performed in parallel against different versions of various browsers.

![Running Selenium in a Grid of Containers](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Running-Selenium-in-a-Grid-of-Containers.png)

This approach uses the ‘Hub/Node’ model of the Selenium Grid. Test requests are sent by the client (or test code) to the Hub, which then dispatches the test request(s) to the nodes that are best suited for executing the tests.

To demonstrate how to run Selenium tests in Docker using a Grid of Containers, we use a setup that is best suited for the development environment. We will use the Debug variant nodes or standalone images so that we can see the tests in action inside the Docker using the VNC Viewer.

By default, the debug images start the VNC Server on port number 5900. However, the default port can be remapped to any external port that is currently not in use.

**Pull the required Docker Images**

The Grid is a composition of multiple Docker images, and those images should be first pulled before we use the Hub and Nodes.

| Image | Command |
| --- | --- |
| Selenium Hub | docker pull selenium/hub |
| Chrome Node | docker pull selenium/node-chrome-debug |
| Firefox Node | docker pull selenium/node-firefox-debug |

By default, the latest versions of the Container images are downloaded. Shown below are the screenshots that indicate that the Hub image and debug images of Chrome and Firefox were pulled successfully.

![Container images](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Container-images.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image30.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image29.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image28-1024x314.png)

Run the command docker images to ensure that all the images are pulled successfully.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image22.png)

Grid nodes with Chrome and Firefox installed have to be connected to the Grid Hub. Now that we have the required images, we can follow one of the following approaches to run Selenium in a Grid of containers:

- Trigger the docker run command to run and start the containers one at a time.
- Use docker-compose (or Compose) to define and run multi-container Docker applications and configure the application services.

In the first approach, we manually run the required commands to start the Selenium Hub and connect the required browser nodes (or images) to the Hub. This approach is best-suited for a smaller number of tests since the Hub and Nodes have to be started manually using the necessary commands.

In docker-compose (or Compose), you use a YAML file for configuring the application services. With a single command, you have the flexibility to create and start all the services from the configuration. The other upside of using Compose is that it works in a range of environments such as staging, production, development, testing, and CI workflows.

### How to use Docker run to start Docker containers

Here, we use the docker run command to start the downloaded Selenium image. Once the Hub is started, we connect the Chrome and Firefox Nodes to the Hub so that Selenium web automation tests can be performed on the same.

Here is the syntax of the docker run command:

```
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
```

The docker run command should mandatorily specify an image to derive the container. Let’s use the docker run command to start the Hub and attach Nodes to the same.

**Running the Selenium Hub**

Once the required Docker images are pulled, we start the Selenium Hub inside the Docker. We start the Selenium Hub using the following command:

```
docker run -d -P -p "4444:4444" --name selenium-hub selenium/hub
```

Here, we tell Docker to execute a container with the image called ‘selenium/hub.’ The image is tagged as ‘selenium-hub,’ which acts as an identifier of the image.

To expose a port, we use the following format:

```
[ip]:host_port:container_port
```

The [ip] field is used for defining the sources, and it defaults to 0.0.0.0 (if ip is not defined). The –publish list (or –p) option publishes the container’s port to the Host. The –publish-all (or –P) option publishes all the exposed ports to random ports.

Here, the host\_port 4444 (the first occurrence in 4444:4444) is accessible to the external world. You can monitor the status of the Grid running on the said port by navigating to the URL: `http://localhost:4444/grid/console`.

We verify whether the Selenium Hub container has started by running the command docker ps –a on the terminal.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image25-1024x166.png)

**Linking Browser to the Selenium Hub**

The –link flag takes the following form:

```
--link <name or id>:alias
```

Where ‘name’ is the name of the container that needs to be linked and ‘alias’ is the alias of the link name.

With the Selenium Hub up & running, we now start the Chrome and Firefox nodes by running the following commands on the terminal:

**Chrome (Debug) Node**

```
docker run -d -P -p 5900:5900 --link selenium-hub:hub selenium/node-chrome-debug
```

**Firefox (Debug) Node**

```
docker run -d -P -p 5901:5900 --link selenium-hub:hub selenium/node-firefox-debug
```

In our case, selenium-hub (–link **selenium-hub** : hub ) is the container that we are linking to, and hub is the alias of the container ( –link selenium-hub : hub ).

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image26-1024x174.png)

After executing the above commands, Chrome and Firefox node images will be connected (or linked) to the Container named selenium-hub. We verify whether the browser containers are running or not using the docker ps –a command.

To check whether the Selenium Hub (or server) is running and the Chrome & Firefox nodes are connected to the hub, run the command docker logs \<Selenium Hub ContainerId\>.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image47-1024x506.png)

Alternately, the URL `http://localhost:4444/grid/console` will show the status of the Selenium Hub and the Nodes connected to the hub. In case you are running the Selenium Hub container on a different port, please use that port number instead of 4444 in the URL.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image35-1024x228.png)

### How to run tests with Selenium Grid using Docker Compose

Manual triggering of docker run command to run Selenium tests in Docker is ideally suited in scenarios where less number of tests have to be executed on the Hub image. More the number of browser (and corresponding version) combinations, difficult it is to manage with docker run commands.

Configuring the Grid through docker-compose (or Compose) is relatively easy, as the Grid is a composition of multiple docker images. Using Compose is a three-step process:

1. Define the app’s environment with a Dockerfile so that it can be reproduced anywhere.
2. Define the requisite services that make up the app in a YAML file (e.g., docker-compose.yml) so that it can be run in an isolated environment.
3. Run the command docker-compose –f .\\<docker-file.yml\> up –d so that compose starts and runs the complete app.

Here is the Compose file (docker-compose.yml) for running the respective test scenarios on Chrome and Firefox browsers.

```
version: "3.9"
services:
 
  hub:
    image: selenium/hub
    ports:
      - "4444:4444"
 
    environment:
      GRID_MAX_SESSION: 16
      GRID_BROWSER_TIMEOUT: 3000
      GRID_TIMEOUT: 3000
 
  chrome:
    image: selenium/node-chrome-debug
    container_name: web-chrome
    depends_on:
      - hub
    environment:
      HUB_PORT_4444_TCP_ADDR: hub
      HUB_PORT_4444_TCP_PORT: 4444
      NODE_MAX_SESSION: 4
      NODE_MAX_INSTANCES: 4
    volumes:
      - /dev/shm:/dev/shm
    ports:
      - "5900:5900"
    links:
      - hub
 
  firefox:
    image: selenium/node-firefox-debug
    container_name: web-firefox
    depends_on:
      - hub
    environment:
      HUB_PORT_4444_TCP_ADDR: hub
      HUB_PORT_4444_TCP_PORT: 4444
      NODE_MAX_SESSION: 2
      NODE_MAX_INSTANCES: 2
    volumes:
      - /dev/shm:/dev/shm
    ports:
      - "5901:5900"
    links:
      - hub
```
 

Here is the overview of the Docker Compose file used for running the tests:

- **version –** The latest version of the docker-compose files.
- **services (or containers) –** This section contains the list of images being used and their configurations (e.g., the maximum number of instances, container names, host port & container port, etc.).
- **image –** The image used to start the container. Selenium Hub is started with the container image selenium/hub. Container named web-chrome is started using the image selenium/node-chrome-debug. Similarly, a container named web-firefox is started using the image selenium/node-firefox-debug.
- **ports –** Ports published in the \<Host:Container\> format.
- **volumes –** Host path is mounted to the service in \<Host:Container\> format.
- **depends\_on –** This indicates the dependency order of the containers. In our case, Firefox and Chrome images should be started only after the Hub starts. Hence, depends\_on for selenium/node-chrome-debug and selenium/node-firefox-debug containers is set to hub (i.e. selenium/hub container).
- **links –** The container that needs to be linked to. It is similar to the flags used in the –link command, which was discussed earlier.
- **environment –** These consist of the environment variables used across the container images. The environment variable HUB\_PORT\_4444\_TCP\_PORT indicates the container port number exposed by the Hub (which is 4444).
- **NODE\_MAX\_INSTANCES –** This indicates the maximum number of browser instances that can be instantiated at any given moment. We have set the maximum node instances (of chrome-debug and firefox-debug) to two, which means that at most two instances of Chrome and two firefox instances can run in parallel.
- **NODE\_MAX\_SESSION –** This environment variable indicates how many browsers (any browser and version) can run in parallel. For example, if the NODE\_MAX\_INSTANCES is set to 4 and NODE\_MAX\_SESSION is set to 2, you can run a Chrome Node (or Firefox Node) with 4 instances of Chrome (or Firefox) at the max parallelization level of 2 (as set in NODE\_MAX\_SESSION).

The docker-compose YML file (docker-compose.yml) when run command starts a Hub Container (selenium/hub) and two node services – selenium/node-chrome-debug and selenium/node-firefox-debug. The container names (or aliases) of the Node services are web-chrome and web-firefox, respectively. We start the Hub and Nodes by triggering the following command on the terminal:

```
docker-compose -f /path/to/docker-compose.yml up -d
```

The –d (or –detach) option in docker-compose up runs the containers in the background and prints the container names. This option is useful in cases where you want to start the containers running in the background and leave them running, thereby removing the hassle to trigger the docker-compose file each time you want to start the containers.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image33-1024x171.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image32.png)

We use the docker ps -a command to check whether the Selenium Hub Container and the Chrome & Firefox Nodes are spun:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image31-1024x72.png)

Since the Selenium Hub container starts at port 4444, we use the same URL `http://localhost:4444/grid/console` to check the status of the Hub and the Nodes connected to it.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image39-1024x230.png)

**Implementation**

The implementation for running tests on Selenium Grid using Docker Compose is similar to the implementation demonstrated in the section ‘Running Selenium in a Standalone Container.’ The only difference is that the tests would now run in a Docker Container that comprises debug versions of Chrome and Firefox images.

The Grid is configured to run on port 4444, and the test requests are executed in the respective Docker (Chrome/Firefox) based on the desired browser for the test. Hence, change is only involved in Helper.java where the remote URL is set to `http://localhost:4444/wd/hub`.

```
package org.testnggroup;
 
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.safari.SafariOptions;
 
public class Helper {
    protected static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<>();
    public static String remote_url = "http://localhost:4444/wd/hub";
 
    public void setupThread(String browserName) throws MalformedURLException
    {
        if(browserName.equalsIgnoreCase("chrome"))
        {
            ChromeOptions options = new ChromeOptions();
            driver.set(new RemoteWebDriver(new URL(remote_url), options));
        }
        else if (browserName.equalsIgnoreCase("firefox"))
        {
            FirefoxOptions options = new FirefoxOptions();
            driver.set(new RemoteWebDriver(new URL(remote_url), options));
        }
    }
 
    public WebDriver getDriver()
    {
        return driver.get();
    }
 
    public void tearDownDriver()
    {
        getDriver().quit();
    }
}
```

The rest of the implementation remains the same, as seen in the previous section.

**Execution**

As seen above, you can run tests using the Docker run command or Docker Compose (docker-compose), which in turn spins the required Containers. In both the cases:

- **Selenium Hub Container –** It is spun at port 4444 (as seen in 4444 : 4444). The Browser Timeout and Grid Timeout are set to 3000 seconds. At any given time, the Hub can handle 16 concurrent sessions (or tests).
- **Node Containers –** selenium/node-chrome-debug and selenium/node-firefox-debug containers are spun at ports 5900 and 5901 respectively. These ports are visible to the external world, and the same can be used for capturing the status of the tests using the VNC Viewer (or VNC Client).

As seen in the execution snapshot, the tests are running successfully on the Selenium Grid. The two instances of Chrome (as well as Firefox) are greyed out (or disabled), indicating that the tests to run on Chrome (and Firefox) were executed in parallel.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image49-1024x239.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image43-1024x232.png)

Since the Parallel attribute in testng.xml is set to Methods, all the methods with the @Test annotation are executed in parallel.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image41-1024x149.png)

## Debugging Docker Container with RealVNC Viewer

The major advantage of using debug variant of the Node or standalone images is that VNC Server is preinstalled in those images. By default, the VNC Server in the debug images starts at port number 5900. Hence, the images can be used for debugging the tests running in the corresponding containers.

On the whole, it helps you understand what’s happening inside the Docker Containers.

### Download RealVNC Viewer

The first step is downloading real-vnc (or VNC Viewer) for installing on the host machine. In our case, the host OS is Windows 10, so we downloaded [VNC Viewer for Windows](https://www.realvnc.com/en/connect/download/viewer/windows/).

### Pull debug images of the Nodes

We need the debug images of the respective Nodes (i.e., [selenium/node-chrome-debug](https://hub.docker.com/r/selenium/node-chrome-debug) and [selenium/node-firefox-debug](https://hub.docker.com/r/selenium/node-firefox-debug)).

As a part of the demonstration under the section Running Selenium in a Grid of Containers, we have already pulled the debug variants of Chrome and Firefox Nodes. Once the debug images of the Nodes are pulled, you have to start the Docker container of the image. We started the Docker container in the demonstration under the section How to run tests with Selenium Grid using Docker Compose.

We verify whether the Hub and Nodes have started successfully by triggering the docker ps -a command on the terminal:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image37.png)

As seen in the command screenshot, the ports numbers of the respective nodes are below:

| Image | Container Port No. |
| --- | --- |
| selenium/node-chrome-debug | 5900 |
| selenium/node-firefox-debug | 5901 |

To see what is happening on the respective nodes using the RealVNC Viewer, the VNC Server has to be set to the following:

| Image | Container Port No. | VNC Server Setting |
| --- | --- | --- |
| selenium/node-chrome-debug | 5900 | 0.0.0:5900 (or localhost:5900) |
| selenium/node-firefox-debug | 5901 | 0.0.0:5901 (or localhost:5901) |

The next step is configuring the respective VNC Server values in the Real VNC Viewer installed on the host machine.

### Starting the VNC Viewer for monitoring the tests

Follow the below-mentioned steps for checking what is happening inside the container so that you can monitor the status of Selenium web automation tests:

1. Acquire the port that the VNC Server is exposed to by running the below command:

```
docker port <Container Name | Container Id> 5900
```

In our case, the ID of the node web-chrome is 7ee5a430ff46. The port 5900 can be acquired by running either of the commands:

```
docker port 7ee5a430ff46 5900
```

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image38.png)

```
docker port 7ee5a430ff46 5900
```

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image34.png)

2. In Real VNC Viewer, create a new connection by navigating to File 🡪 Create a New Connection.
3. Create two connections with the settings shown earlier for monitoring the tests running on nodes – selenium/node-chrome-debug and selenium/node-firefox-debug.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image54-1024x696.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image55-1024x721.png)

4. Open the connections that we created in step(2).
5. When prompted for the password, enter the password as secret. Click on Remember Password so that you do not have to enter the password each time you open the connection.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image40.png)

6. Now that the Selenium WebDriver Container and VNC Server are running, you can see the tests running in the respective browsers on the VNC Server.

![lambdatest blogs](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/lambdatest-blogs.png)

![lambdatest blogs](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/lambdatest-blogs-1.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image46.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image56-1024x448.png)

The VNC Server is useful for debugging and checking what is happening inside the Container. The primary requirement is using debug variants of the respective images since the images have VNC Server preinstalled in the same.

## Running Selenium Tests on LambdaTest with Docker

In this guide on how to run Selenium tests in Docker, we have seen it is easy to integrate Selenium Grid with Docker. However, the capabilities offered by the Selenium Grid and Docker can be further enhanced by integrating a cloud-based Selenium Grid like LambdaTest with Docker. This integration is possible with Zalenium, an open-source Docker-based Selenium Grid framework. Zalenium provides useful features like video recording, live preview, dashboard, and basic authentication.

### What is Zalenium ?

Zalenium is an open-source Docker-based solution that eliminates the need for maintaining an in-house Selenium Grid. Zalenium makes this possible by offering a Docker-based Selenium Grid on the cloud that is automatically updated with the latest browsers and browser versions.

Akin to Selenium desired capabilities, Zalenium also offers capabilities that are used for defining the Desired Capabilities in the test automation suite. Zalenium also lets you perform automation testing of the locally hosted pages. However, the downside of this approach is that automated browser testing can only be performed on the browsers installed on the local machine.

### Major Features of Zalenium

The [docker-selenium](https://github.com/elgalu/docker-selenium) based solution can be used for running tests on an in-house Selenium Grid as well as redirecting the tests to a cloud-based Selenium Grid offered by LambdaTest.

Here are the major features offered by Zalenium:

- An intuitive dashboard for analyzing the logs of the Selenium script execution.
- Live previews of the Selenium script execution on Selenium Grid.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image60-1024x413.png)

- Custom capabilities for running cross-browser tests and responsive tests on preferred screen resolutions and time-zones.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image42.png)

- The recorded video of the Selenium tests helps in the review and debug process.
- Zalenium Grid on the cloud comes with basic authentication, thereby providing basic security when accessing the Grid.

### How to use LambdaTest with Zalenium Docker

LambdaTest, when integrated with [Zalenium Docker](https://www.lambdatest.com/blog/zalenium-integration-with-lambdatest/?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu), can be used for performing automated browser testing for locally hosted pages across 2,000+ browsers and browser versions.

Here are the prerequisites for using LambdaTest docker:

1. Ensure that you have the Zalenium docker setup ready. For setting up the Zalenium Docker, pull the following images – Docker-Selenium (elgalu/selenium) and Zalenium (dosel/zalenium). Run the following commands on the terminal (as an administrator):

```
docker pull elgalu/selenium
 
docker pull dosel/zalenium
```
 
2. Here are the download screenshots of the following images:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image57.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image58-1024x753.png)

3. You need a working (or valid) account on LambdaTest. Please make a note of the username and access-key from the [LambdaTest Profile Page](https://accounts.lambdatest.com/detail/profile).
4. Set up the necessary environment variables (LT\_USERNAME and LT\_ACCESS\_KEY) by running the following commands on Cygwin (on Windows):

```
export LT_USERNAME=<lt_username>
 
export LT_ACCESS_KEY=<lt_access_key>
```

Here is the execution screenshot when run on Cygwin:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image50.png)

5. Now that we have downloaded the necessary docker images, the next step is to specify LambdaTest environment variables into the Zalenium Docker.

When using the Zalenium Docker with the LambdaTest Selenium Grid, you have the option to use the LambdaTest tunnel. For configuring the LambdaTest tunnel, download UnderPass and install it on the local machine. Start the tunnel from [UnderPass](https://downloads.lambdatest.com/underpass/master/UnderPass%20Setup.exe) as shown below:

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image51.png)

6. Declare the LambdaTest environment variables into the respective Zalenium Docker over which the automated browser testing has to be performed:
 
```
docker run --rm -ti --name zalenium -p 4444:4444 \
-e LT_USERNAME -e LT_ACCESS_KEY -e https://hub.lambdatest.com/wd/hub \
-v /c/Test_Videos:/home/seluser/videos \
-v /var/run/docker.sock:/var/run/docker.sock \
--privileged dosel/zalenium start --lambdaTestEnabled true --startTunnel true
```

Let’s figure out what every parameter in the test means:

- The image zalenium (i.e., dosel/zalenium) is started at port 4444.
- The environment variables which we declared in the previous step are used for accessing the LambdaTest Selenium Grid [i.e., `https://hub.lambdatest.com/wd/hub`].
- The execution videos will be stored in the folder C:/Test\_Videos. Create a folder in the desired destination before running the tests.
- The variable lambdaTestEnabled is set to true since we would be running the tests on LambdaTest Selenium Grid.
- Setting startTunnel to true means that the LambdaTest tunnel will be used in the tests. It does not create the tunnel but only starts the tunnel.

When you check ‘Containers/Apps’ in Docker, you would see that the Zalenium Docker is running on port 4444.

![Zalenium Docker](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Zalenium-Docker.png)

As seen below, the node is registered to the hub, which is running at `http://localhost:4444/grid/register` Zalenium and LambdaTest are now ready for use.

![Zalenium and LambdaTest](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Zalenium-and-LambdaTest-1024x397.png)

The status of the Grid can be monitored by entering `http://localhost:4444/grid/console` in the browser.

With this, we are all set to run the tests on the LambdaTest Grid using the Zalenium Docker. The implementation is similar to the one used for running Selenium tests in Docker on a local Selenium Grid, except that the cross browser requests are now redirected by Zalenium Docker to the cloud-based Selenium Grid on LambdaTest.

**Implementation**

```java
package org.testnggroup;
 
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.safari.SafariOptions;
 
public class Helper {
    protected static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<>();
    public static String username = "user-name";
    public static String access_key = "access-key";
    public static String remote_url = "http://localhost:4444/wd/hub";
 
    public void setupLTCombination (String build, String name, String platformName, String browserName, String browserVersion) throws MalformedURLException
    {
        DesiredCapabilities capabilities = new DesiredCapabilities();
 
        capabilities.setCapability("build", build);
        capabilities.setCapability("name", name);
        capabilities.setCapability("platform", platformName);
        capabilities.setCapability("browserName", browserName);
        capabilities.setCapability("version",browserVersion);
        capabilities.setCapability("tunnel",true);
 
        driver.set(new RemoteWebDriver(new URL(remote_url), capabilities));
    }
 
    public WebDriver getDriver()
    {
        return driver.get();
    }
 
    public void tearDownDriver()
    {
        getDriver().quit();
    }
}
```

As the Zalenium docker image (with LambdaTest integration) is running on port 4444, the test URL is set to `http://localhost:4444/wd/hub`.

```java
package org.testnggroup;
 
import org.openqa.selenium.*;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.IExecutionListener;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import java.io.Console;
import java.net.MalformedURLException;
import java.net.URL;
 
public class TestNG_SearchGroup extends Helper implements IExecutionListener
{
    public static String status = "passed";
 
    @Override
    public void onExecutionStart()
    {
        System.out.println("onExecutionStart");
    }
 
    @Test(priority = 1, groups = {"Search"})
    @Parameters({"environment"})
    public void test_GoogleSearch(String environment) throws InterruptedException, MalformedURLException
    {
        String search_string =" LambdaTest";
        String exp_title = "Most Powerful Cross Browser Testing Tool Online | LambdaTest";
 
        if (environment.equalsIgnoreCase("cloud"))
        {
            setupLTCombination("test_GoogleSearch", "test_GoogleSearch",
                    "MacOS Big sur", "Safari", "14.0");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://www.google.com");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
 
        try {
            /* Enter the search term in the Google Search Box */
            WebElement search_box = webdriver.findElement(By.xpath("//input[@name='q']"));
            search_box.sendKeys(search_string);
 
            search_box.submit();
            Thread.sleep(3000);
 
            /* Click on the first result which will open up the LambdaTest homepage */
            WebElement lt_link = webdriver.findElement(By.xpath("//span[.='LambdaTest: Most Powerful Cross Browser Testing Tool Online']"));
            lt_link.click();
            Thread.sleep(5000);
 
            String curr_window_title = webdriver.getTitle();
            Assert.assertEquals(curr_window_title, exp_title);
            status = "passed";
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        if (getDriver() != null)
        {
            //webdriver.quit();
            tearDownDriver();
        }
    }
 
    @Test(priority = 2, groups = {"Search"})
    @Parameters({"environment"})
    public void test_BingSearch(String environment) throws InterruptedException, MalformedURLException {
        String search_string ="LambdaTest Blog";
        String exp_title = "LambdaTest | A Cross Browser Testing Blog";
 
        if (environment.equalsIgnoreCase("cloud"))
        {
            setupLTCombination("test_BingSearch", "test_BingSearch",
                    "Windows 7", "Firefox", "84.0");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://www.bing.com");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
 
        try {
            /* Enter the search term in the Google Search Box */
            WebElement search_box = webdriver.findElement(By.xpath("//input[@id='sb_form_q']"));
            search_box.sendKeys(search_string + Keys.ENTER);
            Thread.sleep(3000);
 
            /* Click on the first result which will open up the LambdaTest homepage */
            WebElement lt_link = webdriver.findElement(By.xpath("//a[.='LambdaTest | A Cross Browser Testing Blog']"));
            lt_link.click();
            Thread.sleep(5000);
 
            String curr_window_title = webdriver.getTitle();
            Assert.assertEquals(curr_window_title, exp_title);
            status = "passed";
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        if (getDriver() != null)
        {
            //webdriver.quit();
            tearDownDriver();
        }
    }
 
    @Override
    public void onExecutionFinish()
    {
        System.out.println("onExecutionFinish");
    }
}
```

```java
package org.testnggroup;
 
import org.openqa.selenium.*;
import org.testng.IExecutionListener;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
 
public class TestNG_ToDoGroup extends Helper implements IExecutionListener {
    public static String status = "passed";
 
    @Override
    public void onExecutionStart()
    {
        System.out.println("onExecutionStart");
    }
 
    @Test(priority = 1, groups = {"ToDo"})
    @Parameters({"environment"})
    public void test_Selenium4_ToDoApp_Test1(String environment) throws InterruptedException, MalformedURLException
    {
        if (environment.equalsIgnoreCase("cloud"))
        {
            setupLTCombination("test_Selenium4_ToDoApp_Test1", "test_Selenium4_ToDoApp_Test1",
                    "Windows 10", "MicrosoftEdge", "87.0");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://lambdatest.github.io/sample-todo-app/");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
        Thread.sleep(5000);
 
        try
        {
            /* Let's mark done first two items in the list. */
            webdriver.findElement(By.name("li1")).click();
            webdriver.findElement(By.name("li2")).click();
 
            /* Let's add an item in the list. */
            webdriver.findElement(By.id("sampletodotext")).sendKeys("Happy Testing at LambdaTest");
            webdriver.findElement(By.id("addbutton")).click();
 
            /* Let's check that the item we added is added in the list. */
            String enteredText = webdriver.findElement(By.xpath("/html/body/div/div/div/ul/li[6]/span")).getText();
            if (enteredText.equals("Happy Testing at LambdaTest")) {
                System.out.println("Demonstration is complete");
                status = "passed";
            }
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        if (getDriver() != null)
        {
            //webdriver.quit();
            tearDownDriver();
        }
    }
 
    @Test(priority = 2, groups = {"ToDo"})
    @Parameters({"environment"})
    public void test_Selenium4_ToDoApp_Test2(String environment) throws InterruptedException, MalformedURLException {
        if (environment.equalsIgnoreCase("cloud"))
        {
            setupLTCombination("test_Selenium4_ToDoApp_Test2", "test_Selenium4_ToDoApp_Test2",
                    "Windows 8", "Firefox", "84.0");
        }
        WebDriver webdriver = getDriver();
        webdriver.navigate().to("https://lambdatest.github.io/sample-todo-app/");
        webdriver.manage().window().maximize();
        System.out.println("Started session");
        Thread.sleep(5000);
 
        try
        {
            /* Let's mark done first three items in the list. */
            webdriver.findElement(By.name("li1")).click();
            webdriver.findElement(By.name("li2")).click();
            webdriver.findElement(By.name("li3")).click();
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        status = "passed";
        if (getDriver() != null)
        {
            //webdriver.quit();
            tearDownDriver();
        }
    }
 
    @Override
    public void onExecutionFinish()
    {
        System.out.println("onExecutionFinish");
    }
}
```

```java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestNG Group Test" thread-count="4" parallel="methods">
    <!-- Tested in the Chrome instance -->
    <parameter name="environment" value="cloud"/>
    <test name="Search" verbose="2" preserve-order="true" enabled="true">
        <groups>
            <run>
                <include name = "Search"></include>
            </run>
        </groups>
        <classes>
            <class name="org.testnggroup.TestNG_SearchGroup"></class>
        </classes>
    </test>
 
    <!-- Tested in the Firefox instance -->
    <parameter name="environment" value="cloud"/>
    <test name="ToDoApp" verbose="2" preserve-order="true" enabled="true">
        <groups>
            <run>
                <include name = "ToDo"></include>
            </run>
        </groups>
        <classes>
            <class name="org.testnggroup.TestNG_ToDoGroup"></class>
        </classes>
    </test>
</suite>
```

As seen in testng.xml, a parameter named ‘environment’ is passed to the respective tests. The parameter is set to Cloud to indicate that the LambdaTest Selenium Grid is used for running the tests. We would not delve deeper into the implementation as the code is self-explanatory.

**Execution**

Run the TestNG project, showcasing the use of Zalenium Docker with LambdaTest by triggering the tests in testng.xml. We monitor the status of allocated resources by logging on to `http://localhost:4444/grid/console`.

Since we are running parallel tests on all the @Test Methods (i.e., parallel=”methods”), two methods in a single class run in parallel. When the tests are running, the two sessions on LambdaTest Grid indicate that the tests are currently running on the Grid.

![TestNG project](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/TestNG-project-1024x353.png)

Here is the execution snapshot from the LambdaTest Automation Dashboard, which indicates the progress of tests running parallel.

![Automation Dashboard](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/Automation-Dashboard-1024x241.png)

Here is the final execution snapshot obtained from the Automation Dashboard and IntelliJ IDEA, which indicate that the tests were executed successfully.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image64-1024x195.png)

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image65-1024x329.png)

When setting up the Zalenium docker with LambdaTest, we specified that the test execution videos should be stored at C:\Test\_Videos.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image59.png)

As seen below, the execution videos are available at C:\Test\_Videos. The video recording facility is built-in the Zalenium docker, and it should be leveraged to verify the status of the test scenarios.

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image61.png)

## Dock It Up

![](https://www.lambdatest.com/blog/wp-content/uploads/2021/03/image67.gif)

In this tutorial on how to run [Selenium](https://www.lambdatest.com/selenium?utm_source=dev&utm_medium=Blog&utm_campaign=Himanshu-17052021&utm_term=Himanshu) tests in Docker, we have seen how Docker lets you run tests in containers and isolate the tests in development and deployment. Docker with Selenium provides a light-weight solution to run UI tests, that too in an isolated environment.

The Zalenium docker can be used with the local Selenium Grid for performing automated browser testing. However, the Zalenium docker, when integrated with cloud-based Selenium Grid by LambdaTest, enables you to perform cross browser testing at scale. In a nutshell, Docker and Selenium WebDriver provide the ideal combination for performing automated browser tests for a range of web projects.