Last Updated On
In this tutorial, we will be discussing about how to run the same tests on different browsers using Selenium Grid 4 with Docker.
Table of Contents
- Prerequisite
- What is Cross Browser Testing?
- What is Selenium Grid?
- What is new in Selenium Grid 4?
- What is Docker?
- What is Docker Compose?
- Project Structure
- How to perform cross browser testing with Selenium Grid and Docker
Prerequisite:
- JAVA is installed
- Eclipse or IntelliJ is installed
- TestNG is installed
- Maven is installed
- MAVEN_HOME and JAVA_HOME are configures
What is Cross Browser Testing?
Cross-browser testing is a software testing practice that involves evaluating the compatibility and functionality of a website or web application across different web browsers. The goal of cross-browser testing is to ensure that the website or application works consistently and as expected on various browsers, operating systems, and devices.
Since different web browsers (such as Google Chrome, Mozilla Firefox, Microsoft Edge, Safari, etc.) may interpret and render HTML, CSS, and JavaScript code differently, cross-browser testing helps identify and address any discrepancies or issues that might arise. These differences can affect the visual appearance, layout, performance, and functionality of a website or application.
What is Selenium Grid?
Selenium Grid enables the execution of WebDriver scripts on remote machines (virtual or physical) by routing client commands to remote browser instances. Selenium Grid is a component of the Selenium testing framework that allows you to distribute and run tests across multiple browsers, operating systems, and machines simultaneously. It is particularly useful for performing parallel testing and cross-browser testing, helping to speed up the testing process and ensure consistent behavior across different environments.
What is new in Selenium Grid 4?
Grid 4 makes use of a variety of new technologies to enable scaling while allowing for local execution.
Selenium Grid 4 is a new implementation that does not share the previous version’s codebase.
I like how noVNC is packaged with Selenium Grid. In the dashboard, there is a Sessions tab that, when clicked, displays the links to the browser sessions that are now active, along with a video icon. When you click the video icon, you will be prompted to enter the password (“secret”), following which you will be taken to the current browser session where you can view the test live.
If we wanted to observe what was going on inside the browser session, we had to explicitly configure the grid for noVNC viewer in the prior version. From the grid, we just saw the browser icons highlighted, letting us know that the tests were being run in this or that browser.
What is Docker?
Docker is an open platform for developing, shipping, and running applications inside the containers. Containers are lightweight, portable, and self-sufficient units that package an application and its dependencies (such as libraries, frameworks, and runtime environments) together. Docker provides a consistent environment for running applications across different systems, making it easier to ensure that an application behaves the same way in development, testing, and production environments.
CLI Options for Docker
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-51.png?w=1200)
What is Docker Compose?
Docker Compose is a tool provided by Docker that allows you to define and manage multi-container Docker applications. It uses a simple and declarative YAML file to define the services, networks, and volumes that make up your application stack.
Project Structure
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-70.png?w=778)
How to perform cross browser testing with Selenium Grid and Docker
1. Install Docker on Windows
Download Docker in Windows: https://docs.docker.com/docker-for-windows/install/
Docker Desktop does not start automatically after installation. To start Docker Desktop, search for Docker, and select Docker Desktop in the search results.
When the whale icon in the status bar stays steady, Docker Desktop is up-and-running, and is accessible from any terminal window.
2. Verify Installation of Docker
Go to CMD and type below command:
docker -version
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-56.png?w=380)
3. Create a Maven project
Click here to know How to create a Maven project
Below is the Maven project structure. Here,
Group Id – com.example
Artifact Id – CrossBrowser_SeleniumGrid4
Version – 0.0.1-SNAPSHOT
Package – com. example
4. Add dependencies to the project
Add Selenium, Selenium WebDriverManager and TestNG dependencies to the pom.xml.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>SeleniumGrid4</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SeleniumGrid4</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<selenium.version>4.11.0</selenium.version>
<webdrivermanager.version>5.4.1</webdrivermanager.version>
<testng.version>7.8.0</testng.version>
<maven.compiler.plugin.version>3.10.1</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.0.0-M7</maven.surefire.plugin.version>
<maven.compiler.source.version>11</maven.compiler.source.version>
<maven.compiler.target.version>11</maven.compiler.target.version>
</properties>
<dependencies>
<!-- Selenium 4 Dependency -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
<!-- Selenium WebDriver Manager -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>${webdrivermanager.version}</version>
</dependency>
<!-- TestNG Dependency -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${maven.compiler.source.version}</source>
<target>${maven.compiler.target.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
5. Create a Test Code
Creating an instance of the Remote WebDriver and passing the selenium endpoint and chrome options defined in it.
To run a Remote WebDriver client, we first need to connect to the RemoteWebDriver. We do this by pointing the URL to the address of the server running our tests. In order to customize our configuration, we set desired capabilities.
BaseTests
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;
import java.net.URL;
import java.time.Duration;
public class BaseTests {
protected static ThreadLocal<RemoteWebDriver> driver = new ThreadLocal<RemoteWebDriver>();
public static String remote_url = "http://localhost:4444";
public final static int TIMEOUT = 5;
@BeforeMethod
@Parameters("browser")
public void setUp(String browser) throws Exception {
if(browser.equalsIgnoreCase("chrome")) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
options.addArguments("--headless=new");
options.addArguments("--remote-allow-origins=*");
driver.set(new RemoteWebDriver(new URL(remote_url), options));
System.out.println("Browser Started :"+ browser);
} else if (browser.equalsIgnoreCase("firefox")) {
FirefoxOptions options = new FirefoxOptions();
options.addArguments("--start-maximized");
options.addArguments("-headless");
driver.set(new RemoteWebDriver(new URL(remote_url), options));
System.out.println("Browser Started :"+ browser);
} else if (browser.equalsIgnoreCase("edge")) {
EdgeOptions options = new EdgeOptions();
options.addArguments("--start-maximized");
options.addArguments("--headless=new");
driver.set(new RemoteWebDriver(new URL(remote_url), options));
System.out.println("Browser Started :"+ browser);
} else {
throw new Exception ("Browser is not correct");
}
driver.get().get("https://opensource-demo.orangehrmlive.com/");
driver.get().manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
public WebDriver getDriver() {
return driver.get();
}
@AfterMethod
public void closeBrowser() {
driver.get().quit();
driver.remove();
}
}
LoginPageTests
import org.openqa.selenium.By;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
public class LoginPageTests extends BaseTests {
By userName = By.name("username");
By passWord = By.name("password");
By loginBtn = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button");
By errorMessage = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p");
By blankUsername = By.xpath("//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span");
By dashboardPage = By.xpath("//*[@id='app']/div[1]/div[1]/header/div[1]/div[1]/span/h6");
@Test
public void invalidCredentials() {
getDriver().findElement(userName).sendKeys("1234");
getDriver().findElement(passWord).sendKeys("12342");
getDriver().findElement(loginBtn).click();
String actualErrorMessage = getDriver().findElement(errorMessage).getText();
System.out.println("Actual ErrorMessage :" + actualErrorMessage);
assertEquals(actualErrorMessage,"Invalid credentials");
}
@Test
public void blankUsername() {
getDriver().findElement(userName).sendKeys("");
getDriver().findElement(passWord).sendKeys("12342");
getDriver().findElement(loginBtn).click();
String actualErrorMessage = getDriver().findElement(blankUsername).getText();
System.out.println("Actual ErrorMessage :" + actualErrorMessage);
assertEquals(actualErrorMessage,"Required");
}
@Test
public void successfulLogin() {
getDriver().findElement(userName).sendKeys("Admin");
getDriver().findElement(passWord).sendKeys("admin123");
getDriver().findElement(loginBtn).click();
String actualMessage = getDriver().findElement(dashboardPage).getText();
System.out.println("Message :" + actualMessage);
assertEquals(actualMessage,"Dashboard");
}
}
6. Create a testng.xml
It is very easy to create testng.xml in the case of Eclipse. Right-click on the project, and select TestNG -> Convert to TestNG. It will create a basic testng.xml structure. In case of IntelliJ, create a new file with the name of testng.xml and copy the code from here. Here, we are running the tests parallelly also.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="tests" thread-count="3">
<test name="Chrome Test">
<parameter name="browser" value="chrome"></parameter>
<classes>
<class name="com.example.tests.LoginPageTests"/>
</classes>
</test> <!-- Test -->
<test name="Firefox Test">
<parameter name="browser" value="firefox"></parameter>
<classes>
<class name="com.example.tests.LoginPageTests"/>
</classes>
</test> <!-- Test -->
<test name="Edge Test">
<parameter name="browser" value="edge"></parameter>
<classes>
<class name="com.example.tests.LoginPageTests"/>
</classes>
</test> <!-- Test -->
</suite> <!-- Suite -->
7. Create docker-compose file
version: "3"
services:
chrome:
image: selenium/node-chrome:4.11.0-20230801
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
firefox:
image: selenium/node-firefox:4.11.0-20230801
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
edge:
image: selenium/node-edge:4.11.0-20230801
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
selenium-hub:
image: selenium/hub:4.11.0-20230801
container_name: selenium-hub
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"
- version: 3. It is the latest version of the docker-compose files.
- services(containers): This contains the list of the images and their configurations.
- image: It defines which image will be used to spin up container.
- ports: Published ports with host:container format.
- container_name: You can give name to your containers.
- depends_on: This defines the required dependency before spinning up the container. In our docker-compose.yml file, containers Chrome and Firefox are dependent upon container hub to spin up.
- SE_NODE_MAX_INSTANCES: This defines how many instances of same version of browser can run over the Remote System.
- SE_NODE_MAX_SESSIONS: This defines maximum number of concurrent sessions that will be allowed.
8. Start the Selenium Grid
We have the docker compose file ready with all the configurations required to start the selenium grid.
To start the grid we need to navigate to the folder where our docker compose file is located and run the following command:
docker-compose up
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-57.png?w=1200)
Once the grid is up and running, we can navigate to http://localhost:4444 and checkout the instances which are up and running as per the configurations we gave in the docker compose file.
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-66.png?w=1200)
9. Execute the tests
Go to the command line and execute the tests using the below command:
mvn clean test
The output of the above program is shown below:
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-69.png?w=1107)
Checkout the image below, this is how the selenium grid dashboard looks when the tests execution gets started
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-67.png?w=1200)
As mentioned earlier, in selenium grid 4, we have the sessions overview as well. So, when we click on the Session Tab we can see the execution happening live and there are other details as well displayed in the Dashboard like Capabilities, Start time, Duration and Node URI which are useful metrics from the test automation reporting.
We need to click on the video icon beside the browser session to watch the session live and it will ask for password here. The password is “secret”
This is how the test execution in Chrome looks like and its actually executing the tests.
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-59.png?w=1200)
10. View the Reports
TestNG generate the reports. Go to target/surefire-reports as shown in the below image.
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-71.png?w=465)
Emailable-Report.html
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-72.png?w=973)
Index.html
![](https://qaautomation.expert/wp-content/uploads/2023/08/image-74.png?w=1200)
11. Stop the Selenium Grid
Once the execution of the tests are finished, it is advisable to stop the Grid. To stop the grid, we can press ctrl+c in the command prompt/terminal and it will instantly stop the containers. To Stop and remove containers, networks, volumes, and images created by docker we can use the following command:
docker-compose down
Congratulations!!. The above steps allow running Selenium tests in Docker seamlessly. Happy Learning.