When performing cross browser testing manually, one roadblock that you might have hit during the verification phase is testing the functionalities of your web application/web product across different operating systems / devices / browsers are the test coverage with respect to time. With thousands of browsers available in the market, automation testing for validating cross browser compatibility has become a necessity.
Referring to automation and considering our love for open-source softwares, it is inevitable to turn a blind eye from one of the most renowned test automation framework called “Selenium”. We have covered automation testing with Selenium WebDriver for cross browser testing previously on our blog where we discussed different variants of Selenium i.e IDE, RC, WebDriver etc and ran our first automation script.
In that article we emphasized the limitation of working with Local Selenium WebDriver. With ‘Local Selenium WebDriver’, you can perform browser compatibility testing ‘only’ on the browsers that are installed on the machine (where testing is performed) i.e. your testing effort is limited to only a certain combination of (device + operating system + browser).
Verification of your web-application/web product with the ‘local’ version of the Selenium WebDriver is not a scalable approach. Some of the problems that you encounter with this kind of setup are:
Though local Selenium WebDriver is ideal for testing on a smaller scale, the necessary amount of ‘scalability’ & ‘performance’ can be achieved after you setup a ‘Selenium Grid’.
This article is a Selenium Grid tutorial where you would realize how web-developers and software testers leverage the power of the Selenium Grid setup to perform automated cross browser testing. I will demonstrate you with an example scenario.
We will be making use of the following languages, frameworks & tools (IDE) to write better automation code.
Selenium Grid is a testing tool (which is a part of the Selenium Suite) that is based on the ‘client-server’ architecture. In Selenium Grid terminology, Client machine is termed as ‘Hub’ and server(s) are termed as ‘Nodes’.
Selenium Grid setup allows you to execute cross browser testing through a variety of different machines across different browsers (as well as different versions of browsers) & different operating systems. Hence, it brings the require amount of ‘parallelism’ & ‘distribution’ to your test execution environment.
A Selenium Grid setup can have only one Hub and ‘n’ number of nodes. The primary job of the ‘hub machine’ is to distribute the test case supplied to the ‘node machine’ which matches the capabilities/requirements required for executing the test case for performing cross browser testing. We would discuss more Hub & Node (which are the core components for the setup of Selenium Grid infrastructure) in further sections.
There are two versions of Selenium Grid available, namely Selenium Grid 2.0 & Selenium Grid 1.0. Selenium Grid 2.0 is most popular amongst automation testers since it supports Selenium RC (Remote Control) and Selenium WebDriver scripts.
There are a number of benefits of Selenium Grid setup. Here, we have a look at some of the top advantages of Selenium Grid setup as a part of your test execution strategy for performing cross browser testing.
By default, the execution after the setup of Selenium Grid is not parallel in nature. In order to take the advantage of parallelism, the selenium tests should be written in a manner that takes ‘parallel execution’ for cross browser testing into account.
In our previous articles on tutorial of Selenium webdriver for cross browser testing, the core focus was on ‘Selenium for local testing’, you would have observed that a local WebDriver API/interface has to be used in order to perform the testing. In case you want to use the Selenium WebDriver to execute tests on a separate machine, you have to use Remote WebDriver interface.
Since the tests (in normal scenarios) have to be executed on a different machine, RemoteWebDriver is based on the traditional ‘Client-Server’ model. The RemoteWebDriver consists of two main parts – Hub (Server) and Node(Client). Let’s have a detailed look at the same in this section.
Hub/Server – The Hub is the central component of the ‘Selenium Grid architecture’. It loads the tests that have to be executed. There can only be one ‘Hub’ which acts as the ‘Master’ in the setup of Selenium Grid infrastructure. Once the Hub receives an input/test case that needs to be executed, it searches for a Node (client) which matches the desired capabilities and diverts the ‘test execution request’ to the matching node.
For example, if you have setup a Selenium Grid with (hub + two nodes) where the node configuration is as below:
If there is a test case that has the ‘Desired Capabilities requirement’ – (Windows 10 + Chrome), the hub first receives the request for this requirement. By looking at the requirement, it diverts the execution request to Node 1.
Node – Node is a machine on which the tests are executed. Node can have a different configuration than the hub. There is no limit on the number of nodes that can be connected to the hub.
Since the test code execution will occur on the node(s); it is recommended that you choose machines with the best possible configuration so that you can get the best performance out of your Selenium Grid setup.
[Note – Our development environment is installed on Windows 10 machine. For demonstration, Hub & Node are installed on the same machine.]
Step 1 – In order to setup Selenium Grid infrastructure, you need to first download the Selenium Server jar from the official website of Selenium. It was formerly called as the ‘Selenium RC server’. The download link is here.
Once the selenium server jar file is downloaded, you should configure the hub using following command (java -jar selenium-server-standalone-x.x.x.jar -role hub)
java -jar selenium-server-standalone-3.9.1.jar -role hub
Step 2 – By default, the hub would use the port 4444. The port can be changed by using the configuration option –port . Below is the screenshot of the logs observed once the above command is executed.
In order to verify whether the hub is configured correctly, open the browser window and type the following in the address bar:
http://107.108.86.20:4444/wd/hub
Below is the output snapshot when the above URL is opened in the Firefox browser:
Step 3 – Now that the ‘Hub’ is up & running, you have to now configure the nodes for the purpose of cross browser testing. Execute the following command on the terminal:
java -jar selenium-server-standalone-3.9.1.jar -role node -hub http:///grid/register/ -browser "browserName=firefox,maxinstance=1,platform=WINDOWS" –port
In our case, the Hub is configured on port number 4444 and the node is configured on port numbers 5555 & 5556. One node is configured for Platform as Windows & browser as Firefox. Second node is configured for Platform as Windows & browser as Chrome.
java -jar selenium-server-standalone-3.9.1.jar -role node -hub http://107.108.86.20:4444/grid/register/ -browser "browserName=firefox,maxinstance=1,platform=WINDOWS" -port 5555
The output for the command is as shown below.
For verifying whether the Node has been configured correctly, please enter the following in the address bar.
http://localhost:4444/grid/console?config=true&configDebug=true#
For configuring the node on port number 5556 (with Operating System as Windows and Browser as Chrome), please execute the following command on the terminal:
java -jar selenium-server-standalone-3.9.1.jar -role node -hub http://107.108.86.20:4444/grid/register/ -port 5556 -browser "browserName=chrome,maxinstance=1,platform=WINDOWS"
Now, when you visit http://localhost:4444/grid/console?config=true&configDebug=true# on the address bar, you will also see details about ports 5556 as well.
In case you are planning to use the Internet Explorer browser, you need to just pass the correct browser name as an input argument to the jar file. Below is the command which you can use for using Internet Explorer browser:
java -jar selenium-server-standalone-3.9.1.jar -role node -hub http://107.108.86.20:4444/grid/register/ -port 5556 -browser "browserName=internet explorer,maxinstance=1,platform=WINDOWS"
There are other parameters apart from browserName which you might require, if needed:
Now that you have knowledge about Selenium Grid, let’s have a look at an example where we use pytest with our Selenium Grid setup(or the Remote WebDriver interface). We have a detailed article about test automation using Pytest and Selenium WebDriver interface where we have explained about the installation of pytest, Selenium with pytest, fixtures in pytest, etc.
For the purpose of demonstration, Hub (Server) & Nodes (Clients) are configured on the same machine. We would be using the machine IP address when configuring the Remote WebDriver. Let’s configure the Hub & Nodes using the respective commands for automated cross browser testing.
Please go to the directory where you have the Selenium Server jar file (In our case, we are using the version 3.9.1 and the jar file name is selenium-server-standalone-3.9.1.jar) by using the ‘cd’ command.
Start the Hub by executing the below command on the terminal:
java -jar selenium-server-standalone-3.9.1.jar -role hub
As discussed before, by default the Hub would start on port 4444. ‘Nodes’ can connect to the ‘Hub’ using the link http://:/wd/hub. In our case, the Hub/Server is configured on a machine that has IP address ‘107.108.86.20’ and the port on which it is configured is 4444. Hence, nodes need to use the link http://107.108.86.20:4444/wd/hub in order to divert their request to the configured Hub.
Now that the Hub is configured, the next step for setup of Selenium Grid is the Nodes. We will configure two nodes that have the below requirements.
On the terminal, execute the below commands to configure the two nodes:
Configuration of Node 1
java -jar selenium-server-standalone-3.9.1.jar -role node -hub http://107.108.86.20:4444/grid/register/ -browser "browserName=firefox,maxinstance=1,platform=WINDOWS" -port 5555
Configuration of Node 2
java -jar selenium-server-standalone-3.9.1.jar -role node -hub http://107.108.86.20:4444/grid/register/ -browser "browserName=chrome,maxinstance=1,platform=WINDOWS" -port 5556
You can visit to verify whether the nodes have been configured properly. Below is the screenshot which shows the status of the nodes.
The end goal that we plan to achieve is to divert the request from the nodes to the hub, invoke the ‘required browser instance’, open the webpage inputted to the browser & terminate the browser session i.e. perform cleaning up of allocated resources.
Since we are using pytest for development, we recommend that you download PyCharm (Community Edition) from here.
command_executor – Information about the Hub i.e. the address on which the Hub is configured. If the hub is configured incorrectly i.e. wrong IP address/wrong port is used, you may get an error ‘Couldn’t register the node’ while doing the node registration.
desired_capabilities – The required capabilities/requirements are passed through the Remote WebDriver. Based on the details inputted as a part of desired_capabilities, the ‘best matching’ node is selected for execution.
The first test case has to be executed on a node that has ‘Chrome browser’ and the second test case requires has to be executed on a node that has ‘Firefox browser’. You can have a look at how we modified ‘Local WebDriver’ implementation to ‘Remote WebDriver’ implementation by configuring the WebDriver to execute requests on a remote machine i.e. matching node. The complete implementation is below:
#FileName - test_selenium_grid_firefox_chrome.py
# Import the 'modules' that are required for the execution
import pytest
#import pytest_html
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from time import sleep
#Fixture for Firefox
@pytest.fixture(params=["chrome", "firefox"],scope="class")
def driver_init(request):
if request.param == "chrome":
#Local webdriver implementation
#web_driver = webdriver.Chrome()
#Remote WebDriver implementation
web_driver = webdriver.Remote(
command_executor='http://107.108.86.20:4444/wd/hub',
desired_capabilities={'browserName': 'chrome', 'javascriptEnabled': True})
if request.param == "firefox":
#Local webdriver implementation
#web_driver = webdriver.Firefox()
#Remote WebDriver implementation
web_driver = webdriver.Remote(
command_executor='http://107.108.86.20:4444/wd/hub',
desired_capabilities={'browserName': 'firefox'})
request.cls.driver = web_driver
yield
web_driver.close()
@pytest.mark.usefixtures("driver_init")
class BasicTest:
pass
class Test_URL(BasicTest):
def test_open_url(self):
self.driver.get("https://www.lambdatest.com/")
print(self.driver.title)
sleep(5)
The remaining implementation remains the same since the only thing that changes is using Remote WebDriver interface. For more information about the above implementation (including fixtures, classes, etc. in pytest), please refer our earlier article here.
To execute the code, please use the command on the local terminal (or terminal on PyCharm).
py.test --verbose --capture=no test_selenium_grid_firefox_chrome.py
Once the Hub receives a request for the execution of ‘testcase 1’, the request would be diverted to Node 2 (where Chrome browser is configured) and request for the execution of ‘testcase 2’, the request would be diverted to Node 1 (where Firefox browser is configured). The output is shown below.
Selenium Grid setup is very useful when you have to execute a large number of test cases on different machines. In order to get the best out Selenium Grid setup & automation testing, you may require to have machines with different Operating Systems with different types (and versions) of browsers installed on the same. Setting up such an infrastructure would involve a huge amount of cost and a significant amount of effort to maintain the same.
In such a scenario, the team can make use of LambdaTest, a scalable cloud based cross browser testing platform where you can perform testing on 2000+ browsers (of different versions) installed on different machines & devices (mobiles, tablets, etc.). The upside of using Selenium grid setup offered by LambdaTest is that you can cut down heavily on your build & execution times.
To get started, you need to create an account on LambdaTest. Once you have logged into your account, please head over to the ‘Automation’ tab by visiting https://automation.lambdatest.com/
Before you start the automation test, you might need to set the capabilities required for execution. In the example which we used earlier, the tests had to be executed on Windows 10 machines with the browser being Firefox & Chrome. We generate the required capabilities using the ‘Capabilities Generator’ on LambdaTest. Shown below is a capability created using the generator where platform = Windows 10, BrowserName = Firefox.
Capabilities Generated Using Capability Generator
capabilities = {
"build" : "your build name",
"name" : "your test name",
"platform" : "Windows 10",
"browserName" : "Firefox",
"version" : "64.0",
"selenium_version" : "3.13.0",
"firefox.driver" : v0.23.0
}
Let’s have a close look at the various parameters which are supplied for setting the desired capabilities:
It is important to note that some of the capability parameters mentioned above are optional e.g. If you just specify platform as Windows 10 and BrowserName as Firefox, the test would be performed on a node that has ‘Firefox on Windows 10’ (irrespective of the version of Firefox on that machine).
In our example, we declare the capabilities obtained from LambdaTest Capabilities generator as shown below:
#Set capabilities for testing on Chrome
ch_caps = {
"build" : "Sel-Grid-Chrome",
"name" : "Testing on Chrome using Selenium Grid",
"platform" : "Windows 10",
"browserName" : "Chrome",
"version" : "71.0",
"selenium_version" : "3.13.0",
"chrome.driver" : 2.42
}
#Set capabilities for testing on Firefox
ff_caps = {
"build" : "Sel-Grid-Firefox",
"name" : "Testing on Firefox using Selenium Grid",
"platform" : "Windows 10",
"browserName" : "Firefox",
"version" : "64.0",
}
In order to perform the testing, you have to enter your credentials – ‘username’ & ‘application key’, which are supplied to the Remote WebDriver. The credentials (that have to be kept confidential) can be obtained by visiting your LambdaTest Automation Dashboard. Here, ‘username’ is the email-address with which you login on LambdaTest and ‘application key’ is the Access Token for authenticating to your LambdaTest account from external systems.
If the credentials are correct, the test would be executed on the remote URL
/* user_name – userid for login on Lambdatest */
/* app_key – Access token obtained from Lambdatest */
remote_url = "https://" + user_name + ":" + app_key + "@hub.lambdatest.com/wd/hub"
The ‘Remote URL’ also consists of @hub.lambdatest.com/wd/hub which is the LambdaTest grid URL for your account. The remote WebDriver API now takes input as ‘remote_url’ and capabilities (ch_caps/ff_caps) which are generated using the LambdaTest Capabilities generator. Apart from these changes, the entire implementation is kept same (like implementation using ‘Remote WebDriver interface without using LambdaTest’).
The complete implementation is below (Note – Global variables are stored in another Python file which is imported at the beginning of the implementation).
# Obtain the credentials by visiting https://accounts.lambdatest.com/profile UserName = "user-name"
AppKey = "access-token"
# Import the 'modules' that are required for execution
import pytest
#import pytest_html
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from time import sleep
import urllib3
import warnings
#FileName – test_lam_selenium_grid_firefox_chrome.py
#Global variables are declared in a seperate file
import test_lam_var
#Set capabilities for testing on Chrome
ch_caps = {
"build" : "Sel-Grid-Chrome",
"name" : "Testing on Chrome using Selenium Grid",
"platform" : "Windows 10",
"browserName" : "Chrome",
"version" : "71.0",
"selenium_version" : "3.13.0",
"chrome.driver" : 2.42
}
#Set capabilities for testing on Firefox
ff_caps = {
"build" : "Sel-Grid-Firefox",
"name" : "Testing on Firefox using Selenium Grid",
"platform" : "Windows 10",
"browserName" : "Firefox",
"version" : "64.0",
}
user_name = test_lam_var.UserName
app_key = test_lam_var.AppKey
#Fixture for Firefox
@pytest.fixture(params=["chrome", "firefox"],scope="class")
def driver_init(request):
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
remote_url = "https://" + user_name + ":" + app_key + "@hub.lambdatest.com/wd/hub"
if request.param == "chrome":
#Remote WebDriver implementation
#web_driver = webdriver.Remote(
#command_executor='http://107.108.86.20:4444/wd/hub',
#desired_capabilities={'browserName': 'chrome', 'javascriptEnabled': True})
web_driver = webdriver.Remote(command_executor=remote_url, desired_capabilities=ch_caps)
if request.param == "firefox":
#Remote WebDriver implementation
#web_driver = webdriver.Remote(
# command_executor='http://107.108.86.20:4444/wd/hub',
# desired_capabilities={'browserName': 'firefox'})
web_driver = webdriver.Remote(command_executor=remote_url, desired_capabilities=ff_caps)
request.cls.driver = web_driver
yield
web_driver.close()
@pytest.mark.usefixtures("driver_init")
class BasicTest:
pass
class Test_URL(BasicTest):
def test_open_url(self):
self.driver.get("https://www.lambdatest.com/")
print(self.driver.title)
sleep(5)
Below is the output when the python code is executed using py.test command:
Though the command has been triggered on your machine, the execution happens on the ‘Node on the LambdaTest cloud infrastructure’ which matches the capabilities supplied to the Remote WebDriver API. In order to check the execution status on the server, you have to navigate to the Automation tab where you can identify the tests executed using ‘build’ & ‘test-name’ which were entered while creating the capabilities. Below is the snapshot of the sample code when executed on the LambdaTest server.
For the purpose of Analysis & Debugging, you can have a look at the different tabs namely Exception, Command, Network, Logs, MetaData, etc. in the location where details about Automation tests are mentioned.
Testing using Selenium Grid setup can be instrumental in speeding up your entire test execution process since you can take the advantage of Parallelism while implementing your tests. Though, Selenium Grid setup (without a cloud infrastructure) can be a ‘scalable approach’, its scalability can become limited if an in-house infrastructure is setup.
Along with the initial setup, there would be ‘repeated expenses’ for maintaining the infrastructure too.
By leveraging setup of Selenium Grid infrastructure through LambdaTest, you can speed up your entire testing process since all the tests executed on the LambdaTest cloud. You can make use of test automation frameworks with respect to various programming languages such as Python, C#, Ruby, Java, PHP, Javascript, etc. for implementation, which makes it more developer friendly.
As far as implementation is concerned, porting an existing code (using an in-house Selenium Grid setup) to the Selenium Grid setup offered by LambdaTest is easy and considerable time-saving.
Previously published at https://www.lambdatest.com/blog/selenium-grid-setup-tutorial-for-cross-browser-testing/