Automation Data
Automation Data
Ready to level up your Selenium skills? Learn from the experts at SeleniumConf! March 28-30 in Chicago.
Get Tickets
Selenium is an umbrella project for a range of tools and libraries that enable and support the automation
of web browsers.
It provides extensions to emulate user interaction with browsers, a distribution server for scaling
browser allocation, and the infrastructure for implementations of the W3C WebDriver specification that
lets you write interchangeable code for all major web browsers.
This project is made possible by volunteer contributors who have put in thousands of hours of their own
time, and made the source code freely available for anyone to use, enjoy, and improve.
Selenium brings together browser vendors, engineers, and enthusiasts to further an open discussion
around automation of the web platform. The project organises an annual conference to teach and
nurture the community.
At the core of Selenium is WebDriver, an interface to write instruction sets that can be run
interchangeably in many browsers. Once you’ve installed everything, only a few lines of code get you
inside a browser. You can find a more comprehensive example in Writing your first Selenium script
https://www.selenium.dev/documentation/_print/ 3/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
package dev.selenium.hello;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
driver.get("https://selenium.dev");
driver.quit();
}
}
See the Overview to check the different project components and decide if Selenium is the right tool for
you.
You should continue on to Getting Started to understand how you can install Selenium and successfully
use it as a test automation tool, and scaling simple tests like this to run in large, distributed
environments on multiple browsers, on several different operating systems.
https://www.selenium.dev/documentation/_print/ 4/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
1 - Selenium Overview
Is Selenium for you? See an overview of the different project components.
Selenium is not just one tool or API but it composes many tools.
WebDriver
If you are beginning with desktop website or mobile website test automation, then you are going to be
using WebDriver APIs. WebDriver uses browser automation APIs provided by browser vendors to
control the browser and run tests. This is as if a real user is operating the browser. Since WebDriver does
not require its API to be compiled with application code; It is not intrusive. Hence, you are testing the
same application which you push live.
IDE
IDE (Integrated Development Environment) is the tool you use to develop your Selenium test cases. It’s
an easy-to-use Chrome and Firefox extension and is generally the most efficient way to develop test
cases. It records the users’ actions in the browser for you, using existing Selenium commands, with
parameters defined by the context of that element. This is not only a time-saver but also an excellent
way of learning Selenium script syntax.
Grid
Selenium Grid allows you to run test cases in different machines across different platforms. The control
of triggering the test cases is on the local end, and when the test cases are triggered, they are
automatically executed by the remote end.
After the development of the WebDriver tests, you may face the need to run your tests on multiple
browsers and operating system combinations. This is where Grid comes into the picture.
https://www.selenium.dev/documentation/_print/ 5/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Terminology
API: Application Programming Interface. This is the set of “commands” you use to manipulate
WebDriver.
Library: A code module that contains the APIs and the code necessary to implement them.
Libraries are specific to each language binding, eg .jar files for Java, .dll files for .NET, etc.
Driver: Responsible for controlling the actual browser. Most drivers are created by the browser
vendors themselves. Drivers are generally executable modules that run on the system with the
browser itself, not the system executing the test suite. (Although those may be the same system.)
NOTE: Some people refer to the drivers as proxies.
Framework: An additional library that is used as a support for WebDriver suites. These
frameworks may be test frameworks such as JUnit or NUnit. They may also be frameworks
supporting natural language features such as Cucumber or Robotium. Frameworks may also be
written and used for tasks such as manipulating or configuring the system under test, data
creation, test oracles, etc.
The driver is specific to the browser, such as ChromeDriver for Google’s Chrome/Chromium, GeckoDriver
for Mozilla’s Firefox, etc. The driver runs on the same system as the browser. This may or may not be the
same system where the tests themselves are executed.
This simple example above is direct communication. Communication to the browser may also be remote
communication through Selenium Server or RemoteWebDriver. RemoteWebDriver runs on the same
system as the driver and the browser.
https://www.selenium.dev/documentation/_print/ 6/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Remote communication can also take place using Selenium Server or Selenium Grid, both of which in
turn talk to the driver on the host system
This is where various frameworks come into play. At a minimum, you will need a test framework that
matches the language bindings, e.g., NUnit for .NET, JUnit for Java, RSpec for Ruby, etc.
The test framework is responsible for running and executing your WebDriver and related steps in your
tests. As such, you can think of it looking akin to the following image.
Natural language frameworks/tools such as Cucumber may exist as part of that Test Framework box in
the figure above, or they may wrap the Test Framework entirely in their custom implementation.
https://www.selenium.dev/documentation/_print/ 7/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium allows users to simulate common activities performed by end-users; entering text into fields,
selecting drop-down values and checking boxes, and clicking links in documents. It also provides many
other controls such as mouse movement, arbitrary JavaScript execution, and much more.
Although used primarily for front-end testing of websites, Selenium is, at its core, a browser user agent
library. The interfaces are ubiquitous to their application, encouraging composition with other libraries to
suit your purpose.
Imagine a bank of computers in your server room or data center all firing up browsers at the same time
hitting your site’s links, forms, and tables—testing your application 24 hours a day. Through the simple
programming interface provided for the most common languages, these tests will run tirelessly in
parallel, reporting back to you when errors occur.
It is an aim to help make this a reality for you, by providing users with tools and documentation to not
only control browsers but to make it easy to scale and deploy such grids.
As the web becomes more complicated and new technologies are added to websites, it’s the mission of
this project to keep up with them where possible. Being an open-source project, this support is provided
through the generous donation of time from many volunteers, every one of which has a “day job.”
Another mission of the project is to encourage more volunteers to partake in this effort, and build a
strong community so that the project can continue to keep up with emerging technologies and remain a
dominant platform for functional test automation.
https://www.selenium.dev/documentation/_print/ 8/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
2 - WebDriver
WebDriver drives a browser natively, learn more about it.
WebDriver drives a browser natively, as a user would, either locally or on a remote machine using the
Selenium server, marks a leap forward in terms of browser automation.
Selenium WebDriver refers to both the language bindings and the implementations of the individual
browser controlling code. This is commonly referred to as just WebDriver.
https://www.selenium.dev/documentation/_print/ 9/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium supports automation of all the major browsers in the market through the use of WebDriver.
WebDriver is an API and protocol that defines a language-neutral interface for controlling the behaviour
of web browsers. Each browser is backed by a specific WebDriver implementation, called a driver. The
driver is the component responsible for delegating down to the browser, and handles communication to
and from Selenium and the browser.
This separation is part of a conscious effort to have browser vendors take responsibility for the
implementation for their browsers. Selenium makes use of these third party drivers where possible, but
also provides its own drivers maintained by the project for the cases when this is not a reality.
The Selenium framework ties all of these pieces together through a user-facing interface that enables
the different browser backends to be used transparently, enabling cross-browser and cross-platform
automation.
Selenium setup is quite different from the setup of other commercial tools. Before you can start writing
Selenium code, you have to install the language bindings libraries for your language of choice, the
browser you want to use, and the driver for that browser.
Follow the links below to get up and going with Selenium WebDriver.
If you wish to start with a low-code/record and playback tool, please check Selenium IDE
Once you get things working, if you want to scale up your tests, check out the Selenium Grid.
https://www.selenium.dev/documentation/_print/ 10/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
First you need to install the Selenium bindings for your automation project. The installation process for
libraries depends on the language you choose to use. Make sure you check the Selenium downloads
page to make sure you are using the latest version.
Requirements by language
Java Python CSharp Ruby JavaScript Kotlin
Maven
Specify the dependency in the project’s pom.xml file:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.8.0</version>
</dependency>
Gradle
Specify the dependency in the project build.gradle file as
testImplementation :
testImplementation 'org.seleniumhq.selenium:selenium-jav
Next Step
Install the browser drivers
https://www.selenium.dev/documentation/_print/ 11/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Through WebDriver, Selenium supports all major browsers on the market such as Chrome/Chromium,
Firefox, Internet Explorer, Edge, and Safari. Where possible, WebDriver drives the browser using the
browser’s built-in support for automation.
Since all the driver implementations except for Internet Explorer are provided by the browser vendors
themselves, they are not included in the standard Selenium distribution. This section explains the basic
requirements for getting started with the different browsers.
Read about more advanced options for starting a driver in our driver configuration documentation.
Selenium Manager helps you to get a working environment to run Selenium out of the box. Beta 1 of
Selenium Manager will configure the drivers for Chrome, Firefox, and Edge if they are not found on the
PATH . No extra configuration is needed. Future releases of Selenium Manager will eventually even
download browsers if necessary.
1. Import WebDriverManager
import io.github.bonigarcia.wdm.WebDriverManager;
2. Call setup() :
WebDriverManager.chromedriver().setup();
This is a flexible option to change location of drivers without having to update your code, and will work
on multiple machines without requiring that each machine put the drivers in the same place.
You can either place the drivers in a directory that is already listed in PATH , or you can place them in a
directory and add it to PATH .
To see what directories are already on PATH , open a Terminal and execute:
https://www.selenium.dev/documentation/_print/ 12/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
echo $PATH
If the location to your driver is not already in a directory listed, you can add a
new directory to PATH:
You can test if it has been added correctly by starting the driver:
chromedriver
If your PATH is configured correctly above, you will see some output relating to the startup of the
driver:
System.setProperty("webdriver.chrome.driver","/path/to/chromedriv
ChromeDriver driver = new ChromeDriver();
Quick Reference
Issue
Browser Supported OS Maintained by Download Tracker
Note: The Opera driver no longer works with the latest functionality of Selenium and is currently
officially unsupported.
https://www.selenium.dev/documentation/_print/ 13/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Next Step
Create your first Selenium script
https://www.selenium.dev/documentation/_print/ 14/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Once you have Selenium installed and Drivers installed, you’re ready to write Selenium code.
driver.get("https://www.selenium.dev/selenium/web/we
Essentially you want to make sure that the element is on the page before you attempt to locate it and
the element is in an interactable state before you attempt to interact with it.
An implicit wait is rarely the best solution, but it’s the easiest to demonstrate here, so we’ll use it as a
placeholder.
driver.manage().timeouts().implicitlyWait(Duration.o
5. Find an element
The majority of commands in most Selenium sessions are element related, and you can’t interact with
one without first finding an element
textBox.sendKeys("Selenium");
submitButton.click();
driver.quit();
https://www.selenium.dev/documentation/_print/ 16/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
package dev.selenium.getting_started;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.time.Duration;
@Test
public void eightComponents() {
WebDriver driver = new ChromeDriver();
driver.get("https://www.selenium.dev/selenium/web/we
driver.manage().timeouts().implicitlyWait(Duration.o
textBox.sendKeys("Selenium");
submitButton.click();
driver.quit();
}
Test Runners
If you are using Selenium for testing, you will want to execute your Selenium code using test runner
tools.
Many of the code examples in this documentation can be found in our example repositories. There are
multiple options in each language, but here is what we are using in our examples:
https://www.selenium.dev/documentation/_print/ 17/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
// Add instructions
Next Steps
Take what you’ve learned and build out your Selenium code.
As you find more functionality that you need, read up on the rest of our WebDriver documentation.
https://www.selenium.dev/documentation/_print/ 18/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Upgrading to Selenium 4 should be a painless process if you are using one of the officially supported
languages (Ruby, JavaScript, C#, Python, and Java). There might be some cases where a few issues can
happen, and this guide will help you to sort them out. We will go through the steps to upgrade your
project dependencies and understand the major deprecations and changes the version upgrade brings.
Note: while Selenium 3.x versions were being developed, support for the W3C WebDriver standard was
implemented. Both this new protocol and the legacy JSON Wire Protocol were supported. Around
version 3.11, Selenium code became compliant with the level W3C 1 specification. The W3C compliant
code in the latest version of Selenium 3 will work as expected in Selenium 4.
Capabilities
If the test capabilities are not structured to be W3C compliant, may cause a session to not be started.
Here is the list of W3C WebDriver standard capabilities:
browserName
pageLoadStrategy
proxy
timeouts
unhandledPromptBehavior
Any capability that is not contained in the list above, needs to include a vendor prefix. This applies to
browser specific capabilities as well as cloud vendor specific capabilities. For example, if your cloud
vendor uses build and name capabilities for your tests, you need to wrap them in a cloud:options
block (check with your cloud vendor for the appropriate prefix).
Before
Java JavaScript CSharp Ruby Python
After
https://www.selenium.dev/documentation/_print/ 19/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Before After
driver.findElementByClassName( driver.findElement(By.classNam
driver.findElementByCssSelecto driver.findElement(By.cssSelec
driver.findElementById("elemen driver.findElement(By.id("elem
driver.findElementByLinkText(" driver.findElement(By.linkText
driver.findElementByName("elem driver.findElement(By.name("el
driver.findElementByPartialLin driver.findElement(By.partialL
driver.findElementByTagName("e driver.findElement(By.tagName(
driver.findElementByXPath("xPa driver.findElement(By.xpath("x
Before After
driver.findElementsByClassName driver.findElements(By.classNa
driver.findElementsByCssSelect driver.findElements(By.cssSele
driver.findElementsById("eleme driver.findElements(By.id("ele
driver.findElementsByLinkText( driver.findElements(By.linkTex
driver.findElementsByName("ele driver.findElements(By.name("e
driver.findElementsByPartialLi driver.findElements(By.partial
driver.findElementsByTagName(" driver.findElements(By.tagName
driver.findElementsByXPath("xP driver.findElements(By.xpath("
Upgrading dependencies
Check the subsections below to install Selenium 4 and have your project dependencies upgraded.
https://www.selenium.dev/documentation/_print/ 20/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Java
The process of upgrading Selenium depends on which build tool is being used. We will cover the most
common ones for Java, which are Maven and Gradle. The minimum Java version required is still 8.
Maven
Before After
<dependencies> <dependencies>
<!-- more dependencies ... - <!-- more dependencies ...
<dependency> <dependency>
<groupId>org.seleniumhq.se <groupId>org.seleniumh
<artifactId>selenium-java< <artifactId>selenium-j
<version>3.141.59</version <version>4.4.0</versio
</dependency> </dependency>
<!-- more dependencies ... - <!-- more dependencies ...
</dependencies> </dependencies>
After making the change, you could execute mvn clean compile on the same directory where the
pom.xml file is.
Gradle
Before After
plugins { plugins {
id 'java' id 'java'
} }
group 'org.example' group 'org.example'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
repositories { repositories {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
testImplementation 'org.junit testImplementation 'org.junit
testRuntimeOnly 'org.junit.ju testRuntimeOnly 'org.junit.jup
implementation group: 'org.se implementation group: 'org.se
} }
test { test {
useJUnitPlatform() useJUnitPlatform()
} }
After making the change, you could execute ./gradlew clean build on the same directory where the
build.gradle file is.
https://www.selenium.dev/documentation/_print/ 21/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
C#
The place to get updates for Selenium 4 in C# is NuGet. Under the Selenium.WebDriver package you
can get the instructions to update to the latest version. Inside of Visual Studio, through the NuGet
Package Manager you can execute:
Python
The most important change to use Python is the minimum required version. Selenium 4 will require a
minimum Python 3.7 or higher. More details can be found at the Python Package Index. To upgrade from
the command line, you can execute:
Ruby
The update details for Selenium 4 can be seen at the selenium-webdriver gem in RubyGems. To install
the latest version, you can execute:
JavaScript
The selenium-webdriver package can be found at the Node package manager, npmjs. Selenium 4 can be
found here. To install it, you could either execute:
{
"name": "selenium-tests",
"version": "1.0.0",
"dependencies": {
"selenium-webdriver": "^4.4.0"
}
}
https://www.selenium.dev/documentation/_print/ 22/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Java
Before After
driver.manage().timeouts().imp driver.manage().timeouts().imp
driver.manage().timeouts().set driver.manage().timeouts().scr
driver.manage().timeouts().pag driver.manage().timeouts().pag
Waits are also expecting different parameters now. WebDriverWait is now expecting a Duration
instead of a long for timeout in seconds and milliseconds. The withTimeout and pollingEvery
utility methods from FluentWait have switched from expecting (long time, TimeUnit unit) to
expect (Duration duration) .
Before After
Before After
As a result, the options object was The result of the merge call needs to be
getting modified. assigned to an object.
Firefox Legacy
https://www.selenium.dev/documentation/_print/ 23/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Before GeckoDriver was around, the Selenium project had a driver implementation to automate Firefox
(version <48). However, this implementation is not needed anymore as it does not work in recent
versions of Firefox. To avoid major issues when upgrading to Selenium 4, the setLegacy option will be
shown as deprecated. The recommendation is to stop using the old implementation and rely only on
GeckoDriver. The following code will show the setLegacy line deprecated after upgrading.
BrowserType
The BrowserType interface has been around for a long time, however it is getting deprecated in favour
of the new Browser interface.
Before After
C#
AddAdditionalCapability is deprecated
Before After
Python
executable_path has been deprecated, please pass in a Service
object
In Selenium 4, you’ll need to set the driver’s executable_path from a Service object to prevent
deprecation warnings. (Or don’t set the path and instead make sure that the driver you need is on the
System PATH.)
Before After
https://www.selenium.dev/documentation/_print/ 24/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Summary
We went through the major changes to be taken into consideration when upgrading to Selenium 4.
Covering the different aspects to cover when test code is prepared for the upgrade, including
suggestions on how to prevent potential issues that can show up when using the new version of
Selenium. To finalize, we also covered a set of possible issues that you can bump into after upgrading,
and we shared potential fixes for those issues.
https://www.selenium.dev/documentation/_print/ 25/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Creating Sessions
Creating a new session corresponds with the W3C command for New session
Each language allows a session to be created with arguments from one of these classes (or equivalent):
Options to describe the kind of session you want; default values are used for local, but this is
required for remote
Some form of CommandExecutor (the implementation varies between languages)
Listeners
Local Driver
The primary unique argument for starting a local driver includes information about starting the required
driver service on the local machine.
Service object applies only to local drivers and provides information about the browser driver
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Remote Driver
The primary unique argument for starting a remote driver includes information about where to execute
the code. Read the details in the Remote Driver Section
Quitting Sessions
Quitting a session corresponds to W3C command for Deleting a Session.
Important note: the quit method is different from the close method, and it is recommended to
always use quit to end the session
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
https://www.selenium.dev/documentation/_print/ 26/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
In Selenium 3, capabilities were defined in a session by using Desired Capabilities classes. As of Selenium
4, you must use the browser options classes. For remote driver sessions, a browser options instance is
required as it determines which browser will be used.
Each browser has custom options that may be defined in addition to the ones defined in the
specification.
browserName
This capability is used to set the browserName for a given session. If the specified browser is not
installed at the remote end, the session creation will fail.
browserVersion
This capability is optional, this is used to set the available browser version at remote end. For Example, if
ask for Chrome version 75 on a system that only has 80 installed, the session creation will fail.
pageLoadStrategy
Three types of page load strategies are available.
The page load strategy queries the document.readyState as described in the table below:
Ready
Strategy State Notes
eager interactive DOM access is ready, but other resources like images may still be
loading
The document.readyState property of a document describes the loading state of the current
document.
When navigating to a new page via URL, by default, WebDriver will hold off on completing a navigation
method (e.g., driver.navigate().get()) until the document ready state is complete. This does not
necessarily mean that the page has finished loading, especially for sites like Single Page Applications
that use JavaScript to dynamically load content after the Ready State returns complete. Note also that
this behavior does not apply to navigation that is a result of clicking an element or submitting a form.
If a page takes a long time to load as a result of downloading assets (e.g., images, css, js) that aren’t
important to the automation, you can change from the default parameter of normal to eager or
none to speed up the session. This value applies to the entire session, so make sure that your waiting
strategy is sufficient to minimize flakiness.
normal (default)
WebDriver waits until the load event fire is returned.
https://www.selenium.dev/documentation/_print/ 27/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.chrome.ChromeDriver;
eager
WebDriver waits until DOMContentLoaded event fire is returned.
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.chrome.ChromeDriver;
none
WebDriver only waits until the initial page is downloaded.
https://www.selenium.dev/documentation/_print/ 28/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.chrome.ChromeDriver;
platformName
This identifies the operating system at the remote-end, fetching the platformName returns the OS
name.
acceptInsecureCerts
This capability checks whether an expired (or) invalid TLS Certificate is used while navigating during
a session.
If the capability is set to false , an insecure certificate error will be returned as navigation encounters
any domain certificate problems. If set to true , invalid certificate will be trusted by the browser.
All self-signed certificates will be trusted by this capability by default. Once set, acceptInsecureCerts
capability will have an effect for the entire session.
timeouts
A WebDriver session is imposed with a certain session timeout interval, during which the user can
control the behaviour of executing scripts or retrieving information from the browser.
Each session timeout is configured with combination of different timeouts as described below:
Script Timeout
Specifies when to interrupt an executing script in a current browsing context. The default timeout
30,000 is imposed when a new session is created by WebDriver.
unhandledPromptBehavior
Specifies the state of current session’s user prompt handler . Defaults to dismiss and notify state
dismiss
accept
dismiss and notify
accept and notify
ignore
setWindowRect
Indicates whether the remote end supports all of the resizing and repositioning commands.
strictFileInteractability
This new capability indicates if strict interactability checks should be applied to input type=file elements.
As strict interactability checks are off by default, there is a change in behaviour when using Element
Send Keys with hidden file upload controls.
proxy
A proxy server acts as an intermediary for requests between a client and a server. In simple, the traffic
flows through the proxy server on its way to the address you requested and back.
A proxy server for automation scripts with Selenium could be helpful for:
If you are in a corporate environment, and a browser fails to connect to a URL, this is most likely
because the environment needs a proxy to be accessed.
https://www.selenium.dev/documentation/_print/ 30/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
https://www.selenium.dev/documentation/_print/ 31/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
https://www.selenium.dev/documentation/_print/ 32/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
https://www.selenium.dev/documentation/_print/ 33/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
https://www.selenium.dev/documentation/_print/ 34/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
A remote WebDriver is composed of two pieces: a client and a server. The client is your WebDriver test
and the server is simply a Java servlet, which can be hosted in any modern JEE app server.
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. Below is an example of instantiating a remote WebDriver object pointing to
our remote web server, www.example.com, running our tests on Firefox.
To further customize our test configuration, we can add other desired capabilities.
Browser options
For example, suppose you wanted to run Chrome on Windows XP, using Chrome version 67:
driver.setFileDetector(new LocalFileDetector());
Once the above code is defined, you can upload a file in your test in the following way:
https://www.selenium.dev/documentation/_print/ 35/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
driver.get("http://sso.dev.saucelabs.com/test/guinea-file-upload"
WebElement upload = driver.findElement(By.id("myfile"));
upload.sendKeys("/Users/sso/the/local/path/to/darkbulb.jpg");
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-jaeger</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>1.35.0</version>
</dependency>
System.setProperty("otel.traces.exporter", "jaeger");
System.setProperty("otel.exporter.jaeger.endpoint", "http://local
System.setProperty("otel.resource.attributes", "service.name=sele
driver.get("http://www.google.com");
driver.quit();
Please refer to Tracing Setup for more information on external dependencies versions required for the
desired Selenium version.
OpenTelemetry: https://opentelemetry.io
https://www.selenium.dev/documentation/_print/ 36/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 37/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
By default, Selenium 4 is compatible with Chrome v75 and greater. Note that the version of the Chrome
browser and the version of chromedriver must match the major version.
Options
Capabilities common to all browsers are described on the Options page.
Capabilities unique to Chrome can be found at Google’s page for Capabilities & ChromeOptions
Starting a Chrome session with basic defined options looks like this:
Arguments
The args parameter is for a list of Command Line Switches used when starting the browser. Commonly
used args include --start-maximized and --headless=new
Add Example
https://www.selenium.dev/documentation/_print/ 38/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Add extensions
The extensions parameter accepts crx files. As for unpacked directories, please use the load-
extension argument instead, as mentioned in this post.
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Excluding arguments
Chrome adds various arguments, if you do not want those arguments added, pass them into
excludeSwitches . A common example is to turn the popup blocker back on.
Add Example
Casting
You can drive Chrome Cast devices, including sharing tabs
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
Network conditions
You can simulate various network conditions.
https://www.selenium.dev/documentation/_print/ 39/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The following examples are for local webdrivers. For remote webdrivers, please refer to the Remote
WebDriver page.
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Logs
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Permissions
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
DevTools
See the Chrome DevTools section for more information about using Chrome DevTools
https://www.selenium.dev/documentation/_print/ 40/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Microsoft Edge is implemented with Chromium, with the earliest supported version of v79. Similar to
Chrome, the major version number of edgedriver must match the major version of the Edge browser.
All capabilities and options found on the Chrome page work for Edge as well.
Options
Starting an Edge session with basic defined options looks like this:
Arguments
The args parameter is for a list of Command Line Switches used when starting the browser. Commonly
used args include --start-maximized and --headless=new
https://www.selenium.dev/documentation/_print/ 41/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium 4 requires Firefox 78 or greater. It is recommended to always use the latest version of
geckodriver.
Options
Capabilities common to all browsers are described on the Options page.
Starting a Firefox session with basic defined options looks like this:
Arguments
The args parameter is for a list of Command line switches used when starting the browser.
Commonly used args include -headless and "-profile", "/path/to/profile"
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Profiles
There are several ways to work with Firefox profiles
Add-ons
Unlike Chrome, Firefox extensions are not added as part of capabilities as mentioned in this issue, they
are created after starting the driver.
The following examples are for local webdrivers. For remote webdrivers, please refer to the Remote
WebDriver page.
Installation
A signed xpi file you would get from Mozilla Addon page
Uninstallation
Uninstalling an addon requires knowing its id. The id can be obtained from the return value when
installing the add-on.
Unsigned installation
When working with an unfinished or unpublished extension, it will likely not be signed. As such, it can
only be installed as “temporary.” This can be done by passing in either a zip file or a directory, here’s an
example with a directory:
https://www.selenium.dev/documentation/_print/ 43/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
Context
The following examples are for local webdrivers. For remote webdrivers, please refer to the Remote
WebDriver page.
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
https://www.selenium.dev/documentation/_print/ 44/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
As of June 2022, Selenium officially no longer supports standalone Internet Explorer. The Internet
Explorer driver still supports running Microsoft Edge in “IE Compatibility Mode.”
Special considerations
The IE Driver is the only driver maintained by the Selenium Project directly. While binaries for both the
32-bit and 64-bit versions of Internet Explorer are available, there are some known limitations with the
64-bit driver. As such it is recommended to use the 32-bit driver.
Additional information about using Internet Explorer can be found on the IE Driver Server page
Options
Starting a Microsoft Edge browser in Internet Explorer Compatibility mode with basic defined options
looks like this:
If IE is not present on the system (default in Windows 11), you do not need to use the two
parameters above. IE Driver will use Edge and will automatically locate it.
If IE and Edge are both present on the system, you only need to set attaching to Edge, IE Driver
will automatically locate Edge on your system.
fileUploadDialogTimeout
In some environments, Internet Explorer may timeout when opening the File Upload dialog. IEDriver has
a default timeout of 1000ms, but you can increase the timeout using the fileUploadDialogTimeout
capability.
https://www.selenium.dev/documentation/_print/ 45/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
ensureCleanSession
When set to true , this capability clears the Cache, Browser History and Cookies for all running
instances of InternetExplorer including those started manually or by the driver. By default, it is set to
false .
Using this capability will cause performance drop while launching the browser, as the driver will wait
until the cache gets cleared before launching the IE browser.
ignoreZoomSetting
InternetExplorer driver expects the browser zoom level to be 100%, else the driver will throw an
exception. This default behaviour can be disabled by setting the ignoreZoomSetting to true.
ignoreProtectedModeSettings
Whether to skip the Protected Mode check while launching a new IE session.
If not set and Protected Mode settings are not same for all zones, an exception will be thrown by the
driver.
If capability is set to true , tests may become flaky, unresponsive, or browsers may hang. However, this
is still by far a second-best choice, and the first choice should always be to actually set the Protected
Mode settings of each zone manually. If a user is using this property, only a “best effort” at support will
be given.
silent
When set to true , this capability suppresses the diagnostic output of the IEDriverServer.
https://www.selenium.dev/documentation/_print/ 46/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Command-Line Options
Internet Explorer includes several command-line options that enable you to troubleshoot and configure
the browser.
-private : Used to start IE in private browsing mode. This works for IE 8 and later versions.
-k : Starts Internet Explorer in kiosk mode. The browser opens in a maximized window that does
not display the address bar, the navigation buttons, or the status bar.
-extoff : Starts IE in no add-on mode. This option specifically used to troubleshoot problems with
browser add-ons. Works in IE 7 and later versions.
Note: forceCreateProcessApi should to enabled in-order for command line arguments to work.
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.ie.InternetExplorerOptions;
forceCreateProcessApi
Forces launching Internet Explorer using the CreateProcess API. The default value is false.
For IE 8 and above, this option requires the “TabProcGrowth” registry value to be set to 0.
https://www.selenium.dev/documentation/_print/ 47/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.ie.InternetExplorerOptions;
https://www.selenium.dev/documentation/_print/ 48/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Unlike Chromium and Firefox drivers, the safaridriver is installed with the Operating System. To enable
automation on Safari, run the following command from the terminal:
safaridriver --enable
Options
Capabilities common to all browsers are described on the Options page.
Capabilities unique to Safari can be found at Apple’s page About WebDriver for Safari
Starting a Safari session with basic defined options looks like this:
Mobile
Those looking to automate Safari on iOS should look to the Appium project.
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
https://www.selenium.dev/documentation/_print/ 49/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
2.4 - Waits
WebDriver can generally be said to have a blocking API. Because it is an out-of-process library that
instructs the browser what to do, and because the web platform has an intrinsically asynchronous
nature, WebDriver does not track the active, real-time state of the DOM. This comes with some
challenges that we will discuss here.
From experience, most intermittent issues that arise from use of Selenium and WebDriver are connected
to race conditions that occur between the browser and the user’s instructions. An example could be that
the user instructs the browser to navigate to a page, then gets a no such element error when trying to
find an element.
<!doctype html>
<meta charset=utf-8>
<title>Race Condition Example</title>
<script>
var initialised = false;
window.addEventListener("load", function() {
var newElement = document.createElement("p");
newElement.textContent = "Hello from JavaScript!";
document.body.appendChild(newElement);
initialised = true;
});
</script>
driver.get("file:///race_condition.html");
WebElement element = driver.findElement(By.tagName("p"));
assertEquals(element.getText(), "Hello from JavaScript!");
The issue here is that the default page load strategy used in WebDriver listens for the
document.readyState to change to "complete" before returning from the call to navigate. Because
the p element is added after the document has completed loading, this WebDriver script might be
intermittent. It “might” be intermittent because no guarantees can be made about elements or events
that trigger asynchronously without explicitly waiting—or blocking—on those events.
Waiting is having the automated task execution elapse a certain amount of time before continuing with
the next step.
To overcome the problem of race conditions between the browser and your WebDriver script, most
Selenium clients ship with a wait package. When employing a wait, you are using what is commonly
referred to as an explicit wait.
https://www.selenium.dev/documentation/_print/ 50/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Explicit wait
Explicit waits are available to Selenium clients for imperative, procedural languages. They allow your
code to halt program execution, or freeze the thread, until the condition you pass it resolves. The
condition is called with a certain frequency until the timeout of the wait is elapsed. This means that for
as long as the condition returns a falsy value, it will keep trying and waiting.
Since explicit waits allow you to wait for a condition to occur, they make a good fit for synchronising the
state between the browser and its DOM, and your WebDriver script.
To remedy our buggy instruction set from earlier, we could employ a wait to have the findElement call
wait until the dynamically added element from the script has been added to the DOM:
We pass in the condition as a function reference that the wait will run repeatedly until its return value is
truthy. A “truthful” return value is anything that evaluates to boolean true in the language at hand, such
as a string, number, a boolean, an object (including a WebElement), or a populated (non-empty)
sequence or list. That means an empty list evaluates to false. When the condition is truthful and the
blocking wait is aborted, the return value from the condition becomes the return value of the wait.
With this knowledge, and because the wait utility ignores no such element errors by default, we can
refactor our instructions to be more concise:
In that example, we pass in an anonymous function (but we could also define it explicitly as we did
earlier so it may be reused). The first and only argument that is passed to our condition is always a
reference to our driver object, WebDriver. In a multi-threaded environment, you should be careful to
operate on the driver reference passed in to the condition rather than the reference to the driver in the
outer scope.
Because the wait will swallow no such element errors that are raised when the element is not found, the
condition will retry until the element is found. Then it will take the return value, a WebElement, and
pass it back through to our script.
If the condition fails, e.g. a truthful return value from the condition is never reached, the wait will
throw/raise an error/exception called a timeout error.
Options
The wait condition can be customised to match your needs. Sometimes it is unnecessary to wait the full
extent of the default timeout, as the penalty for not hitting a successful condition can be expensive.
https://www.selenium.dev/documentation/_print/ 51/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Expected conditions
Because it is quite a common occurrence to have to synchronise the DOM and your instructions, most
clients also come with a set of predefined expected conditions. As might be obvious by the name, they
are conditions that are predefined for frequent wait operations.
The conditions available in the different language bindings vary, but this is a non-exhaustive list of a
few:
alert is present
element exists
element is visible
title contains
title is
element staleness
visible text
You can refer to the API documentation for each client binding to find an exhaustive list of expected
conditions:
Implicit wait
There is a second type of wait that is distinct from explicit wait called implicit wait. By implicitly waiting,
WebDriver polls the DOM for a certain duration when trying to find any element. This can be useful
when certain elements on the webpage are not available immediately and need some time to load.
Implicit waiting for elements to appear is disabled by default and will need to be manually enabled on a
per-session basis. Mixing explicit waits and implicit waits will cause unintended consequences, namely
waits sleeping for the maximum time even if the element is available or condition is true.
Warning: Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. For
example, setting an implicit wait of 10 seconds and an explicit wait of 15 seconds could cause a timeout
to occur after 20 seconds.
An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an
element or elements if they are not immediately available. The default setting is 0, meaning disabled.
Once set, the implicit wait is set for the life of the session.
https://www.selenium.dev/documentation/_print/ 52/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
FluentWait
FluentWait instance defines the maximum amount of time to wait for a condition, as well as the
frequency with which to check the condition.
Users may configure the wait to ignore specific types of exceptions whilst waiting, such as
NoSuchElementException when searching for an element on the page.
https://www.selenium.dev/documentation/_print/ 53/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The majority of most people’s Selenium code involves working with web elements.
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
class fileUploadDoc{
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SE
driver.get("https://the-internet.herokuapp.com/upload");
//we want to import selenium-snapshot file.
driver.findElement(By.id("file-upload")).sendKeys("seleni
driver.findElement(By.id("file-submit")).submit();
if(driver.getPageSource().contains("File Uploaded!")) {
System.out.println("file uploaded");
}
else{
System.out.println("file not uploaded");
}
driver.quit();
}
}
So the above example code helps to understand how we can upload a file using Selenium.
https://www.selenium.dev/documentation/_print/ 54/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
A locator is a way to identify elements on a page. It is the argument passed to the Finding element
methods.
Check out our encouraged test practices for tips on locators, including which to use when and why to
declare locators separately from the finding methods.
Traditional Locators
Selenium provides support for these 8 traditional location strategies in WebDriver:
Locator Description
class name Locates elements whose class name contains the search value (compound class
names are not permitted)
name Locates elements whose NAME attribute matches the search value
link text Locates anchor elements whose visible text matches the search value
partial link Locates anchor elements whose visible text contains the search value. If multiple
text elements are matching, only the first one will be selected.
tag name Locates elements whose tag name matches the search value
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Relative Locators
Selenium 4 introduces Relative Locators (previously called as Friendly Locators). These locators are
helpful when it is not easy to construct a locator for the desired element, but easy to describe spatially
where the element is in relation to an element that does have an easily constructed locator.
How it works
Selenium uses the JavaScript function getBoundingClientRect() to determine the size and position of
elements on the page, and can use this information to locate neighboring elements.
find the relative elements.
Relative locator methods can take as the argument for the point of origin, either a previously located
element reference, or another locator. In these examples we’ll be using locators only, but you could swap
the locator in the final method with an element object and it will work the same.
https://www.selenium.dev/documentation/_print/ 55/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Let us consider the below example for understanding the relative locators.
Above
If the email text field element is not easily identifiable for some reason, but the password text field
element is, we can locate the text field element using the fact that it is an “input” element “above” the
password element.
By emailLocator = RelativeLocator.with(By.tagName("input")).above
Below
If the password text field element is not easily identifiable for some reason, but the email text field
element is, we can locate the text field element using the fact that it is an “input” element “below” the
email element.
By passwordLocator = RelativeLocator.with(By.tagName("input")).be
Left of
If the cancel button is not easily identifiable for some reason, but the submit button element is, we can
locate the cancel button element using the fact that it is a “button” element to the “left of” the submit
element.
By cancelLocator = RelativeLocator.with(By.tagName("button")).toL
Right of
If the submit button is not easily identifiable for some reason, but the cancel button element is, we can
locate the submit button element using the fact that it is a “button” element “to the right of” the cancel
element.
https://www.selenium.dev/documentation/_print/ 56/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
By submitLocator = RelativeLocator.with(By.tagName("button")).toR
Near
If the relative positioning is not obvious, or it varies based on window size, you can use the near method
to identify an element that is at most 50px away from the provided locator. One great use case for this
is to work with a form element that doesn’t have an easily constructed locator, but its associated input
label element does.
By emailLocator = RelativeLocator.with(By.tagName("input")).near(
By submitLocator = RelativeLocator.with(By.tagName("button")).bel
https://www.selenium.dev/documentation/_print/ 57/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
One of the most fundamental aspects of using Selenium is obtaining element references to work with.
Selenium offers a number of built-in locator strategies to uniquely identify an element. There are many
ways to use the locators in very advanced scenarios. For the purposes of this documentation, let’s
consider this HTML snippet:
<ol id="vegetables">
<li class="potatoes">…
<li class="onions">…
<li class="tomatoes"><span>Tomato is a Vegetable</span>…
</ol>
<ul id="fruits">
<li class="bananas">…
<li class="apples">…
<li class="tomatoes"><span>Tomato is a Fruit</span>…
</ul>
One solution is to locate an element with a unique attribute that is an ancestor of the desired element
and not an ancestor of the undesired element, then call find element on that object:
https://www.selenium.dev/documentation/_print/ 58/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Java and C#
WebDriver , WebElement and ShadowRoot classes all implement a SearchContext
interface, which is considered a role-based interface. Role-based interfaces allow you to
determine whether a particular driver implementation supports a given feature. These
interfaces are clearly defined and try to adhere to having only a single role of
responsibility.
Optimized locator
A nested lookup might not be the most effective location strategy since it requires two separate
commands to be issued to the browser.
To improve the performance slightly, we can use either CSS or XPath to find this element in a single
command. See the Locator strategy suggestions in our Encouraged test practices section.
Get element
Often you get a collection of elements but want to work with a specific element, which means you need
to iterate over the collection and identify the one you want.
https://www.selenium.dev/documentation/_print/ 59/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
https://www.selenium.dev/documentation/_print/ 60/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Additional validations
These methods are designed to closely emulate a user’s experience, so, unlike the Actions API, it
attempts to perform two things before attempting the specified action.
1. If it determines the element is outside the viewport, it scrolls the element into view, specifically it
will align the bottom of the element with the bottom of the viewport.
2. It ensures the element is interactable before taking the action. This could mean that the scrolling
was unsuccessful, or that the element is not otherwise displayed. Determining if an element is
displayed on a page was too difficult to define directly in the webdriver specification, so Selenium
sends an execute command with a JavaScript atom that checks for things that would keep the
element from being displayed. If it determines an element is not in the viewport, not displayed, not
keyboard-interactable, or not pointer-interactable, it returns an element not interactable error.
Click
The element click command is executed on the center of the element. If the center of the element is
obscured for some reason, Selenium will return an element click intercepted error.
Send keys
The element send keys command types the provided keys into an editable element. Typically, this means
an element is an input element of a form with a text type or an element with a content-editable
attribute. If it is not editable, an invalid element state error is returned.
https://www.selenium.dev/documentation/_print/ 61/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
Clear
The element clear command resets the content of an element. This requires an element to be editable,
and resettable. Typically, this means an element is an input element of a form with a text type or an
element with a content-editable attribute. If these conditions are not met, an invalid element state
error is returned.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
https://www.selenium.dev/documentation/_print/ 62/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Submit
In Selenium 4 this is no longer implemented with a separate endpoint and functions by executing a
script. As such, it is recommended not to use this method and to click the applicable form submission
button instead.
https://www.selenium.dev/documentation/_print/ 63/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
There are a number of details you can query about a specific element.
Is Displayed
This method is used to check if the connected Element is displayed on a webpage. Returns a Boolean
value, True if the connected element is displayed in the current browsing context else returns false.
This functionality is mentioned in, but not defined by the w3c specification due to the impossibility of
covering all potential conditions. As such, Selenium cannot expect drivers to implement this functionality
directly, and now relies on executing a large JavaScript function directly. This function makes many
approximations about an element’s nature and relationship in the tree to return a value.
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
Is Enabled
This method is used to check if the connected Element is enabled or disabled on a webpage. Returns a
boolean value, True if the connected element is enabled in the current browsing context else returns
false.
//navigates to url
driver.get("https://www.google.com/");
Is Selected
This method determines if the referenced Element is Selected or not. This method is widely used on
Check boxes, radio buttons, input elements, and option elements.
https://www.selenium.dev/documentation/_print/ 64/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Returns a boolean value, True if referenced element is selected in the current browsing context else
returns false.
//navigates to url
driver.get("https://the-internet.herokuapp.com/checkboxes");
Tag Name
It is used to fetch the TagName of the referenced Element which has the focus in the current browsing
context.
//navigates to url
driver.get("https://www.example.com");
// Navigate to url
driver.get("https://www.example.com");
https://www.selenium.dev/documentation/_print/ 65/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
// Navigate to Url
driver.get("https://www.example.com");
Text Content
Retrieves the rendered text of the specified element.
// Navigate to url
driver.get("https://example.com");
https://www.selenium.dev/documentation/_print/ 66/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
driver.getTitle();
driver.getCurrentUrl();
https://www.selenium.dev/documentation/_print/ 67/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
//Convenient
driver.get("https://selenium.dev");
//Longer way
driver.navigate().to("https://selenium.dev");
Back
Pressing the browser’s back button:
driver.navigate().back();
Forward
Pressing the browser’s forward button:
driver.navigate().forward();
Refresh
Refresh the current page:
driver.navigate().refresh();
https://www.selenium.dev/documentation/_print/ 68/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Alerts
The simplest of these is referred to as an alert, which shows a custom message, and a single button
which dismisses the alert, labelled in most browsers as OK. It can also be dismissed in most browsers by
pressing the close button, but this will always do the same thing as the OK button. See an example alert.
WebDriver can get the text from the popup and accept or dismiss these alerts.
Confirm
A confirm box is similar to an alert, except the user can also choose to cancel the message. See a sample
confirm.
https://www.selenium.dev/documentation/_print/ 69/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Prompt
Prompts are similar to confirm boxes, except they also include a text input. Similar to working with form
elements, you can use WebDriver’s send keys to fill in a response. This will completely replace the
placeholder text. Pressing the cancel button will not submit any text. See a sample prompt.
https://www.selenium.dev/documentation/_print/ 70/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
WebDriver API provides a way to interact with cookies with built-in methods:
Add Cookie
It is used to add a cookie to the current browsing context. Add Cookie only accepts a set of defined
serializable JSON object. Here is the link to the list of accepted JSON key values
First of all, you need to be on the domain that the cookie will be valid for. If you are trying to preset
cookies before you start interacting with a site and your homepage is large / takes a while to load an
alternative is to find a smaller page on the site (typically the 404 page is small, e.g.
http://example.com/some404page)
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
https://www.selenium.dev/documentation/_print/ 71/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.Set;
Delete Cookie
It deletes the cookie data matching with the provided cookie name.
https://www.selenium.dev/documentation/_print/ 72/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
/*
Selenium Java bindings also provides a way to delete
cookie by passing cookie object of current browsing
*/
driver.manage().deleteCookie(cookie1);
} finally {
driver.quit();
}
}
}
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
https://www.selenium.dev/documentation/_print/ 73/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Strict:
When the sameSite attribute is set as Strict, the cookie will not be sent along with requests initiated by
third party websites.
Lax:
When you set a cookie sameSite attribute to Lax, the cookie will be sent along with the GET request
initiated by third party website.
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
https://www.selenium.dev/documentation/_print/ 74/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If you need to work with frames or iframes, WebDriver allows you to work with them in the same way.
Consider a button within an iframe. If we inspect the element using the browser development tools, we
might see the following:
<div id="modal">
<iframe id="buttonframe" name="myframe" src="https://seleniumhq.github.io">
<button>Click here</button>
</iframe>
</div>
If it was not for the iframe we would expect to click on the button using something like:
However, if there are no buttons outside of the iframe, you might instead get a no such element error.
This happens because Selenium is only aware of the elements in the top level document. To interact
with the button, we will need to first switch to the frame, in a similar way to how we switch windows.
WebDriver offers three ways of switching to a frame.
Using a WebElement
Switching using a WebElement is the most flexible option. You can find the frame using your preferred
selector and switch to it.
Using a name or ID
If your frame or iframe has an id or name attribute, this can be used instead. If the name or ID is not
unique on the page, then the first one found will be switched to.
https://www.selenium.dev/documentation/_print/ 75/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
//Using the ID
driver.switchTo().frame("buttonframe");
Using an index
It is also possible to use the index of the frame, such as can be queried using window.frames in
JavaScript.
Leaving a frame
To leave an iframe or frameset, switch back to the default content like so:
https://www.selenium.dev/documentation/_print/ 76/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
driver.getWindowHandle();
However, Selenium 4 provides a new api NewWindow which creates a new tab (or) new window and
automatically switches to it.
Forgetting to switch back to another window handle after closing a window will leave WebDriver
executing on the now closed page, and will trigger a No Such Window Exception. You must switch
back to a valid window handle in order to continue execution.
driver.quit();
Quit will:
Close all the windows and tabs associated with that WebDriver session
Close the browser process
Close the background driver process
Notify Selenium Grid that the browser is no longer in use so it can be used by another
session (if you are using Selenium Grid)
Failure to call quit will leave extra background processes and ports running on your machine which could
cause you problems later.
Some test frameworks offer methods and annotations which you can hook into to tear down at the end
of a test.
https://www.selenium.dev/documentation/_print/ 78/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
/**
* Example using JUnit
* https://junit.org/junit5/docs/current/api/org/junit/jupiter/ap
*/
@AfterAll
public static void tearDown() {
driver.quit();
}
If not running WebDriver in a test context, you may consider using try / finally which is offered by
most languages so that an exception will still clean up the WebDriver session.
try {
//WebDriver code here...
} finally {
driver.quit();
}
Python’s WebDriver now supports the python context manager, which when using the with keyword
can automatically quit the driver at the end of execution.
Window management
Screen resolution can impact how your web application renders, so WebDriver provides mechanisms for
moving and resizing the browser window.
https://www.selenium.dev/documentation/_print/ 79/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Maximize window
Enlarges the window. For most operating systems, the window will fill the screen, without blocking the
operating system’s own menus and toolbars.
driver.manage().window().maximize();
Minimize window
Minimizes the window of current browsing context. The exact behavior of this command is specific to
individual window managers.
driver.manage().window().minimize();
Fullscreen window
Fills the entire screen, similar to pressing F11 in most browsers.
https://www.selenium.dev/documentation/_print/ 80/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
driver.manage().window().fullscreen();
TakeScreenshot
Used to capture screenshot for current browsing context. The WebDriver endpoint screenshot returns
screenshot which is encoded in Base64 format.
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.*;
import org.openqa.selenium.*;
TakeElementScreenshot
Used to capture screenshot of an element for current browsing context. The WebDriver endpoint
screenshot returns screenshot which is encoded in Base64 format.
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.File;
import java.io.IOException;
Execute Script
Executes JavaScript code snippet in the current context of a selected frame or window.
https://www.selenium.dev/documentation/_print/ 81/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Print Page
Prints the current page within the browser.
import org.openqa.selenium.print.PrintOptions;
driver.get("https://www.selenium.dev");
printer = (PrintsPage) driver;
https://www.selenium.dev/documentation/_print/ 82/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Web applications can enable a public key-based authentication mechanism known as Web
Authentication to authenticate users in a passwordless manner. Web Authentication defines APIs that
allows a user to create a public-key credential and register it with an authenticator. An authenticator can
be a hardware device or a software entity that stores user’s public-key credentials and retrieves them on
request.
As the name suggests, Virtual Authenticator emulates such authenticators for testing.
https://www.selenium.dev/documentation/_print/ 83/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
((HasVirtualAuthenticator) driver).removeVirtualAuthent
Add Credential
Registers the credential with the authenticator.
https://www.selenium.dev/documentation/_print/ 84/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Get Credential
Returns the list of credentials owned by the authenticator.
authenticator.addCredential(residentCredential);
Remove Credential
Removes a credential from the authenticator based on the passed credential id.
https://www.selenium.dev/documentation/_print/ 85/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
VirtualAuthenticator authenticator =
((HasVirtualAuthenticator) driver).addVirtualAuthenti
authenticator.addCredential(credential);
authenticator.removeCredential(credentialId);
VirtualAuthenticator authenticator =
((HasVirtualAuthenticator) driver).addVirtualAuthenti
authenticator.addCredential(residentCredential);
authenticator.removeAllCredentials();
https://www.selenium.dev/documentation/_print/ 86/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
In addition to the high-level element interactions, the Actions API provides granular control over exactly
what designated input devices can do. Selenium provides an interface for 3 kinds of input sources: a key
input for keyboard devices, a pointer input for a mouse, pen or touch devices, and wheel inputs for scroll
wheel devices (introduced in Selenium 4.2). Selenium allows you to construct individual action
commands assigned to specific inputs and chain them together and call the associated perform method
to execute them all at once.
Action Builder
In the move from the legacy JSON Wire Protocol to the new W3C WebDriver Protocol, the low level
building blocks of actions became especially detailed. It is extremely powerful, but each input device has
a number of ways to use it and if you need to manage more than one device, you are responsible for
ensuring proper synchronization between them.
Thankfully, you likely do not need to learn how to use the low level commands directly, since almost
everything you might want to do has been given a convenience method that combines the lower level
commands for you. These are all documented in keyboard, mouse, pen, and wheel pages.
Pause
Pointer movements and Wheel scrolling allow the user to set a duration for the action, but sometimes
you just need to wait a beat between actions for things to work correctly.
There is a special method to release all currently depressed keys and pointer buttons. This method is
implemented differently in each of the languages because it does not get executed with the perform
method.
((RemoteWebDriver) driver).resetInputState();
https://www.selenium.dev/documentation/_print/ 87/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 88/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
There are only 2 actions that can be accomplished with a keyboard: pressing down on a key, and
releasing a pressed key. In addition to supporting ASCII characters, each keyboard key has a
representation that can be pressed or released in designated sequences.
Keys
In addition to the keys represented by regular unicode, unicode values have been assigned to other
keyboard keys for use with Selenium. Each language has its own way to reference these keys; the full
list can be found here.
Key down
Java Python CSharp Ruby JavaScript Kotlin
new Actions(driver)
.keyDown(Keys.SHIFT)
.sendKeys("a")
.perform();
Key up
Java Python CSharp Ruby JavaScript Kotlin
new Actions(driver)
.keyDown(Keys.SHIFT)
.sendKeys("a")
.keyUp(Keys.SHIFT)
.sendKeys("b")
.perform();
Send keys
This is a convenience method in the Actions API that combines keyDown and keyUp commands in one
action. Executing this command differs slightly from using the element method, but primarily this gets
used when needing to type multiple characters in the middle of other actions.
https://www.selenium.dev/documentation/_print/ 89/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Active Element
Java Python CSharp Ruby JavaScript Kotlin
new Actions(driver)
.sendKeys("abc")
.perform();
Designated Element
Java Python CSharp Ruby JavaScript Kotlin
new Actions(driver)
.sendKeys(textField, "Selenium!")
.perform();
Assertions.assertEquals("SeleniumSelenium!", textFie
https://www.selenium.dev/documentation/_print/ 90/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
There are only 3 actions that can be accomplished with a mouse: pressing down on a button, releasing a
pressed button, and moving the mouse. Selenium provides convenience methods that combine these
actions in the most common ways.
Context Click
This method combines moving to the center of an element with pressing and releasing the right mouse
button (button 2). This is otherwise known as “right-clicking”:
https://www.selenium.dev/documentation/_print/ 91/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Back Click
There is no convenience method for this, it is just pressing and releasing mouse button 3
((RemoteWebDriver) driver).perform(Collections.sing
Forward Click
There is no convenience method for this, it is just pressing and releasing mouse button 4
((RemoteWebDriver) driver).perform(Collections.sing
Double click
This method combines moving to the center of an element with pressing and releasing the left mouse
button twice.
https://www.selenium.dev/documentation/_print/ 92/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Move to element
This method moves the mouse to the in-view center point of the element. This is otherwise known as
“hovering.” Note that the element must be in the viewport or else the command will error.
Move by offset
These methods first move the mouse to the designated origin and then by the number of pixels in the
provided offset. Note that the position of the mouse must be in the viewport or else the command will
error.
https://www.selenium.dev/documentation/_print/ 93/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
((RemoteWebDriver) driver).perform(Collections.sing
Note that the first argument X specifies to move right when positive, while the second argument Y
specifies to move down when positive. So moveByOffset(30, -10) moves right 30 and up 10 from the
current mouse position.
new Actions(driver)
.moveByOffset(13, 15)
.perform();
https://www.selenium.dev/documentation/_print/ 94/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 95/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Chromium Only
A Pen is a type of pointer input that has most of the same behavior as a mouse, but can also have event
properties unique to a stylus. Additionally, while a mouse has 5 buttons, a pen has 3 equivalent button
states:
Using a Pen
Java Python CSharp Ruby JavaScript Kotlin
Selenium v4.2
((RemoteWebDriver) driver).perform(Collections.sing
https://www.selenium.dev/documentation/_print/ 96/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium v4.2
Chromium Only
Scroll to element
This is the most common scenario. Unlike traditional click and send keys methods, the actions class does
not automatically scroll the target element into view, so this method will need to be used if elements are
not already inside the viewport.
Regardless of whether the element is above or below the current viewscreen, the viewport will be
scrolled so the bottom of the element is at the bottom of the screen.
To execute this use the “Scroll From” method, which takes 3 arguments. The first represents the
origination point, which we designate as the element, and the second two are the delta x and delta y
values.
https://www.selenium.dev/documentation/_print/ 97/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If the element is out of the viewport, it will be scrolled to the bottom of the screen, then the page will be
scrolled by the provided delta x and delta y values.
This uses the “Scroll From” method again, and in addition to specifying the element, an offset is
specified to indicate the origin point of the scroll. The offset is calculated from the center of the provided
element.
If the element is out of the viewport, it first will be scrolled to the bottom of the screen, then the origin
of the scroll will be determined by adding the offset to the coordinates of the center of the element, and
finally the page will be scrolled by the provided delta x and delta y values.
Note that if the offset from the center of the element falls outside of the viewport, it will result in an
exception.
This uses the “Scroll From” method again, but the viewport is designated instead of an element. An
offset is specified from the upper left corner of the current viewport. After the origin point is
determined, the page will be scrolled by the provided delta x and delta y values.
Note that if the offset from the upper left corner of the viewport falls outside of the screen, it will result
in an exception.
https://www.selenium.dev/documentation/_print/ 98/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 99/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The traditional WebDriver model of strict request/response commands will be supplemented with the
ability to stream events from the user agent to the controlling software via WebSockets, better
matching the evented nature of the browser DOM.
As it is not a good idea to tie your tests to a specific version of any browser, the Selenium project
recommends using WebDriver BiDi wherever possible.
While the specification is in works, the browser vendors are parallely implementing the WebDriver
BiDirectional Protocol. Refer web-platform-tests dashboard to see how far along the browser vendors
are. Selenium is trying to keep up with the browser vendors and has started implementing W3C BiDi
APIs. The goal is to ensure APIs are W3C compliant and uniform among the different language bindings.
However, until the specification and corresponding Selenium implementation is complete there are
many useful things that CDP offers. Selenium offers some useful helper classes that use CDP.
https://www.selenium.dev/documentation/_print/ 100/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Mutation Observation
Mutation Observation is the ability to capture events via WebDriver BiDi when there are DOM
mutations on a specific element in the DOM.
driver.get("https://www.google.com");
WebElement span = driver.findElement(By.cssSelector("span"));
((JavascriptExecutor) driver).executeScript("arguments[0].setAttr
driver.quit();
https://www.selenium.dev/documentation/_print/ 101/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Listen to JS Exceptions
Listen to the JS Exceptions and register callbacks to process the exception details.
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
Network Interception
If you want to capture network events coming into the browser and you want manipulate them you are
able to do it with the following examples.
https://www.selenium.dev/documentation/_print/ 102/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.remote.http.Contents;
import org.openqa.selenium.remote.http.Filter;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
driver.get("https://example-sausages-site.com");
assertThat(source).contains("delicious cheese!");
https://www.selenium.dev/documentation/_print/ 103/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Java
Mutation Observation
Mutation Observation is the ability to capture events via WebDriver BiDi when there are DOM
mutations on a specific element in the DOM.
Java
https://www.selenium.dev/documentation/_print/ 104/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
kind.initializeListener(augmentedDr
}
}).augment(driver);
Java
devTools.send(org.openqa.selenium.devtools.v85.runtime.
devTools.send(Log.enable());
devTools.addListener(Log.entryAdded(),
logEntry -> {
System.out.println("log: " + log
System.out.println("level: " + lo
latch.countDown();
});
devTools.addListener(org.openqa.selenium.devtools.v85.r
consoleLog -> System.out.println("T
https://www.selenium.dev/documentation/_print/ 105/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Network Interception
If you want to capture network events coming into the browser and you want manipulate them you are
able to do it with the following examples.
Java
https://www.selenium.dev/documentation/_print/ 106/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Many browsers provide “DevTools” – a set of tools that are integrated with the browser that developers
can use to debug web apps and explore the performance of their pages. Google Chrome’s DevTools
make use of a protocol called the Chrome DevTools Protocol (or “CDP” for short). As the name suggests,
this is not designed for testing, nor to have a stable API, so functionality is highly dependent on the
version of the browser.
WebDriver Bidi is the next generation of the W3C WebDriver protocol and aims to provide a stable API
implemented by all browsers, but it’s not yet complete. Until it is, Selenium provides access to the CDP
for those browsers that implement it (such as Google Chrome, or Microsoft Edge, and Firefox), allowing
you to enhance your tests in interesting ways. Some examples of what you can do with it are given
below.
https://www.selenium.dev/documentation/_print/ 107/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
devTools.send(Emulation.setGeolocationOverride(Optional.of(52.504
Optional.of(13.450
Optional.of(1)));
driver.get("https://my-location.org/");
driver.quit();
https://www.selenium.dev/documentation/_print/ 108/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
driver.get("https://google.com");
driver.quit();
for(Metric m : metricList) {
System.out.println(m.getName() + " = " + m.getValue());
}
}
https://www.selenium.dev/documentation/_print/ 109/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If there is additional functionality you’d like to see, please raise a feature request.
https://www.selenium.dev/documentation/_print/ 110/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
String id = driver.getWindowHandle();
BrowsingContext browsingContext = new BrowsingContex
A reference browsing context is a top-level browsing context. The API allows to pass the reference
browsing context, which is used to create a new window. The implementation is operating system
specific.
https://www.selenium.dev/documentation/_print/ 111/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
BrowsingContext
browsingContext =
new BrowsingContext(driver, WindowType.WINDO
BrowsingContext
browsingContext =
new BrowsingContext(driver, WindowType.TAB,
Navigate to a URL
Java Ruby JavaScript Kotlin
Assertions.assertNotNull(browsingContext.getId());
Assertions.assertNull(info.getNavigationId());
Assertions.assertTrue(info.getUrl().contains("/bidi/
Assertions.assertNotNull(browsingContext.getId());
Assertions.assertNull(info.getNavigationId());
Assertions.assertTrue(info.getUrl().contains("/bidi/
https://www.selenium.dev/documentation/_print/ 112/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
parentWindow.navigate("https://www.selenium.dev/sele
Assertions.assertEquals(1, contextInfoList.size());
BrowsingContextInfo info = contextInfoList.get(0);
Assertions.assertEquals(1, info.getChildren().size(
Assertions.assertEquals(referenceContextId, info.get
Assertions.assertTrue(info.getChildren().get(0).getU
parentWindow.navigate("https://www.selenium.dev/sele
Assertions.assertEquals(1, contextInfoList.size());
BrowsingContextInfo info = contextInfoList.get(0);
Assertions.assertNull(info.getChildren()); // since
Assertions.assertEquals(referenceContextId, info.get
https://www.selenium.dev/documentation/_print/ 113/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Assertions.assertEquals(2, contextInfoList.size());
Close a tab/window
Java Ruby JavaScript Kotlin
window2.close();
Assertions.assertThrows(BiDiException.class, window
https://www.selenium.dev/documentation/_print/ 114/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
2.8.4.2 - Log
This section contains the APIs related to logging.
driver.get("https://www.selenium.dev/selenium/we
driver.findElement(By.id("consoleLog")).click()
Listen to JS Exceptions
Listen to the JS Exceptions and register callbacks to process the exception details.
driver.get("https://www.selenium.dev/selenium/we
driver.findElement(By.id("jsException")).click(
https://www.selenium.dev/documentation/_print/ 115/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Listen to JS Logs
Listen to all JS logs at all levels and register callbacks to process the log.
driver.get("https://www.selenium.dev/selenium/we
driver.findElement(By.id("jsException")).click(
https://www.selenium.dev/documentation/_print/ 116/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The core libraries of Selenium try to be low level and non-opinionated. The Support classes in each
language provide opinionated wrappers for common interactions that may be used to simplify some
behaviors.
import org.openqa.selenium.support.Color;
You can now start creating colour objects. Every colour object will need to be created from a string
representation of your colour. Supported colour representations are:
The Color class also supports all of the base colour definitions specified in http://www.w3.org/TR/css3-
color/#html4.
Sometimes browsers will return a colour value of “transparent” if no colour has been set on an element.
The Color class also supports this:
https://www.selenium.dev/documentation/_print/ 117/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
You can now safely query an element to get its colour/background colour knowing that any response
will be correctly parsed and converted into a valid Color object:
assert loginButtonBackgroundColour.equals(HOTPINK);
Or you can convert the colour into one of the following formats and perform a static validation:
assert loginButtonBackgroundColour.asHex().equals("#ff69b4");
assert loginButtonBackgroundColour.asRgba().equals("rgba(255, 105
assert loginButtonBackgroundColour.asRgb().equals("rgb(255, 105,
https://www.selenium.dev/documentation/_print/ 118/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The Select object will now give you a series of commands that allow you to interact with a <select>
element.
If you are using Java or .NET make sure that you’ve properly required the support package in your code.
See the full code from GitHub in any of the examples below.
Note that this class only works for HTML elements select and option . It is possible to design drop-
downs with JavaScript overlays using div or li , and this class will not work for those.
Types
Select methods may behave differently depending on which type of <select> element is being worked
with.
Single select
This is the standard drop-down object where one and only one option may be selected.
<select name="selectomatic">
<option selected="selected" id="non_multi_option" value="one">One</option>
<option value="two">Two</option>
<option value="four">Four</option>
<option value="still learning how to count, apparently">Still learning how to
</select>
Multiple select
This select list allows selecting and deselecting more than one option at a time. This only applies to
<select> elements with the multiple attribute.
Create class
First locate a <select> element, then use it to initialize a Select object. Note that as of Selenium 4.5,
you can’t create a Select object if the <select> element is disabled.
https://www.selenium.dev/documentation/_print/ 119/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
List options
There are two lists that can be obtained:
All options
Get a list of all options in the <select> element:
Selected options
Get a list of selected options in the <select> element. For a standard select list this will only be a list
with one element, for a multiple select list it can contain zero or many elements.
Select option
The Select class provides three ways to select an option. Note that for multiple select type Select lists,
you can repeat these methods for each element you want to select.
Text
Select the option based on its visible text
select.selectByVisibleText("Four");
Value
Select the option based on its value attribute
select.selectByValue("two");
https://www.selenium.dev/documentation/_print/ 120/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Index
Select the option based on its position in the list
select.selectByIndex(3);
Disabled options
Selenium v4.5
<select name="single_disabled">
<option id="sinlge_disabled_1" value="enabled">Enabled</option>
<option id="sinlge_disabled_2" value="disabled" disabled="disabled">Disable
</select>
Assertions.assertThrows(UnsupportedOperationExceptio
select.selectByValue("disabled");
});
De-select option
Only multiple select type select lists can have options de-selected. You can repeat these methods for
each element you want to select.
select.deselectByValue("eggs");
https://www.selenium.dev/documentation/_print/ 121/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
2.9.3 - ThreadGuard
ThreadGuard checks that a driver is called only from the same thread that created it. Threading issues
especially when running tests in Parallel may have mysterious and hard to diagnose errors. Using this
wrapper prevents this category of errors and will raise an exception when it happens.
static {
System.setProperty("webdriver.chrome.driver", "<Set path to your Chromedriver
}
//Thread-1 (id 24) is calling the same driver causing the clash to happen
Runnable r1 = () -> {protectedDriver.get("https://selenium.dev");};
Thread thr1 = new Thread(r1);
void runThreads(){
thr1.start();
}
We use Java Runnable to spin up a new process and a new Thread to run the process
Both Thread will clash because the Main Thread does not have protectedDriver in it’s
memory.
ThreadGuard.protect will throw an exception.
Note:
This does not replace the need for using ThreadLocal to manage drivers when running parallel.
https://www.selenium.dev/documentation/_print/ 122/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
1. The most common Selenium-related error is a result of poor synchronization. Read about Waiting
Strategies. If you aren’t sure if it is a synchronization strategy you can try temporarily hard coding
a large sleep where you see the issue, and you’ll know if adding an explicit wait can help.
2. Note that many errors that get reported to the project are actually caused by issues in the
underlying drivers that Selenium sends the commands to. You can rule out a driver problem by
executing the command in multiple browsers.
3. If you have questions about how to do things, check out the Support options for ways get
assistance.
4. If you think you’ve found a problem with Selenium code, go ahead and file a Bug Report on
GitHub.
https://www.selenium.dev/documentation/_print/ 123/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Likely Cause
The CSS or XPath selector you are trying to use has invalid characters or an invalid query.
Possible Solutions
Run your selector through a validator service:
CSS Validator
xPath Validator
SelectorsHub
Likely Cause
You are looking for the element in the wrong place (perhaps a previous action was unsuccessful).
You are looking for the element at the wrong time (the element has not shown up in the DOM,
yet)
The locator has changed since you wrote the code
Possible Solutions
Make sure you are on the page you expect to be on, and that previous actions in your code
completed correctly
Make sure you are using a proper Waiting Strategy
Update the locator with the browser’s devtools console or use a browser extension like:
SelectorsHub
Common Causes
This can happen when:
You have refreshed the page, or the DOM of the page has dynamically changed.
You have navigated to a different page.
You have switched to another window or into or out of a frame or iframe.
https://www.selenium.dev/documentation/_print/ 124/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Common Solutions
The DOM has changed
When the page is refreshed or items on the page have moved around, there is still an element with the
desired locator on the page, it is just no longer accessible by the element object being used, and the
element must be relocated before it can be used again. This is often done in one of two ways:
Always relocate the element every time you go to use it. The likelihood of the element going stale
in the microseconds between locating and using the element is small, though possible. The
downside is that this is not the most efficient approach, especially when running on a remote grid.
Wrap the Web Element with another object that stores the locator, and caches the located
Selenium element. When taking actions with this wrapped object, you can attempt to use the
cached object if previously located, and if it is stale, exception can be caught, the element relocated
with the stored locator, and the method re-tried. This is more efficient, but it can cause problems if
the locator you’re using references a different element (and not the one you want) after the page
has changed.
Element objects are stored for a given context, so if you move to a different context — like a different
window or a different frame or iframe — the element reference will still be valid, but will be temporarily
inaccessible. In this scenario, it won’t help to relocate the element, because it doesn’t exist in the current
context. To fix this, you need to make sure to switch back to the correct context before using the
element.
This scenario is when you haven’t just changed contexts, you have navigated to another page and have
destroyed the context in which the element was located. You can’t just relocate it from the current
context, and you can’t switch back to an active context where it is valid. If this is the reason for your
error, you must both navigate back to the correct location and relocate it.
https://www.selenium.dev/documentation/_print/ 125/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Each language adopts a distinctly different approach to logging information about the activity of the
program.
Ruby
Ruby uses a custom implementation of the default Logger class with some interesting additional
features.
Logger output
By default, logs are sent to the console in stdout . if you want to store the logs in a file, add this to your
code:
Selenium::WebDriver.logger.output = '/path/to/selenium.log'
Logger level
The basic levels for the Ruby logger are: :debug , :info , :warn , :error , :fatal
Selenium uses :info and :debug similar to “verbose” and “very verbose”, so the default is :warn .
Selenium::WebDriver.logger.level = :fatal
WARN
Warnings include everything we want users to be aware of by default. This is mostly used for
deprecations. For various reasons, Selenium project does not follow standard Semantic Versioning
practices. Our policy is to mark things as deprecated for 3 releases and then remove them. As such, Ruby
logs deprecations as warnings, specifying what is changing, what needs to be used instead. It may
include additional messages, and always includes an ID.
For example:
Because these items can get annoying, we’ve provided an easy way to turn them off.
Selenium::WebDriver.logger.ignore(:jwp_caps)
https://www.selenium.dev/documentation/_print/ 126/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium::WebDriver.logger.ignore(:deprecations)
INFO
This is where the most useful information gets logged. Selenium logs the endpoints and payloads sent
to and received from the driver or server. This is a great way to see what Selenium is actually doing
under the hood, and can be used to determine if it is Selenium code or driver code that is causing a
problem. (Unfortunately, we can’t blame the driver if Selenium is sending incorrect syntax).
DEBUG
This is less useful information where we log things about the servers and the sockets, and header
information, etc. Debug mode is set if either $DEBUG is true or ENV['DEBUG'] has a value.
Content Help ×
Note: This section needs additional and/or updated content
Descriptions of how to set and use logging in Java, Python, JavaScript, and
.NET
https://www.selenium.dev/documentation/_print/ 127/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
3 - Grid
Want to run tests in parallel across multiple machines? Then, Grid is for you.
Selenium Grid allows the execution of WebDriver scripts on remote machines by routing commands sent
by the client to remote browser instances.
Interested? Go through the following sections to understand how Grid works, and how to set up your
own.
https://www.selenium.dev/documentation/_print/ 128/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Quick start
1. Prerequisites
Java 11 or higher installed
Browser(s) installed
Browser driver(s)
If using Selenium 4.6, Selenium Manager will configure the drivers for Chrome, Firefox,
and Edge if they are not found on the PATH.
Installed and on the PATH
Download the Selenium Server jar file from the latest release
2. Start the Grid
java -jar selenium-server-<version>.jar standalone
*Wondering how to point your tests to http://localhost:4444? Check the RemoteWebDriver section.
To learn more about the different configuration options, go through the sections below.
Grid roles
Grid is composed by six different components, which gives you the option to deploy it in different ways.
Depending on your needs, you can start each one of them on its own (Distributed), group them in Hub &
Node, or all in one on a single machine (Standalone).
Standalone
Standalone combines all Grid components seamlessly into one. Running a Grid in Standalone mode
gives you a fully functional Grid with a single command, within a single process. Standalone can only
run on a single machine.
Standalone is also the easiest mode to spin up a Selenium Grid. By default, the server will listen for
RemoteWebDriver requests on http://localhost:4444. By default, the server will detect the available
drivers that it can use from the System PATH .
After starting successfully the Grid in Standalone mode, point your WebDriver tests to
http://localhost:4444.
https://www.selenium.dev/documentation/_print/ 129/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Hub
A Hub is composed by the following components: Router, Distributor, Session Map, New Session Queue,
and Event Bus.
Node
During startup time, the Node will detect the available drivers that it can use from the System PATH .
The command below assumes the Node is running on the same machine where the Hub is running.
Node 2
To successfully register a Node to a Hub, it is important to expose the Event Bus ports (4442 and 4443
by default) on the Hub machine. This also applies for the Node port. With that, both Hub and Node will
be able to communicate.
If the Hub is using the default ports, the --hub flag can be used to register the Node
When the Hub is not using the default ports, the --publish-events and --subscribe-events flags
are needed.
For example, if the Hub uses ports 8886 , 8887 , and 8888
https://www.selenium.dev/documentation/_print/ 130/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Distributed
When using a Distributed Grid, each component is started separately, and ideally on different machines.
It is important to expose all ports properly in order to allow fluent communication between all
components.
2. New Session Queue: adds new session requests to a queue, which will be queried by the
Distributor
3. Session Map: maps session IDs to the Node where the session is running
Default Session Map port is 5556 . Session Map interacts with the Event Bus.
4. Distributor: queries the New Session Queue for new session requests, and assigns them to a
Node when the capabilities match. Nodes register to the Distributor the way they register to the
Hub in a Hub/Node Grid.
Default Distributor port is 5553 . Distributor interacts with New Session Queue, Session Map,
Event Bus, and the Node(s).
5. Router: redirects new session requests to the queue, and redirects running sessions requests to
the Node running that session.
Default Router port is 4444 . Router interacts with New Session Queue, Session Map, and
Distributor.
https://www.selenium.dev/documentation/_print/ 131/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
6. Node(s)
Metadata in tests
Add metadata to your tests and consume it via GraphQL or visualize parts of it (like se:name ) through
the Selenium Grid UI.
Metadata can be added by prefixing a capability with se: . Here is a quick example in Java showing
that.
The Grid UI can be reached by opening your preferred browser and heading to http://localhost:4444.
API calls can be done through the http://localhost:4444/status endpoint or using GraphQL
For simplicity, all command examples shown in this page assume that components are
running locally. More detailed examples and usages can be found in the Configuring
Components section.
By default, Grid will use AsyncHttpClient. AsyncHttpClient is an open-source library built on top of
Netty. It allows the execution of HTTP requests and responses asynchronously. Additionally it also
provides WebSocket support. Hence it is a good fit.
https://www.selenium.dev/documentation/_print/ 132/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
However, AsyncHttpClient is not been actively maintained since June 2021. It coincides with the fact that
Java 11+ provides a built-in HTTP and WebSocket client. Currently, Selenium has plans to upgrade the
minimum version supported to Java 11. However, it is a sizeable effort. Aligning it with major releases
and accompanied announcements is crucial to ensure the user experience is intact.
To do use the Java 11 client, you will need to download the selenium-http-jdk-client jar file and use
the --ext flag to make it available in the Grid jar’s classpath.
The jar file can be downloaded directly from repo1.maven.org and then start the Grid in the following
way:
If you are using the Hub/Node(s) mode or the Distributed mode, setting the -
Dwebdriver.http.factory=jdk-http-client and --ext flags needs to be done for each one of the
components.
Grid sizes
Choosing a Grid role depends on what operating systems and browsers need to be supported, how
many parallel sessions need to be executed, the amount of available machines, and how powerful (CPU,
RAM) those machines are.
Creating sessions concurrently relies on the available processors to the Distributor. For example, if a
machine has 4 CPUs, the Distributor will only be able to create up to 4 sessions concurrently.
By default, the maximum amount of concurrent sessions a Node supports is limited by the number of
CPUs available. For example, if the Node machine has 8CPUs, it can run up to 8 concurrent browser
sessions (with the exception of Safari, which is always one). Additionally, it is expected that each
browser session should use around 1GB RAM.
In general, it is a recommended to have Nodes as small as possible. Instead of having a machine with
32CPUs and 32GB RAM to run 32 concurrent browser sessions, it is better to have 32 small Nodes in
order to better isolate processes. With this, if a Node fails, it will do it in an isolated way. Docker is a
good tool to achieve this approach.
Note that the default values (1CPU/1GB RAM per browser) are a recommendation and they could not
apply to your context. It is recommended to use them as a reference, but measuring performance
continuously will help to determine the ideal values for your environment.
Grid sizes are relative to the amount of supported concurrent sessions and amount of Nodes, and there
is no “one size fits all”. Sizes mentioned below are rough estimations thay can vary between different
environments. For example a Hub/Node with 120 Nodes might work well when the Hub has enough
resources. Values below are not set on stone, and feedback is welcomed!
Small
Standalone or Hub/Node with 5 or less Nodes.
Middle
Hub/Node between 6 and 60 Nodes.
https://www.selenium.dev/documentation/_print/ 133/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Large
Hub/Node between 60 and 100 Nodes. Distributed with over 100 Nodes.
Warning
Selenium Grid must be protected from external access using appropriate firewall permissions.
Failure to protect your Grid could result in one or more of the following occurring:
See this blog post on Detectify, which gives a good overview of how a publicly exposed Grid could be
misused: Don’t Leave your Grid Wide Open
Further reading
Components: learn how Grid’s internal components relate to each other.
Configuration: customize your Grid setup.
Architecture: understand key concepts in Grid.
Advanced Features: explore more possibilities through Grid’s features.
https://www.selenium.dev/documentation/_print/ 134/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
To run your tests in parallel, against different browser types, browser versions, operating systems
To reduce the time needed to execute a test suite
Selenium Grid runs test suites in parallel against multiple machines (called Nodes). For large and long-
running test suites, this can save minutes, hours, or perhaps days. This shortens the turnaround time for
test results as your application under test (AUT) changes.
Grid can run tests (in parallel) against multiple different browsers, and it can run against multiple
instances of the same browser. As an example, let’s imagine a Grid with six Nodes. The first machine has
Firefox’s latest version, the second has Firefox “latest minus one”, the third gets the latest Chrome, and
the remaining three machines are Mac Minis, which allows for three tests to run in parallel on the latest
version of Safari.
Number of Tests * Average Test Time / Number of Nodes = Total Execution Time
As the test suite is executing, the Grid allocates the tests to run against these browsers as configured in
the tests.
A configuration such as this can greatly speed up the execution time of even the largest Selenium test
suites.
Selenium Grid is a completely native part of the Selenium project, and is maintained in parallel by the
same team of committers who work in the core Selenium development. Recognizing the importance of
test execution speed, Grid has been a critical part of the Selenium project since the earliest days.
https://www.selenium.dev/documentation/_print/ 135/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium Grid 4 is a ground-up rewrite from previous versions. In addition to a comprehensive set of
improvements to performance and standards compliance, the different functions of the grid were
broken out to reflect a more modern age of computing and software development. Purpose-build for
containerization and cloud-distributed scalability, Selenium Grid 4 is a wholly new solution for the
modern era.
Grid Components
Router
The Router is the entry point of the Grid, receiving all external requests, and forwards them to the
correct component.
If the Router receives a new session request, it will be forwarded to the New Session Queue.
If the request belongs to an existing session, the Router will query the Session Map to get the Node ID
where the session is running, and then the request will be forwarded directly to the Node.
The Router balances the load in the Grid by sending the requests to the component that is able to
handle them better, without overloading any component that is not needed in the process.
Distributor
The Distributor has two main responsibilities:
Query the New Session Queue and process any pending new session
requests
https://www.selenium.dev/documentation/_print/ 136/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
When a new session request is sent to the Router, it gets forwarded to the New Session Queue,
where it will wait in the queue. The Distributor will poll the New Session Queue for pending new
session requests, and then finds a suitable Node where the session can be created. After the session has
been created, the Distributor stores in the Session Map the relation between the session id and Node
where the session is being executed.
Session Map
The Session Map is a data store that keeps the relationship between the session id and the Node
where the session is running. It supports the Router in the process of forwarding a request to the
Node. The Router will ask the Session Map for the Node associated to a session id.
The Router adds the new session request to the New Session Queue and waits for the response. The
New Session Queue regularly checks if any request in the queue has timed out, if so the request is
rejected and removed immediately.
The Distributor regularly checks if a slot is available. If so, the Distributor polls the New Session
Queue for the first matching request. The Distributor then attempts to create a new session.
Once the requested capabilities match the capabilities of any of the free Node slots, the Distributor
attempts to get the available slot. If all the slots are busy, the Distributor will send the request back to
the queue. If request times out while retrying or adding to the front of the queue, it will be rejected.
After a session is created successfully, the Distributor sends the session information to the New
Session Queue, which then gets sent back to the Router, and finally to the client.
Node
A Grid can contain multiple Nodes. Each Node manages the slots for the available browsers of the
machine where it is running.
The Node registers itself to the Distributor through the Event Bus, and its configuration is sent as part
of the registration message.
By default, the Node auto-registers all browser drivers available on the path of the machine where it
runs. It also creates one slot per available CPU for Chromium based browsers and Firefox. For Safari, only
one slot is created. Through a specific configuration, it can run sessions in Docker containers or relay
commands.
A Node only executes the received commands, it does not evaluate, make judgments, or control
anything other than the flow of commands and responses. The machines where the Node is running
does not need to have the same operating system as the other components. For example, A Windows
Node might have the capability of offering IE Mode on Edge as a browser option, whereas this would
not be possible on Linux or Mac, and a Grid can have multiple Nodes configured with Windows, Mac, or
Linux.
Event Bus
The Event Bus serves as a communication path between the Nodes, Distributor, New Session
Queue, and Session Map. The Grid does most of its internal communication through messages,
avoiding expensive HTTP calls. When starting the Grid in its fully distributed mode, the Event Bus is the
first component that should be started.
Looking forward to using all these components and run your own Grid? Head to the “Getting
Started” section to understand how to put all these pieces together.
https://www.selenium.dev/documentation/_print/ 138/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The help commands display information based on the current code implementation.
Hence, it will provide accurate information in case the documentation is not updated. It
is the easiest way to learn about Grid 4 configuration for any new version.
Info Command
The info command provides detailed docs on the following topics:
Configuring Selenium
Security
Session Map setup
Tracing
Config help
Quick config help and overview is provided by running:
Security
To get details on setting up the Grid servers for secure communication and node registration:
https://www.selenium.dev/documentation/_print/ 139/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
It will show all the available commands and description for each one.
Standalone
Hub
Sessions
Distributor
Router
Node
https://www.selenium.dev/documentation/_print/ 140/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Different sections are available to configure a Grid. Each section has options can be configured through
command line arguments.
Note that this documentation could be outdated if an option was modified or added
but has not been documented yet. In case you bump into this situation, please check
the “Config help” section and feel free to send us a pull request updating this page.
Sections
Standalone Hub Node Distributor Router Sessions SessionQueue
Distributor
Docker
Events
Logging
Network
Node
Router
Relay
Server
SessionQueue
Sessions
Distributor
Option Type Value/Example
https://www.selenium.dev/documentation/_print/ 141/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 142/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Docker
Option Type Value/Example Description
Events
Option Type Value/Example Descriptio
https://www.selenium.dev/documentation/_print/ 143/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Logging
Option Type Value/Example Description
--log string Windows path example : File to write out logs. Ensure t
'\path\to\file\gridlog.log' operating system’s file path.
or
'C:\path\path\to\file\gridlog.log'
https://www.selenium.dev/documentation/_print/ 144/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Network
Option Type Value/Example Description
--relax- boolean false Relax checks on origin header and content type of
checks incoming requests, in contravention of strict W3C spec
compliance.
Node
Option Type Value/Example Des
--max- int 8 Ma
sessions con
Def
num
pro
https://www.selenium.dev/documentation/_print/ 145/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 146/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 147/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Relay
Option Type Value/Example Description
Router
Option Type Value/Example Description
-- string admin User name clients must use to connect to the server.
username Both this and the password need to be set in order to
be used.
Server
Option Type Value/Example Description
https://www.selenium.dev/documentation/_print/ 148/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
--bind-host boolean true Whether the server should bind to the host
address/name, or only use it to" report its
reachable url. Helpful in complex network
topologies where the server cannot report
itself with the current IP/hostname but rather
an external IP or hostname (e.g. inside a
Docker container)
--https- path /path/to/cert.pem Server certificate for https. Get more detailed
certificate information by running “java -jar selenium-
server.jar info security”
--https- path /path/to/key.pkcs8 Private key for https. Get more detailed
private-key information by running “java -jar selenium-
server.jar info security”
SessionQueue
Option Type Value/Example Description
Sessions
Option Type Value/Example Description
https://www.selenium.dev/documentation/_print/ 149/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Configuration examples
All the options mentioned above can be used when starting the Grid components. They are a good way
of exploring the Grid options, and trying out values to find a suitable configuration.
We recommend the use of Toml files to configure a Grid. Configuration files improve
readability, and you can also check them in source control.
When needed, you can combine a Toml file configuration with CLI arguments.
Command-line flags
To pass config options as command-line flags, identify the valid options for the component and follow
the template below.
Hub, setting a new session request timeout, a main port, and disabling
tracing
Node, with 4 max sessions, with debug(fine) log, 7777 as port, and only with
Firefox and Edge
Distributor, setting Session Map server url, Session Queue server url, and
disabling bus
https://www.selenium.dev/documentation/_print/ 150/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Matching Node A
Below is an example in Java that shows how to download a file named my_file.pdf .
https://www.selenium.dev/documentation/_print/ 151/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.io.Zip;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpMethod;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
// The download happens in a remote Node, which makes difficult to know when
// has been completely downloaded. For demonstration purposes, this example u
// 10 second sleep which should be enough time for a file to be downloaded.
// We strongly recommend to avoid hardcoded sleeps, and ideally, to modify yo
// application under test so it offers a way to know when the file has been c
// downloaded.
TimeUnit.SECONDS.sleep(10);
//The file contents would always be a zip file and has to be unzipped.
Zip.unzip(encodedContents, dirToCopyTo);
} finally {
driver.quit();
}
}
https://www.selenium.dev/documentation/_print/ 153/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
All the options shown in CLI options can be configured through a TOML file. This page shows
configuration examples for the different Grid components.
Note that this documentation could be outdated if an option was modified or added
but has not been documented yet. In case you bump into this situation, please check
the “Config help” section and feel free to send us a pull request updating this page.
Overview
Selenium Grid uses TOML format for config files. The config file consists of sections and each section
has options and its respective value(s).
Refer to the TOML documentation for detailed usage guidance. In case of parsing errors, validate the
config using TOML linter.
[section1]
option1="value"
[section2]
option2=["value1","value2"]
option3=true
Below are some examples of Grid components configured with a Toml file, the component can be
started in the following way:
Standalone
A Standalone server, running on port 4449, and a new session request timeout of 500 seconds.
[server]
port = 4449
[sessionqueue]
session-request-timeout = 500
[node]
drivers = ["chrome", "firefox"]
max-sessions = 3
https://www.selenium.dev/documentation/_print/ 154/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
[node]
detect-drivers = false
[[node.driver-configuration]]
max-sessions = 100
display-name = "Firefox Nightly"
stereotype = "{\"browserName\": \"firefox\", \"browserVersion\": \"93\", \"platfo
[[node.driver-configuration]]
display-name = "Chrome Beta"
stereotype = "{\"browserName\": \"chrome\", \"browserVersion\": \"94\", \"platfor
[[node.driver-configuration]]
display-name = "Chrome Dev"
stereotype = "{\"browserName\": \"chrome\", \"browserVersion\": \"95\", \"platfor
webdriver-executable = '/path/to/chromedriver/95/chromedriver'
[node]
detect-drivers = false
max-sessions = 2
[docker]
configs = [
"selenium/standalone-chrome:93.0", "{\"browserName\": \"chrome\", \"browserVe
"selenium/standalone-firefox:92.0", "{\"browserName\": \"firefox\", \"browserV
]
#Optionally define all device files that should be mapped to docker containers
#devices = [
# "/dev/kvm:/dev/kvm"
#]
url = "http://localhost:2375"
video-image = "selenium/video:latest"
It is useful to connect an external service that supports WebDriver to Selenium Grid. An example of such
service could be a cloud provider or an Appium server. In this way, Grid can enable more coverage to
platforms and versions not present locally.
https://www.selenium.dev/documentation/_print/ 155/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
[node]
detect-drivers = false
[relay]
# Default Appium/Cloud server endpoint
url = "http://localhost:4723/wd/hub"
status-endpoint = "/status"
# Stereotypes supported by the service. The initial number is "max-sessions", and
# that many test slots to that particular configuration
configs = [
"5", "{\"browserName\": \"chrome\", \"platformName\": \"android\", \"appium:pla
]
[router]
username = "admin"
password = "myStrongPassword"
Here is a Java example showing how to start a session using the configured user and password.
[node]
detect-drivers = false
[[node.driver-configuration]]
display-name = "firefox"
stereotype = '{"browserName": "firefox", "platformName": "macOS", "browserVersion
max-sessions = 5
https://www.selenium.dev/documentation/_print/ 156/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
[node]
downloads-path = "/usr/downloads"
https://www.selenium.dev/documentation/_print/ 157/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Event Bus
Used for sending messages which may be received asynchronously between the other components.
New Session Queue
Maintains a list of incoming sessions which have yet to be assigned to a Node by the Distributor.
Distributor
Responsible for maintaining a model of the available locations in the Grid where a session may run
(known as "slots") and taking any incoming new session requests and assigning them to a slot.
Node
Runs a WebDriver session. Each session is assigned to a slot, and each node has one or more slots.
Session Map
Maintains a mapping between the session ID and the address of the Node the session is running on.
Router
Acts as the front-end of the Grid. This is the only part of the Grid which may be exposed to the wider
Web (though we strongly caution against it). This routes incoming requests to either the New Session
Queue or the Node on which the session is running.
While discussing the Grid, there are some other useful concepts to keep in mind:
How do we pick which communication mechanism to use? After all, we could model the entire Grid in an
event-based way, and it would work out just fine.
The answer is that if the action being performed is synchronous (eg. most WebDriver calls), or if missing
the response would be problematic, the Grid uses a synchronous call. If, instead, we want to broadcast
information to anyone who’s interested, or if missing the response doesn’t matter, then we prefer to use
the event bus.
One interesting thing to note is that the async calls are more decoupled from their listeners than the
synchronous calls are.
https://www.selenium.dev/documentation/_print/ 158/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
1. The Event Bus and Session Map start first. These have no other dependencies, not even on each
other, and so are safe to start in parallel.
2. The Session Queue starts next.
3. It is now possible to start the Distributor. This will periodically connect to the Session Queue and
poll for jobs, though this polling might be initiated either by an event (that a New Session has
been added to the queue) or at regular intervals.
4. The Router(s) can be started. New Session requests will be directed to the Session Queue, and the
Distributor will attempt to find a slot to run the session on.
5. We are now able to start a Node. See below for details about how the Node is registered with the
Grid. Once registration is complete, the Grid is ready to serve traffic.
You can picture the dependencies between components this way, where a “✅” indicates that there is a
synchronous dependency between the components.
Event Bus X
Distributor ✅ X ✅ ✅
Node ✅ X
Router ✅ X ✅
Session Map X
Session Queue ✅ X
Node Registration
The process of registering a new Node to the Grid is lightweight.
1. When the Node starts, it should emit a “heart beat” event on a regular basis. This heartbeat
contains the node status.
2. The Distributor listens for the heart beat events. When it sees one, it attempts to GET the
/status endpoint of the Node. It is from this information that the Grid is set up.
The Distributor will use the same /status endpoint to check the Node on a regular basis, but the Node
should continue sending heart beat events even after started so that a Distributor without a persistent
store of the Grid state can be restarted and will (eventually) be up to date and correct.
externalUrl string The URI that the other components in the Grid should connect to.
lastSessionCreated integer The epoch timestamp of when the last session was created on this
Node. The Distributor will attempt to send new sessions to the
Node that has been idle longest if all other things are equal.
https://www.selenium.dev/documentation/_print/ 159/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
maxSessionCount integer Although a session count can be inferred by counting the number of
available slots, this integer value is used to determine the maximum
number of sessions that should be running simultaneously on the
Node before it is considered “full”.
osInfo object An object with arch , name , and version fields. This is used by
the Grid UI and the GraphQL queries.
version string The version of the Node (for Selenium, this will match the Selenium
version number)
lastStarted string When the slot last had a session started, in ISO-8601 format
stereotype object The minimal set of capabilities this slot will match against. A minimal
example is {"browserName": "firefox"}
capabilities object The actual capabilities provided by the session. Will match the return value
from the new session command
stereotype object The minimal set of capabilities this slot will match against. A minimal
example is {"browserName": "firefox"}
uri string The URI used by the Node to communicate with the session
https://www.selenium.dev/documentation/_print/ 160/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium Grid
Grid aids in scaling and distributing tests by executing tests on various browser and operating system
combinations.
Observability
Observability has three pillars: traces, metrics and logs. Since Selenium Grid 4 is designed to be fully
distributed, observability will make it easier to understand and debug the internals.
Distributed tracing
A single request or transaction spans multiple services and components. Tracing tracks the request
lifecycle as each service executes the request. It is useful in debugging in an error scenario. Some key
terms used in tracing context are:
Trace Tracing allows one to trace a request through multiple services, starting from its origin to its final
destination. This request’s journey helps in debugging, monitoring the end-to-end flow, and identifying
failures. A trace depicts the end-to-end request flow. Each trace has a unique id as its identifier.
Span Each trace is made up of timed operations called spans. A span has a start and end time and it
represents operations done by a service. The granularity of span depends on how it is instrumented.
Each span has a unique identifier. All spans within a trace have the same trace id.
Span Attributes Span attributes are key-value pairs which provide additional information about each
span.
Events Events are timed-stamped logs within a span. They provide additional context to the existing
spans. Events also contain key-value pairs as event attributes.
Event logging
Logging is essential to debug an application. Logging is often done in a human-readable format. But for
machines to search and analyze the logs, it has to have a well-defined format. Structured logging is a
common practice of recording logs consistently in a fixed format. It commonly contains fields like:
Timestamp
Logging level
https://www.selenium.dev/documentation/_print/ 161/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Logger class
Log message (This is further broken down into fields relevant to the operation where the log was
recorded)
Logs and events are closely related. Events encapsulate all the possible information available to do a
single unit of work. Logs are essentially subsets of an event. At the crux, both aid in debugging. Refer
following resources for detailed understanding:
1. https://www.honeycomb.io/blog/how-are-structured-logs-different-from-events/
2. https://charity.wtf/2019/02/05/logs-vs-structured-events/
Grid Observability
Selenium server is instrumented with tracing using OpenTelemetry. Every request to the server is traced
from start to end. Each trace consists of a series of spans as a request is executed within the server.
Most spans in the Selenium server consist of two events:
1. Normal event - records all information about a unit of work and marks successful completion of
the work.
2. Error event - records all information till the error occurs and then records the error information.
Marks an exception event.
1. Standalone
2. Hub and Node
3. Fully Distributed
4. Docker
Visualizing Traces
All spans, events and their respective attributes are part of a trace. Tracing works while running the
server in all of the above-mentioned modes.
By default, tracing is enabled in the Selenium server. Selenium server exports the traces via two
exporters:
1. Console - Logs all traces and their included spans at FINE level. By default, Selenium server prints
logs at INFO level and above. The log-level flag can be used to pass a logging level of choice while
running the Selenium Grid jar/s.
2. Jaeger UI - OpenTelemetry provides the APIs and SDKs to instrument traces in the code. Whereas
Jaeger is a tracing backend, that aids in collecting the tracing telemetry data and providing
querying, filtering and visualizing features for the data.
Detailed instructions of visualizing traces using Jaeger UI can be obtained by running the command :
A very good example and scripts to run the server and send traces to Jaeger
https://www.selenium.dev/documentation/_print/ 162/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Span Id spanId Each span within a trace is uniquely identified by a span id.
Span Kind spanKind Span kind is a property of span indicating the type of span. It helps
in understanding the nature of the unit of work done by the Span.
Event eventAttributes This forms the crux of the event logs, based on the operation
attributes executed, it has JSON formatted key-value pairs. This also includes
a handler class attribute, to show the logger class.
Sample log
FINE [LoggingOptions$1.lambda$export$1] - {
"traceId": "fc8aef1d44b3cc8bc09eb8e581c4a8eb",
"spanId": "b7d3b9865d3ddd45",
"spanKind": "INTERNAL",
"eventTime": 1597819675128886121,
"eventName": "Session request execution complete",
"attributes": {
"http.status_code": 200,
"http.handler_class": "org.openqa.selenium.grid.router.HandleSession",
"http.url": "\u002fsession\u002fdd35257f104bb43fdfb06242953f4c85",
"http.method": "DELETE",
"session.id": "dd35257f104bb43fdfb06242953f4c85"
}
}
In addition to the above fields, based on OpenTelemetry specification error logs consist of :
Exception exception.stacktrace Prints the call stack at the point of time when the
stacktrace exception was thrown. Helps in understanding the origin of
the exception.
https://www.selenium.dev/documentation/_print/ 163/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
WARN [LoggingOptions$1.lambda$export$1] - {
"traceId": "7efa5ea57e02f89cdf8de586fe09f564",
"spanId": "914df6bc9a1f6e2b",
"spanKind": "INTERNAL",
"eventTime": 1597820253450580272,
"eventName": "exception",
"attributes": {
"exception.type": "org.openqa.selenium.ScriptTimeoutException",
"exception.message": "Unable to execute request: java.sql.SQLSyntaxErrorException
"exception.stacktrace": "org.openqa.selenium.ScriptTimeoutException: java.sql.SQL
"http.handler_class": "org.openqa.selenium.grid.distributor.remote.RemoteDistribut
"http.url": "\u002fsession",
"http.method": "POST"
}
}
Note: Logs are pretty printed above for readability. Pretty printing for logs is turned off in Selenium
server.
The steps above should set you up for seeing traces and logs.
References
1. Understanding Tracing
2. OpenTelemetry Tracing API Specification
3. Selenium Wiki
4. Structured logs vs events
5. Jaeger framework
https://www.selenium.dev/documentation/_print/ 164/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Enums
Enums represent possible sets of values for a field.
For example, the Node object has a field called status. The state is an enum (specifically, of type
Status ) because it may be UP , DRAINING or UNAVAILABLE .
Scalars
Scalars are primitive values: Int , Float , String , Boolean , or ID .
When calling the GraphQL API, you must specify nested subfield until you return only scalars.
https://www.selenium.dev/documentation/_print/ 165/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
{
session(id: "<session-id>") : {
id,
capabilities,
startTime,
uri,
nodeId,
nodeUri,
sessionDurationMillis
slot : {
id,
stereotype,
lastStarted
}
}
grid: {
uri,
totalSlots,
nodeCount,
maxSession,
sessionCount,
version,
sessionQueueSize
}
sessionsInfo: {
sessionQueueRequests,
sessions: [
{
id,
capabilities,
startTime,
uri,
nodeId,
nodeUri,
sessionDurationMillis
slot : {
id,
stereotype,
lastStarted
}
}
]
}
nodesInfo: {
nodes : [
{
id,
uri,
status,
maxSession,
slotCount,
sessions: [
{
id,
capabilities,
startTime,
uri,
nodeId,
nodeUri,
sessionDurationMillis
slot : {
id,
stereotype,
https://www.selenium.dev/documentation/_print/ 166/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
lastStarted
}
}
],
sessionCount,
stereotypes,
version,
osInfo: {
arch,
name,
version
}
}
]
}
}
Querying GraphQL
The best way to query GraphQL is by using curl requests. The query is interpreted as JSON. Ensure
double quotes are properly escaped to avoid unexpected errors. GraphQL allows you to fetch only the
data that you want, nothing more nothing less.
Some of the example GraphQL queries are given below. You can build your own queries as you like.
https://www.selenium.dev/documentation/_print/ 167/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Query for getting all session details for all nodes in the Grid :
Query to get slot information for all sessions in each Node in the Grid
:
Query for getting the current requests in the New Session Queue:
https://www.selenium.dev/documentation/_print/ 168/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
In the Standalone mode, the Grid URL is the Standalone server address.
In the Hub-Node mode, the Grid URL is the Hub server address.
In the fully distributed mode, the Grid URL is the Router server address.
Distributor
Remove Node
To remove the Node from the Grid, use the cURL command enlisted below. It does not stop any ongoing
session running on that Node. The Node continues running as it is unless explicitly killed. The Distributor
is no longer aware of the Node and hence any matching new session request will not be forwarded to
that Node.
In the Standalone mode, the Distributor URL is the Standalone server address.
In the Hub-Node mode, the Distributor URL is the Hub server address.
In the fully distributed mode, the URL is the Distributor server address.
If no registration secret has been configured while setting up the Grid, then use
Drain Node
Node drain command is for graceful node shutdown. Draining a Node stops the Node after all the
ongoing sessions are complete. However, it does not accept any new session requests.
In the Standalone mode, the Distributor URL is the Standalone server address.
In the Hub-Node mode, the Distributor URL is the Hub server address.
https://www.selenium.dev/documentation/_print/ 169/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
In the fully distributed mode, the URL is the Distributor server address.
If no registration secret has been configured while setting up the Grid, then use
Node
The endpoints in this section are applicable for Hub-Node mode and fully distributed Grid mode where
the Node runs independently. The default Node URL is http://localhost:5555 in case of one Node. In case
of multiple Nodes, use Grid status to get all Node details and locate the Node address.
Status
The Node status is essentially a health-check for the Node. Distributor pings the node status are regular
intervals and updates the Grid Model accordingly. The status includes information regarding availability,
sessions, and slots.
Drain
Distributor passes the drain command to the appropriate node identified by the node-id. To drain the
Node directly, use the cuRL command enlisted below. Both endpoints are valid and produce the same
result. Drain finishes the ongoing sessions before stopping the Node.
If no registration secret has been configured while setting up the Grid, then use
https://www.selenium.dev/documentation/_print/ 170/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If no registration secret has been configured while setting up the Grid, then use
It will return true if the session belongs to the Node else it will return false.
Delete session
Deleting the session terminates the WebDriver session, quits the driver and removes it from the active
sessions map. Any request using the removed session-id or reusing the driver instance will throw an
error.
If no registration secret has been configured while setting up the Grid, then use
In the Standalone mode, the Queue URL is the Standalone server address.
In the Hub-Node mode, the Queue URL is the Hub server address.
In the fully distributed mode, the Queue URL is New Session Queue server address.
If no registration secret has been configured while setting up the Grid, then use
https://www.selenium.dev/documentation/_print/ 171/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
In the Standalone mode, the Queue URL is the Standalone server address.
In the Hub-Node mode, the Queue URL is the Hub server address.
In the fully distributed mode, the Queue URL is New Session Queue server address.
https://www.selenium.dev/documentation/_print/ 172/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
For e.g., we may like to do some additional setup before a session begins execution and some clean-up
after a session runs to completion.
Add a static method (this will be our factory method) to the newly created class whose signature
looks like this:
Within this factory method, include logic for creating your new Class.
To wire in this new customized logic into the hub, start the node and pass in the fully qualified
class name of the above class to the argument --node-implementation
Note: If you are using Maven as a build tool, please prefer using maven-shade-plugin instead of maven-
assembly-plugin because maven-assembly plugin seems to have issues with being able to merge
multiple Service Provider Interface files ( META-INF/services )
https://www.selenium.dev/documentation/_print/ 173/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Below is a sample that just prints some messages on to the console whenever there’s an activity of
interest (session created, session deleted, a webdriver command executed etc.,) on the Node.
These classes are good starting points to learn how to build a custom Node and also to learn the
internals of a Node.
https://www.selenium.dev/documentation/_print/ 174/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
Selenium Grid allows you to persist information related to currently running sessions into an external
data store. The external data store could be backed by your favourite database (or) Redis Cache system.
Setup
Coursier - As a dependency resolver, so that we can download maven artifacts on the fly and
make them available in our classpath
Docker - To manage our PostGreSQL/Redis docker containers.
We will spin off a PostGreSQL database as a docker container using a docker compose file.
Steps
You can skip this step if you already have a PostGreSQL database instance available at your disposal.
In the same directory as the init.sql , create a file named docker-compose.yml with its
contents as below:
https://www.selenium.dev/documentation/_print/ 175/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
version: '3.8'
services:
db:
image: postgres:9.6-bullseye
restart: always
environment:
- POSTGRES_USER=seluser
- POSTGRES_PASSWORD=seluser
- POSTGRES_DB=selenium_sessions
ports:
- "5432:5432"
volumes:
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
docker-compose up -d
Our database name is selenium_sessions with its username and password set to seluser
If you are working with an already running PostGreSQL DB instance, then you just need to create a
database named selenium_sessions and the table sessions_map using the above mentioned SQL
statement.
Create a Selenium Grid configuration file named sessions.toml with the below contents:
[sessions]
implementation = "org.openqa.selenium.grid.sessionmap.jdbc.JdbcBackedSessionMap"
jdbc-url = "jdbc:postgresql://localhost:5432/selenium_sessions"
jdbc-user = "seluser"
jdbc-password = "seluser"
Note: If you plan to use an existing PostGreSQL DB instance, then replace localhost:5432 with the
actual host and port number of your instance.
Below is a simple shell script (let’s call it distributed.sh ) that we will use to bring up our
distributed Grid.
https://www.selenium.dev/documentation/_print/ 176/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
SE_VERSION=<current_selenium_version>
JAR_NAME=selenium-server-${SE_VERSION}.jar
PUBLISH="--publish-events tcp://localhost:4442"
SUBSCRIBE="--subscribe-events tcp://localhost:4443"
SESSIONS="--sessions http://localhost:5556"
SESSIONS_QUEUE="--sessionqueue http://localhost:5559"
echo 'Starting Event Bus'
java -jar $JAR_NAME event-bus $PUBLISH $SUBSCRIBE --port 5557 &
echo 'Starting New Session Queue'
java -jar $JAR_NAME sessionqueue --port 5559 &
echo 'Starting Sessions Map'
java -jar $JAR_NAME \
--ext $(coursier fetch -p org.seleniumhq.selenium:selenium-session-map-jdbc:${SE_V
sessions $PUBLISH $SUBSCRIBE --port 5556 --config sessions.toml &
echo 'Starting Distributor'
java -jar $JAR_NAME distributor $PUBLISH $SUBSCRIBE $SESSIONS $SESSIONS_QUEUE --
echo 'Starting Router'
java -jar $JAR_NAME router $SESSIONS --distributor http://localhost:5553 $SESSION
echo 'Starting Node'
java -jar $JAR_NAME node $PUBLISH $SUBSCRIBE &
At this point the current directory should contain the following files:
docker-compose.yml
init.sql
sessions.toml
distributed.sh
You can now spawn the Grid by running distributed.sh shell script and quickly run a test. You
will notice that the Grid now stores session information into the PostGreSQL database.
export SE_VERSION=<current_selenium_version>
java -jar selenium-server-${SE_VERSION}.jar \
--ext $(coursier fetch -p org.seleniumhq.selenium:selenium-session-map-jdbc:${SE_V
sessions --publish-events tcp://localhost:4442 \
--subscribe-events tcp://localhost:4443 \
--port 5556 --config sessions.toml
The variable names from the above script have been replaced with their actual values for clarity.
Remember to substitute localhost with the actual hostname of the machine where your
Event-Bus is running.
The arguments being passed to coursier are basically the GAV (Group Artifact Version) Maven
co-ordinates of:
selenium-session-map-jdbc which is needed to help us store sessions information in
database
postgresql which is needed to help us talk PostGreSQL database.
sessions.toml is the configuration file that we created earlier.
https://www.selenium.dev/documentation/_print/ 177/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Steps
You can skip this step if you already have a Redis Cache instance available at your disposal.
version: '3.8'
services:
redis:
image: redis:bullseye
restart: always
ports:
- "6379:6379"
docker-compose up -d
Create a Selenium Grid configuration file named sessions.toml with the below contents:
[sessions]
scheme = "redis"
implementation = "org.openqa.selenium.grid.sessionmap.redis.RedisBackedSessionMap
hostname = "localhost"
port = 6379
Note: If you plan to use an existing Redis Cache instance, then replace localhost and 6379 with the
actual host and port number of your instance.
Below is a simple shell script (let’s call it distributed.sh ) that we will use to bring up our
distributed grid.
SE_VERSION=<current_selenium_version>
JAR_NAME=selenium-server-${SE_VERSION}.jar
PUBLISH="--publish-events tcp://localhost:4442"
SUBSCRIBE="--subscribe-events tcp://localhost:4443"
SESSIONS="--sessions http://localhost:5556"
SESSIONS_QUEUE="--sessionqueue http://localhost:5559"
echo 'Starting Event Bus'
java -jar $JAR_NAME event-bus $PUBLISH $SUBSCRIBE --port 5557 &
echo 'Starting New Session Queue'
java -jar $JAR_NAME sessionqueue --port 5559 &
echo 'Starting Session Map'
java -jar $JAR_NAME \
--ext $(coursier fetch -p org.seleniumhq.selenium:selenium-session-map-redis:${SE_
sessions $PUBLISH $SUBSCRIBE --port 5556 --config sessions.toml &
echo 'Starting Distributor'
java -jar $JAR_NAME distributor $PUBLISH $SUBSCRIBE $SESSIONS $SESSIONS_QUEUE --
echo 'Starting Router'
java -jar $JAR_NAME router $SESSIONS --distributor http://localhost:5553 $SESSION
echo 'Starting Node'
java -jar $JAR_NAME node $PUBLISH $SUBSCRIBE &
https://www.selenium.dev/documentation/_print/ 178/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
At this point the current directory should contain the following files:
docker-compose.yml
sessions.toml
distributed.sh
You can now spawn the Grid by running distributed.sh shell script and quickly run a test. You
will notice that the Grid now stores session information into the Redis instance. You can perhaps
make use of a Redis GUI such as TablePlus to see them (Make sure that you have setup a debug
point in your test, because the values will get deleted as soon as the test runs to completion).
export SE_VERSION=<current_selenium_version>
java -jar selenium-server-${SE_VERSION}.jar \
--ext $(coursier fetch -p org.seleniumhq.selenium:selenium-session-map-redis:${SE_
sessions --publish-events tcp://localhost:4442 \
--subscribe-events tcp://localhost:4443 \
--port 5556 --config sessions.toml
The variable names from the above script have been replaced with their actual values for clarity.
Remember to substitute localhost with the actual hostname of the machine where your
Event-Bus is running.
The arguments being passed to coursier are basically the GAV (Group Artifact Version) Maven
co-ordinates of:
selenium-session-map-redis which is needed to help us store sessions information in Redis
Cache.
sessions.toml is the configuration file that we created earlier.
https://www.selenium.dev/documentation/_print/ 179/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
4 - IE Driver Server
The Internet Explorer Driver is a standalone server that implements the WebDriver
specification.
The driver supports running 32-bit and 64-bit versions of the browser. The choice of how to determine
which “bit-ness” to use in launching the browser depends on which version of the IEDriverServer.exe is
launched. If the 32-bit version of IEDriverServer.exe is launched, the 32-bit version of IE will be
launched. Similarly, if the 64-bit version of IEDriverServer.exe is launched, the 64-bit version of IE will be
launched.
Installing
You do not need to run an installer before using the InternetExplorerDriver , though some
configuration is required. The standalone server executable must be downloaded from the Downloads
page and placed in your PATH.
Pros
Runs in a real browser and supports JavaScript
Cons
Obviously the InternetExplorerDriver will only work on Windows!
Comparatively slow (though still pretty snappy :)
Command-Line Switches
As a standalone executable, the behavior of the IE driver can be modified through various command-line
arguments. To set the value of these command-line arguments, you should consult the documentation
for the language binding you are using. The command line switches supported are described in the table
below. All - <switch> , – <switch> and / <switch> are supported.
Switch Meaning
–port= <portNumber> Specifies the port on which the HTTP server of the IE driver will
listen for commands from language bindings. Defaults to 5555.
–host= Specifies the IP address of the host adapter on which the HTTP
<hostAdapterIPAddress> server of the IE driver will listen for commands from language
bindings. Defaults to 127.0.0.1.
–log-level= <logLevel> Specifies the level at which logging messages are output. Valid
values are FATAL, ERROR, WARN, INFO, DEBUG, and TRACE.
Defaults to FATAL.
–log-file= <logFile> Specifies the full path and file name of the log file. Defaults to
stdout.
https://www.selenium.dev/documentation/_print/ 180/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Switch Meaning
–extract-path= <path> Specifies the full path to the directory used to extract supporting
files used by the server. Defaults to the TEMP directory if not
specified.
webdriver.ie.driver.logfile Specifies the full path and file name of the log file.
Required Configuration
The IEDriverServer executable must be downloaded and placed in your PATH.
On IE 7 or higher on Windows Vista, Windows 7, or Windows 10, you must set the Protected
Mode settings for each zone to be the same value. The value can be on or off, as long as it is the
same for every zone. To set the Protected Mode settings, choose “Internet Options…” from the
Tools menu, and click on the Security tab. For each zone, there will be a check box at the bottom of
the tab labeled “Enable Protected Mode”.
Additionally, “Enhanced Protected Mode” must be disabled for IE 10 and higher. This option is
found in the Advanced tab of the Internet Options dialog.
The browser zoom level must be set to 100% so that the native mouse events can be set to the
correct coordinates.
For Windows 10, you also need to set “Change the size of text, apps, and other items” to 100% in
display settings.
For IE 11 only, you will need to set a registry entry on the target computer so that the driver can
maintain a connection to the instance of Internet Explorer it creates. For 32-bit Windows
installations, the key you must examine in the registry editor is
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet
Explorer\Main\FeatureControl\FEATURE_BFCACHE . For 64-bit Windows installations, the key is
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet
Explorer\Main\FeatureControl\FEATURE_BFCACHE . Please note that the FEATURE_BFCACHE
subkey may or may not be present, and should be created if it is not present. Important: Inside
this key, create a DWORD value named iexplore.exe with the value of 0.
https://www.selenium.dev/documentation/_print/ 181/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Browser Focus
The challenge is that IE itself appears to not fully respect the Windows messages we send the IE
browser window ( WM\_MOUSEDOWN and WM\_MOUSEUP ) if the window doesn’t have the focus.
Specifically, the element being clicked on will receive a focus window around it, but the click will not be
processed by the element. Arguably, we shouldn’t be sending messages at all; rather, we should be
using the SendInput() API, but that API explicitly requires the window to have the focus. We have
two conflicting goals with the WebDriver project.
First, we strive to emulate the user as closely as possible. This means using native events rather than
simulating the events using JavaScript.
Second, we want to not require focus of the browser window being automated. This means that just
forcing the browser window to the foreground is suboptimal.
An additional consideration is the possibility of multiple IE instances running under multiple WebDriver
instances, which means any such “bring the window to the foreground” solution will have to be
wrapped in some sort of synchronizing construct (mutex?) within the IE driver’s C++ code. Even so, this
code will still be subject to race conditions, if, for example, the user brings another window to the
foreground between the driver bringing IE to the foreground and executing the native event.
The discussion around the requirements of the driver and how to prioritize these two conflicting goals is
ongoing. The current prevailing wisdom is to prioritize the former over the latter, and document that
your machine will be unavailable for other tasks when using the IE driver. However, that decision is far
from finalized, and the code to implement it is likely to be rather complicated.
Similarly, there are some scenarios when submitting an HTML form via WebElement’s submit()
method may have the same effect. This can happen if the driver calls the JavaScript submit() function
on the form, and there is an onSubmit event handler that calls the JavaScript alert() , confirm() , or
prompt() functions.
https://www.selenium.dev/documentation/_print/ 182/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
There are 2 solutions for problem with cookies (and another session items) shared between multiple
instances of InternetExplorer.
The first is to start your InternetExplorer in private mode. After that InternetExplorer will be started
with clean session data and will not save changed session data at quiting. To do so you need to pass 2
specific capabilities to driver: ie.forceCreateProcessApi with true value and
ie.browserCommandLineSwitches with -private value. Be note that it will work only for
InternetExplorer 8 and newer, and Windows Registry
HKLM_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Main path should contain key
TabProcGrowth with 0 value.
The second is to clean session during InternetExplorer starting. For this you need to pass specific
ie.ensureCleanSession capability with true value to driver. This clears the cache for all running
instances of InternetExplorer, including those started manually.
https://www.selenium.dev/documentation/_print/ 183/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Memory Management
The IE driver utilizes the Active Template Library (ATL) to take advantage of its implementation of smart
pointers to COM objects. This makes reference counting and cleanup of COM objects much easier.
In IE 7, this will usually manifest itself as a new top-level browser window; in IE 8, a new IExplore.exe
process will be created, but it will usually (not always!) seamlessly attach it to the existing IE top-level
frame window. Any browser automation framework that drives IE externally (as opposed to using a
WebBrowser control) will run into these problems.
In order to work around that problem, we dictate that to work with IE, all zones must have the same
Protected Mode setting. As long as it’s on for all zones, or off for all zones, we can prevent the
transistions to different Protected Mode zones that would invalidate our browser object. It also allows
users to continue to run with UAC turned on, and to run securely in the browser if they set Protected
Mode “on” for all zones.
In earlier releases of the IE driver, if the user’s Protected Mode settings were not correctly set, we would
launch IE, and the process would simply hang until the HTTP request timed out. This was suboptimal, as
it gave no indication what needed to be set. Erring on the side of caution, we do not modify the user’s
Protected Mode settings. Current versions, however check that the Protected Mode settings are
properly set, and will return an error response if they are not.
There are two ways that we could simulate keyboard and mouse input. The first way, which is used in
parts of webdriver, is to synthesize events on the DOM. This has a number of drawbacks, since each
browser (and version of a browser) has its own unique quirks; to model each of these is a demanding
task, and impossible to get completely right (for example, it’s hard to tell what window.selection
should be and this is a read-only property on some browsers) The alternative approach is to synthesize
keyboard and mouse input at the OS level, ideally without stealing focus from the user (who tends to be
doing other things on their computer as long-running webdriver tests run)
The code for doing this is in interactions.cpp The key thing to note here is that we use PostMessages to
push window events on to the message queue of the IE instance. Typing, in particular, is interesting: we
only send the “keydown” and “keyup” messages. The “keypress” event is created if necessary by IE’s
internal event processing. Because the key press event is not always generated (for example, not every
character is printable, and if the default event bubbling is cancelled, listeners don’t see the key press
event) we send a “probe” event in after the key down. Once we see that this has been processed, we
https://www.selenium.dev/documentation/_print/ 184/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
know that the key press event is on the stack of events to be processed, and that it is safe to send the
key up event. If this was not done, it is possible for events to fire in the wrong order, which is definitely
sub-optimal.
Once the basic setup is done, you can start working on the code pretty quickly. You can attach to the
process you execute your code from using Visual Studio (from the Debug menu, select Attach to
Process…).
https://www.selenium.dev/documentation/_print/ 185/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
5 - Selenium IDE
The Selenium IDE is a browser extension that records and plays back a user’s actions.
https://www.selenium.dev/documentation/_print/ 186/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
6 - Test Practices
Some guidelines and recommendations on testing from the Selenium project.
A note on “Best Practices”: We’ve intentionally avoided the phrase “Best Practices” in this
documentation. No one approach works for all situations. We prefer the idea of “Guidelines and
Recommendations.” We encourage you to read through these and thoughtfully decide what approaches
will work for you in your particular environment.
Functional testing is challenging to get right for many reasons. As if application state, complexity, and
dependencies do not make testing difficult enough, dealing with browsers (especially with cross-
browser incompatibilities) makes writing good tests a challenge.
Selenium provides tools to make functional user interaction easier, but does not help you write well-
architected test suites. In this chapter, we offer advice, guidelines, and recommendations on how to
approach functional web page automation.
This chapter records software design patterns popular amongst many of the users of Selenium that have
proven successful over the years.
https://www.selenium.dev/documentation/_print/ 187/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Overview
Over time, projects tend to accumulate large numbers of tests. As the total number of tests increases, it
becomes harder to make changes to the codebase — a single “simple” change may cause numerous tests
to fail, even though the application still works properly. Sometimes these problems are unavoidable, but
when they do occur you want to be up and running again as quickly as possible. The following design
patterns and strategies have been used before with WebDriver to help make tests easier to write and
maintain. They may help you too.
DomainDrivenDesign: Express your tests in the language of the end-user of the app. PageObjects: A
simple abstraction of the UI of your web app. LoadableComponent: Modeling PageObjects as
components. BotStyleTests: Using a command-based approach to automating tests, rather than the
object-based approach that PageObjects encourage
Loadable Component
What Is It?
The LoadableComponent is a base class that aims to make writing PageObjects less painful. It does this
by providing a standard way of ensuring that pages are loaded and providing hooks to make debugging
the failure of a page to load easier. You can use it to help reduce the amount of boilerplate code in your
tests, which in turn makes maintaining your tests less tiresome.
There is currently an implementation in Java that ships as part of Selenium 2, but the approach used is
simple enough to be implemented in any language.
Simple Usage
As an example of a UI that we’d like to model, take a look at the new issue page. From the point of view
of a test author, this offers the service of being able to file a new issue. A basic Page Object would look
like:
https://www.selenium.dev/documentation/_print/ 188/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
package com.example.webdriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
In order to turn this into a LoadableComponent, all we need to do is to set that as the base type:
This signature looks a little unusual, but all it means is that this class represents a LoadableComponent
that loads the EditIssue page.
@Override
protected void load() {
driver.get("https://github.com/SeleniumHQ/selenium/issues/new");
}
@Override
protected void isLoaded() throws Error {
String url = driver.getCurrentUrl();
assertTrue("Not on the issue entry page: " + url, url.endsWith("/new"));
}
The load method is used to navigate to the page, whilst the isLoaded method is used to determine
whether we are on the right page. Although the method looks like it should return a boolean, instead it
performs a series of assertions using JUnit’s Assert class. There can be as few or as many assertions as
you like. By using these assertions it’s possible to give users of the class clear information that can be
used to debug tests.
https://www.selenium.dev/documentation/_print/ 189/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
package com.example.webdriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
// By default the PageFactory will locate elements with the same name or id
// as the field. Since the summary element has a name attribute of "summary"
// we don't need any additional annotations.
private WebElement summary;
// But we'd prefer a different name in our code than "comment", so we use the
// FindBy annotation to tell the PageFactory how to locate the element.
@FindBy(name = "comment") private WebElement description;
@Override
protected void load() {
driver.get("https://github.com/SeleniumHQ/selenium/issues/new");
}
@Override
protected void isLoaded() throws Error {
String url = driver.getCurrentUrl();
assertTrue("Not on the issue entry page: " + url, url.endsWith("/new"));
}
That doesn’t seem to have bought us much, right? One thing it has done is encapsulate the information
about how to navigate to the page into the page itself, meaning that this information’s not scattered
through the code base. It also means that we can do this in our tests:
This call will cause the driver to navigate to the page if that’s necessary.
https://www.selenium.dev/documentation/_print/ 190/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Nested Components
LoadableComponents start to become more useful when they are used in conjunction with other
LoadableComponents. Using our example, we could view the “edit issue” page as a component within a
project’s website (after all, we access it via a tab on that site). You also need to be logged in to file an
issue. We could model this as a tree of nested components:
+ ProjectPage
+---+ SecuredPage
+---+ EditIssue
What would this look like in code? For a start, each logical component would have its own class. The
“load” method in each of them would “get” the parent. The end result, in addition to the EditIssue class
above is:
ProjectPage.java:
package com.example.webdriver;
import org.openqa.selenium.WebDriver;
@Override
protected void load() {
driver.get("http://" + projectName + ".googlecode.com/");
}
@Override
protected void isLoaded() throws Error {
String url = driver.getCurrentUrl();
assertTrue(url.contains(projectName));
}
}
and SecuredPage.java:
https://www.selenium.dev/documentation/_print/ 191/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
package com.example.webdriver;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
@Override
protected void load() {
parent.get();
// Sign in
driver.get("https://www.google.com/accounts/ServiceLogin?service=code");
driver.findElement(By.name("Email")).sendKeys(username);
WebElement passwordField = driver.findElement(By.name("Passwd"));
passwordField.sendKeys(password);
passwordField.submit();
@Override
protected void isLoaded() throws Error {
// If you're signed in, you have the option of picking a different login.
// Let's check for the presence of that.
try {
WebElement div = driver.findElement(By.id("multilogin-dropdown"));
} catch (NoSuchElementException e) {
fail("Cannot locate user name link");
}
}
}
@Override
protected void load() {
securedPage.get();
driver.get("https://github.com/SeleniumHQ/selenium/issues/new");
}
This shows that the components are all “nested” within each other. A call to get() in EditIssue will
cause all its dependencies to load too. The example usage:
https://www.selenium.dev/documentation/_print/ 192/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
@Before
public void prepareComponents() {
WebDriver driver = new FirefoxDriver();
@Test
public void demonstrateNestedLoadableComponents() {
editIssue.get();
editIssue.setSummary("Summary");
editIssue.enterDescription("This is an example");
}
}
If you’re using a library such as Guiceberry in your tests, the preamble of setting up the PageObjects can
be omitted leading to nice, clear, readable tests.
Bot Pattern
(previously located: https://github.com/SeleniumHQ/selenium/wiki/Bot-Style-Tests)
Although PageObjects are a useful way of reducing duplication in your tests, it’s not always a pattern
that teams feel comfortable following. An alternative approach is to follow a more “command-like” style
of testing.
A “bot” is an action-oriented abstraction over the raw Selenium APIs. This means that if you find that
commands aren’t doing the Right Thing for your app, it’s easy to change them. As an example:
/**
* Type something into an input field. WebDriver doesn't normally clear these
* before typing, so this method does that first. It also sends a return key
* to move the focus out of the element.
*/
public void type(By locator, String text) {
WebElement element = driver.findElement(locator);
element.clear();
element.sendKeys(text + "\n");
}
}
Once these abstractions have been built and duplication in your tests identified, it’s possible to layer
PageObjects on top of bots.
https://www.selenium.dev/documentation/_print/ 193/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Functional end-user tests such as Selenium tests are expensive to run, however. Furthermore, they
typically require substantial infrastructure to be in place to be run effectively. It is a good rule to always
ask yourself if what you want to test can be done using more lightweight test approaches such as unit
tests or with a lower-level approach.
Once you have made the determination that you are in the web browser testing business, and you have
your Selenium environment ready to begin writing tests, you will generally perform some combination
of three steps:
You will want to keep these steps as short as possible; one or two operations should be enough most of
the time. Browser automation has the reputation of being “flaky”, but in reality, that is because users
frequently demand too much of it. In later chapters, we will return to techniques you can use to mitigate
apparent intermittent problems in tests, in particular on how to overcome race conditions between the
browser and WebDriver.
By keeping your tests short and using the web browser only when you have absolutely no alternative,
you can have many tests with minimal flake.
A distinct advantage of Selenium tests is their inherent ability to test all components of the application,
from backend to frontend, from a user’s perspective. So in other words, whilst functional tests may be
expensive to run, they also encompass large business-critical portions at one time.
Testing requirements
As mentioned before, Selenium tests can be expensive to run. To what extent depends on the browser
you are running the tests against, but historically browsers’ behaviour has varied so much that it has
often been a stated goal to cross-test against multiple browsers.
Selenium allows you to run the same instructions against multiple browsers on multiple operating
systems, but the enumeration of all the possible browsers, their different versions, and the many
operating systems they run on will quickly become a non-trivial undertaking.
The general workflow (what we will call the “happy path”) is something like this:
Create an account
Configure the unicorn
Add it to the shopping cart
Check out and pay
Give feedback about the unicorn
It would be tempting to write one grand Selenium script to perform all these operations–many will try.
Resist the temptation! Doing so will result in a test that a) takes a long time, b) will be subject to some
common issues around page rendering timing issues, and c) is such that if it fails, it will not give you a
concise, “glanceable” method for diagnosing what went wrong.
The preferred strategy for testing this scenario would be to break it down to a series of independent,
speedy tests, each of which has one “reason” to exist.
Let us pretend you want to test the second step: Configuring your unicorn. It will perform the following
actions:
Create an account
https://www.selenium.dev/documentation/_print/ 194/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Configure a unicorn
Note that we are skipping the rest of these steps, we will test the rest of the workflow in other small,
discrete test cases after we are done with this one.
To start, you need to create an account. Here you have some choices to make:
Regardless of how you answer this question, the solution is to make it part of the “set up the data”
portion of the test. If Larry has exposed an API that enables you (or anyone) to create and update user
accounts, be sure to use that to answer this question. If possible, you want to launch the browser only
after you have a user “in hand”, whose credentials you can just log in with.
If each test for each workflow begins with the creation of a user account, many seconds will be added to
the execution of each test. Calling an API and talking to a database are quick, “headless” operations that
don’t require the expensive process of opening a browser, navigating to the right pages, clicking and
waiting for the forms to be submitted, etc.
Ideally, you can address this set-up phase in one line of code, which will execute before any browser is
launched:
As you can imagine, the UserFactory can be extended to provide methods such as
createAdminUser() , and createUserWithPayment() . The point is, these two lines of code do not
distract you from the ultimate purpose of this test: configuring a unicorn.
The intricacies of the Page Object model will be discussed in later chapters, but we will introduce the
concept here:
Your tests should be composed of actions, performed from the user’s point of view, within the context
of pages in the site. These pages are stored as objects, which will contain specific information about
how the web page is composed and how actions are performed– very little of which should concern you
as a tester.
What kind of unicorn do you want? You might want pink, but not necessarily. Purple has been quite
popular lately. Does she need sunglasses? Star tattoos? These choices, while difficult, are your primary
concern as a tester– you need to ensure that your order fulfillment center sends out the right unicorn to
the right person, and that starts with these choices.
Notice that nowhere in that paragraph do we talk about buttons, fields, drop-downs, radio buttons, or
web forms. Neither should your tests! You want to write your code like the user trying to solve their
problem. Here is one way of doing this (continuing from the previous example):
https://www.selenium.dev/documentation/_print/ 195/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Now that you have configured your unicorn, you need to move on to step 3: making sure it actually
worked.
Note that the tester still has not done anything but talk about unicorns in this code– no buttons, no
locators, no browser controls. This method of modelling the application allows you to keep these test-
level commands in place and unchanging, even if Larry decides next week that he no longer likes Ruby-
on-Rails and decides to re-implement the entire site in the latest Haskell bindings with a Fortran front-
end.
Your page objects will require some small maintenance in order to conform to the site redesign, but
these tests will remain the same. Taking this basic design, you will want to keep going through your
workflows with the fewest browser-facing steps possible. Your next workflow will involve adding a
unicorn to the shopping cart. You will probably want many iterations of this test in order to make sure
the cart is keeping its state properly: Is there more than one unicorn in the cart before you start? How
many can fit in the shopping cart? If you create more than one with the same name and/or features, will
it break? Will it only keep the existing one or will it add another?
Each time you move through the workflow, you want to try to avoid having to create an account, login
as the user, and configure the unicorn. Ideally, you will be able to create an account and pre-configure a
unicorn via the API or database. Then all you have to do is log in as the user, locate Sparkles, and add her
to the cart.
It is not always advantageous to automate test cases. There are times when manual testing may be
more appropriate. For instance, if the application’s user interface will change considerably in the near
future, then any automation might need to be rewritten anyway. Also, sometimes there simply is not
enough time to build test automation. For the short term, manual testing may be more effective. If an
application has a very tight deadline, there is currently no test automation available, and it’s imperative
that the testing gets done within that time frame, then manual testing is the best solution.
https://www.selenium.dev/documentation/_print/ 196/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
For web applications, the automation of this testing can be done directly with Selenium by simulating
user expected behaviour. This simulation could be done by record/playback or through the different
supported languages as explained in this documentation. Note: Acceptance testing is a subtype of
functional testing, which some people might also refer to.
Functional testing
This type of testing is done to determine if a feature or system functions properly without issues. It
checks the system at different levels to ensure that all scenarios are covered and that the system does
what it’s supposed to do. It’s a verification activity that answers the question:
This generally includes: the tests work without errors (404, exceptions…), in a usable way (correct
redirections),
in an accessible way and matching its specifications (see acceptance testing above).
For web applications, the automation of this testing can be done directly with Selenium by simulating
expected returns.
This simulation could be done by record/playback or through the different supported languages as
explained in this documentation.
Performance testing
As its name indicates, performance tests are done to measure how well an application is performing.
Load testing
Load testing is done to verify how well the application works under different defined loads (usually a
particular number of users connected at once).
Stress testing
Stress testing is done to verify how well the application works under stress (or above the maximum
supported load).
Generally, performance tests are done by executing some Selenium written tests simulating different
users hitting a particular function on the web app and retrieving some meaningful measurements.
This is generally done by other tools that retrieve the metrics. One such tool is JMeter.
For a web application, details to measure include throughput, latency, data loss, individual component
loading times…
Note 1: All browsers have a performance tab in their developers’ tools section (accessible by pressing
F12)
Note 2: is a subtype of non-functional testing as this is generally measured per system and not per
function/feature.
https://www.selenium.dev/documentation/_print/ 197/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Regression testing
This testing is generally done after a change, fix or feature addition.
To ensure that the change has not broken any of the existing functionality, some already executed tests
are executed again.
The set of re-executed tests can be full or partial and can include several different types, depending on
the application and development team.
Each cycle starts by creating a set of unit tests that the feature should eventually pass (they should fail
their first time executed).
After this, development takes place to make the tests pass. The tests are executed again, starting
another cycle and this process continues until all tests are passing.
This aims to speed up the development of an application based on the fact that defects are less costly
the earlier they are found.
Each cycle starts by creating some specifications (which should fail). Then create the failing unit tests
(which should also fail) and then do the development.
In order to do so, a specification language is used. It should be understandable by all parties and simple,
standard and explicit. Most tools use Gherkin as this language.
The goal is to be able to detect even more errors than TDD, by targeting potential acceptance errors too
and make communication between parties smoother.
A set of tools are currently available to write the specifications and match them with code functions,
such as Cucumber or SpecFlow.
A set of tools are built on top of Selenium to make this process even faster by directly transforming the
BDD specifications into executable code. Some of these are JBehave, Capybara and Robot
Framework.
https://www.selenium.dev/documentation/_print/ 198/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
A note on “Best Practices”: We’ve intentionally avoided the phrase “Best Practices” in this
documentation. No one approach works for all situations. We prefer the idea of “Guidelines and
Recommendations”. We encourage you to read through these and thoughtfully decide what approaches
will work for you in your particular environment.
Functional testing is difficult to get right for many reasons. As if application state, complexity, and
dependencies do not make testing difficult enough, dealing with browsers (especially with cross-
browser incompatibilities) makes writing good tests a challenge.
Selenium provides tools to make functional user interaction easier, but does not help you write well-
architected test suites. In this chapter we offer advice, guidelines, and recommendations on how to
approach functional web page automation.
This chapter records software design patterns popular amongst many of the users of Selenium that have
proven successful over the years.
https://www.selenium.dev/documentation/_print/ 199/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Overview
Within your web app’s UI, there are areas where your tests interact with. A Page Object only models
these as objects within the test code. This reduces the amount of duplicated code and means that if the
UI changes, the fix needs only to be applied in one place.
Page Object is a Design Pattern that has become popular in test automation for enhancing test
maintenance and reducing code duplication. A page object is an object-oriented class that serves as an
interface to a page of your AUT. The tests then use the methods of this page object class whenever they
need to interact with the UI of that page. The benefit is that if the UI changes for the page, the tests
themselves don’t need to change, only the code within the page object needs to change. Subsequently,
all changes to support that new UI are located in one place.
Advantages
There is a clean separation between the test code and page-specific code, such as locators (or their
use if you’re using a UI Map) and layout.
There is a single repository for the services or operations the page offers rather than having these
services scattered throughout the tests.
In both cases, this allows any modifications required due to UI changes to all be made in one place.
Helpful information on this technique can be found on numerous blogs as this ‘test design pattern’ is
becoming widely used. We encourage readers who wish to know more to search the internet for blogs
on this subject. Many have written on this design pattern and can provide helpful tips beyond the scope
of this user guide. To get you started, we’ll illustrate page objects with a simple example.
Examples
First, consider an example, typical of test automation, that does not use a page object:
/***
* Tests login feature
*/
public class Login {
There is no separation between the test method and the AUT’s locators (IDs in this example); both
are intertwined in a single method. If the AUT’s UI changes its identifiers, layout, or how a login is
input and processed, the test itself must change.
The ID-locators would be spread in multiple tests, in all tests that had to use this login page.
https://www.selenium.dev/documentation/_print/ 200/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Applying the page object techniques, this example could be rewritten like this in the following example
of a page object for a Sign-in page.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
/**
* Page Object encapsulates the Sign-in page.
*/
public class SignInPage {
protected WebDriver driver;
/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/
public HomePage loginValidUser(String userName, String password) {
driver.findElement(usernameBy).sendKeys(userName);
driver.findElement(passwordBy).sendKeys(password);
driver.findElement(signinBy).click();
return new HomePage(driver);
}
}
and page object for a Home page could look like this.
https://www.selenium.dev/documentation/_print/ 201/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
/**
* Page Object encapsulates the Home Page
*/
public class HomePage {
protected WebDriver driver;
// <h1>Hello userName</h1>
private By messageBy = By.tagName("h1");
/**
* Get message (h1 tag)
*
* @return String message text
*/
public String getMessageText() {
return driver.findElement(messageBy).getText();
}
So now, the login test would use these two page objects as follows.
/***
* Tests login feature
*/
public class TestLogin {
@Test
public void testLogin() {
SignInPage signInPage = new SignInPage(driver);
HomePage homePage = signInPage.loginValidUser("userName", "password");
assertThat(homePage.getMessageText(), is("Hello userName"));
}
There is a lot of flexibility in how the page objects may be designed, but there are a few basic rules for
getting the desired maintainability of your test code.
https://www.selenium.dev/documentation/_print/ 202/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
There is one, single, verification which can, and should, be within the page object and that is to verify
that the page, and possibly critical elements on the page, were loaded correctly. This verification should
be done while instantiating the page object. In the examples above, both the SignInPage and HomePage
constructors check that the expected page is available and ready for requests from the test.
Implementation Notes
PageObjects can be thought of as facing in two directions simultaneously. Facing toward the developer
of a test, they represent the services offered by a particular page. Facing away from the developer, they
should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a
page) It’s simplest to think of the methods on a Page Object as offering the “services” that a page offers
rather than exposing the details and mechanics of the page. As an example, think of the inbox of any
web-based email system. Amongst the services it offers are the ability to compose a new email, choose
to read a single email, and list the subject lines of the emails in the inbox. How these are implemented
shouldn’t matter to the test.
Because we’re encouraging the developer of a test to try and think about the services they’re interacting
with rather than the implementation, PageObjects should seldom expose the underlying WebDriver
instance. To facilitate this, methods on the PageObject should return other PageObjects. This means we
can effectively model the user’s journey through our application. It also means that should the way that
pages relate to one another change (like when the login page asks the user to change their password
the first time they log into a service when it previously didn’t do that), simply changing the appropriate
method’s signature will cause the tests to fail to compile. Put another way; we can tell which tests
would fail without needing to run them when we change the relationship between pages and reflect
this in the PageObjects.
One consequence of this approach is that it may be necessary to model (for example) both a successful
and unsuccessful login; or a click could have a different result depending on the app’s state. When this
happens, it is common to have multiple methods on the PageObject:
https://www.selenium.dev/documentation/_print/ 203/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The code presented above shows an important point: the tests, not the PageObjects, should be
responsible for making assertions about the state of a page. For example:
Of course, as with every guideline, there are exceptions, and one that is commonly seen with
PageObjects is to check that the WebDriver is on the correct page when we instantiate the PageObject.
This is done in the example below.
Finally, a PageObject need not represent an entire page. It may represent a section that appears
frequently within a site or page, such as site navigation. The essential principle is that there is only one
place in your test suite with knowledge of the structure of the HTML of a particular (part of a) page.
Summary
The public methods represent the services that the page offers
Try not to expose the internals of the page
Generally don’t make assertions
Methods return other PageObjects
Need not represent an entire page
Different results for the same action are modelled as different methods
https://www.selenium.dev/documentation/_print/ 204/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Example
public class LoginPage {
private final WebDriver driver;
// The login page contains several HTML elements that will be represented as WebEl
// The locators for these elements should only be defined once.
By usernameLocator = By.id("username");
By passwordLocator = By.id("passwd");
By loginButtonLocator = By.id("login");
// The login page allows the user to type their username into the username field
public LoginPage typeUsername(String username) {
// This is the only place that "knows" how to enter a username
driver.findElement(usernameLocator).sendKeys(username);
// Return the current page object as this action doesn't navigate to a page r
return this;
}
// The login page allows the user to type their password into the password field
public LoginPage typePassword(String password) {
// This is the only place that "knows" how to enter a password
driver.findElement(passwordLocator).sendKeys(password);
// Return the current page object as this action doesn't navigate to a page r
return this;
}
// The login page allows the user to submit the login form
public HomePage submitLogin() {
// This is the only place that submits the login form and expects the destinat
// A seperate method should be created for the instance of clicking login whil
driver.findElement(loginButtonLocator).submit();
// Return a new page object representing the destination. Should the login pag
// go somewhere else (for example, a legal disclaimer) then changing the metho
// for this method will mean that all tests that rely on this behaviour won't
return new HomePage(driver);
}
// The login page allows the user to submit the login form knowing that an invalid
public LoginPage submitLoginExpectingFailure() {
// This is the only place that submits the login form and expects the destinat
driver.findElement(loginButtonLocator).submit();
// Return a new page object representing the destination. Should the user eve
// expected to fail login, the script will fail when it attempts to instantiat
return new LoginPage(driver);
}
// Conceptually, the login page offers the user the service of being able to "log
// the application using a user name and password.
public HomePage loginAs(String username, String password) {
// The PageObject methods that enter username, password & submit login have al
typeUsername(username);
typePassword(password);
return submitLogin();
https://www.selenium.dev/documentation/_print/ 205/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
}
}
Support in WebDriver
There is a PageFactory in the support package that provides support for this pattern and helps to
remove some boiler-plate code from your Page Objects at the same time.
https://www.selenium.dev/documentation/_print/ 206/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Your users, in general, do not care how your site looks. They do not care about the decoration,
animations, or graphics. They want to use your system to push their new employees through the
process with minimal difficulty; they want to book travel to Alaska; they want to configure and buy
unicorns at a discount. Your job as tester is to come as close as you can to “capturing” this mind-set.
With that in mind, we set about “modeling” the application you are working on, such that the test
scripts (the user’s only pre-release proxy) “speak” for, and represent the user.
The goal is to use ubiquitous language. Rather than referring to “load data into this table” or “click on
the third column” it should be possible to use language such as “create a new account” or “order
displayed results by name”
With Selenium, DSL is usually represented by methods, written to make the API simple and readable –
they enable a report between the developers and the stakeholders (users, product owners, business
intelligence specialists, etc.).
Benefits
Readable: Business stakeholders can understand it.
Writable: Easy to write, avoids unnecessary duplication.
Extensible: Functionality can (reasonably) be added without breaking contracts and existing
functionality.
Maintainable: By leaving the implementation details out of test cases, you are well-insulated
against changes to the AUT*.
Further Reading
(previously located: https://github.com/SeleniumHQ/selenium/wiki/Domain-Driven-Design)
And to whet your appetite there’s a useful smaller book available online for download at
http://www.infoq.com/minibooks/domain-driven-design-quickly
Java
Here is an example of a reasonable DSL method in Java. For brevity’s sake, it assumes the driver
object is pre-defined and available to the method.
https://www.selenium.dev/documentation/_print/ 207/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
/**
* Takes a username and password, fills out the fields, and clicks "login".
* @return An instance of the AccountPage
*/
public AccountPage loginAsUser(String username, String password) {
WebElement loginField = driver.findElement(By.id("loginField"));
loginField.clear();
loginField.sendKeys(username);
// Fill out the password field. The locator we're using is "By.id", and we shou
// have it defined elsewhere in the class.
WebElement passwordField = driver.findElement(By.id("password"));
passwordField.clear();
passwordField.sendKeys(password);
// Create and return a new instance of the AccountPage (via the built-in Seleni
// PageFactory).
return PageFactory.newInstance(AccountPage.class);
}
This method completely abstracts the concepts of input fields, buttons, clicking, and even pages from
your test code. Using this approach, all a tester has to do is call this method. This gives you a
maintenance advantage: if the login fields ever changed, you would only ever have to change this
method - not your tests.
// Now that we're logged in, do some other stuff--since we used a DSL to supp
// our testers, it's as easy as choosing from available methods.
do.something();
do.somethingElse();
Assert.assertTrue("Something should have been done!", something.wasDone());
It bears repeating: one of your primary goals should be writing an API that allows your tests to address
the problem at hand, and NOT the problem of the UI. The UI is a secondary concern for your users –
they do not care about the UI, they just want to get their job done. Your test scripts should read like a
laundry list of things the user wants to DO, and the things they want to KNOW. The tests should not
concern themselves with HOW the UI requires you to go about it.
https://www.selenium.dev/documentation/_print/ 208/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 209/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 210/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 211/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Do not share test data. Imagine several tests that each query the database for valid orders before
picking one to perform an action on. Should two tests pick up the same order you are likely to get
unexpected behavior.
Clean up stale data in the application that might be picked up by another test e.g. invalid order
records.
Create a new WebDriver instance per test. This helps ensure test isolation and makes
parallelization simpler.
https://www.selenium.dev/documentation/_print/ 212/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
In general, if HTML IDs are available, unique, and consistently predictable, they are the preferred method
for locating an element on a page. They tend to work very quickly, and forego much processing that
comes with complicated DOM traversals.
If unique IDs are unavailable, a well-written CSS selector is the preferred method of locating an element.
XPath works as well as CSS selectors, but the syntax is complicated and frequently difficult to debug.
Though XPath selectors are very flexible, they are typically not performance tested by browser vendors
and tend to be quite slow.
Selection strategies based on linkText and partialLinkText have drawbacks in that they only work on link
elements. Additionally, they call down to querySelectorAll selectors internally in WebDriver.
Tag name can be a dangerous way to locate elements. There are frequently multiple elements of the
same tag present on the page. This is mostly useful when calling the findElements(By) method which
returns a collection of elements.
The recommendation is to keep your locators as compact and readable as possible. Asking WebDriver to
traverse the DOM structure is an expensive operation, and the more you can narrow the scope of your
search, the better.
https://www.selenium.dev/documentation/_print/ 213/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Let us say there is a content management system with which you can create some custom content
which then appears on your website as a module after publishing, and it may take some time to sync
between the CMS and the application.
A wrong way of testing your module is that the content is created and published in one test, and then
checking the module in another test. This is not feasible as the content may not be available immediately
for the other test after publishing.
Instead, you can create a stub content which can be turned on and off within the affected test, and use
that for validating the module. However, for content creation, you can still have a separate test.
https://www.selenium.dev/documentation/_print/ 214/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
driver.get( "http://www.google.com/webhp?hl=en&tab=ww" );
GoogleSearchPage gsp = new GoogleSearchPage();
gsp.withFluent().setSearchString().clickSearchButton();
The Google page object class with this fluent behavior might look like this:
https://www.selenium.dev/documentation/_print/ 215/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
@Override
protected void isLoaded() throws Error {
Assert.assertTrue("Google search page is not yet loaded.", isSearchFieldVisib
}
@Override
protected void load() {
if ( isSFieldPresent ) {
Wait<WebDriver> wait = new WebDriverWait( driver, Duration.ofSeconds(3) );
wait.until( visibilityOfElementLocated( By.id("gbqfq") ) ).click();
}
}
}
https://www.selenium.dev/documentation/_print/ 216/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 217/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
6.5.1 - Captchas
CAPTCHA, short for Completely Automated Public Turing test to tell Computers and Humans Apart, is
explicitly designed to prevent automation, so do not try! There are two primary strategies to get around
CAPTCHA checks:
https://www.selenium.dev/documentation/_print/ 218/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The HtmlUnit driver can download attachments by accessing them as input streams by implementing
the AttachmentHandler interface. The AttachmentHandler can then be added to the HtmlUnit
WebClient.
https://www.selenium.dev/documentation/_print/ 219/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium WebDriver is a completely different approach to browser automation, preferring to act more
like a user. This is represented in the way you write tests with WebDriver. In automated functional
testing, checking the status code is not a particularly important detail of a test’s failure; the steps that
preceded it are more important.
The browser will always represent the HTTP status code, imagine for example a 404 or a 500 error
page. A simple way to “fail fast” when you encounter one of these error pages is to check the page title
or content of a reliable point (e.g. the <h1> tag) after every page load. If you are using the page object
model, you can include this check in your class constructor or similar point where the page load is
expected. Occasionally, the HTTP code may even be represented in the browser’s error page and you
could use WebDriver to read this and improve your debugging output.
Checking the webpage itself is in line with WebDriver’s ideal practice of representing and asserting
upon the user’s view of the website.
If you insist, an advanced solution to capturing HTTP status codes is to replicate the behaviour of
Selenium RC by using a proxy. WebDriver API provides the ability to set a proxy for the browser, and
there are a number of proxies that will programmatically allow you to manipulate the contents of
requests sent to and received from the web server. Using a proxy lets you decide how you want to
respond to redirection response codes. Additionally, not every browser makes the response codes
available to WebDriver, so opting to use a proxy allows you to have a solution that works for every
browser.
https://www.selenium.dev/documentation/_print/ 220/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The ideal practice is to use the APIs that email providers offer, or in the case of Facebook the developer
tools service which exposes an API for creating test accounts, friends and so forth. Although using an
API might seem like a bit of extra hard work, you will be paid back in speed, reliability, and stability. The
API is also unlikely to change, whereas webpages and HTML locators change often and require you to
update your test framework.
Logging in to third party sites using WebDriver at any point of your test increases the risk of your test
failing because it makes your test longer. A general rule of thumb is that longer tests are more fragile
and unreliable.
WebDriver implementations that are W3C conformant also annotate the navigator object with a
WebDriver property so that Denial of Service attacks can be mitigated.
https://www.selenium.dev/documentation/_print/ 221/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 222/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
It may seem ideal to performance test in the context of the user but a suite of WebDriver tests are
subjected to many points of external and internal fragility which are beyond your control; for example
browser startup speed, speed of HTTP servers, response of third party servers that host JavaScript or
CSS, and the instrumentation penalty of the WebDriver implementation itself. Variation at these points
will cause variation in your results. It is difficult to separate the difference between the performance of
your website and the performance of external resources, and it is also hard to tell what the performance
penalty is for using WebDriver in the browser, especially if you are injecting scripts.
The other potential attraction is “saving time” — carrying out functional and performance tests at the
same time. However, functional and performance tests have opposing objectives. To test functionality, a
tester may need to be patient and wait for loading, but this will cloud the performance testing results
and vice versa.
To improve the performance of your website, you will need to be able to analyse overall performance
independent of environment differences, identify poor code practices, breakdown of performance of
individual resources (i.e. CSS or JavaScript), in order to know what to improve. There are performance
testing tools available that can do this job already, that provide reporting and analysis, and can even
make improvement suggestions.
https://www.selenium.dev/documentation/_print/ 223/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Instead of using WebDriver for this, you could save a ton of time by executing a curl command, or using
a library such as BeautifulSoup since these methods do not rely on creating a browser and navigating to
a page. You are saving tonnes of time by not using WebDriver for this task.
https://www.selenium.dev/documentation/_print/ 224/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Disable 2FA for certain Users in the test environment, so that you can use those user credentials in
the automation.
Disable 2FA in your test environment.
Disable 2FA if you login from certain IPs. That way we can configure our test machine IPs to avoid
this.
https://www.selenium.dev/documentation/_print/ 225/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
7 - Legacy
Documentation related to the legacy components of Selenium. Meant to be kept
purely for historical reasons and not as a incentive to use deprecated components.
Introduction
Selenium RC was the main Selenium project for a long time, before the WebDriver/Selenium merge
brought up Selenium 2, a more powerful tool. It is worth to highlight that Selenium 1 is not supported
anymore.
RC Components
Selenium RC components are:
The Selenium Server which launches and kills browsers, interprets and runs the Selenese
commands passed from the test program, and acts as an HTTP proxy, intercepting and verifying
HTTP messages passed between the browser and the AUT.
Client libraries which provide the interface between each programming language and the Selenium
RC Server.
The diagram shows the client libraries communicate with the Server passing each Selenium command
for execution. Then the server passes the Selenium command to the browser using Selenium-Core
JavaScript commands. The browser, using its JavaScript interpreter, executes the Selenium command.
This runs the Selenese action or verification you specified in your test script.
https://www.selenium.dev/documentation/_print/ 226/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium Server
Selenium Server receives Selenium commands from your test program, interprets them, and reports
back to your program the results of running those tests.
The RC server bundles Selenium Core and automatically injects it into the browser. This occurs when
your test program opens the browser (using a client library API function). Selenium-Core is a JavaScript
program, actually a set of JavaScript functions which interprets and executes Selenese commands using
the browser’s built-in JavaScript interpreter.
The Server receives the Selenese commands from your test program using simple HTTP GET/POST
requests. This means you can use any programming language that can send HTTP requests to automate
Selenium tests on the browser.
Client Libraries
The client libraries provide the programming support that allows you to run Selenium commands from a
program of your own design. There is a different client library for each supported language. A Selenium
client library provides a programming interface (API), i.e., a set of functions, which run Selenium
commands from your own program. Within each interface, there is a programming function that
supports each Selenese command.
The client library takes a Selenese command and passes it to the Selenium Server for processing a
specific action or test against the application under test (AUT). The client library also receives the result
of that command and passes it back to your program. Your program can receive the result and store it
into a program variable and report it as a success or failure, or possibly take corrective action if it was an
unexpected error.
So to create a test program, you simply write a program that runs a set of Selenium commands using a
client library API. And, optionally, if you already have a Selenese test script created in the Selenium-IDE,
you can generate the Selenium RC code. The Selenium-IDE can translate (using its Export menu item) its
Selenium commands into a client-driver’s API function calls. See the Selenium-IDE chapter for specifics
on exporting RC code from Selenium-IDE.
Installation
Installation is rather a misnomer for Selenium. Selenium has a set of libraries available in the
programming language of your choice. You could download them from the downloads page.
Once you’ve chosen a language to work with, you simply need to:
This can be simplified by creating a batch or shell executable file (.bat on Windows and .sh on Linux)
containing the command above. Then make a shortcut to that executable on your desktop and simply
double-click the icon to start the server.
https://www.selenium.dev/documentation/_print/ 227/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
For the server to run you’ll need Java installed and the PATH environment variable correctly configured
to run it from the console. You can check that you have Java correctly installed by running the following
on a console.
java -version
If you get a version number (which needs to be 1.5 or later), you’re ready to start using Selenium RC.
For details on Java test project configuration, see the Appendix sections Configuring Selenium RC With
Eclipse and Configuring Selenium RC With Intellij.
For details on Python client driver configuration, see the appendix Python Client Driver Configuration.
For specific details on .NET client driver configuration with Visual Studio, see the appendix .NET client
driver configuration.
https://www.selenium.dev/documentation/_print/ 228/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
For details on Ruby client driver configuration, see the Selenium-Client documentation _
open /
type q selenium rc
clickAndWait btnG
Note: This example would work with the Google search page http://www.google.com
CSharp
https://www.selenium.dev/documentation/_print/ 229/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using Selenium;
namespace SeleniumTests
{
[TestFixture]
public class NewTest
{
private ISelenium selenium;
private StringBuilder verificationErrors;
[SetUp]
public void SetupTest()
{
selenium = new DefaultSelenium("localhost", 4444, "*firefox",
selenium.Start();
verificationErrors = new StringBuilder();
}
[TearDown]
public void TeardownTest()
{
try
{
selenium.Stop();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
Assert.AreEqual("", verificationErrors.ToString());
}
[Test]
public void TheNewTest()
{
selenium.Open("/");
selenium.Type("q", "selenium rc");
selenium.Click("btnG");
selenium.WaitForPageToLoad("30000");
Assert.AreEqual("selenium rc - Google Search", selenium.GetTi
}
}
}
Java
https://www.selenium.dev/documentation/_print/ 230/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
import com.thoughtworks.selenium.*;
import java.util.regex.Pattern;
Php
<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
function testMyTestCase()
{
$this->open("/");
$this->type("q", "selenium rc");
$this->click("btnG");
$this->waitForPageToLoad("30000");
$this->assertTrue($this->isTextPresent("Results * for selenium rc"));
}
}
?>
Python
https://www.selenium.dev/documentation/_print/ 231/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
class NewTest(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("localhost", 4444, "*firefox",
"http://www.google.com/")
self.selenium.start()
def test_new(self):
sel = self.selenium
sel.open("/")
sel.type("q", "selenium rc")
sel.click("btnG")
sel.wait_for_page_to_load("30000")
self.failUnless(sel.is_text_present("Results * for selenium rc"))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
Ruby
require "selenium/client"
require "test/unit"
def teardown
@selenium.stop unless $selenium
assert_equal [], @verification_errors
end
def test_new
@selenium.open "/"
@selenium.type "q", "selenium rc"
@selenium.click "btnG"
@selenium.wait_for_page_to_load "30000"
assert @selenium.is_text_present("Results * for selenium rc")
end
end
In the next section we’ll explain how to build a test program using the generated code.
https://www.selenium.dev/documentation/_print/ 232/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Generate your script into a programming language from Selenium-IDE, optionally modifying the
result.
Write a very simple main program that executes the generated code.
Optionally, you can adopt a test engine platform like JUnit or TestNG for Java, or NUnit for .NET if you
are using one of those languages.
Here, we show language-specific examples. The language-specific APIs tend to differ from one to
another, so you’ll find a separate explanation for each.
Java
C#
Python
Ruby
Perl, PHP
Java
For Java, people use either JUnit or TestNG as the test engine.
Some development environments like Eclipse have direct support for these via plug-ins. This makes it
even easier. Teaching JUnit or TestNG is beyond the scope of this document however materials may be
found online and there are publications available. If you are already a “java-shop” chances are your
developers will already have some experience with one of these test frameworks.
You will probably want to rename the test class from “NewTest” to something of your own choosing.
Also, you will need to change the browser-open parameters in the statement:
The Selenium-IDE generated code will look like this. This example has comments added manually for
additional clarity.
https://www.selenium.dev/documentation/_print/ 233/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
package com.example.tests;
// We specify the package of our tests
import com.thoughtworks.selenium.*;
// This is the driver's import. You'll use this for instantiating a
// browser and making it do what you need.
import java.util.regex.Pattern;
// Selenium-IDE add the Pattern module because it's sometimes used for
// regex validations. You can remove the module if it's not used in your
// script.
C#
The .NET Client Driver works with Microsoft.NET. It can be used with any .NET testing framework like
NUnit or the Visual Studio 2005 Team System.
Selenium-IDE assumes you will use NUnit as your testing framework. You can see this in the generated
code below. It includes the using statement for NUnit along with corresponding NUnit attributes
identifying the role for each member function of the test class.
You will probably have to rename the test class from “NewTest” to something of your own choosing.
Also, you will need to change the browser-open parameters in the statement:
https://www.selenium.dev/documentation/_print/ 234/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using Selenium;
namespace SeleniumTests
{
[TestFixture]
{
private ISelenium selenium;
[SetUp]
{
selenium = new DefaultSelenium("localhost", 4444, "*iehta",
"http://www.google.com/");
selenium.Start();
[TearDown]
catch (Exception)
{
// Ignore errors if unable to close the browser
}
Assert.AreEqual("", verificationErrors.ToString());
}
[Test]
You can allow NUnit to manage the execution of your tests. Or alternatively, you can write a simple
main() program that instantiates the test object and runs each of the three methods, SetupTest() ,
TheNewTest() , and TeardownTest() in turn.
Python
Pyunit is the test framework to use for Python.
https://www.selenium.dev/documentation/_print/ 236/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
class NewTest(unittest.TestCase):
# We create our unittest test case
def setUp(self):
self.verificationErrors = []
# This is an empty array where we will store any verification errors
# we find in our tests
def test_new(self):
# This is the test code. Here you should put the actions you need
# the browser to do during your test.
sel = self.selenium
# We assign the browser to the variable "sel" (just to save us from
# typing "self.selenium" each time we want to call the browser).
sel.open("/")
sel.type("q", "selenium rc")
sel.click("btnG")
sel.wait_for_page_to_load("30000")
self.failUnless(sel.is_text_present("Results * for selenium rc"))
# These are the real test steps
def tearDown(self):
self.selenium.stop()
# we close the browser (I'd recommend you to comment this line while
# you are creating and debugging your tests)
self.assertEqual([], self.verificationErrors)
# And make the test fail if we found that any verification errors
# were found
Ruby
Old (pre 2.0) versions of Selenium-IDE generate Ruby code that requires the old Selenium gem.
Therefore, it is advisable to update any Ruby scripts generated by the IDE as follows:
You probably also want to change the class name to something more informative than “Untitled,” and
change the test method’s name to something other than “test_untitled.”
Here is a simple example created by modifying the Ruby code generated by Selenium IDE, as described
above.
https://www.selenium.dev/documentation/_print/ 237/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
end
https://www.selenium.dev/documentation/_print/ 238/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
begin
rescue Test::Unit::AssertionFailedError
end
end
end
Perl, PHP
The members of the documentation team have not used Selenium RC with Perl or PHP. If you are using
Selenium RC with either of these two languages please contact the Documentation Team (see the
chapter on contributing). We would love to include some examples from you and your experiences, to
support Perl and PHP users.
Java
setUp("http://www.google.com/", "*firefox");
Perl
Php
https://www.selenium.dev/documentation/_print/ 239/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
$this->setBrowser("*firefox");
$this->setBrowserUrl("http://www.google.com/");
Python
Ruby
Each of these examples opens the browser and represents that browser by assigning a “browser
instance” to a program variable. This program variable is then used to call methods from the browser.
These methods execute the Selenium commands, i.e. like open or type or the verify commands.
host Specifies the IP address of the computer where the server is located. Usually, this is the same
machine as where the client is running, so in this case localhost is passed. In some clients this is an
optional parameter.
port Specifies the TCP/IP socket where the server is listening waiting for the client to establish a
connection. This also is optional in some client drivers.
browser The browser in which you want to run the tests. This is a required parameter.
url The base url of the application under test. This is required by all the client libs and is integral
information for starting up the browser-proxy-AUT communication.
Note that some of the client libraries require the browser to be started explicitly by calling its start()
method.
Running Commands
Once you have the browser initialized and assigned to a variable (generally named “selenium”) you can
make it run Selenese commands by calling the respective methods from the browser variable. For
example, to call the type method of the selenium object:
selenium.type("field-id","string to type")
In the background the browser will actually perform a type operation, essentially identical to a user
typing input into the browser, by
using the locator and the string you specified during the method call.
Reporting Results
Selenium RC does not have its own mechanism for reporting results. Rather, it allows you to build your
reporting customized to your needs using features of your chosen programming language. That’s great,
but what if you simply want something quick that’s already done for you? Often an existing library or
test framework can meet your needs faster than developing your own test reporting code.
https://www.selenium.dev/documentation/_print/ 240/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
We won’t teach the frameworks themselves here; that’s beyond the scope of this user guide. We will
simply introduce the framework features that relate to Selenium along with some techniques you can
apply. There are good books available on these test frameworks however along with information on the
internet.
If Selenium Test cases are developed using TestNG then no external task is required to generate
test reports. The TestNG framework generates an HTML report which list details of tests.
ReportNG is a HTML reporting plug-in for the TestNG framework. It is intended as a replacement
for the default TestNG HTML report. ReportNG provides a simple, colour-coded view of the test
results.
https://www.selenium.dev/documentation/_print/ 241/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
You will find as you transition from the simple tests of the existence of page elements to tests of
dynamic functionality involving multiple web-pages and varying data that you will require programming
logic for verifying expected results. Basically, the Selenium-IDE does not support iteration and standard
condition statements. You can do some conditions by embedding JavaScript in Selenese parameters,
however iteration is impossible, and most conditions will be much easier in a
programming language. In addition, you may need exception handling for error recovery. For these
reasons and others, we have written this section to illustrate the use of common programming
techniques to give you greater ‘verification power’ in your automated testing.
The examples in this section are written in C# and Java, although the code is simple and can be easily
adapted to the other supported languages. If you have some basic knowledge of an object-oriented
programming language you shouldn’t have difficulty understanding this section.
Iteration
Iteration is one of the most common things people need to do in their tests. For example, you may want
to to execute a search multiple times. Or, perhaps for verifying your test results you need to process a
“result set” returned from a database.
Using the same Google search example we used earlier, let’s check the Selenium search results. This test
could use the Selenese:
open /
type q selenium rc
clickAndWait btnG
clickAndWait btnG
clickAndWait btnG
The code has been repeated to run the same steps 3 times. But multiple copies of the same code is not
good program practice because it’s more work to maintain. By using a programming language, we can
iterate over the search results for a more flexible and maintainable solution.
In C#
https://www.selenium.dev/documentation/_print/ 242/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Condition Statements
To illustrate using conditions in tests we’ll start with an example. A common problem encountered while
running Selenium tests occurs when an expected element is not available on page. For example, when
running the following line:
This can cause your test to abort. For some tests that’s what you want. But often that is not desirable as
your test script has many other subsequent tests to perform.
A better approach is to first validate whether the element is really present and then take alternatives
when it it is not. Let’s look at this using Java.
The advantage of this approach is to continue with test execution even if some UI elements are not
available on page.
Consider an application having check boxes with no static identifiers. In this case one could evaluate
JavaScript from Selenium RC to get ids of all check boxes and then exercise them.
https://www.selenium.dev/documentation/_print/ 243/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
selenium.getEval("window.document.images.length;");
Remember to use window object in case of DOM expressions as by default selenium window is referred
to, not the test window.
Server Options
When the server is launched, command line options can be used to change the default server behaviour.
To see the list of options, run the server with the -h option.
You’ll see a list of all the options you can use with the server and a brief description of each. The
provided descriptions will not always be enough, so we’ve provided explanations for some of the more
important options.
Proxy Configuration
If your AUT is behind an HTTP proxy which requires authentication then you should configure
http.proxyHost, http.proxyPort, http.proxyUser and http.proxyPassword using the following command.
https://www.selenium.dev/documentation/_print/ 244/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Multi-Window Mode
If you are using Selenium 1.0 you can probably skip this section, since multiwindow mode is the default
behavior. However, prior to version 1.0, Selenium by default ran the application under test in a sub frame
as shown here.
Some applications didn’t run correctly in a sub frame, and needed to be loaded into the top frame of the
window. The multi-window mode option allowed the AUT to run in a separate window rather than in
the default frame where it could then have the top frame it required.
For older versions of Selenium you must specify multiwindow mode explicitly with the following option:
-multiwindow
https://www.selenium.dev/documentation/_print/ 245/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
As of Selenium RC 1.0, if you want to run your test within a single frame (i.e. using the standard for
earlier Selenium versions) you can state this to the Selenium Server using the option
-singlewindow
First, to create a separate Firefox profile, follow this procedure. Open the Windows Start menu, select
“Run”, then type and enter one of the following:
firefox.exe -profilemanager
firefox.exe -P
Create the new profile using the dialog. Then when you run Selenium Server, tell it to use this new
Firefox profile with the server command-line option -firefoxProfileTemplate and specify the path to the
profile using its filename and directory path.
Warning: Be sure to put your profile in a new folder separate from the default!!! The Firefox profile
manager tool will delete all files in a folder if you delete a profile, regardless of whether they are profile
files or not.
More information about Firefox profiles can be found in Mozilla’s Knowledge Base
This will automatically launch your HTML suite, run all the tests and save a nice HTML report with the
results.
Note: When using this option, the server will start the tests and wait for a specified number of seconds
for the test to complete; if the test doesn’t complete within that amount of time, the command will exit
with a non-zero exit code and no results file will be generated.
This command line is very long so be careful when you type it. Note this requires you to pass in an
HTML Selenese suite, not a single test. Also be aware the -htmlSuite option is incompatible with -
interactive You cannot run both at the same time.
https://www.selenium.dev/documentation/_print/ 246/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Server-Side Logs
When launching Selenium server the -log option can be used to record valuable debugging information
reported by the Selenium Server to a text file.
This log file is more verbose than the standard console logs (it includes DEBUG level logging messages).
The log file also includes the logger name, and the ID number of the thread that logged the message.
For example:
Browser-Side Logs
JavaScript on the browser side (Selenium Core) also logs important messages; in many cases, these can
be more useful to the end-user than the regular Selenium Server logs. To access browser-side logs, pass
the -browserSideLog argument to the Selenium Server.
-browserSideLog must be combined with the -log argument, to log browserSideLogs (as well as all
other DEBUG level logging messages) to a file.
Selenium RC Architecture
Note: This topic tries to explain the technical implementation behind Selenium RC. It’s not fundamental
for a Selenium user to know this, but could be useful for understanding some of the problems you might
find in the future.
https://www.selenium.dev/documentation/_print/ 247/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
To understand in detail how Selenium RC Server works and why it uses proxy injection and heightened
privilege modes you must first understand the same origin policy _.
To work within this policy, Selenium-Core (and its JavaScript commands that make all the magic happen)
must be placed in the same origin as the Application Under Test (same URL).
Historically, Selenium-Core was limited by this problem since it was implemented in JavaScript. Selenium
RC is not, however, restricted by the Same Origin Policy. Its use of the Selenium Server as a proxy avoids
this problem. It, essentially, tells the browser that the browser is working on a single “spoofed” website
that the Server provides.
Note: You can find additional information about this topic on Wikipedia pages about Same Origin Policy
and XSS.
Proxy Injection
The first method Selenium used to avoid the The Same Origin Policy was Proxy Injection. In Proxy
Injection Mode, the Selenium Server acts as a client-configured HTTP proxy1, that sits between the
browser and the Application Under Test2. It then masks the AUT under a fictional URL (embedding
Selenium-Core and the set of tests and delivering them as if they were coming from the same origin).
https://www.selenium.dev/documentation/_print/ 249/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
5. The browser receives the open request and asks the Web Server for the page. Once the browser
receives the web page, renders it in the frame/window reserved for it.
To ensure the HTTPS site is genuine, the browser will need a security certificate. Otherwise, when the
browser accesses the AUT using HTTPS, it will assume that application is not ’trusted’. When this occurs
the browser displays security popups, and these popups cannot be closed using Selenium RC.
When dealing with HTTPS in a Selenium RC test, you must use a run mode that supports this and
handles the security certificate for you. You specify the run mode when your test program initializes
Selenium.
In Selenium RC 1.0 beta 2 and later use *firefox or *iexplore for the run mode. In earlier versions,
including Selenium RC 1.0 beta 1, use *chrome or *iehta, for the run mode. Using these run modes, you
will not need to install any special security certificates; Selenium RC will handle it for you.
In version 1.0 the run modes *firefox or *iexplore are recommended. However, there are additional run
modes of *iexploreproxy and *firefoxproxy. These are provided for backwards compatibility only, and
should not be used unless required by legacy test programs. Their use will present limitations with
security certificate handling and with the running of multiple windows if your application opens
additional browser windows.
In earlier versions of Selenium RC, *chrome or *iehta were the run modes that supported HTTPS and the
handling of security popups. These were considered ‘experimental modes although they became quite
stable and many people used them. If you are using Selenium 1.0 you do not need, and should not use,
these older run modes.
To get around this, Selenium RC, (again when using a run mode that support this) will install its own
security certificate, temporarily, to your client machine in a place where the browser can access it. This
tricks the browser into thinking it’s accessing a site different from your AUT and effectively suppresses
the popups.
Another method used with earlier versions of Selenium was to install the Cybervillians security
certificate provided with your Selenium installation. Most users should no longer need to do this
however; if you are running Selenium RC in proxy injection mode, you may need to explicitly install this
security certificate.
https://www.selenium.dev/documentation/_print/ 250/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
For example, you can launch Firefox with a custom configuration like this:
Note that when launching the browser this way, you must manually configure the browser to use the
Selenium Server as a proxy. Normally this just means opening your browser preferences and specifying
“localhost:4444” as an HTTP proxy, but instructions for this can differ radically from browser to browser.
Consult your browser’s documentation for details.
Be aware that Mozilla browsers can vary in how they start and stop. One may need to set the
MOZ_NO_REMOTE environment variable to make Mozilla browsers behave a little more predictably.
Unix users should avoid launching the browser using a shell script; it’s generally better to use the binary
executable (e.g. firefox-bin) directly.
If you see a message like this, be sure you started the Selenium Server. If so, then there is a problem
with the connectivity between the Selenium Client Library and the Selenium Server.
When starting with Selenium RC, most people begin by running their test program (with a Selenium
Client Library) and the Selenium Server on the same machine. To do this use “localhost” as your
connection parameter. We recommend beginning this way since it reduces the influence of potential
networking problems which you’re getting started. Assuming your operating system has typical
networking and TCP/IP settings you should have little difficulty. In truth, many people choose to run the
tests this way.
If, however, you do want to run Selenium Server on a remote machine, the connectivity should be fine
assuming you have valid TCP/IP connectivity between the two machines.
If you have difficulty connecting, you can use common networking tools like ping, telnet,
ifconfig(Unix)/ipconfig (Windows), etc to ensure you have a valid network connection. If unfamilar with
these, your system administrator can assist you.
https://www.selenium.dev/documentation/_print/ 251/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Firefox (prior to Selenium 1.0) cannot start because the browser is already open and you did not
specify a separate profile. See the section on Firefox profiles under Server Options.
The run mode you’re using doesn’t match any browser on your machine. Check the parameters
you passed to Selenium when you program opens the browser.
You specified the path to the browser explicitly (using “*custom”–see above) but the path is
incorrect. Check to be sure the path is correct. Also check the user group to be sure there are no
known issues with your browser and the “*custom” parameters.
This can easily happen. When you use Selenium-IDE to export your script, it inserts a dummy URL. You
must manually change the URL to the correct one for your application to be tested.
Versioning Problems
Make sure your version of Selenium supports the version of your browser. For example, Selenium RC
0.92 does not support Firefox 3. At times you may be lucky (I was). But don’t forget to check which
browser versions are supported by the version of Selenium you are using. When in doubt, use the latest
release version of Selenium with the most widely used version of your browser.
https://www.selenium.dev/documentation/_print/ 252/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
To check double-check your java version, run this from the command line.
java -version
If you see a lower version number, you may need to update the JRE, or you may simply need to add it to
your PATH environment variable.
iexplore: If the browser is launched using *iexplore, you could be having a problem with Internet
Explorer’s proxy settings. Selenium Server attempts To configure the global proxy settings in the
Internet Options Control Panel. You must make sure that those are correctly configured when
Selenium Server launches the browser. Try looking at your Internet Options control panel. Click on
the “Connections” tab and click on “LAN Settings”.
If you need to use a proxy to access the application you want to test, you’ll need to start
Selenium Server with “-Dhttp.proxyHost”; see the Proxy Configuration _ for more details.
You may also try configuring your proxy manually and then launching the browser with
*custom, or with *iehta browser launcher.
custom: When using *custom you must configure the proxy correctly(manually), otherwise you’ll
get a 404 error. Double-check that you’ve configured your proxy settings correctly. To check
whether you’ve configured the proxy correctly is to attempt to intentionally configure the browser
incorrectly. Try configuring the browser to use the wrong proxy server hostname, or the wrong
port. If you had successfully configured the browser’s proxy settings incorrectly, then the browser
will be unable to connect to the Internet, which is one way to make sure that one is adjusting the
relevant settings.
For other browsers (*firefox, *opera) we automatically hard-code the proxy for you, and so there
are no known issues with this functionality. If you’re encountering 404 errors and have followed
this user guide carefully post your results to user group for some help from the user community.
This error can also occur when JavaScript attempts to find UI objects which are not yet available (before
the page has completely loaded), or are no longer available (after the page has started to be unloaded).
This is most typically encountered with AJAX pages which are working with sections of a page or
subframes that load and/or reload independently of the larger page.
https://www.selenium.dev/documentation/_print/ 253/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
This error can be intermittent. Often it is impossible to reproduce the problem with a debugger because
the trouble stems from race conditions which are not reproducible when the debugger’s overhead is
added to the system. Permission issues are covered in some detail in the tutorial. Read the section about
the The Same Origin Policy , Proxy Injection carefully.
HTTP basic authentication dialogs: These dialogs prompt for a username/password to login to the
site. To login to a site that requires HTTP basic authentication, use a username and password in
the URL, as described in RFC 1738 _, like this:
open(“http://myusername:[email protected]/blah/blah/blah").
SSL certificate warnings: Selenium RC automatically attempts to spoof SSL certificates when it is
enabled as a proxy; see more on this in the section on HTTPS. If your browser is configured
correctly, you should never see SSL certificate warnings, but you may need to configure your
browser to trust our dangerous “CyberVillains” SSL certificate authority. Again, refer to the HTTPS
section for how to do this.
modal JavaScript alert/confirmation/prompt dialogs: Selenium tries to conceal those dialogs from
you (by replacing window.alert, window.confirm and window.prompt) so they won’t stop the
execution of your page. If you’re seeing an alert pop-up, it’s probably because it fired during the
page load process, which is usually too early for us to protect the page. Selenese contains
commands for asserting or verifying alert and confirmation popups. See the sections on these
topics in Chapter 4.
cmd=getNewBrowserSession&1=*firefox /usr/local/firefox/firefox-bin&2=http://www
No. Selenium relies on interceptors to determine window names as they are being loaded. These
interceptors work best in catching new windows if the windows are loaded AFTER the onload()
function. Selenium may not recognize windows loaded before the onload function.
Firefox on Linux
On Unix/Linux, versions of Selenium before 1.0 needed to invoke “firefox-bin” directly, so if you are using
a previous version, make sure that the real executable is on the path.
https://www.selenium.dev/documentation/_print/ 254/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
/usr/lib/firefox-x.x.x/
Where the x.x.x is the version number you currently have. So, to add that path to the user’s path. you
will have to add the following to your .bashrc file:
export PATH="$PATH:/usr/lib/firefox-x.x.x/"
If necessary, you can specify the path to firefox-bin directly in your test, like this:
"*firefox /usr/lib/firefox-x.x.x/firefox-bin"
//td[@style="background-color:yellow"]
This would work perfectly in Firefox, Opera or Safari but not with IE. IE interprets the keys in @style as
uppercase. So, even if the source code is in lowercase, you should use:
//td[@style="BACKGROUND-COLOR:yellow"]
This is a problem if your test is intended to work on multiple browsers, but you can easily code your test
to detect the situation and try the alternative locator that only works in IE.
selenium.start("commandLineFlags=--disable-web-security");
1. The proxy is a third person in the middle that passes the ball between the two parts. It acts as a
“web server” that delivers the AUT to the browser. Being a proxy gives Selenium Server the
capability of “lying” about the AUT’s real URL. ↩︎
2. The browser is launched with a configuration profile that has set localhost:4444 as the HTTP
proxy, this is why any HTTP request that the browser does will pass through Selenium server and
the response will pass through it and not from the real server. ↩︎
https://www.selenium.dev/documentation/_print/ 255/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
7.2 - Selenium 2
Selenium 2 was a rewrite of Selenium 1 that was implemented with WebDriver code.
The method presented here describes a piecemeal migration to the WebDriver APIs without needing to
rework everything in one massive push. This means that you can allow more time for migrating your
existing tests, which may make it easier for you to decide where to spend your effort.
This guide is written using Java, because this has the best support for making the migration. As we
provide better tools for other languages, this guide shall be expanded to include those languages.
Smaller, compact API. WebDriver’s API is more Object Oriented than the original Selenium RC API.
This can make it easier to work with.
Better emulation of user interactions. Where possible, WebDriver makes use of native events in
order to interact with a web page. This more closely mimics the way that your users work with
your site and apps. In addition, WebDriver offers the advanced user interactions APIs which allow
you to model complex interactions with your site.
Support by browser vendors. Opera, Mozilla and Google are all active participants in WebDriver’s
development, and each have engineers working to improve the framework. Often, this means that
support for WebDriver is baked into the browser itself: your tests run as fast and as stably as
possible.
Before Starting
In order to make the process of migrating as painless as possible, make sure that all your tests run
properly with the latest Selenium release. This may sound obvious, but it’s best to have it said!
Getting Started
The first step when starting the migration is to change how you obtain your instance of Selenium.
When using Selenium RC, this is done like so:
https://www.selenium.dev/documentation/_print/ 256/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Next Steps
Once your tests execute without errors, the next stage is to migrate the actual test code to use the
WebDriver APIs. Depending on how well abstracted your code is, this might be a short process or a long
one. In either case, the approach is the same and can be summed up simply: modify code to use the new
API when you come to edit it.
If you need to extract the underlying WebDriver implementation from the Selenium instance, you can
simply cast it to WrapsDriver:
This allows you to continue passing the Selenium instance around as normal, but to unwrap the
WebDriver instance as required.
At some point, you’re codebase will mostly be using the newer APIs. At this point, you can flip the
relationship, using WebDriver throughout and instantiating a Selenium instance on demand:
Common Problems
Fortunately, you’re not the first person to go through this migration, so here are some common
problems that others have seen, and how to solve them.
This relies on the fact that “type” simply replaces the content of the identified element without also
firing all the events that would normally be fired if a user interacts with the page. The final direct
invocations of “key*” cause the JS handlers to fire as expected.
When using the WebDriverBackedSelenium, the result of filling in the form field would be “exciting
texttt”: not what you’d expect! The reason for this is that WebDriver more accurately emulates user
behavior, and so will have been firing events all along.
This same fact may sometimes cause a page load to fire earlier than it would do in a Selenium 1 test. You
can tell that this has happened if a “StaleElementException” is thrown by WebDriver.
WebDriver attempts to simulate the original Selenium behavior, but this doesn’t always work perfectly
for various reasons. The most common reason is that it’s hard to tell the difference between a page load
not having started yet, and a page load having completed between method calls. This sometimes means
that control is returned to your test before the page has finished (or even started!) loading.
The solution to this is to wait on something specific. Commonly, this might be for the element you want
to interact with next, or for some Javascript variable to be set to a specific value. An example would be:
This may look complex, but it’s almost all boiler-plate code. The only interesting bit is that the
“ExpectedCondition” will be evaluated repeatedly until the “apply” method returns something that is
neither “null” nor Boolean.FALSE.
Of course, adding all these “wait” calls may clutter up your code. If that’s the case, and your needs are
simple, consider using the implicit waits:
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
By doing this, every time an element is located, if the element is not present, the location is retried until
either it is present, or until 30 seconds have passed.
CSS Selectors in Selenium 1 were implemented using the Sizzle library. This implements a superset of the
CSS Selector spec, and it’s not always clear where you’ve crossed the line. If you’re using the
WebDriverBackedSelenium and use a Sizzle locator instead of a CSS Selector for finding elements, a
warning will be logged to the console. It’s worth taking the time to look for these, particularly if tests are
failing because of not being able to find elements.
There is No Browserbot
Selenium RC was based on Selenium Core, and therefore when you executed Javascript, you could access
bits of Selenium Core to make things easier. As WebDriver is not based on Selenium Core, this is no
longer possible. How can you tell if you’re using Selenium Core? Simple! Just look to see if your “getEval”
or similar calls are using “selenium” or “browserbot” in the evaluated Javascript.
https://www.selenium.dev/documentation/_print/ 258/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
You might be using the browserbot to obtain a handle to the current window or document of the test.
Fortunately, WebDriver always evaluates JS in the context of the current window, so you can use
“window” or “document” directly.
Alternatively, you might be using the browserbot to locate elements. In WebDriver, the idiom for doing
this is to first locate the element, and then pass that as an argument to the Javascript. Thus:
becomes:
Notice how the passed in “element” variable appears as the first item in the JS standard “arguments”
array.
becomes:
https://www.selenium.dev/documentation/_print/ 259/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The Java and .NET versions of Selenium 2 provided implementations of the original
Selenium API
// You may use any WebDriver implementation. Firefox is used here as an example
WebDriver driver = new FirefoxDriver();
// And get the underlying WebDriver implementation back. This will refer to the
// same WebDriver instance as the "driver" variable above.
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getUnderlyingWebDrive
Pros
Allows for WebDriver and Selenium to live side-by-side.
Provides a simple mechanism for a managed migration from the existing Selenium API to
WebDriver’s.
Does not require the standalone Selenium RC server to be run
Cons
Does not implement every method
But we’d love feedback!
Does also emulate Selenium Core
So more advanced Selenium usage (that is, using “browserbot” or other built-in Javascript
methods from Selenium Core) may need work
Some methods may be slower due to underlying implementation differences
Does not support Selenium’s “user extensions” (i.e., user-extensions.js)
Notes
After creating a WebDriverBackedSelenium instance with a given Driver, one does not have to call
start() - as the creation of the Driver already started the session. At the end of the test, stop()
should be called instead of the Driver’s quit() method.
This is more similar to WebDriver’s behaviour - as creating a Driver instance starts a session, yet it has
to be terminated explicitly with a call to quit() .
https://www.selenium.dev/documentation/_print/ 260/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Provided you keep a reference to the original WebDriver and Selenium objects you created, you can use
even the two APIs interchangeably. The magic is the “ *webdriver ” browser name passed to the
Selenium instance, and that you pass the WebDriver instance when calling start() .
In languages where DefaultSelenium doesn’t have start(driver) , you can connect the WebDriver and
Selenium objects together yourself, by supplying the WebDriver session ID to the Selenium object.
There are currently some major limitations with this approach, notably that findElements doesn’t
work as expected. Also, because we’re using Selenium Core for the heavy lifting of driving the browser,
you are limited by the Javascript sandbox.
https://www.selenium.dev/documentation/_print/ 261/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
About
Firefox driver is included in the selenium-server-stanalone.jar available in the downloads. The driver
comes in the form of an xpi (firefox extension) which is added to the firefox profile when you start a
new instance of FirefoxDriver.
Pros
Runs in a real browser and supports Javascript
Faster than the InternetExplorerDriver
Cons
Slower than the HtmlUnitDriver
webdriver.firefox.profile The name of the profile to use when starting firefox. This defaults to
webdriver creating an anonymous profile
Normally the Firefox binary is assumed to be in the default location for your particular operating system:
Mac /Applications/Firefox.app/Contents/MacOS/firefox-bin
https://www.selenium.dev/documentation/_print/ 262/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
FirefoxDriver Internals
(Previously located: https://github.com/SeleniumHQ/selenium/wiki/FirefoxDriver-Internals)
The FirefoxDriver is largely written in the form of a Firefox extension. Language bindings control the
driver by connecting over a socket and sending commands (described in the JsonWireProtocol page) in
UTF-8. The extension makes use of the XPCOM primitives offered by Firefox in order to do its work. The
important thing to notice is that the command names map directly on to methods exposed on the
“FirefoxDriver.prototype” in the javascript code.
Secondly, take a look at the Mozilla Developer Center, particularly the section to do with setting up an
extension development environment. You should now be ready to edit code. It’s best to create a test
around the area of code that you’re working on, and to run this using the SingleTestSuite . The
FirefoxDriver logs errors to Firefox’s error console (“Tools->Error Console”), so if a test fails, that’s a
great place to start looking.
To actually log information to the console, use the “ Utils.dumpn() ” method in your javascript code. If
you find that you’d like to examine an object in detail, use the “ Utils.dump() ” method, which will
report which interfaces an object implements, as well as outputting as much information as it can to the
console..
https://www.selenium.dev/documentation/_print/ 263/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
Grid allows you to :
Quick Start
This example will show you how to start the Selenium 2 Hub, and register both a WebDriver node
and a Selenium 1 RC legacy node. We’ll also show you how to call the grid from Java. The hub and
nodes are shown here running on the same machine, but of course you can copy the selenium-
server-standalone to multiple machines. Note: The selenium-server-standalone package includes the
Hub, WebDriver, and legacy RC needed to run the grid. Ant is not required anymore. You can
download the selenium-server-standalone- * .jar from http://selenium-
release.storage.googleapis.com/index.html This walk-through assumes you already have Java
installed.
The Hub is the central point that will receive all the test request and distribute them the the right nodes.
Open a command prompt and navigate to the directory where you copied the selenium-server-
standalone file. Type the following command:
The hub will automatically start-up using port 4444 by default. To change the default port, you can add
the optional parameter -port when you run the command. You can view the status of the hub by
opening a browser window and navigating to: http://localhost:4444/grid/console
Regardless on whether you want to run a grid with new WebDriver functionality, or a grid with
Selenium 1 RC functionality, or both at the same time, you use the same selenium-server-standalone jar
file to start the nodes.
Note: The port defaults to 5555 if not specified whenever the “-role” option is provided and is not hub.
For backwards compatibility “wd” and “rc” roles are still a valid subset of the “node” role. But those roles
limit the types of remote connections to their corresponding API, while “node” allows both RC and
WebDriver remote connections.
https://www.selenium.dev/documentation/_print/ 264/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
For WebDriver nodes, you will need to use the RemoteWebDriver and the DesiredCapabilities object
to define which browser, version and platform you wish to use. Create the target browser capabilities
you want to run the tests against:
A node matches if all the requested capabilities are met. To request specific capabilities on the grid,
specify them before passing it into the WebDriver object.
capability.setBrowserName();
capability.setPlatform();
capability.setVersion()
capability.setCapability(,);
-browser browserName=firefox,version=3.6,platform=LINUX
capability.setBrowserName(“firefox” );
capability.setPlatform(“LINUX”);
capability.setVersion(“3.6”);
capability.setBrowserName(“firefox” );
capability.setVersion(“3.6”);
The capabilities that are not specified will be ignored. If you specify capabilities that do not exist on your
grid (for example, your test specifies Firefox version 4.0, but have no Firefox 4 instance) then there will
be no match and the test will fail to run.
https://www.selenium.dev/documentation/_print/ 265/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
-browser browserName=firefox,version=3.6,maxInstances=5,platform=LINUX
If your remote machine has multiple versions of Firefox you’d like to use, you can map the location of
each binary to a particular version on the same machine:
-browser browserName=firefox,version=3.6,firefox_binary=/home/myhomedir/firefox36/fir
Tip: If you need to provide a space somewhere in your browser parameters, then surround the
parameters with quotation marks:
Optional parameters
-port 4444 (4444 is default)
-host <IP | hostname> specify the hostname or IP. usually not needed and determined
automatically. For exotic network configuration, network with VPN, specifying the host might be
necessary.
-timeout 30 (300 is default) The timeout in seconds before the hub automatically releases a
node that hasn’t received any requests for more than the specified number of seconds. After this
time, the node will be released for another test in the queue. This helps to clear client crashes
without manual intervention. To remove the timeout completely, specify -timeout 0 and the hub
will never release the node.
Note: This is NOT the WebDriver timeout for all ”wait for WebElement” type of commands.
-maxSession 5 (5 is default) The maximum number of browsers that can run in parallel on the
node. This is different from the maxInstance of supported browsers (Example: For a node that
supports Firefox 3.6, Firefox 4.0 and Internet Explorer 8, maxSession=1 will ensure that you never
have more than 1 browser running. With maxSession=2 you can have 2 Firefox tests at the same
time, or 1 Internet Explorer and 1 Firefox test).
-browser < params > If -browser is not set, a node will start with 5 firefox, 1 chrome, and 1
internet explorer instance (assuming it’s on a windows box). This parameter can be set multiple
times on the same line to define multiple types of browsers. Parameters allowed for -browser:
browserName={android, chrome, firefox, htmlunit, internet explorer, iphone, opera} version=
{browser version} firefox_binary={path to executable binary} chrome_binary={path to executable
binary} maxInstances={maximum number of browsers of this type} platform={WINDOWS, LINUX,
MAC}
-registerCycle N = how often in ms the node will try to register itself again. Allow to restart
the hub without having to restart the nodes.
Really large (>50 node) Hub installations may need to increase the jetty threads by setting -
DPOOL_MAX=512 (or larger) on the java command line.
To preserve run-time integrity of a grid with selenium-servers, there are two other timeout values that
can be set.
On the hub, setting the -timeout command line option to “30” seconds will ensure all resources are
reclaimed 30 seconds after a client crashes. On the hub you can also set -browserTimeout 60 to make
the maximum time a node is willing to hang inside the browser 60 seconds. This will ensure all resources
are reclaimed slightly after 60 seconds. All the nodes use these two values from the hub if they are set.
Locally set parameters on a single node has precedence, it is generally recommended not to set these
timeouts on the node.
A sample nodeconfig file for server version 3.x.x (>= beta4) can be seen at
https://github.com/SeleniumHQ/selenium/blob/selenium-
3.141.59/java/server/src/org/openqa/grid/common/defaults/DefaultNodeWebDriver.json
Note: the configuration { ... } object in version 2.x.x has been flattened in version 3.x.x (>= beta4)
Reason Cause/fix
TIMEOUT The session timed out because the client did not access it
within the timeout. If the client has been somehow
suspended, this may happen when it wakes up
BROWSER_TIMEOUT The node timed out the browser because it was hanging for
too long (parameter browserTimeout)
https://www.selenium.dev/documentation/_print/ 267/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Reason Cause/fix
FORWARDING_TO_NODE_FAILED The hub was unable to forward to the node. Out of memory
errors/node stability issues or network problems
CREATIONFAILED The node failed to create the browser. This can typically
happen when there are environmental/configuration problems
on the node. Try using the node directly to track problem.
PROXY_REREGISTRATION The session has been discarded because the node has re-
registered on the grid (in mid-test)
This section describes the PLATFORM option used in configuring Selenium Grid Nodes and
[DesiredCapabilities] object.
History of Platforms
When requesting a new WebDriver session from the Grid, user can specify the [DesiredCapabilities] of
the remote browser. Things such as the browser name, version, and platform are among the list of
options that can be specified by the test. Specifying desired.
The following code demonstrates the DesiredCapability of Internet Explorer, version 9, on Windows XP
platform:
The request for a new session with specified DesiredCapability is sent to the Grid Hub, which will look
through all of the registered nodes to see if any of them match the specification given by the test. If no
node matches the specification, a CapabilityNotPresentOnTheGridException will be returned.
It is a common misconception that the PLATFORM determines the ability to choose the Operating
System on which the new session will be created. In this situation, platform and operating system are
not the same, thus specifying the platform to “Windows 2003 Server” will not allow you to choose
between a Windows XP, Vista, and 2003 server. This misconception can be born from platforms such as
Mac OSX and Linux, where the name of the platform matches the name of the Operating System.
In case of Selenium Grid, platform refers to the underlying interactions between the Driver Atoms and
the web browser. Mac OSX and Linux based Operating Systems (Centos, Ubuntu, Debian, etc..) have a
relatively stable communication with the web browsers such as Firefox and Chrome. Thus the platform
names are simple to understand, as seen in the example bellow:
https://www.selenium.dev/documentation/_print/ 268/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The prior to release of Vista, Windows based Operating Systems only had one platform, shown here:
However, with the introduction of UAC in Windows Vista, there were major changes done to the
underlying interactions between WebDriver and Internet Explorer. To work around the UAC constrains a
new platform was added to nodes with Windows based Operating systems:
With the release of Windows 8, another major overhaul happened in how the WebDriver communicates
with Internet Explorer, thus a new platform was added for Windows 8 based nodes:
Similar story happened with introduction of Windows 8.1, in this example the platform is set to
Windows 8.1:
MAC****All OSX Operating Systems LINUX Centos Ubuntu UNIXSolarisBSD XP Windows Server
2003 Windows XP Windows NT VISTAWindows VistaWindows 2008 Server****Windows 7 WIN8
Windows 2012 Server Windows 8 WIN8_1****Windows 8.1
Families
Different platforms are grouped into “Families” of platform. For example, Win8 and XP platforms are a
part of the WINDOWS family. Similarly ANDROID and LINUX are part of the UNIX family.
More Information
For more information on the latest platforms, please view this file:
org.openqa.selenium.Platform.java
https://www.selenium.dev/documentation/_print/ 269/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
History of Platforms
When requesting a new WebDriver session from the Grid, user can specify the [DesiredCapabilities] of
the remote browser. Things such as the browser name, version, and platform are among the list of
options that can be specified by the test. Specifying desired.
The following code demonstrates the DesiredCapability of Internet Explorer, version 9, on Windows XP
platform:
The request for a new session with specified DesiredCapability is sent to the Grid Hub, which will look
through all of the registered nodes to see if any of them match the specification given by the test. If no
node matches the specification, a CapabilityNotPresentOnTheGridException will be returned.
It is a common misconception that the PLATFORM determines the ability to choose the Operating
System on which the new session will be created. In this situation, platform and operating system are
not the same, thus specifying the platform to “Windows 2003 Server” will not allow you to choose
between a Windows XP, Vista, and 2003 server. This misconception can be born from platforms such as
Mac OSX and Linux, where the name of the platform matches the name of the Operating System.
In case of Selenium Grid, platform refers to the underlying interactions between the Driver Atoms and
the web browser. Mac OSX and Linux based Operating Systems (Centos, Ubuntu, Debian, etc..) have a
relatively stable communication with the web browsers such as Firefox and Chrome. Thus the platform
names are simple to understand, as seen in the example bellow:
The prior to release of Vista, Windows based Operating Systems only had one platform, shown here:
However, with the introduction of UAC in Windows Vista, there were major changes done to the
underlying interactions between WebDriver and Internet Explorer. To work around the UAC constrains a
new platform was added to nodes with Windows based Operating systems:
With the release of Windows 8, another major overhaul happened in how the WebDriver communicates
with Internet Explorer, thus a new platform was added for Windows 8 based nodes:
https://www.selenium.dev/documentation/_print/ 270/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Similar story happened with introduction of Windows 8.1, in this example the platform is set to
Windows 8.1:
MAC****All OSX Operating Systems LINUX Centos Ubuntu UNIXSolarisBSD XP Windows Server
2003 Windows XP Windows NT VISTAWindows VistaWindows 2008 Server****Windows 7 WIN8
Windows 2012 Server Windows 8 WIN8_1****Windows 8.1
Families
Different platforms are grouped into “Families” of platform. For example, Win8 and XP platforms are a
part of the WINDOWS family. Similarly ANDROID and LINUX are part of the UNIX family.
More Information
For more information on the latest platforms, please view this file:
org.openqa.selenium.Platform.java
https://www.selenium.dev/documentation/_print/ 271/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The server will always run on the machine with the browser you want to test. The server can be used
either from the command line or through code configuration.
The selenium-server keeps in-memory logs for each ongoing session, which are cleared when
Selenium#stop() or WebDriver#quit is called. If you forget to terminate these sessions, your server
may leak memory. If you keep extremely long-running sessions, you will probably need to stop/quit
every now and then (or increase memory with -Xmx jvm option).
browserTimeout
Controls how long the browser is allowed to hang (value in seconds).
timeout
Controls how long the client is allowed to be gone before the session is reclaimed (value in
seconds).
Please note that the browserTimeout is intended as a backup timeout mechanism when the ordinary
timeout mechanism fails, which should be used mostly in grid/server environments to ensure that
crashed/lost processes do not stay around for too long, polluting the runtime environment.
https://www.selenium.dev/documentation/_print/ 272/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Create a new class called AppServer . Here, we are using Jetty, so you will need to download that
as well:
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSocketConnector;
import org.mortbay.jetty.webapp.WebAppContext;
import javax.servlet.Servlet;
import java.io.File;
import org.openqa.selenium.remote.server.DriverServlet;
context.addServlet(DriverServlet.class, "/wd/*");
server.start();
}
}
https://www.selenium.dev/documentation/_print/ 273/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
WebDriver instantiation
While an individual WebDriver instance cannot be shared among threads, it is easy to create multiple
WebDriver instances.
Ephemeral sockets
There is a general problem of TCP/IP v4, where the TCP/IP stack uses ephemeral ports when making a
connection between two sockets. The typical symptom of this is that connection failures start appearing
after a short time of running, often a minute or two. The message will vary somewhat but it always
appears after some time, and if you reduce the number of browsers it will eventually work fine.
Wikipedia on Ephemeral ports or a quick google of “ephemeral sockets ” will tell you what your current
OS delivers and how to set it.
Currently (2.13.0) it seems like a firefox running at full blast consumes something in the range of 2000
ephemeral ports per firefox; your mileage will vary here. This means you can run out of ephemeral port
on Windows XP with as litttle as 2 browsers, maybe even 1 if you for instance iterate extermly quickly .
Will it be fixed ?
The solution to the ephemeral socket problem is HTTP1.1 keep alive on the connections. Firefox does not
support keep-alive as of version 2.13.0.
The means you can use the java client to scale out to remote boxes running selenium server and never
have any problems on the central build server. You may need to solve socket problems on the remote
boxes though.
Microsoft Windows
If you are using the old versions of Windows (<=2003, inc XP) you should not be waiting for port usage
to get low enough to fit in this space. That may simply never happen, although some combinations
probably will. See http://support.microsoft.com/kb/196271 on how to adjust it.
If you for technical reasons cannot adjust the port range on your Windows machine you will not be able
to run more than 2-3 firefox browsers.
https://www.selenium.dev/documentation/_print/ 274/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If you’re using a suite-less test setup (like many JUnit4 users), you often start/stop the browsers in
@BeforeClass/@AfterClass methods. Another option is to start the browsers in @BeforeClass and use
something like JUnit/TestNG run listeners to shut down all the browsers at the end of the test run.
Maven surefire supports run listeners for both JUnit and TestNG.
(TODO: Strategies to disable the socket lock and manage the ports yourself)
Native events
Due to a shared file in the native events logic, the firefox driver should probably not be using native
events when running concurrently. (Watch this issue).
https://www.selenium.dev/documentation/_print/ 275/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
This page describes an essential component of the native events implementation on Linux - focus
maintaining. In order for native events to be processed in Firefox, it must always retain focus. In case the
user decides to switch to another window (a thing which could be understood), Firefox must not know
it lost focus.
Solution overview
Basic idea
The basic idea is to get between the XLib (X-Windows client library) layer and the application. X-
Windows notifies the application of events (user input, windows being destroyed, mouse movements)
by asynchronous events. The events that indicate loss of focus FocusOut are discarded. The idea is
based on Jordan Sissel’s implementation of a pre-loaded library that over-rides XNextEvent - see
http://www.semicomplete.com/blog/geekery/xsendevent-xdotool-and-ld_preload.html.
Extension
This simple implementation works well as long as there’s one browser window. When multiple windows
are involved, several challenges arise:
Even though new windows may be opened, native events must continue to flow to the active
window. However, most window managers will give focus to newly-opened windows.
Window Switching: When wishing to switch to another window, the focus has to be moved. This
requires cooperation between WebDriver’s Firefox extension and this component.
Closing windows: When a window is closed, focus must move to another window. By design,
WebDriver does not guarantee anything if the active window is closed - until a new window is
being switched to. In this situation, special care must be taken.
Involved technologies
To understand this solution, one should be familiar with X-Windows and its events. Knowledge of the
GDK event processing loop is also useful.
Implementation Details
All of this describes the code in firefox/src/cpp/linux-specific/x_ignore_nofocus.c .
https://www.selenium.dev/documentation/_print/ 276/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Identifying events
Under the basic idea, FocusOut events will be simply discarded. However, window switching
complicates matters.
Data structure
There’s a global data structure that remembers the following information:
Firefox starts up
FocusIn event arrives and the active window ID is 0. A new active window is set. Note that during the
creation of the main window, another sub-window is created and a FocusOut event is sent to the
active window. Fortunately, this FocusOut event indicates that the focus is going to move to a sub-
window (identified by NotifyInferior ) so it is allowed.
Important Links
Jordan Sissel’s original XSendEvent hack
XLib events and the XLib programming manual
The X programming manual / specification
https://www.selenium.dev/documentation/_print/ 277/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
This page details how WebDriver is able to accept untrusted SSL certificates, allowing users to test
trusted sites in a testing environment, where valid certificates usually do not exist. This feature is turned
on by default for all supported browsers (Currently Firefox).
Firefox
Outline of solution
Firefox has an interface for overriding invalid certificates, called nsICertOverrideService. Implement this
interface as a proxy to the original service - unless untrusted certificates are allowed. In that case, when
asked about a certificate (a call to hasMatchingOverride for an invalid certificate) - indicate it’s trusted.
Implementation details
Implementing the idea is mostly straightforward - badCertListener.js is a stand-alone module, that,
when loaded, registers a factory for returning an instance of the service. The interesting function is
hasMatchingOverride:
WdCertOverrideService.prototype.hasMatchingOverride = function(
aHostName, aPort, aCert, aOverrideBits, aIsTemporary)
The aOverrideBits and aIsTemporary are output arguments. This is where things get a bit tricky: There
are three possible override bits:
ERROR_UNTRUSTED: 1,
ERROR_MISMATCH: 2,
ERROR_TIME: 4
It’s impossible to just set them all, since Firefox expects a perfect match between the offences generated
by the certificate and the function’s return value:
(security/manager/ssl/src/SSLServerCertVerification.cpp:302):
if (overrideService)
{
PRBool haveOverride;
PRBool isTemporaryOverride; // we don't care
if (!remaining_display_errors) {
// all errors are covered by override rules, so let's accept the cert
return SECSuccess;
}
https://www.selenium.dev/documentation/_print/ 278/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
var flags = 0;
if(gSSLStatus.isUntrusted)
flags |= overrideService.ERROR_UNTRUSTED;
if(gSSLStatus.isDomainMismatch)
flags |= overrideService.ERROR_MISMATCH;
if(gSSLStatus.isNotValidAtThisTime)
flags |= overrideService.ERROR_TIME;
Calling nsIX509Cert.verifyForUsage
Comparing hostname against nsIX509Cert.commonName . If those are not equal, ERROR_MISMATCH
is set.
The second check indicates whether ERROR_MISMATCH should be set. The first check should indicate
whether ERROR_UNTRUSTED and ERROR_TIME should be set. Unfortunately, it does not work reliably
when the certificate expired and is from an untrusted issuer. When the certificate has expired, the
return code would be CERT_EXPIRED even if it is also untrusted. For this reason, the FirefoxDriver
assumes that certificates will be untrusted - it always sets the ERROR_UNTRUSTED bit - the other two
will be set only if the conditions for them are met.
This could pose a problem for someone testing a site with a valid certificate that does not match the
host name it’s served from (e.g. test environment serving production certificates). An additional feature
for FirefoxProfile was added: FirefoxProfile.setAssumeUntrustedCertificateIssuer . Calling
this function with false will turn the ERROR_UNTRUSTED bit off and allow a user to work in such
situation.
HTMLUnit
Not tested yet.
IE
Not implemented yet.
Chrome
Not implemented yet.
https://www.selenium.dev/documentation/_print/ 279/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
We provide mobile drivers for two major mobile platforms: Android and iOS (iPhone & iPad).
They can be run on real devices and in an Android emulator or in the iOS Simulator, as appropriate. They
are packaged as an app. The app needs to be installed on the emulator or device. The app embeds a
RemoteWebDriver server and a light-weight HTTP server which receive, and respond to, requests from
WebDriver Clients i.e. from your automated tests.
The connection between the server on the mobile platform and your tests uses an IP connection. The
connection may need to be configured. For Android you can connect establish an IP connection over
USB.
In some cases your existing WebDriver tests may run successfully e.g. where a common web site serves
mobile and desktop users and where the UI is relatively straight-forward. However in other cases you
may end up needing to create specific tests for the mobile site; particularly when the site provides
specific capabilities, user interfaces, etc. for mobile browsers.
Even when a common web site serves both desktop and mobile browsers, you may want to consider
writing specific tests that incorporate factors such as the screen-size of the mobile devices, and different
ways users are likely to interact with your web site or web app.
Getting Started
Android Setup
Headless WebKit WebDriver. Many mobile browsers are WebKit based. Headless WebKit provides a fast
light-weight solution.
These projects don’t appear to be active, however they may provide a starting point for future work on
these platforms.
https://www.selenium.dev/documentation/_print/ 280/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Q: What is WebDriver?
A: WebDriver is a tool for writing automated tests of websites. It aims to mimic the behaviour of a real
user, and as such interacts with the HTML of the application.
Q: How do I migrate from using the original Selenium APIs to the new
WebDriver APIs?
A: The process is described in the Selenium documentation at
http://seleniumhq.org/docs/appendix_migrating_from_rc_to_webdriver.html
We also realise that there will be times when this is a limitation. As a result, for those browsers that
support it, you can execute Javascript by casting the WebDriver instance to a JavascriptExecutor. In Java,
this looks like:
https://www.selenium.dev/documentation/_print/ 281/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Other language bindings will follow a similar approach. Take a look at the UsingJavascript page for more
information.
js.executeScript("document.title");
js.executeScript("return document.title");
As can be told by the name of the constant, this may introduce flakiness in your tests. If all sites are in
the same protection domain, you should be okay.
https://www.selenium.dev/documentation/_print/ 282/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
You can’t interact with the native OS file browser dialog directly, but we do some magic so that if you
call WebElement#sendKeys("/path/to/file") on a file upload element, it does the right thing. Make sure
you don’t WebElement#click() the file upload element, or the browser will probably hang.
Handy hint: You can’t interact with hidden elements without making them un-hidden. If your element is
hidden, it can probably be un-hidden with some code like:
((JavascriptExecutor)driver).executeScript("arguments[0].style.visibility = 'visible'
return client;
}
};
https://www.selenium.dev/documentation/_print/ 283/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Q: Is WebDriver thread-safe?
A: WebDriver is not thread-safe. Having said that, if you can serialise access to the underlying driver
instance, you can share a reference in more than one thread. This is not advisable. You /can/ on the other
hand instantiate one WebDriver instance for each thread.
driver.switchTo().frame("foo");
WebElement editable = driver.switchTo().activeElement();
editable.sendKeys("Your text here");
Sometimes this doesn’t work, and this is because the iframe doesn’t have any content. On Firefox you
can execute the following before “sendKeys”:
This is needed because the iframe has no content by default: there’s nothing to send keyboard input to.
This method call inserts an empty tag, which sets everything up nicely.
Remember to switch out of the frame once you’re done (as all further interactions will be with this
specific frame):
driver.switchTo().defaultContent();
To get the socket to bind both to IPv6 and IPv4 addresses of the host with the same calls. More
permanent solution is disabling this behaviour by editing /etc/sysctl.d/bindv6only.conf
https://www.selenium.dev/documentation/_print/ 284/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Explanation: WebDriver has a blocking API, generally. However, under some conditions it is possible for
a get call to return before the page has finished loading. The classic example is Javascript starting to run
after the page has loaded (triggered by onload). Browsers (e.g. Firefox) will notify WebDriver when the
basic HTML content has been loaded, which is when WebDriver returns. It’s difficult (if not impossible)
to know when Javascript has finished executing, since JS code may schedule functions to be called in the
future, depend on server response, etc. This is also true for clicking - when the platform supports native
events (Windows, Linux) clicking is done by sending a mouse click event with the element’s coordinates
at the OS level - WebDriver cannot track the exact sequence of operations this click creates. For this
reason, the blocking API is imperfect - WebDriver cannot wait for all conditions to be met before the
test proceeds because it does not know them. Usually, the important matter is whether the element
involved in the next interaction is present and ready.
Solution: Use the Wait class to wait for a specific element to appear. This class simply calls findElement
over and over, discarding the NoSuchElementException each time, until the element is found (or a
timeout has expired). Since this is the behaviour desired by default for many users, a mechanism for
implicitly-waiting for elements to appear has been implemented. This is accessible through the
WebDriver.manage().timeouts() call. (This was previously tracked on issue 26).
Triggering a specific event cannot be achieved directly using the API, but one can use the Javascript
execution abilities to call methods on an element.
However, it is possible to use Javascript execution abilities to call getText directly from the element:
https://www.selenium.dev/documentation/_print/ 285/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
A:
driver.findElement(By.tagName("body")).getText()
will get you the text of the page. To verifyTextPresent/assertTextPresent, from that you can use your
favourite test framework to assert on the text. To waitForTextPresent, you may want to investigate the
WebDriverWait class.
Q: The socket lock seems like a bad design. I can make it better
A: the socket lock that guards the starting of firefox is constructed with the following design
constraints:
It is shared among all the language bindings; ruby, java and any of the other bindings can coexist
at the same time on the same machine.
Certain critical parts of starting firefox must be exclusive-locked on the machine in question.
The socket lock itself is not the primary bottleneck, starting firefox is.
The SocketLock is an implementation of the Lock interface. This allows for a pluggable strategy for your
own implementation of it. To switch to a different implementation, subclass the FirefoxDriver and
override the “obtainLock” method.
A: You likely don’t have a Locale set on your system. Please set a locale LANG=en_US.UTF-8 and
LC_CTYPE=“en_US.UTF-8” for example.
https://www.selenium.dev/documentation/_print/ 286/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If you’ve ever wondered who to thank (or blame!) for Selenium, then you’ve come to the right place.
This page introduces you to the contributors and shows you what they’re working on.
SimonStewart: Original WebDriver developer and leading the Selenium 2 effort. He works mainly with
Java and can be seen all over the code base, patching holes and adding features. By day he works as a
Software Engineer in Test at Google. By night, he hacks on the crazy fun build grammar.
Julian Harty: Dabbled with WebDriver since 2007 mainly finding ways to make the code real and
useful by testing it, and by documenting it. Currently working at eBay to find ways to make software
testing more efficient and effective. He’s also involved in various open source initiatives, accessibility
software, and writing material. Search for “Julian Harty” in your favorite search engine to track down his
public work.
Jari Bakken: Has been working on WebDriver since late 2009, developed and now maintaining all
things Ruby. Lead developer of Celerity and watir-webdriver and a committer on the Watir project. Day
job is as a test engineer for classified ads website FINN.no, and by night I try to make use of my degree
in jazz guitar.
David Burns: Has been working with Selenium 1 for about 4 years and with WebDriver since the
beginning of 2010 and now maintaining the .NET and Python bindings. Senior Software Engineer in Test
at Mozilla helping lead the Test Automation on Web propjects from within WebQA.
Anthony Long: Has been working with Selenium since 2008, and is currently working to improve the
Selenium Python bindings. Anthony is the organizer of Quality Assurance and author of numerous
python modules for use in the Quality Assurance field. He has used selenium extensively as a QA Lead at
HUGE and most recently and currently, at AdMeld.
Jim Evans: Started working with the WebDriver and Selenium since the end of 2009, working mostly on
the .NET bindings. His test automation experience includes 12 years at Microsoft, and has worked for the
past 7 years as a Senior QA Engineer at Numara Software. When he’s not hacking code, he enjoys
spending time with his family and performing as a singer and songwriter.
https://www.selenium.dev/documentation/_print/ 287/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
7.3 - Selenium 3
Selenium 3 was the implementation of WebDriver without the Selenium RC Code. It
has since been replaced with Selenium 4, which implements the W3C WebDriver
specification.
7.3.1 - Grid 3
Selenium Grid 3 supported WebDriver without Selenium RC code. Grid 3 was
completely rewritten for the new Grid 4.
You can read our documentation for more information about Grid 4
Selenium Grid is a smart proxy server that allows Selenium tests to route commands to remote web
browser instances. Its aim is to provide an easy way to run tests in parallel on multiple machines.
With Selenium Grid, one server acts as the hub that routes JSON formatted test commands to one or
more registered Grid nodes. Tests contact the hub to obtain access to remote browser instances. The
hub has a list of registered servers that it provides access to, and allows control of these instances.
Selenium Grid allows us to run tests in parallel on multiple machines, and to manage different browser
versions and browser configurations centrally (instead of in each individual test).
Selenium Grid is not a silver bullet. It solves a subset of common delegation and distribution problems,
but will for example not manage your infrastructure, and might not suit your specific needs.
https://www.selenium.dev/documentation/_print/ 288/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
To use Selenium Grid, you need to maintain your own infrastructure for the nodes. As this can be a
cumbersome and time intense effort, many organizations use IaaS providers such as Amazon EC2 and
Google Compute to provide this infrastructure.
Other options include using providers such as Sauce Labs or Testing Bot who provide a Selenium Grid as
a service in the cloud. It is certainly possible to also run nodes on your own hardware. This chapter will
go into detail about the option of running your own grid, complete with its own node infrastructure.
Quick start
This example will show you how to start the Selenium 2 Grid Hub, and register both a WebDriver node
and a Selenium 1 RC legacy node. We will also show you how to call the grid from Java. The hub and
nodes are shown here running on the same machine, but of course you can copy the selenium-server-
standalone to multiple machines.
The selenium-server-standalone package includes the hub, WebDriver, and legacy RC needed to run
the Grid, ant is not required anymore. You can download the selenium-server-standalone.jar from
https://selenium.dev/downloads/.
Because a test’s desired capabilities are just what the name implies, desired, the hub cannot guarantee
that it will locate a node fully matching the requested desired capabilities set.
Open a command prompt and navigate to the directory where you copied the selenium-server-
standalone.jar file. You start the hub by passing the -role hub flag to the standalone server:
The Hub will listen to port 4444 by default. You can view the status of the hub by opening a browser
window and navigating to http://localhost:4444/grid/console.
To change the default port, you can add the optional -port flag with an integer representing the port
to listen to when you run the command. Also, all of the other options you see in the JSON config file
(seen below) are possible command-line flags.
You certainly can get by with only the simple command shown above, but if you need more advanced
configuration, you can also specify a JSON format config file, for convenience, to configure the hub when
you start it. You can do it like so:
Below you will see an example of a hubConfig.json file. We will go into more detail on how to provide
node configuration files in step 2.
https://www.selenium.dev/documentation/_print/ 289/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
{
"_comment" : "Configuration for Hub - hubConfig.json",
"host": ip,
"maxSession": 5,
"port": 4444,
"cleanupCycle": 5000,
"timeout": 300000,
"newSessionWaitTimeout": -1,
"servlets": [],
"prioritizer": null,
"capabilityMatcher": "org.openqa.grid.internal.utils.DefaultCapabilityMatcher",
"throwOnCapabilityNotPresent": true,
"nodePolling": 180000,
"platform": "WINDOWS"}
If a port is not specified through the -port flag, a free port will be chosen. You can run multiple nodes
on one machine but if you do so, you need to be aware of your systems memory resources and problems
with screenshots if your tests take them.
Passing JVM properties (using the -D flag before the -jar argument) on the command line as well, and
these will be picked up and propagated to the nodes:
-Dwebdriver.chrome.driver=chromedriver.exe
https://www.selenium.dev/documentation/_print/ 290/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
{
"capabilities": [
{
"browserName": "firefox",
"acceptSslCerts": true,
"javascriptEnabled": true,
"takesScreenshot": false,
"firefox_profile": "",
"browser-version": "27",
"platform": "WINDOWS",
"maxInstances": 5,
"firefox_binary": "",
"cleanSession": true
},
{
"browserName": "chrome",
"maxInstances": 5,
"platform": "WINDOWS",
"webdriver.chrome.driver": "C:/Program Files (x86)/Google/Chrome/Applicatio
},
{
"browserName": "internet explorer",
"maxInstances": 1,
"platform": "WINDOWS",
"webdriver.ie.driver": "C:/Program Files (x86)/Internet Explorer/iexplore.e
}
],
"configuration": {
"_comment" : "Configuration for Node",
"cleanUpCycle": 2000,
"timeout": 30000,
"proxy": "org.openqa.grid.selenium.proxy.WebDriverRemoteProxy",
"port": 5555,
"host": ip,
"register": true,
"hubPort": 4444,
"maxSession": 5
}
}
For both hub and node, if the -host flag is not specified, 0.0.0.0 will be used by default. This will
bind to all the public (non-loopback) IPv4 interfaces of the machine. If you have a special network
configuration or any component that creates extra network interfaces, it is advised to set the -host
flag with a value that allows the hub/node to be reachable from a different machine.
Troubleshooting
Using Log file
For advanced troubleshooting you can specify a log file to log system messages. Start Selenium GRID
hub or node with -log argument. Please see the below example:
https://www.selenium.dev/documentation/_print/ 291/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Use your favorite text editor to open log file (log.txt in the example above) to find “ERROR” logs if you
get issues.
Warning
The Selenium Grid must be protected from external access using appropriate firewall permissions.
Failure to protect your Grid could result in one or more of the following occurring:
See this blog post on Detectify, which gives a good overview of how a publicly exposed Grid could be
misused: Don’t Leave your Grid Wide Open.
Docker Selenium
Docker provides a convenient way to provision and scale Selenium Grid infrastructure in a unit known as
a container. Containers are standardised units of software that contain everything required to run the
desired application, including all dependencies, in a reliable and repeatable way on different machines.
The Selenium project maintains a set of Docker images which you can download and run to get a
working grid up and running quickly. Nodes are available for both Firefox and Chrome. Full details of
how to provision a grid can be found within the Docker Selenium repository.
Prerequisite
The only requirement to run a Grid is to have Docker installed and working. Install Docker.
https://www.selenium.dev/documentation/_print/ 292/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Hub
Intermediary and manager
Accepts requests to run tests
Takes instructions from client and executes them remotely on the nodes
Manages threads
A Hub is a central point where all your tests are sent. Each Selenium Grid consists of exactly one hub.
The hub needs to be reachable from the respective clients (i.e. CI server, Developer machine etc.) The
hub will connect one or more nodes that tests will be delegated to.
Nodes
Where the browsers live
Registers itself to the hub and communicates its capabilities
Receives requests from the hub and executes them
Nodes are different Selenium instances that will execute tests on individual computer systems. There
can be many nodes in a grid. The machines which are nodes do not need to be the same platform or
have the same browser selection as that of the hub or the other nodes. A node on Windows might have
the capability of offering Internet Explorer as a browser option, whereas this wouldn’t be possible on
Linux or Mac.
https://www.selenium.dev/documentation/_print/ 293/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
The Selenium-IDE (Integrated Development Environment) is the tool you use to develop your Selenium
test cases. It’s an easy-to-use Firefox plug-in and is generally the most efficient way to develop test
cases. It also contains a context menu that allows you to first select a UI element from the browser’s
currently displayed page and then select from a list of Selenium commands with parameters pre-defined
according to the context of the selected UI element. This is not only a time-saver, but also an excellent
way of learning Selenium script syntax.
This chapter is all about the Selenium IDE and how to use it effectively.
Firefox will protect you from installing addons from unfamiliar locations, so you will need to click ‘Allow’
to proceed with the installation, as shown in the following screenshot.
When downloading from Firefox, you’ll be presented with the following window.
https://www.selenium.dev/documentation/_print/ 294/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Select Install Now. The Firefox Add-ons window pops up, first showing a progress bar, and when the
download is complete, displays the following.
Restart Firefox. After Firefox reboots you will find the Selenium-IDE listed under the Firefox Tools menu.
https://www.selenium.dev/documentation/_print/ 295/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
IDE Features
Menu Bar
The File menu has options for Test Case and Test Suite (suite of Test Cases). Using these you can add a
new Test Case, open a Test Case, save a Test Case, export Test Case in a language of your choice. You
can also open the recent Test Case. All these options are also available for Test Suite.
The Edit menu allows copy, paste, delete, undo, and select all operations for editing the commands in
your test case. The Options menu allows the changing of settings. You can set the timeout value for
certain commands, add user-defined user extensions to the base set of Selenium commands, and specify
the format (language) used when saving your test cases. The Help menu is the standard Firefox Help
menu; only one item on this menu–UI-Element Documentation–pertains to Selenium-IDE.
Toolbar
The toolbar contains buttons for controlling the execution of your test cases, including a step feature for
debugging your test cases. The right-most button, the one with the red-dot, is the record button.
Run All: Runs the entire test suite when a test suite with multiple test cases is loaded.
Run: Runs the currently selected test. When only a single test is loaded this button and the Run All
button have the same effect.
Step: Allows you to “step” through a test case by running it one command at a time. Use for debugging
test cases.
TestRunner Mode: Allows you to run the test case in a browser loaded with the Selenium-Core
TestRunner. The TestRunner is not commonly used now and is likely to be deprecated. This button is for
evaluating test cases for backwards compatibility with the TestRunner. Most users will probably not
need this button.
Apply Rollup Rules: This advanced feature allows repetitive sequences of Selenium commands to be
grouped into a single action. Detailed documentation on rollup rules can be found in the UI-Element
Documentation on the Help menu.
The other tab - Source displays the test case in the native format in which the file will be stored. By
default, this is HTML although it can be changed to a programming language such as Java or C#, or a
scripting language like Python. See the Options menu for details. The Source view also allows one to
edit the test case in its raw form, including copy, cut and paste operations.
The Command, Target, and Value entry fields display the currently selected command along with its
parameters. These are entry fields where you can modify the currently selected command. The first
parameter specified for a command in the Reference tab of the bottom pane always goes in the Target
field. If a second parameter is specified by the Reference tab, it always goes in the Value field.
If you start typing in the Command field, a drop-down list will be populated based on the first characters
you type; you can then select your desired command from the drop-down.
Log/Reference/UI-Element/Rollup Pane
The bottom pane is used for four different functions–Log, Reference, UI-Element, and Rollup–depending
on which tab is selected.
Log
When you run your test case, error messages and information messages showing the progress are
displayed in this pane automatically, even if you do not first select the Log tab. These messages are
often useful for test case debugging. Notice the Clear button for clearing the Log. Also notice the Info
button is a drop-down allowing selection of different levels of information to log.
https://www.selenium.dev/documentation/_print/ 297/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Reference
The Reference tab is the default selection whenever you are entering or modifying Selenese commands
and parameters in Table mode. In Table mode, the Reference pane will display documentation on the
current command. When entering or modifying commands, whether from Table or Source mode, it is
critically important to ensure that the parameters specified in the Target and Value fields match those
specified in the parameter list in the Reference pane. The number of parameters provided must match
the number specified, the order of parameters provided must match the order specified, and the type of
parameters provided must match the type specified. If there is a mismatch in any of these three areas,
the command will not run correctly.
While the Reference tab is invaluable as a quick reference, it is still often necessary to consult the
Selenium Reference document.
Recording
Many first-time users begin by recording a test case from their interactions with a website. When
Selenium-IDE is first opened, the record button is ON by default. If you do not want Selenium-IDE to
begin recording automatically you can turn this off by going under Options > Options… and deselecting
“Start recording immediately on open.”
During recording, Selenium-IDE will automatically insert commands into your test case based on your
actions. Typically, this will include:
The type command may require clicking on some other area of the web page for it to record.
Following a link usually records a click command. You will often need to change this to
clickAndWait to ensure your test case pauses until the new page is completely loaded. Otherwise,
your test case will continue running commands before the page has loaded all its UI elements. This
will cause unexpected test case failures.
With Selenium-IDE recording, go to the browser displaying your test application and right click
anywhere on the page. You will see a context menu showing verify and/or assert commands.
https://www.selenium.dev/documentation/_print/ 298/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The first time you use Selenium, there may only be one Selenium command listed. As you use the IDE
however, you will find additional commands will quickly be added to this menu. Selenium-IDE will
attempt to predict what command, along with the parameters, you will need for a selected UI element
on the current web-page.
Let’s see how this works. Open a web-page of your choosing and select a block of text on the page. A
paragraph or a heading will work fine. Now, right-click the selected text. The context menu should give
you a verifyTextPresent command and the suggested parameter should be the text itself.
Also, notice the Show All Available Commands menu option. This shows many, many more commands,
again, along with suggested parameters, for testing your currently selected UI element.
Try a few more UI elements. Try right-clicking an image, or a user control like a button or a checkbox.
You may need to use Show All Available Commands to see options other than verifyTextPresent. Once
you select these other options, the more commonly used ones will show up on the primary context
menu. For example, selecting verifyElementPresent for an image should later cause that command to be
available on the primary context menu the next time you select an image and right-click.
Again, these commands will be explained in detail in the chapter on Selenium commands. For now
though, feel free to use the IDE to record and select commands into a test case and then run it. You can
learn a lot about the Selenium commands simply by experimenting with the IDE.
Editing
Insert Command
Table View
Select the point in your test case where you want to insert the command. To do this, in the Test Case
Pane, left-click on the line where you want to insert a new command. Right-click and select Insert
Command; the IDE will add a blank line just ahead of the line you selected. Now use the command
editing text fields to enter your new command and its parameters.
Source View
Select the point in your test case where you want to insert the command. To do this, in the Test Case
Pane, left-click between the commands where you want to insert a new command, and enter the HTML
tags needed to create a 3-column row containing the Command, first parameter (if one is required by
the Command), and second parameter (again, if one is required to locate an element) and third
parameter(again, if one is required to have a value). Example:
<tr>
<td>Command</td>
<td>target (locator)</td>
<td>Value</td>
</tr>
Insert Comment
Comments may be added to make your test case more readable. These comments are ignored when the
test case is run.
Comments may also be used to add vertical white space (one or more blank lines) in your tests; just
create empty comments. An empty command will cause an error during execution; an empty comment
won’t.
Table View
Select the line in your test case where you want to insert the comment. Right-click and select Insert
Comment. Now use the Command field to enter the comment. Your comment will appear in purple text.
Source View
https://www.selenium.dev/documentation/_print/ 299/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Select the point in your test case where you want to insert the comment. Add an HTML-style comment,
i.e., <!-- your comment here --> .
Table View
Simply select the line to be changed and edit it using the Command, Target, and Value fields.
Source View
Since Source view provides the equivalent of a WYSIWYG (What You See is What You Get) editor,
simply modify which line you wish–command, parameter, or comment.
When you open an existing test case or suite, Selenium-IDE displays its Selenium commands in the Test
Case Pane.
Click the Run button to run the currently displayed test case.
Click the Run All button to run all the test cases in the currently loaded test suite.
The Pause button can be used to stop the test case while it is running. The icon of this button then
changes to indicate the Resume button. To continue click Resume.
You can set a breakpoint in the test case to cause it to stop on a particular command. This is useful for
debugging your test case. To set a breakpoint, select a command, right-click, and from the context menu
select Toggle Breakpoint.
You can tell the IDE to begin running from a specific command in the middle of the test case. This also is
used for debugging. To set a startpoint, select a command, right-click, and from the context menu select
Set/Clear Start Point.
Double-click any single command to run it by itself. This is useful when writing a single command. It lets
you immediately test a command you are constructing, when you are not sure if it is correct. You can
double-click it to see if it runs correctly. This is also available from the context menu.
https://www.selenium.dev/documentation/_print/ 300/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
This same test case with a modified Base URL setting would be run against
http://beta.news.portal.com/about.html:
Selenium provides a rich set of commands for fully testing your web-app in virtually any way you can
imagine. The command set is often called selenese. These commands essentially create a testing
language.
In selenese, one can test the existence of UI elements based on their HTML tags, test for specific
content, test for broken links, input fields, selection list options, submitting forms, and table data among
other things. In addition Selenium commands support testing of window size, mouse position, alerts,
Ajax functionality, pop up windows, event handling, and many other web-application features. The
Command Reference lists all the available commands.
A command tells Selenium what to do. Selenium commands come in three “flavors”: Actions,
Accessors, and Assertions.
Actions are commands that generally manipulate the state of the application. They do things like
“click this link” and “select that option”. If an Action fails, or has an error, the execution of the
current test is stopped.
Many Actions can be called with the “AndWait” suffix, e.g. “clickAndWait”. This suffix tells
Selenium that the action will cause the browser to make a call to the server, and that Selenium
should wait for a new page to load.
Accessors examine the state of the application and store the results in variables, e.g. “storeTitle”.
They are also used to automatically generate Assertions.
Assertions are like Accessors, but they verify that the state of the application conforms to what is
expected. Examples include “make sure the page title is X” and “verify that this checkbox is
checked”.
https://www.selenium.dev/documentation/_print/ 301/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
All Selenium Assertions can be used in 3 modes: “assert”, “verify”, and ” waitFor”. For example, you can
“assertText”, “verifyText” and “waitForText”. When an “assert” fails, the test is aborted. When a “verify”
fails, the test will continue execution, logging the failure. This allows a single “assert” to ensure that the
application is on the correct page, followed by a bunch of “verify” assertions to test form field values,
labels, etc.
“waitFor” commands wait for some condition to become true (which can be useful for testing Ajax
applications). They will succeed immediately if the condition is already true. However, they will fail and
halt the test if the condition does not become true within the current timeout setting (see the
setTimeout action below).
Script Syntax
Selenium commands are simple, they consist of the command and two parameters. For example:
The parameters are not always required; it depends on the command. In some cases both are required, in
others one parameter is required, and in still others the command may take no parameters at all. Here
are a couple more examples:
goBackAndWait
The command reference describes the parameter requirements for each command.
Locators, text patterns, Selenium variables, and the commands themselves are described in considerable
detail in the section on Selenium Commands.
Selenium scripts that will be run from Selenium-IDE will be stored in an HTML text file format. This
consists of an HTML table with three columns. The first column identifies the Selenium command, the
second is a target, and the final column contains a value. The second and third columns may not require
values depending on the chosen Selenium command, but they should be present. Each table row
represents a new Selenium command. Here is an example of a test that opens a page, asserts the page
title and then verifies some content on the page:
<table>
<tr><td>open</td><td>/download/</td><td></td></tr>
<tr><td>assertTitle</td><td></td><td>Downloads</td></tr>
<tr><td>verifyText</td><td>//h2</td><td>Downloads</td></tr>
</table>
https://www.selenium.dev/documentation/_print/ 302/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
open /download/
assertTitle Downloads
The Selenese HTML syntax can be used to write and run tests without requiring knowledge of a
programming language. With a basic knowledge of selenese and Selenium-IDE you can quickly produce
and run testcases.
Test Suites
A test suite is a collection of tests. Often one will run all the tests in a test suite as one continuous batch-
job.
When using Selenium-IDE, test suites also can be defined using a simple HTML file. The syntax again is
simple. An HTML table defines a list of tests where each row defines the filesystem path to each test.
An example tells it all.
<html>
<head>
<title>Test Suite Function Tests - Priority 1</title>
</head>
<body>
<table>
<tr><td><b>Suite Of Tests</b></td></tr>
<tr><td><a href="./Login.html">Login</a></td></tr>
<tr><td><a href="./SearchValues.html">Test Searching for Values</a></td></tr>
<tr><td><a href="./SaveValues.html">Test Save</a></td></tr>
</table>
</body>
</html>
A file similar to this would allow running the tests all at once, one after another, from the Selenium-IDE.
Test suites can also be maintained when using Selenium-RC. This is done via programming and can be
done a number of ways. Commonly Junit is used to maintain a test suite if one is using Selenium-RC with
Java. Additionally, if C# is the chosen language, Nunit could be employed. If using an interpreted
language like Python with Selenium-RC then some simple programming would be involved in setting up
a test suite. Since the whole reason for using Selenium-RC is to make use of programming logic for your
testing this usually isn’t a problem.
open
click/clickAndWait
performs a click operation, and optionally waits for a new page to load.
verifyTitle/assertTitle
verifyTextPresent
https://www.selenium.dev/documentation/_print/ 303/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
verifyElementPresent
verifies an expected UI element, as defined by its HTML tag, is present on the page.
verifyText
verifies expected text and its corresponding HTML tag are present on the page.
verifyTable
waitForPageToLoad
pauses execution until an expected new page loads. Called automatically when clickAndWait is used.
waitForElementPresent
pauses execution until an expected UI element, as defined by its HTML tag, is present on the page.
For example, if you are testing a text heading, the text and its position at the top of the page are
probably relevant for your test. If, however, you are testing for the existence of an image on the home
page, and the web designers frequently change the specific image file along with its position on the
page, then you only want to test that an image (as opposed to the specific image file) exists somewhere
on the page.
Assertion or Verification?
Choosing between “assert” and “verify” comes down to convenience and management of failures.
There’s very little point checking that the first paragraph on the page is the correct one if your test has
already failed when checking that the browser is displaying the expected page. If you’re not on the
correct page, you’ll probably want to abort your test case so that you can investigate the cause and fix
the issue(s) promptly. On the other hand, you may want to check many attributes of a page without
aborting the test case on the first failure as this will allow you to review all failures on the page and take
the appropriate action. Effectively an “assert” will fail the test and abort the current test case, whereas a
“verify” will fail the test and continue to run the test case.
The best use of this feature is to logically group your test commands, and start each group with an
“assert” followed by one or more “verify” test commands. An example follows:
open /download/
assertTitle Downloads
https://www.selenium.dev/documentation/_print/ 304/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The above example first opens a page and then “asserts” that the correct page is loaded by comparing
the title with the expected value. Only if this passes will the following command run and “verify” that
the text is present in the expected location. The test case then “asserts” the first column in the second
row of the first table contains the expected value, and only if this passed will the remaining cells in that
row be “verified”.
verifyTextPresent
The command verifyTextPresent is used to verify specific text exists somewhere on the page. It
takes a single argument–the text pattern to be verified. For example:
This would cause Selenium to search for, and verify, that the text string “Marketing Analysis” appears
somewhere on the page currently being tested. Use verifyTextPresent when you are interested in only
the text itself being present on the page. Do not use this when you also need to test where the text
occurs on the page.
verifyElementPresent
Use this command when you must test for the presence of a specific UI element, rather than its content.
This verification does not check the text, only the HTML tag. One common use is to check for the
presence of an image.
verifyElementPresent //div/p/img
This command verifies that an image, specified by the existence of an HTML tag, is present on the page,
and that it follows a
tag and a
tag. The first (and only) parameter is a locator for telling the Selenese command how to find the
element. Locators are explained in the next section.
verifyElementPresent can be used to check the existence of any HTML tag within the page. You can
check the existence of links, paragraphs, divisions
verifyElementPresent //div/p
verifyElementPresent //div/a
verifyElementPresent id=Login
verifyElementPresent //a[2]
verifyElementPresent //head/title
https://www.selenium.dev/documentation/_print/ 305/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
These examples illustrate the variety of ways a UI element may be tested. Again, locators are explained
in the next section.
verifyText
Use verifyText when both the text and its UI element must be tested. verifyText must use a locator. If
you choose an XPath or DOM locator, you can verify that specific text appears at a specific location on
the page relative to other UI components on the page.
verifyText //table/tr/td/div/p This is my text and it occurs right after the div inside the table.
Locating Elements
For many Selenium commands, a target is required. This target identifies an element in the content of
the web application, and consists of the location strategy followed by the location in the format
locatorType=location . The locator type can be omitted in many cases. The various locator types are
explained below with examples for each.
Locating by Identifier
This is probably the most common method of locating elements and is the catch-all default when no
recognized locator type is used. With this strategy, the first element with the id attribute value matching
the location will be used. If no element has a matching id attribute, then the first element with a name
attribute matching the location will be used.
For instance, your page source could have id and name attributes as follows:
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
</form>
</body>
<html>
The following locator strategies would return the elements from the HTML snippet above indicated by
line number:
identifier=loginForm (3)
identifier=password (5)
identifier=continue (6)
continue (6)
Since the identifier type of locator is the default, the identifier= in the first three examples above
is not necessary.
Locating by Id
This type of locator is more limited than the identifier locator type, but also more explicit. Use this when
you know an element’s id attribute.
https://www.selenium.dev/documentation/_print/ 306/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
id=loginForm (3)
Locating by Name
The name locator type will locate the first element with a matching name attribute. If multiple elements
have the same value for a name attribute, then you can use filters to further refine your location
strategy. The default filter type is value (matching the value attribute).
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
name=username (4)
name=continue value=Clear (7)
name=continue Clear (7)
name=continue type=button (7)
Note: Unlike some types of XPath and DOM locators, the three types of locators above allow Selenium
to test a UI element independent of its location on the page. So if the page structure and organization is
altered, the test will still pass. You may or may not want to also test whether the page structure
changes. In the case where web designers frequently alter the page, but its functionality must be
regression tested, testing via id and name attributes, or really via any HTML property, becomes very
important.
Locating by XPath
XPath is the language used for locating nodes in an XML document. As HTML can be an implementation
of XML (XHTML), Selenium users can leverage this powerful language to target elements in their web
applications. XPath extends beyond (as well as supporting) the simple methods of locating by id or
name attributes, and opens up all sorts of new possibilities such as locating the third checkbox on the
page.
One of the main reasons for using XPath is when you don’t have a suitable id or name attribute for the
element you wish to locate. You can use XPath to either locate the element in absolute terms (not
advised), or relative to an element that does have an id or name attribute. XPath locators can also be
used to specify elements via attributes other than id and name.
Absolute XPaths contain the location of all elements from the root (html) and as a result are likely to fail
with only the slightest adjustment to the application. By finding a nearby element with an id or name
attribute (ideally a parent element) you can locate your target element based on the relationship. This is
much less likely to change and can make your tests more robust.
Since only xpath locators start with “//”, it is not necessary to include the xpath= label when
specifying an XPath locator.
https://www.selenium.dev/documentation/_print/ 307/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
xpath=/html/body/form[1] (3) - Absolute path (would break if the HTML was changed only
slightly)
//form[1] (3) - First form element in the HTML
xpath=//form[@id='loginForm'] (3) - The form element with attribute named ‘id’ and the value
’loginForm’
xpath=//form[input/@name='username'] (3) - First form element with an input child element
with attribute named ’name’ and the value ‘username’
//input[@name='username'] (4) - First input element with attribute named ’name’ and the value
‘username’
//form[@id='loginForm']/input[1] (4) - First input child element of the form element with
attribute named ‘id’ and the value ’loginForm’
//input[@name='continue'][@type='button'] (7) - Input with attribute named ’name’ and the
value ‘continue’ and attribute named ’type’ and the value ‘button’
//form[@id='loginForm']/input[4] (7) - Fourth input child element of the form element with
attribute named ‘id’ and value ’loginForm’
These examples cover some basics, but in order to learn more, the following references are
recommended:
There are also a couple of very useful Firefox Add-ons that can assist in discovering the XPath of an
element:
<html>
<body>
<p>Are you sure you want to do this?</p>
<a href="continue.html">Continue</a>
<a href="cancel.html">Cancel</a>
</body>
<html>
link=Continue (4)
link=Cancel (5)
Locating by DOM
The Document Object Model represents an HTML document and can be accessed using JavaScript. This
location strategy takes JavaScript that evaluates to an element on the page, which can be simply the
element’s location using the hierarchical dotted notation.
https://www.selenium.dev/documentation/_print/ 308/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Since only dom locators start with “document”, it is not necessary to include the dom= label when
specifying a DOM locator.
<html>
<body>
<form id="loginForm">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
dom=document.getElementById('loginForm') (3)
dom=document.forms['loginForm'] (3)
dom=document.forms[0] (3)
document.forms[0].username (4)
document.forms[0].elements['username'] (4)
document.forms[0].elements[0] (4)
document.forms[0].elements[3] (7)
You can use Selenium itself as well as other sites and extensions to explore the DOM of your web
application. A good reference exists on W3Schools.
Locating by CSS
CSS (Cascading Style Sheets) is a language for describing the rendering of HTML and XML documents.
CSS uses Selectors for binding style properties to elements in the document. These Selectors can be
used by Selenium as another locating strategy.
<html>
<body>
<form id="loginForm">
<input class="required" name="username" type="text" />
<input class="required passfield" name="password" type="password" />
<input name="continue" type="submit" value="Login" />
<input name="continue" type="button" value="Clear" />
</form>
</body>
<html>
css=form#loginForm (3)
css=input[name="username"] (4)
css=input.required[type="text"] (4)
css=input.passfield (5)
css=#loginForm input[type="button"] (7)
css=#loginForm input:nth-child(2) (5)
For more information about CSS Selectors, the best place to go is the W3C publication. You’ll find
additional references there.
Implicit Locators
You can choose to omit the locator type in the following situations:
Locators without an explicitly defined locator strategy will default to using the identifier locator
strategy. See Locating by Identifier _.
Locators starting with “//” will use the XPath locator strategy. See Locating by XPath _.
https://www.selenium.dev/documentation/_print/ 309/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Locators starting with “document” will use the DOM locator strategy. See Locating by DOM _
There are three types of patterns: globbing, regular expressions, and exact.
Globbing Patterns
Most people are familiar with globbing as it is utilized in filename expansion at a DOS or Unix/Linux
command line such as ls *.c . In this case, globbing is used to display all the files ending with a .c
extension that exist in the current directory. Globbing is fairly limited.
Only two special characters are supported in the Selenium implementation:
* which translates to “match anything,” i.e., nothing, a single character, or many characters.
[ ] (character class) which translates to “match any single character found inside the square brackets.”
A dash (hyphen) can be used as a shorthand to specify a range of characters (which are contiguous in
the ASCII character set). A few examples will make the functionality of a character class clear:
In most other contexts, globbing includes a third special character, the ?. However, Selenium globbing
patterns only support the asterisk and character class.
To specify a globbing pattern parameter for a Selenese command, you can prefix the pattern with a
glob: label. However, because globbing patterns are the default, you can also omit the label and specify
just the pattern itself.
Below is an example of two commands that use globbing patterns. The actual link text on the page
being tested was “Film/Television Department”; by using a pattern rather than the exact text, the click
command will work even if the link text is changed to “Film & Television Department” or “Film and
Television Department”. The glob pattern’s asterisk will match “anything or nothing” between the word
“Film” and the word “Television”.
verifyTitle glob:*Film*Television*
The actual title of the page reached by clicking on the link was “De Anza Film And Television
Department - Menu”. By using a pattern rather than the exact text, the verifyTitle will pass as long
as the two words “Film” and “Television” appear (in that order) anywhere in the page’s title. For
example, if the page’s owner should shorten the title to just “Film & Television Department,” the test
would still pass. Using a pattern for both a link and a simple test that the link worked (such as the
verifyTitle above does) can greatly reduce the maintenance for such test cases.
https://www.selenium.dev/documentation/_print/ 310/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Whereas Selenese globbing patterns support only the * and [ ] (character class) features, Selenese
regular expression patterns offer the same wide array of special characters that exist in JavaScript.
Below are a subset of those special characters:
PATTERN MATCH
[] character class: any single character that appears inside the brackets
Regular expression patterns in Selenese need to be prefixed with either regexp: or regexpi: . The
former is case-sensitive; the latter is case-insensitive.
A few examples will help clarify how regular expression patterns can be used with Selenese commands.
The first one uses what is probably the most commonly used regular expression pattern–.* (“dot star”).
This two-character sequence can be translated as “0 or more occurrences of any character” or more
simply, “anything or nothing.” It is the equivalent of the one-character globbing pattern * (a single
asterisk).
verifyTitle regexp:.*Film.*Television.*
The example above is functionally equivalent to the earlier example that used globbing patterns for this
same test. The only differences are the prefix (regexp: instead of glob:) and the “anything or nothing”
pattern (.* instead of just *).
The more complex example below tests that the Yahoo! Weather page for Anchorage, Alaska contains
info on the sunrise time:
open http://weather.yahoo.com/forecast/USAK0012.html
https://www.selenium.dev/documentation/_print/ 311/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Exact Patterns
The exact type of Selenium pattern is of marginal usefulness. It uses no special characters at all. So, if
you needed to look for an actual asterisk character (which is special for both globbing and regular
expression patterns), the exact pattern would be one way to do that. For example, if you wanted to
select an item labeled “Real *” from a dropdown, the following code might work or it might not. The
asterisk in the glob:Real * pattern will match anything or nothing. So, if there was an earlier select
option labeled “Real Numbers,” it would be the option selected rather than the “Real *” option.
In order to ensure that the “Real *” item would be selected, the exact: prefix could be used to create
an exact pattern as shown below:
But the same effect could be achieved via escaping the asterisk in a regular expression pattern:
It’s rather unlikely that most testers will ever need to look for an asterisk or a set of square brackets
with characters inside them (the character class for globbing patterns). Thus, globbing patterns and
regular expression patterns are sufficient for the vast majority of us.
The AndWait alternative is always used when the action causes the browser to navigate to another
page or reload the present one.
Be aware, if you use an AndWait command for an action that does not trigger a navigation/refresh, your
test will fail. This happens because Selenium will reach the AndWait’s timeout without seeing any
navigation or refresh being made, causing Selenium to raise a timeout exception.
https://www.selenium.dev/documentation/_print/ 312/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenese, by itself, does not support condition statements (if-else, etc.) or iteration (for, while, etc.).
Many useful tests can be conducted without flow control. However, for a functional test of dynamic
content, possibly involving multiple pages, programming logic is often needed.
a) Run the script using Selenium-RC and a client library such as Java or PHP to utilize the programming
language’s flow control features. b) Run a small JavaScript snippet from within the script using the
storeEval command. c) Install the goto_sel_ide.js extension .
Most testers will export the test script into a programming language file that uses the Selenium-RC API
(see the Selenium-IDE chapter). However, some organizations prefer to run their scripts from Selenium-
IDE whenever possible (for instance, when they have many junior-level people running tests for them,
or when programming skills are lacking). If this is your case, consider a JavaScript snippet or the
goto_sel_ide.js extension.
The plain store command is the most basic of the many store commands and can be used to simply store
a constant value in a Selenium variable. It takes two parameters, the text value to be stored and a
Selenium variable. Use the standard variable naming conventions of only alphanumeric characters when
choosing a name for your variable.
store [email protected]
Later in your script, you’ll want to use the stored value of your variable. To access the value of a variable,
enclose the variable in curly brackets ({}) and precede it with a dollar sign like this.
Selenium variables can be used in either the first or second parameter and are interpreted by Selenium
prior to any other operations performed by the command. A Selenium variable may also be used within
a locator expression.
An equivalent store command exists for each verify and assert command. Here are a couple more
commonly used store commands.
storeElementPresent
This corresponds to verifyElementPresent. It simply stores a boolean value–“true” or “false”–depending
on whether the UI element is found.
storeText
StoreText corresponds to verifyText. It uses a locator to identify specific page text. The text, if found, is
stored in the variable. StoreText can be used to extract text from the page being tested.
storeEval
This command takes a script as its first parameter. Embedding JavaScript within Selenese is covered in
the next section. StoreEval allows the test to store the result of running the script in a variable.
https://www.selenium.dev/documentation/_print/ 313/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The example below illustrates how a JavaScript snippet can be used to perform a simple numerical
calculation:
store 10 hits
This next example illustrates how a JavaScript snippet can include calls to methods, in this case the
JavaScript String object’s toUpperCase method and toLowerCase method.
storeEval storedVars[’name’].toUpperCase() uc
storeEval storedVars[’name’].toUpperCase() lc
type q javascript{storedVars[‘searchString’].toUpperCase()}
https://www.selenium.dev/documentation/_print/ 314/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript">
function output(resultText){
document.getElementById('output').childNodes[0].nodeValue=resultText;
}
function show_confirm(){
var confirmation=confirm("Chose an option.");
if (confirmation==true){
output("Confirmed.");
}
else{
output("Rejected!");
}
}
function show_alert(){
alert("I'm blocking!");
output("Alert is gone.");
}
function show_prompt(){
var response = prompt("What's the best web QA tool?","Selenium");
output(response);
}
function open_window(windowName){
window.open("newWindow.html",windowName);
}
</script>
</head>
<body>
<br />
<span id="output">
</span>
</body>
</html>
The user must respond to alert/confirm boxes, as well as moving focus to newly opened popup
windows. Fortunately, Selenium can cover JavaScript pop-ups.
https://www.selenium.dev/documentation/_print/ 315/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
But before we begin covering alerts/confirms/prompts in individual detail, it is helpful to understand the
commonality between them. Alerts, confirmation boxes and prompts all have variations of the following
Command Description
assertFoo(pattern) throws error if pattern doesn’t match the text of the pop-up
storeFooPresent(variable) stores the text of the pop-up in a variable and returns true or false
When running under Selenium, JavaScript pop-ups will not appear. This is because the function calls are
actually being overridden at runtime by Selenium’s own JavaScript. However, just because you cannot
see the pop-up doesn’t mean you don’t have to deal with it. To handle a pop-up, you must call its
assertFoo(pattern) function. If you fail to assert the presence of a pop-up your next command will be
blocked and you will get an error similar to the following [error] Error: There was an unexpected
Confirmation! [Chose an option.]
Alerts
Let’s start with alerts because they are the simplest pop-up to handle. To begin, open the HTML sample
above in a browser and click on the “Show alert” button. You’ll notice that after you close the alert the
text “Alert is gone.” is displayed on the page. Now run through the same steps with Selenium IDE
recording, and verify the text is added after you close the alert. Your test will look something like this:
open /
click btnAlert
You may be thinking “That’s odd, I never tried to assert that alert.” But this is Selenium-IDE handling
and closing the alert for you. If you remove that step and replay the test you will get the following error
[error] Error: There was an unexpected Alert! [I'm blocking!] . You must include an assertion
of the alert to acknowledge its presence.
If you just want to assert that an alert is present but either don’t know or don’t care what text it
contains, you can use assertAlertPresent . This will return true or false, with false halting the test.
Confirmations
Confirmations behave in much the same way as alerts, with assertConfirmation and
assertConfirmationPresent offering the same characteristics as their alert counterparts. However, by
default Selenium will select OK when a confirmation pops up. Try recording clicking on the “Show
confirm box” button in the sample page, but click on the “Cancel” button in the popup, then assert the
output text. Your test may look something like this:
open /
click btnConfirm
chooseCancelOnNextConfirmation
https://www.selenium.dev/documentation/_print/ 316/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
verifyTextPresent Rejected
The chooseCancelOnNextConfirmation function tells Selenium that all following confirmation should
return false. It can be reset by calling chooseOkOnNextConfirmation.
You may notice that you cannot replay this test, because Selenium complains that there is an unhandled
confirmation. This is because the order of events Selenium-IDE records causes the click and
chooseCancelOnNextConfirmation to be put in the wrong order (it makes sense if you think about it,
Selenium can’t know that you’re cancelling before you open a confirmation) Simply switch these two
commands and your test will run fine.
Prompts
Prompts behave in much the same way as alerts, with assertPrompt and assertPromptPresent
offering the same characteristics as their alert counterparts. By default, Selenium will wait for you to
input data when the prompt pops up. Try recording clicking on the “Show prompt” button in the sample
page and enter “Selenium” into the prompt. Your test may look something like this:
open /
answerOnNextPrompt Selenium!
click id=btnPrompt
verifyTextPresent Selenium!
If you choose cancel on the prompt, you may notice that answerOnNextPrompt will simply show a
target of blank. Selenium treats cancel and a blank entry on the prompt basically as the same thing.
Debugging
Debugging means finding and fixing errors in your test case. This is a normal part of test case
development.
We won’t teach debugging here as most new users to Selenium will already have some basic experience
with debugging. If this is new to you, we recommend you ask one of the developers in your
organization.
To set a breakpoint, select a command, right-click, and from the context menu select Toggle Breakpoint.
Then click the Run button to run your test case from the beginning up to the breakpoint.
It is also sometimes useful to run a test case from somewhere in the middle to the end of the test case
or up to a breakpoint that follows the starting point.
For example, suppose your test case first logs into the website and then performs a series of tests and
you are trying to debug one of those tests.
However, you only need to login once, but you need to keep rerunning your tests as you are developing
them. You can login once, then run your test case from a startpoint placed after the login portion of your
test case. That will prevent you from having to manually logout each time you rerun your test case.
To set a startpoint, select a command, right-click, and from the context menu select Set/Clear Start
Point. Then click the Run button to execute the test case beginning at that startpoint.
https://www.selenium.dev/documentation/_print/ 317/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
1. Start the test case running with the Run button from the toolbar.
2. Immediately pause the executing test case with the Pause button.
Find Button
The Find button is used to see which UI element on the currently displayed webpage (in the browser) is
used in the currently selected Selenium command.
This is useful when building a locator for a command’s first parameter (see the section on :ref: locators
<locators-section> in the Selenium Commands chapter). It can be used with any command that
identifies a UI element on a webpage, i.e. click, clickAndWait, type, and certain assert and verify
commands, among others.
From Table view, select any command that has a locator parameter. Click the Find button.
Now look on the webpage: There should be a bright green rectangle enclosing the element specified by
the locator parameter.
Alternatively, select just that portion of the webpage for which you want to see the source. Then right-
click the webpage and select View Selection Source. In this case, the separate HTML window will
contain just a small amount of source, with highlighting on the portion representing your selection.
Locator Assistance
Whenever Selenium-IDE records a locator-type argument, it stores additional information which allows
the user to view other possible locator-type arguments that could be used instead. This feature can be
very useful for learning more about locators, and is often needed to help one build a different type of
locator than the type that was recorded.
This locator assistance is presented on the Selenium-IDE window as a drop-down list accessible at the
right end of the Target field (only when the Target field contains a recorded locator-type argument).
Below is a snapshot showing the contents of this drop-down for one command. Note that the first
column of the drop-down provides alternative locators, whereas the second column indicates the type
of each alternative.
https://www.selenium.dev/documentation/_print/ 318/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The test suite pane will be automatically opened when an existing test suite is opened or when the user
selects the New Test Case item from the File menu. In the latter case, the new test case will appear
immediately below the previous test case.
Selenium-IDE also supports loading pre-existing test cases by using the File -> Add Test Case menu
option. This allows you to add existing test cases to a new test suite.
A test suite file is an HTML file containing a one-column table. Each cell of each row in thesection
contains a link to a test case. The example below is of a test suite containing four test cases:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sample Selenium Test Suite</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td>Test Cases for De Anza A-Z Directory Links</td></tr>
</thead>
<tbody>
<tr><td><a href="./a.html">A Links</a></td></tr>
<tr><td><a href="./b.html">B Links</a></td></tr>
<tr><td><a href="./c.html">C Links</a></td></tr>
<tr><td><a href="./d.html">D Links</a></td></tr>
</tbody>
</table>
</body>
</html>
Note: Test case files should not have to be co-located with the test suite file that invokes them. And on
Mac OS and Linux systems, that is indeed the case. However, at the time of this writing, a bug prevents
Windows users from being able to place the test cases elsewhere than with the test suite that invokes
https://www.selenium.dev/documentation/_print/ 319/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
them.
User Extensions
User extensions are JavaScript files that allow one to create his or her own customizations and features
to add additional functionality. Often this is in the form of customized commands although this
extensibility is not limited to additional commands.
.. _ goto_sel_ide.js extension :
Perhaps the most popular of all Selenium-IDE extensions is one which provides flow control in the form
of while loops and primitive conditionals. This extension is the goto_sel_ide.js_. For an example of how
to use the functionality provided by this extension, look at the page_ created by its author.
To install this extension, put the pathname to its location on your computer in the Selenium Core
extensions field of Selenium-IDE’s Options=>Options=>General tab.
After selecting the OK button, you must close and reopen Selenium-IDE in order for the extensions file
to be read. Any change you make to an extension will also require you to close and reopen Selenium-
IDE.
Information on writing your own extensions can be found near the bottom of the Selenium Reference_
document.
Sometimes it can prove very useful to debug step by step Selenium IDE and your User Extension. The
only debugger that appears able to debug XUL/Chrome based extensions is Venkman which is
supported in Firefox until version 32 included. The step by step debug has been verified to work with
Firefox 32 and Selenium IDE 2.9.0.
Format
Format, under the Options menu, allows you to select a language for saving and displaying the test case.
The default is HTML.
If you will be using Selenium-RC to run your test cases, this feature is used to translate your test case
into a programming language. Select the language, e.g. Java, PHP, you will be using with Selenium-RC
for developing your test programs. Then simply save the test case using File=>Export Test Case As. Your
test case will be translated into a series of functions in the language you choose. Essentially, program
code supporting your test is generated for you by Selenium-IDE.
Also, note that if the generated code does not suit your needs, you can alter it by editing a configuration
file which defines the generation process.
Each supported language has configuration settings which are editable. This is under the
Options=>Options=>Formats tab.
Troubleshooting
Below is a list of image/explanation pairs which describe frequent sources of problems with Selenium-
IDE:
An enhancement request has been raised to improve this error message. See issue 1010.
This type of error may indicate a timing problem, i.e., the element specified by a locator in your
command wasn’t fully loaded when the command was executed. Try putting a pause 5000 before the
command to determine whether the problem is indeed related to timing. If so, investigate using an
appropriate waitFor* or *AndWait command before the failing command.
Whenever your attempt to use variable substitution fails as is the case for the open command above, it
indicates that you haven’t actually created the variable whose value you’re trying to access. This is
sometimes due to putting the variable in the Value field when it should be in the Target field or vice
versa. In the example above, the two parameters for the store command have been erroneously placed
in the reverse order of what is required. For any Selenese command, the first required parameter must
go in the Target field, and the second required parameter (if one exists) must go in the Value field.
error loading test case: [Exception… “Component returned failure code: 0x80520012
(NS_ERROR_FILE_NOT_FOUND) [nsIFileInputStream.init]” nresult: “0x80520012
(NS_ERROR_FILE_NOT_FOUND)” location: “JS frame :: chrome://selenium-ide/content/file-utils.js ::
anonymous :: line 48” data: no]
One of the test cases in your test suite cannot be found. Make sure that the test case is indeed located
where the test suite indicates it is located. Also, make sure that your actual test case files have the .html
extension both in their filenames, and in the test suite file where they are referenced.
An enhancement request has been raised to improve this error message. See issue 1011.
https://www.selenium.dev/documentation/_print/ 321/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Your extension file’s contents have not been read by Selenium-IDE. Be sure you have specified the
proper pathname to the extensions file via Options=>Options=>General in the Selenium Core
extensions field. Also, Selenium-IDE must be restarted after any change to either an extensions file or
to the contents of the Selenium Core extensions field.
https://www.selenium.dev/documentation/_print/ 322/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium HTML-runner allows you to run Test Suites from a command line. Test Suites are HTML
exports from Selenium IDE or compatible tools.
Common information
Combination of releases of geckodriver / firefox / selenium-html-runner matters. There might be a
software compatibility matrix somewhere.
selenium-html-runner runs only Test Suite (not Test Case - for example an export from Monitis
Transaction Monitor). Be sure you comply with this.
For Linux users with no DISPLAY - you need to start html-runner with Virtual display (search for
xvfb)
https://www.selenium.dev/documentation/_print/ 323/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
<td>result:</td>
<td>PASS</td>
https://www.selenium.dev/documentation/_print/ 324/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium IDE was the original Firefox extension for Record and Playback. Version 2.x
was updated to support WebDriver.
2.9.1 - to be released
Fix - Fixes https://github.com/SeleniumHQ/selenium/issues/396
Fix - Changed Google code links to GitHub.
Enh - Merged official language plugins into the main xpi eliminating the need for multi-xpi with
the main xpi and multiple language plugin xpis.
Fix - Fixes https://github.com/SeleniumHQ/selenium/issues/570
2.9.0
Enh - Schedule tests for automatic playback at a certain time or periodic intervals.
(http://blog.reallysimplethoughts.com/2015/03/09/selenium-ide-scheduler-has-arrived-part-1/)
Enh - Allow submission of diagnostic information via a gist.
Enh - Improved health logging, including alerts normally hidden.
2.8.0
New - Added visual assist option to help users requiring stronger constrast in colors, turned off by
default. Turn it on from the Options dialog. - Issue 7696 (on Google Code)
New - Health Service to catch unhandled exceptions, statistics, metrics and diagnostics
Enh - Added Search Issues menu item in Help menu to make it easier to search all issues so that
we do not get so many duplicate reports of the same issue
Fix - Fixed broken autocomplete - issue 7928 (on Google Code)
Fix - Fixed cancelling of select button when page is reloaded - issue 7793 (on Google Code)
Fix - Adding select button to the sidebar and reduced button size - issue 7815 (on Google Code)
2.7.0
Fix - Fixed switching between tabs in the bottom info panel in FF32 - issue 7824 (on Google Code)
Fix - Fixes for https://bugzilla.mozilla.org/show_bug.cgi?id=1016305
Enh - Let comments (and commands) span the full width of the commands table
Enh - Show the result of the test case in the log after it has been played
Enh - Group items in the Action menu by function
Enh - Collect more statistics about test case and suite including running time for reporting
purposes
Enh - Improved listboxes supporting drag and drop reordering
Enh - Provide common utility function for plugin authors to deal with files
Enh - Allow pressing tab in the command text box to accept the current autocomplete and move
to the target text box
Enh - Select an autocomplete match when typing in the command text box to speed up manual
entry of commands
Enh - Make promises implementation available via deferred.js for plugin developers
Enh - Make simple http functions available for plugin developers
Enh - Easier to use confirmations for internal use and for plugins
Fix - Disable autocomplete when editing comments
https://www.selenium.dev/documentation/_print/ 325/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
2.6.0
Fix - Fixed broken autocompletion in FF31+ - issue 7645 (on Google Code)
Fix - Fixed options validation on options reset - issue 1050 (on Google Code)
Fix - Fixed C# code formatting for select elements
2.5.0
Enh - Select an element for a command by clicking on the element in the browser window
(http://blog.reallysimplethoughts.com/2014/01/05/manually-adding-and-updating-element-
locators-the-easy-way/)
Enh - Start playing a test suite from any test case (Using right click menu) - issue 1987 (on Google
Code)
Enh - Add a new test case using a keyboard shortcut (ctrl-N or cmd+N)
Fix - Fixed delete test case through right click menu was sometimes disabled - issue 5003 (on
Google Code)
Fix - Fixed Selenium IDE icon is sometimes not visible - issue 5712 (on Google Code)
Fix - Fixed selectWindow using a variable - issue 3270 (on Google Code)
Some minor changes
2.4.0
Enh - Base URL history, recent test cases and recent test suites can be cleared - issue 6135 (on
Google Code)
Enh - Special key now have shorter names
(http://blog.reallysimplethoughts.com/2013/09/25/using-special-keys-in-selenium-ide-part-2/)
Enh - Support for user extensions in Webdriver playback - issue 5675 (on Google Code)
Fix - The recording of entering text in fields uses type instead of sendKeys.
Enh - When developer tools are active, the last open test case or suite is automatically opened
Fix - Fixed is * commands in Webdriver playback in Selenium IDE - issue 6118 (on Google Code)
Enh - Adding ability to show commands as deprecated in Selenium IDE and smartness to show the
correct alternative command
Enh - Deprecating Selenium IDE commands * TextPresent, typeKeys, keyUp, keyDown and
keyPress
Enh - Import json library in exported Ruby Webdriver tests
Enh - Adding support for waitFor * and waitForNot * commands in Webdriver playback - issue
5913 (on Google Code)
2.3.0
New - Added support for HTML5 input fields recording - issue 3765 (on Google Code)
New - Recording for sendKeys command
Enh - Removal of deprecated * TextPresent commands from right click menu
Fix - Dead object error in recording IDE tests - issue 4761 (on Google Code)
Fix - Fixed could not continue in recording - issue 5820 (on Google Code)
Enh - UTF-8 encoded user-extensions.js support - issue 1646 (on Google Code)
https://www.selenium.dev/documentation/_print/ 326/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
New special keys support for sendKeys in Selenium IDE and webdriver playback - issue #6052 (on
Google Code)
New - Special keys support to sendKeys in all official formatters - issue 6053 (on Google Code)
(http://blog.reallysimplethoughts.com/2013/09/25/using-special-keys-in-selenium-ide-part-1/)
Enh - Plugin api enhancement for specifying formatter type + documentaton comments
Fix - Invalid XPath error in Firefox 23 - issue 6055 (on Google Code)
New - Added support for Firefox 23
2.2.0
Fix - keyUp, keyDown, keyPress, typeKeys fixed on Firefox 22 - issue 5883 (on Google Code), issue
5884 (on Google Code)
2.1.0
Enh - Plugin system changed (http://blog.reallysimplethoughts.com/2013/07/07/changes-to-
selenium-ide-plugin-system/)
New - Added support for Firefox 22 + 23 beta
Fix - Click fixed for Firefox 22 - issue 5841 (on Google Code)
2.0.0
New - WebDriver playback support (http://blog.reallysimplethoughts.com/2013/02/18/webdriver-
playback-in-selenium-ide-is-here/)
New - Added support for Firefox 19 & 20
New - Selenium IDE icon on toolbar is added on first install
1.10.0
New - Added support for Firefox 16 & 17
New - Implemented formatting for alert handling commands
Bug - Fixed options for Java 4 WebDriver formatter
Bug - Processing locators before use in getCssCount and getXpathCount. Fixes issue 4784 (on
Google Code)
1.9.1
New - Added support for Firefox 15
New - Added support for assertTextPresent, verifyTextPresent, waitForTextPresent,
assertTextNotPresent, verifyTextNotPresent, waitForTextNotPresent commands to WebDriver
formatters. (http://blog.reallysimplethoughts.com/2012/08/26/selenium-ide-webdriver-formatters-
updated-to-support-textpresent-commands/)
New - Added the target and value parameters in comments when the WebDriver formatters do
not support the command
1.9.0
New - Added Selenese command sendKeys (http://blog.reallysimplethoughts.com/2012/07/19/new-
selenese-command-sendkeys/)
New - Better naming of formatters
New - Added support for Firefox 14
https://www.selenium.dev/documentation/_print/ 327/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
1.8.1
New - Added support for Firefox 13
1.8.0
New - Added support for Firefox 12
1.7.2
Bug - Fixed regression with typing into file input fields - issue 3549 (on Google Code)
1.7.1
Bug - Fixed regression with stored variables - issue 3520 (on Google Code)
1.7.0
New - Added additional useful menu items to the help menu
New - Added support for Firefox 11
Bug - Stored variables can safely contain consecutive dollar signs - issue 834 (on Google Code)
Bug - Don’t trim whitespace when decoding HTML testcases - issue 755 (on Google Code)
New - Formatter menu items are now context sensitive - issue 3327 (on Google Code) and issue
3385 (on Google Code)
Bug - Fixed Ruby WebDriver test suite export - issue 3243 (on Google Code)
Bug - File extensions being added to all file pickers - issue 3336 (on Google Code)
Bug - Record interactions with elements with an id of ‘id’ - issue 3273 (on Google Code)
1.6.0
New - Added support for Firefox 10
New - Added keyboard shortcuts to launch Selenium IDE - issue 3028 (on Google Code)
Bug - Added break command to autocomplete list - issue 3046 (on Google Code)
Bug - Incorrect tooltip displayed in sidebar - issue 3098 (on Google Code)
Bug - Improved XPath locator recording when there are multiple matches - issue 3056 (on Google
Code)
Bug - Locators can now be reordered on Mac - issue 3267 (on Google Code)
1.5.0
New - Added support for Firefox 9
Bug - Changes to user extensions weren’t being updated in Firefox 8 - issue 2801 (on Google
Code)
Bug - Security error was thrown when trying to type into file (upload) input fields in Firefox 8 -
issue 2826 (on Google Code)
Bug - Improved French locale - issue 1912 (on Google Code)
Bug - break command was failing - issue 725 (on Google Code)
Bug - source view is now fixed width (monospace) - issue 522 (on Google Code)
New - Implemented ‘select’ formatting for WebDriver bindings (Java, C#, Python, Ruby)
Bug - Fixed compile-time and run-time errors in the code formatted for
WebDriverBackedSelenium
https://www.selenium.dev/documentation/_print/ 328/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Bug - Fixed ‘baseUrl’ and ‘get’ formatting errors in various formatters to handle relative and
absolute URLs
1.4.1
Bug - Apparently I shipped without switching all the version numbers correctly. (Adam)
1.4.0
New - Firefox 8 support (again, just a version max version bump)
1.3.0
Was going to be just a quick release to get
in, but then I got busy and didn’t push it when I had planned and so now
has leaked in. Most people will want to just leave this the way it is by default. This is brand-spanking-
new and allows you to do visually what you could before using a somewhat arcane bit of JS in an
extension.
1.2.0
Just a quick release primarily for
New - Firefox 6 support (which really was just changing the max version number)
Bug - Recorded CSS locator was not W3C clean wrt attributes
Bug - Deleting of cookies works properly if the cookie name is escaped (such as will ASP sites)
Bug - If the cookie value has an = in it, the whole cookie is now returned instead of just up to the =
You will also notice that the bundle now only has formatters for the officially supported languages of
the project (Java, C#, Python, Ruby). If anyone from the Perl, Groovy or PHP camps wants to take on
ownership of those formats we’ll happily help you out.
1.1.0
Hey! Look at that! A slightly more significant version bump! Any why is that? Well…
Which are the four supported languages of the Selenium project. This also means that Se-IDE is officially
deprecating inclusion of the Groovy, Perl and PHP format plugins in the main release bundle. It would be
outstanding if the community around those languages picks up their development and maintenance.
Read more about the WebDriver exporters on Samit’s blog.
Of course, format switching is still in Experimental purgatory for at least this release. Losing people’s
scripts because of bugs is not acceptable and we’re working on it. To ‘goal’ is to have them back for the
next release.
New - setIndent(n) is now available to formats for greater control over formatting of export
formats
Bug - There was a performance regression in deep in some shared code that has been addressed.
https://www.selenium.dev/documentation/_print/ 329/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
New - Rather than recording ‘foo’ for an element which and an id of ‘foo’ it is captured as ‘id=foo’
to be very specific as to which element would be interacted with
New - Same with ’name’
New - Popups (alerts, confirms, prompts) and new windows work again
1.0.12
This is a minor release with nothing too huge included. But because the last one didn’t get pushed to the
world, it is important to make a note of a big change introduced in 1.0.11.
We have marked the changing of formats as Experimental due to a couple lose-all-your-data bugs. As a
result it is disabled in the toolbar by default. To enable it, click the checkbox in the Options menu. And
because we really don’t want you to lose your data, when you switch formats you will get a big
warning box. This too can be disabled in the Options menu. But if you do both of these things and your
script gets sent to the abyss, you have been warned. :)
1.0.11
It has been half a year since our last release of 1.0.10 and we have put a lot of effort to bring you this
release. The summary of the contributions to this release is as follows:-
Here is the list of changes excluding some minor fixes and code refactoring.
Main Features:
Firefox 4 support (Issue 1470 (on Google Code), Simon Stewart and Samit Badle)
New CSS locator builder! Selenium IDE will now create locators using CSS when recording
(Santiago Suarez Ordoñez)
Added more power to the plugin developers through the new Util command builders support
(Issue 442 (on Google Code), Samit Badle)
New command getCssCount (Adam Goucher)
Usability Improvements:
Selenium IDE is now available from the Web developer menu in Firefox 4 (Issue 1467 (on Google
Code), Samit Badle)
Camel Case search in command text box has been improved allowing you to type vTP for
verifyTextPresent command (Samit Badle with Dave Hunt)
https://www.selenium.dev/documentation/_print/ 330/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Most actions in Selenium IDE are now accessible through the new Actions menu (Issue 1266 (on
Google Code), Samit Badle and Dave Hunt)
Removed help menu items related to Firefox from Selenium IDE help menu (Issue 1704 (on Google
Code), Samit Badle)
Less prompting when saving test suite (Issue 967 (on Google Code), Samit Badle)
A method to Reset IDE Window is now available through the Options menu for people having
trouble when switching from multiple monitors (Issue 1249 (on Google Code), Samit Badle)
Show the name of the test case in save dialog (Issue 984 (on Google Code), Samit Badle)
The preferences for the current format will be automatically shown in options dialog (Samit Badle)
The plugins pane in the Options dialog now has a splitter (Samit Badle)
Default Timeout Value field in the Options dialog now mentions a unit (Issue 896 (on Google
Code), Adam Goucher)
Introduced experimental features option to hide some unstable features (Samit Badle)
Bug Fixes:
Format changing is now marked as experimental due to possible issues, you can turn it on from
the options dialog (Samit Badle)
Fixed the header issue on saving test case in another format (Issue 1164 (on Google Code), Samit
Badle)
Improved alert on changing the format (Issue 1244 (on Google Code), Samit Badle)
Find button is back on Macs and uses a new way to highlight (Issue 1052 (on Google Code), Samit
Badle)
Recording is possible in the middle of a script again (Issue 968 (on Google Code), Samit Badle)
Fixed the annoying skip over one command when recording in the middle of the script (Issue 745
(on Google Code), Samit Badle)
While recording, “clickAndWait” command becomes “click” is now fixed (Issue 419 (on Google
Code), Samit Badle)
Selenium IDE bottom pane folding now works correctly (Issue 614 (on Google Code), Samit Badle)
Changed the ID of Selenium IDE menu from generic name to avoid clashes with other addons.
(Issue 969 (on Google Code), Samit Badle)
Known Issues:
Issue 1728 (on Google Code) - Firefox 4 eliminated support for the highlight. So the Find button
has stopped working under Firefox 4 on Windows.
Issue 1729 (on Google Code) - The Plugin pane in the Options dialog is not shownig any text in
Firefox 4 on Windows 7.
Issues have been reported in Selenium IDE on Ubuntu 11, which are not related to Selenium IDE.
See comments on issue 1642 (on Google Code).
1.0.10
Another packaging problem broke the various things that used getText(). Which of course is one of the
most commonly used bits of the API.
https://www.selenium.dev/documentation/_print/ 331/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
As a result, we’ve started to rebuild the test suite for things. It’s going to take awhile to get the coverage
we’re hoping for, but it’ll be worth it if we can go at least 2 days after a release before becoming
embarrassed.
Upgrade Notes:
Due to the atoms being included properly, some of the behaviour around accessing boolean
attributes has changed. See http://seleniumhq.wordpress.com/2010/12/09/atoms-have-come-to-
selenium-ide/ for details.
1.0.9
What started out as a pretty major change in terms of packaging ended up including two significant bug
fixes as well. Hopefully we avoid that sort of thing with the release. Not that I don’t expect it. :)
NEW - Formatters are all plugins. This effectively separates the development of an individual
format from the development of the editor. Now, this means that when you install things for the
first time you get a tonne of addons. That is ok. Don’t panic. Oh, and it also means if you don’t
want them you have the option to. Not only does this mean fixes to formats get distributed
sooner (PHP, I’m looking at you) but 3rd parties will be able to make better packaging choices by
having the editor plus their formatters.
Other stuff
BUG - the JUnit 4 formatter doesn’t try to use a string as the port number
BUG - the window when creating new formats properly closes now
BUG - removed the ‘find’ button if on OSX since it doesn’t do anything on this platform (its a FF
bug)
BUG - some hard coded strings have been internationalized
NEW - autocomplete has been enhanced somewhat - see
http://code.google.com/p/selenium/issues/detail?id=992
BUG - when switching build systems, the icons for menus and such got left out of the package
BUG - commands are trimmed of whitespace before executing which was sometimes a source of
great confusion
BUG - now preserves whitespace when displaying diffs in the log
1.0.8
This release is primarily to get FF4 support out into the wild since it is getting to the advanced beta
phase, but there is also a fair bit of other bug fixes in there as well. About 75% of the fixes in the release
are directly the work of Samit Badle and the vast remainder by Jérémy Hérault.
BUG - There was an annoying bug where ‘clickAndWait’ would be saved as click, but has been
fixed. see http://code.google.com/p/selenium/issues/detail?id=419
NEW -This could arguably be considered a bug fix, but if you changed format from HTML to
something else then made an edit and switched back again to HTML your script contents would
be lost. At its heart, the HTML -> something conversion is one way and so there is now a warning
about possibly losing your code. The warning only happens the first time though so you can still
shoot yourself in the foot; its just harder
BUG - element locator works for table rows. see http://code.google.com/p/selenium/issues/detail?
id=485
BUG - the default timeout setting of se-ide is now actually used. see
http://code.google.com/p/selenium/issues/detail?id=552
NEW - the ‘run in the selenium testrunner’ option has been removed. The supported methods in
se-ide are the play single, play suite and if you need more there is always se-rc with a language
binding or -htmlSuite
https://www.selenium.dev/documentation/_print/ 332/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
BUG - the base url wouldn’t change on occasion, much to the frustration of many
NEW - a JUnit 4 formatter was added
BUG - the RSpec formatter had some additional tweaks
BUG - test suite html can now have tests from different folders
BUG - test suite saving triggers got a bit of attention so add/delete/modify is a little more robust
NEW - if you resize your se-ide and/or move it around your screen, the size and position are saved
between sessions
BUG - the logic around when to prompt for saving wasn’t really that nice, but its been fixed
NEW - uses ‘browser atoms’ like the rest of Selenium
NEW - CSS locator execution is handled through Sizzle
NEW - can now add multiple test cases to a suite at once
NEW - addition to the se-ide plugin api to add se-ide extensions to manipulate how recording is
done - http://reallysimplethings.wordpress.com/2010/10/11/the-selenium-ide-1-x-plugin-api-part-
12-adding-locator-builders/
NEW - the case of the missing log messages is now solved
NEW - Firefox 4 support
1.0.7
Only a couple of things of note in this release to end-users which is somewhat silly since it is a month
overdue, but that was due to some build changes that took a bit of work to get the kinks worked out.
Should be ok now though.
NEW - you can now drag-and-drop command around instead of the cut-insert-paste dance that
you used to have to do (Jérémy Hérault)
NEW - same thing with tests in the test suite panel (Jérémy Hérault)
NEW - an new optional parameter when registering you se-ide plugin to allow for command
exporting. see http://adam.goucher.ca/?p=1456 for details (Adam Goucher)
NEW - Swedish locale sv-SE now has translations (Olle Jonsson)
BUG - Some people were reporting an annoying popup when starting se-ide without any plugins
installed (Adam oucher)
1.0.6
The big thing in this release is that the scary log message that was showing up on ‘open’ is fixed. The
other big things are:
BUG - The scary log message that was happening when you used ‘open’ has had its underlying
cause fixed (Adam Goucher, Jérémy Hérault)
BUG - fixed a build issue with FF 3.6 and type-ahead for commands (Jérémy Hérault)
BUG - fixed some PHP export issues - see http://jira.openqa.org/browse/SIDE-346 and
http://jira.openqa.org/browse/SIDE-183 (Adam Goucher)
BUG - there was a packaging issue around user-extensions (Adam Goucher)
BUG - ide won’t put ’name=’ as the Target when recording a selectWindow (David Burns)
BUG - to avoid confusion, when viewing formatter source, if it is read-only the button says ‘ok’
and if it is editable then it is ‘save’ (Jérémy Hérault)
NEW - you can now set a preference on whether you want record to be on or off when you start
ide (Adam Goucher)
NEW - se-ide plugin information is read from the plugin’s install.rdf (most people won’t care about
this, but its pretty cool from a geek perspective)
1.0.5
One thing that does not really fit the BUG or NEW label is that the code for Se-IDE is now in the main
repo rather than tucked away in a somewhat hidden location.
BUG - user formats were not appearing in the list (Adam Goucher)
https://www.selenium.dev/documentation/_print/ 333/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
BUG - constrained how iframes were loaded; which is why AMO was unhappy (Adam Goucher)
BUG - a whole bunch of tweaks to the existing formats (Dave Hunt)
BUG - a bunch of French translation fixes / additions (Jérémy Hérault)
BUG - the reload user extensions button only shows up if you have the developer tool checkbox
checked (Jérémy Hérault)
BUG - labelling access keys on test runner (Olle Jonsson)
BUG - cleaned up a bunch of references from OpenQA to SeleniumHQ (Olle Jonsson)
BUG - had an = instead of == (Olle Jonsson)
BUG - adding a bunch of ;’s to make jslint shut up (Olle Jonsson)
BUG - getting rid of the ‘setting something that only has a getter’ message in Firefox 3.6 (Dan
Fabulich)
NEW - self hosting of updates to avoid delays at AMO (Adam Goucher)
NEW - the version of se-ide is now in the title bar (Adam Goucher)
NEW - added some Se-IDE specific icons here and there (Adam Goucher, Dave Hunt)
NEW - preferences can now be Bool’s as well (Adam Goucher)
NEW - added addPlugin(id) to the plugin API (Adam Goucher)
NEW - added a new panel to the Options screen around plugins. It doesn’t do much now other
than list the plugins that registered themselves through addPlugin, but should do more for 1.0.6
(Adam Goucher)
1.0.4
Selenium IDE 1.0.4 marks a resurgence in the project with releases planned for the middle of each
month. Here are the changes that have happened between versions 1.0.2 and 1.0.4 of Selenium IDE.
(Don’t ask what happened to version 1.0.3)
BUG - Supported Firefox version increased to include the 3.6 series (Santiago Suarez Ordoñez)
BUG - Removed the Ruby formatter that was flagged as ‘deprecated’ (Adam Goucher)
NEW - Ruby formatter updated to use the selenium-client gem ( http://selenium-
client.rubyforge.org/ ) (Adam Goucher)
NEW - Ability to add custom user-extensions to extend the Selenium API through plugins to
Selenium IDE (Adam Goucher)
NEW - Ability to add custom formatters to extend which languages are available to users through
plugins to Selenium IDE (Adam Goucher)
NEW - Can now load changes to user extensions without having to restart Selenium IDE (Jérémy
Hérault)
NEW - RSpec formatter
Acknowledgements
Version 1.0.4 would not have happened without the following assistance
For issues with this release or features you would like to see in future releases, please log them in the
Google Code Issue tracker (https://github.com/SeleniumHQ/selenium/issues) using the ide label so they
don’t get lost.
-adam
https://www.selenium.dev/documentation/_print/ 334/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
All implementations of WebDriver that communicate with the browser, or a RemoteWebDriver server
shall use a common wire protocol. This wire protocol defines a RESTful web service using JSON over
HTTP.
The protocol will assume that the WebDriver API has been “flattened”, but there is an expectation that
client implementations will take a more Object-Oriented approach, as demonstrated in the existing Java
API. The wire protocol is implemented in request/response pairs of “commands” and “responses”.
Session
The machine running the RemoteWebDriver. This term may also refer to a specific browser that
implements the wire protocol directly, such as the FirefoxDriver or IPhoneDriver.
The server should maintain one browser per session. Commands sent to a session will be directed to the
corresponding browser.
WebElement
An object in the WebDriver API that represents a DOM element on the page.
ELEMENT string The opaque ID assigned to the element by the server. This ID should be used
in all subsequent commands issued against the element.
browserName string The name of the browser being used; should be one of
{android, chrome, firefox, htmlunit, internet
explorer, iPhone, iPad, opera, safari} .
https://www.selenium.dev/documentation/_print/ 335/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
handlesAlerts boolean Whether the session can interact with modal popups,
such as window.alert and window.confirm .
locationContextEnabled boolean Whether the session can set and query the browser's
location context.
applicationCacheEnabled boolean Whether the session can interact with the application
cache.
browserConnectionEnabled boolean Whether the session can query for the browser's
connectivity and disable it if desired.
rotatable boolean Whether the session can rotate the current page's current
layout between portrait and landscape orientations (only
applies to mobile platforms).
acceptSslCerts boolean Whether the session should accept all SSL certs by
default.
elementScrollBehavior integer Allows the user to specify whether elements are scrolled
into the viewport for interaction to align with the top (0)
or bottom (1) of the viewport. The default value is to align
with the top of the viewport. Supported in IE and Firefox
(since 2.36)
https://www.selenium.dev/documentation/_print/ 336/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Desired Capabilities
A Capabilities JSON Object sent by the client describing the capabilities a new session created by the
server should possess. Any omitted keys implicitly indicate the corresponding capability is irrelevant.
More at DesiredCapabilities.
Actual Capabilities
A Capabilities JSON Object returned by the server describing what features a session actually supports.
Any omitted keys implicitly indicate the corresponding capability is not supported.
expiry number (Optional) When the cookie expires, specified in seconds since midnight,
January 1, 1970 UTC.1
1 When returning Cookie objects, the server should only omit an optional field if it is incapable of
level string The log level of the entry, for example, "INFO" (see log levels).
Log Levels
Log levels in order, with finest level on top and coarsest level at the bottom.
Level Description
ALL All log messages. Used for fetching of logs and configuration of logging.
https://www.selenium.dev/documentation/_print/ 337/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Level Description
Log Type
The table below lists common log types. Other log types, for instance, for performance logging may also
be available.
proxyType string (Required) The type of proxy being used. Possible values are:
direct - A direct connection - no proxy in use, manual - Manual
proxy settings configured, e.g. setting a proxy for HTTP, a proxy
for FTP, etc, pac - Proxy autoconfiguration from a URL,
autodetect - Proxy autodetection, probably with WPAD, system
- Use system settings
ftpProxy, httpProxy, string (Optional, Ignored if proxyType != manual) Specifies the proxies
sslProxy, socksProxy to be used for FTP, HTTP, HTTPS and SOCKS requests
respectively. Behaviour is undefined if a request is made, where
the proxy for the particular protocol is undefined, if proxyType is
manual. Expected format example: hostname.com:1234
https://www.selenium.dev/documentation/_print/ 338/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Messages
Commands
WebDriver command messages should conform to the HTTP/1.1 request specification. Although the
server may be extended to respond to other content-types, the wire protocol dictates that all commands
accept a content-type of application/json;charset=UTF-8 . Likewise, the message bodies for POST
and PUT request must use an application/json;charset=UTF-8 content-type.
Each command in the WebDriver service will be mapped to an HTTP method at a specific path. Path
segments prefixed with a colon (:) indicate that segment is a variable used to further identify the
underlying resource. For example, consider an arbitrary resource mapped as:
GET /favorite/color/:name
Given this mapping, the server should respond to GET requests sent to “/favorite/color/Jack” and
“/favorite/color/Jill”, with the variable :name set to “Jack” and “Jill”, respectively.
Responses
Command responses shall be sent as HTTP/1.1 response messages. If the remote server must return a
4xx response, the response body shall have a Content-Type of text/plain and the message body shall be
a descriptive message of the bad request. For all other cases, if a response includes a message body, it
must have a Content-Type of application/json;charset=UTF-8 and will be a JSON object with the
following properties:
status number A status code summarizing the result of the command. A non-zero value
indicates that the command failed.
https://www.selenium.dev/documentation/_print/ 339/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
The client should interpret a 404 Not Found response from the server as an “Unknown command”
response. All other 4xx and 5xx responses from the server that do not define a status field should be
interpreted as “Unknown error” responses.
Error Handling
There are two levels of error handling specified by the wire protocol: invalid requests and failed
commands.
https://www.selenium.dev/documentation/_print/ 340/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Invalid Requests
All invalid requests should result in the server returning a 4xx HTTP response. The response Content-
Type should be set to text/plain and the message body should be a descriptive error message. The
categories of invalid requests are as follows:
Unknown Commands
If the server receives a command request whose path is not mapped to a resource in the REST service, it
should respond with a 404 Not Found message.
Unimplemented Commands
Every server implementing the WebDriver wire protocol must respond to every defined command. If an
individual command has not been implemented on the server, the server should respond with a 501 Not
Implemented error message. Note this is the only error in the Invalid Request category that does not
return a 4xx status code.
Failed Commands
If a request maps to a valid command and contains all of the expected parameters in the request body,
yet fails to execute successfully, then the server should send a 500 Internal Server Error. This response
should have a Content-Type of application/json;charset=UTF-8 and the response body should be a
well formed JSON response object.
The response status should be one of the defined status codes and the response value should be
another JSON object with detailed information for the failing command:
screen string (Optional) If included, a screenshot of the current page as a base64 encoded
string.
class string (Optional) If included, specifies the fully qualified class name for the exception
that was thrown when the command failed.
stackTrace array (Optional) If included, specifies an array of JSON objects describing the stack
trace for the exception that was thrown when the command failed. The
zeroeth element of the array represents the top of the stack.
Each JSON object in the stackTrace array must contain the following properties:
https://www.selenium.dev/documentation/_print/ 341/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
fileName string The name of the source file containing the line represented by this
frame.
className string The fully qualified class name for the class active in this frame. If the
class name cannot be determined, or is not applicable for the language
the server is implemented in, then this property should be set to the
empty string.
methodName string The name of the method active in this frame, or the empty string if
unknown/not applicable.
lineNumber number The line number in the original source file for the frame, or 0 if
unknown.
Resource Mapping
Resources in the WebDriver REST service are mapped to individual URL patterns. Each resource may
respond to one or more HTTP request methods. If a resource responds to a GET request, then it should
also respond to HEAD requests. All resources should respond to OPTIONS requests with an Allow
header field, whose value is a list of all methods that resource responds to.
If a resource is mapped to a URL containing a variable path segment name, that path segment should be
used to further route the request. Variable path segments are indicated in the resource mapping by a
colon-prefix. For example, consider the following:
/favorite/color/:person
A resource mapped to this URL should parse the value of the :person path segment to further
determine how to respond to the request. If this resource received a request for
/favorite/color/Jack , then it should return Jack’s favorite color. Likewise, the server should return
Jill’s favorite color for any requests to /favorite/color/Jill .
Two resources may only be mapped to the same URL pattern if one of those resources’ patterns
contains variable path segments, and the other does not. In these cases, the server should always route
requests to the resource whose path is the best match for the request. Consider the following two
resource paths:
1. /session/:sessionId/element/active
2. /session/:sessionId/element/:id
Given these mappings, the server should always route requests whose final path segment is active to
the first resource. All other requests should be routed to second.
Command Reference
Command Summary
HTTP
Method Path Summary
https://www.selenium.dev/documentation/_print/ 342/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
HTTP
Method Path Summary
https://www.selenium.dev/documentation/_print/ 343/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
HTTP
Method Path Summary
https://www.selenium.dev/documentation/_print/ 344/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
HTTP
Method Path Summary
https://www.selenium.dev/documentation/_print/ 345/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
HTTP
Method Path Summary
https://www.selenium.dev/documentation/_print/ 346/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
HTTP
Method Path Summary
Command Detail
/status
GET /status
Query the server's current status. The server should respond with a general "HTTP 200 OK" response if
it is alive and accepting commands. The response body should be a JSON object describing the state of
the server. All server implementations should return two basic objects describing the server's current
platform and when the server was built. All fields are optional; if omitted, the client should assume the
value is uknown. Furthermore, server implementations may include additional fields not listed here.
build object
build.revision string The revision of the local source control client from which the server was
built
os object
os.name string The name of the operating system the server is currently running on:
"windows", "linux", etc.
https://www.selenium.dev/documentation/_print/ 347/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Returns:
{object} An object describing the general status of the server.
/session
POST /session
Create a new session. The server should attempt to create a session that most closely matches the
desired and required capabilities. Required capabilities have higher priority than desired capabilities and
must be set for the session to be created.
JSON Parameters:
desiredCapabilities - {object} An object describing the session's desired capabilities.
Returns:
{object} An object describing the session's capabilities.
Potential Errors:
SessionNotCreatedException - If a required capability could not be set.
/sessions
GET /sessions
Returns a list of the currently active sessions. Each session will be returned as a list of JSON objects with
the following keys:
Returns:
{Array.<Object>} A list of the currently active sessions.
/session/:sessionId
GET /session/:sessionId
Retrieve the capabilities of the specified session.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{object} An object describing the session's capabilities.
DELETE /session/:sessionId
Delete the session.
URL Parameters:
:sessionId - ID of the session to route the command to.
/session/:sessionId/timeouts
POST /session/:sessionId/timeouts
Configure the amount of time that a particular type of operation can execute for before they are aborted
and a |Timeout| error is returned to the client.
URL Parameters:
:sessionId - ID of the session to route the command to.
https://www.selenium.dev/documentation/_print/ 348/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
JSON Parameters:
type - {string} The type of operation to set the timeout for. Valid values are: "script" for script
timeouts, "implicit" for modifying the implicit wait timeout and "page load" for setting a page load
timeout.
ms - {number} The amount of time, in milliseconds, that time-limited commands are permitted to run.
/session/:sessionId/timeouts/async_script
POST /session/:sessionId/timeouts/async_script
Set the amount of time, in milliseconds, that asynchronous scripts executed by
/session/:sessionId/execute_async are permitted to run before they are aborted and a |Timeout|
error is returned to the client.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
ms - {number} The amount of time, in milliseconds, that time-limited commands are permitted to run.
/session/:sessionId/timeouts/implicit_wait
POST /session/:sessionId/timeouts/implicit_wait
Set the amount of time the driver should wait when searching for elements. When
searching for a single element, the driver should poll the page until an element is found or
the timeout expires, whichever occurs first. When searching for multiple elements, the driver
should poll the page until at least one element is found or the timeout expires, at which point
it should return an empty list.
If this command is never sent, the driver should default to an implicit wait of 0ms.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
ms - {number} The amount of time to wait, in milliseconds. This value has a lower bound of 0.
/session/:sessionId/window_handle
GET /session/:sessionId/window_handle
Retrieve the current window handle.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The current window handle.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/window_handles
GET /session/:sessionId/window_handles
Retrieve the list of all window handles available to the session.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{Array.<string>} A list of window handles.
https://www.selenium.dev/documentation/_print/ 349/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
/session/:sessionId/url
GET /session/:sessionId/url
Retrieve the URL of the current page.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The current URL.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
POST /session/:sessionId/url
Navigate to a new URL.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
url - {string} The URL to navigate to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/forward
POST /session/:sessionId/forward
Navigate forwards in the browser history, if possible.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/back
POST /session/:sessionId/back
Navigate backwards in the browser history, if possible.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/refresh
POST /session/:sessionId/refresh
Refresh the current page.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/execute
POST /session/:sessionId/execute
Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.
The executed script is assumed to be synchronous and the result of evaluating the script is returned to
https://www.selenium.dev/documentation/_print/ 350/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
the client.
The script argument defines the script to execute in the form of a function body. The value returned by
that function will be returned to the client. The function will be invoked with the provided args array
and the values may be accessed via the arguments object in the order specified.
Arguments may be any JSON-primitive, array, or JSON object. JSON objects that define a WebElement
reference will be converted to the corresponding DOM element. Likewise, any WebElements in the
script result will be returned to the client as WebElement JSON objects.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
script - {string} The script to execute.
Returns:
{*} The script result.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If one of the script arguments is a WebElement that is not attached to the
page's DOM.
JavaScriptError - If the script throws an Error.
/session/:sessionId/execute_async
POST /session/:sessionId/execute_async
Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.
The executed script is assumed to be asynchronous and must signal that is done by invoking the
provided callback, which is always provided as the final argument to the function. The value to this
callback will be returned to the client.
Asynchronous script commands may not span page loads. If an unload event is fired while waiting for a
script result, an error should be returned to the client.
The script argument defines the script to execute in teh form of a function body. The function will be
invoked with the provided args array and the values may be accessed via the arguments object in the
order specified. The final argument will always be a callback function that must be invoked to signal that
the script has finished.
Arguments may be any JSON-primitive, array, or JSON object. JSON objects that define a WebElement
reference will be converted to the corresponding DOM element. Likewise, any WebElements in the
script result will be returned to the client as WebElement JSON objects.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
script - {string} The script to execute.
Returns:
{*} The script result.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If one of the script arguments is a WebElement that is not attached to the
page's DOM.
Timeout - If the script callback is not invoked before the timout expires. Timeouts are controlled by the
/session/:sessionId/timeout/async_script command.
https://www.selenium.dev/documentation/_print/ 351/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
JavaScriptError - If the script throws an Error or if an unload event is fired while waiting for the script
to finish.
/session/:sessionId/screenshot
GET /session/:sessionId/screenshot
Take a screenshot of the current page.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The screenshot as a base64 encoded PNG.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/ime/available_engines
GET /session/:sessionId/ime/available_engines
List all available engines on the machine. To use an engine, it has to be present in this list.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{Array.<string>} A list of available engines
Potential Errors:
ImeNotAvailableException - If the host does not support IME
/session/:sessionId/ime/active_engine
GET /session/:sessionId/ime/active_engine
Get the name of the active IME engine. The name string is platform specific.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The name of the active IME engine.
Potential Errors:
ImeNotAvailableException - If the host does not support IME
/session/:sessionId/ime/activated
GET /session/:sessionId/ime/activated
Indicates whether IME input is active at the moment (not if it's available.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{boolean} true if IME input is available and currently active, false otherwise
Potential Errors:
ImeNotAvailableException - If the host does not support IME
/session/:sessionId/ime/deactivate
POST /session/:sessionId/ime/deactivate
https://www.selenium.dev/documentation/_print/ 352/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Potential Errors:
ImeNotAvailableException - If the host does not support IME
/session/:sessionId/ime/activate
POST /session/:sessionId/ime/activate
Make an engines that is available (appears on the list
returned by getAvailableEngines) active. After this call, the engine will
be added to the list of engines loaded in the IME daemon and the input sent
using sendKeys will be converted by the active engine.
Note that this is a platform-independent method of activating IME
(the platform-specific way being using keyboard shortcuts
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
engine - {string} Name of the engine to activate.
Potential Errors:
ImeActivationFailedException - If the engine is not available or if the activation fails for other
reasons.
ImeNotAvailableException - If the host does not support IME
/session/:sessionId/frame
POST /session/:sessionId/frame
Change focus to another frame on the page. If the frame id is null, the server
should switch to the page's default content.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
id - {string|number|null|WebElement JSON Object} Identifier for the frame to change focus to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/frame/parent
POST /session/:sessionId/frame/parent
Change focus to the parent context. If the current context is the top level browsing context, the context
remains unchanged.
URL Parameters:
:sessionId - ID of the session to route the command to.
/session/:sessionId/window
POST /session/:sessionId/window
Change focus to another window. The window to change focus to may be specified by its
server assigned window handle, or by the value of its name attribute.
URL Parameters:
:sessionId - ID of the session to route the command to.
https://www.selenium.dev/documentation/_print/ 353/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
JSON Parameters:
name - {string} The window to change focus to.
Potential Errors:
NoSuchWindow - If the window specified by name cannot be found.
DELETE /session/:sessionId/window
Close the current window.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window is already closed
/session/:sessionId/window/:windowHandle/size
POST /session/:sessionId/window/:windowHandle/size
Change the size of the specified window. If the :windowHandle URL parameter is "current", the currently
active window will be resized.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
width - {number} The new window width.
GET /session/:sessionId/window/:windowHandle/size
Get the size of the specified window. If the :windowHandle URL parameter is "current", the size of the
currently active window will be returned.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{width: number, height: number} The size of the window.
Potential Errors:
NoSuchWindow - If the specified window cannot be found.
/session/:sessionId/window/:windowHandle/position
POST /session/:sessionId/window/:windowHandle/position
Change the position of the specified window. If the :windowHandle URL parameter is "current", the
currently active window will be moved.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
x - {number} The X coordinate to position the window at, relative to the upper left corner of the screen.
y - {number} The Y coordinate to position the window at, relative to the upper left corner of the screen.
Potential Errors:
NoSuchWindow - If the specified window cannot be found.
GET /session/:sessionId/window/:windowHandle/position
Get the position of the specified window. If the :windowHandle URL parameter is "current", the position
of the currently active window will be returned.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
https://www.selenium.dev/documentation/_print/ 354/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
{x: number, y: number} The X and Y coordinates for the window, relative to the upper left corner of
the screen.
Potential Errors:
NoSuchWindow - If the specified window cannot be found.
/session/:sessionId/window/:windowHandle/maximize
POST /session/:sessionId/window/:windowHandle/maximize
Maximize the specified window if not already maximized. If the :windowHandle URL parameter is
"current", the currently active window will be maximized.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the specified window cannot be found.
/session/:sessionId/cookie
GET /session/:sessionId/cookie
Retrieve all cookies visible to the current page.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{Array.<object>} A list of cookies.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
POST /session/:sessionId/cookie
Set a cookie. If the cookie path is not specified, it should be set to "/". Likewise, if the domain is omitted,
it should default to the current page's domain.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
cookie - {object} A JSON object defining the cookie to add.
DELETE /session/:sessionId/cookie
Delete all cookies visible to the current page.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
InvalidCookieDomain - If the cookie's domain is not visible from the current page.
UnableToSetCookie - If attempting to set a cookie on a page that does not support cookies (e.g. pages
with mime-type text/plain).
/session/:sessionId/cookie/:name
DELETE /session/:sessionId/cookie/:name
Delete the cookie with the given name. This command should be a no-op if there is no
such cookie visible to the current page.
URL Parameters:
:sessionId - ID of the session to route the command to.
https://www.selenium.dev/documentation/_print/ 355/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/source
GET /session/:sessionId/source
Get the current page source.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The current page source.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/title
GET /session/:sessionId/title
Get the current page title.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The current page title.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/element
POST /session/:sessionId/element
Search for an element on the page, starting from the document root. The located element will be
returned as a WebElement JSON object. The table below lists the locator strategies that each server
should support. Each locator must return the first matching element located in the DOM.
Strategy Description
class name Returns an element whose class name contains the search value; compound class
names are not permitted.
name Returns an element whose NAME attribute matches the search value.
link text Returns an anchor element whose visible text matches the search value.
partial link Returns an anchor element whose visible text partially matches the search value.
text
tag name Returns an element whose tag name matches the search value.
URL Parameters:
:sessionId - ID of the session to route the command to.
https://www.selenium.dev/documentation/_print/ 356/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
JSON Parameters:
using - {string} The locator strategy to use.
Returns:
{ELEMENT:string} A WebElement JSON object for the located element.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/elements
POST /session/:sessionId/elements
Search for multiple elements on the page, starting from the document root. The located elements will be
returned as a WebElement JSON objects. The table below lists the locator strategies that each server
should support. Elements should be returned in the order located in the DOM.
Strategy Description
class name Returns all elements whose class name contains the search value; compound class
names are not permitted.
name Returns all elements whose NAME attribute matches the search value.
link text Returns all anchor elements whose visible text matches the search value.
partial link Returns all anchor elements whose visible text partially matches the search value.
text
tag name Returns all elements whose tag name matches the search value.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
using - {string} The locator strategy to use.
Returns:
{Array.<{ELEMENT:string}>} A list of WebElement JSON objects for the located elements.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/element/active
POST /session/:sessionId/element/active
Get the element on the page that currently has focus. The element will be returned as a WebElement
JSON object.
URL Parameters:
https://www.selenium.dev/documentation/_print/ 357/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Returns:
{ELEMENT:string} A WebElement JSON object for the active element.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/element/:id
GET /session/:sessionId/element/:id
Describe the identified element.
Note: This command is reserved for future use; its return type is currently undefined.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/element
POST /session/:sessionId/element/:id/element
Search for an element on the page, starting from the identified element. The located element will be
returned as a WebElement JSON object. The table below lists the locator strategies that each server
should support. Each locator must return the first matching element located in the DOM.
Strategy Description
class Returns an element whose class name contains the search value; compound class
name names are not permitted.
name Returns an element whose NAME attribute matches the search value.
link text Returns an anchor element whose visible text matches the search value.
partial link Returns an anchor element whose visible text partially matches the search value.
text
tag name Returns an element whose tag name matches the search value.
xpath Returns an element matching an XPath expression. The provided XPath expression
must be applied to the server "as is"; if the expression is not relative to the element
root, the server should not modify it. Consequently, an XPath query may return
elements not contained in the root element's subtree.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
using - {string} The locator strategy to use.
https://www.selenium.dev/documentation/_print/ 358/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Returns:
{ELEMENT:string} A WebElement JSON object for the located element.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/elements
POST /session/:sessionId/element/:id/elements
Search for multiple elements on the page, starting from the identified element. The located elements
will be returned as a WebElement JSON objects. The table below lists the locator strategies that each
server should support. Elements should be returned in the order located in the DOM.
Strategy Description
class Returns all elements whose class name contains the search value; compound class
name names are not permitted.
name Returns all elements whose NAME attribute matches the search value.
link text Returns all anchor elements whose visible text matches the search value.
partial link Returns all anchor elements whose visible text partially matches the search value.
text
tag name Returns all elements whose tag name matches the search value.
xpath Returns all elements matching an XPath expression. The provided XPath expression
must be applied to the server "as is"; if the expression is not relative to the element
root, the server should not modify it. Consequently, an XPath query may return
elements not contained in the root element's subtree.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
using - {string} The locator strategy to use.
Returns:
{Array.<{ELEMENT:string}>} A list of WebElement JSON objects for the located elements.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/click
POST /session/:sessionId/element/:id/click
https://www.selenium.dev/documentation/_print/ 359/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Click on an element.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
ElementNotVisible - If the referenced element is not visible on the page (either is hidden by CSS, has
0-width, or has 0-height)
/session/:sessionId/element/:id/submit
POST /session/:sessionId/element/:id/submit
Submit a FORM element. The submit command may also be applied to any element that is a descendant
of a FORM element.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/text
GET /session/:sessionId/element/:id/text
Returns the visible text for the element.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/value
POST /session/:sessionId/element/:id/value
Send a sequence of key strokes to an element.
Any UTF-8 character may be specified, however, if the server does not support native key events, it
should simulate key strokes for a standard US keyboard layout. The Unicode Private Use Area code
points, 0xE000-0xF8FF, are used to represent pressable, non-text keys (see table below).
https://www.selenium.dev/documentation/_print/ 360/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Each key that appears on the keyboard without requiring modifiers are sent as a keydown
followed by a key up.
If the server does not support native events and must simulate key strokes with JavaScript, it must
generate keydown, keypress, and keyup events, in that order. The keypress event should only be
fired when the corresponding key is for a printable character.
If a key requires a modifier key (e.g. "!" on a standard US keyboard), the sequence is: modifier
down, key down, key up, modifier up, where key is the ideal unmodified key value (using the
previous example, a "1").
Modifier keys (Ctrl, Shift, Alt, and Command/Meta) are assumed to be "sticky"; each modifier
should be held down (e.g. only a keydown event) until either the modifier is encountered again in
the sequence, or the NULL (U+E000) key is encountered.
Each key sequence is terminated with an implicit NULL key. Subsequently, all depressed modifier
keys must be released (with corresponding keyup events) at the end of the sequence.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
value - {Array.<string>} The sequence of keys to type. An array must be provided. The server should
flatten the array items to a single string to be typed.
https://www.selenium.dev/documentation/_print/ 361/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
ElementNotVisible - If the referenced element is not visible on the page (either is hidden by CSS, has
0-width, or has 0-height)
/session/:sessionId/keys
POST /session/:sessionId/keys
Send a sequence of key strokes to the active element. This command is similar to the send keys
command in every aspect except the implicit termination: The modifiers are not released at the end of
the call. Rather, the state of the modifier keys is kept between calls, so mouse interactions can be
performed while modifier keys are depressed.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
value - {Array.<string>} The keys sequence to be sent. The sequence is defined in thesend keys
command.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/element/:id/name
GET /session/:sessionId/element/:id/name
Query for an element's tag name.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The element's tag name, as a lowercase string.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/clear
POST /session/:sessionId/element/:id/clear
Clear a TEXTAREA or text INPUT element's value.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
ElementNotVisible - If the referenced element is not visible on the page (either is hidden by CSS, has
0-width, or has 0-height)
InvalidElementState - If the referenced element is disabled.
/session/:sessionId/element/:id/selected
GET /session/:sessionId/element/:id/selected
https://www.selenium.dev/documentation/_print/ 362/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Returns:
{boolean} Whether the element is selected.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/enabled
GET /session/:sessionId/element/:id/enabled
Determine if an element is currently enabled.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{boolean} Whether the element is enabled.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/attribute/:name
GET /session/:sessionId/element/:id/attribute/:name
Get the value of an element's attribute.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string|null} The value of the attribute, or null if it is not set on the element.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/equals/:other
GET /session/:sessionId/element/:id/equals/:other
Test if two element IDs refer to the same DOM element.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{boolean} Whether the two IDs refer to the same element.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
https://www.selenium.dev/documentation/_print/ 363/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
StaleElementReference - If either the element refered to by :id or :other is no longer attached to the
page's DOM.
/session/:sessionId/element/:id/displayed
GET /session/:sessionId/element/:id/displayed
Determine if an element is currently displayed.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{boolean} Whether the element is displayed.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/location
GET /session/:sessionId/element/:id/location
Determine an element's location on the page. The point (0, 0) refers to the upper-left corner of the
page. The element's coordinates are returned as a JSON object with x and y properties.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{x:number, y:number} The X and Y coordinates for the element on the page.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/location_in_view
GET /session/:sessionId/element/:id/location_in_view
Determine an element's location on the screen once it has been scrolled into view.
Note: This is considered an internal command and should only be used to determine an element's
location for correctly generating native events.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{x:number, y:number} The X and Y coordinates for the element.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/size
GET /session/:sessionId/element/:id/size
Determine an element's size in pixels. The size will be returned as a JSON object with width and height
properties.
https://www.selenium.dev/documentation/_print/ 364/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{width:number, height:number} The width and height of the element, in pixels.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/element/:id/css/:propertyName
GET /session/:sessionId/element/:id/css/:propertyName
Query the value of an element's computed CSS property. The CSS property to query should be specified
using the CSS property name, not the JavaScript property name (e.g. background-color instead of
backgroundColor).
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The value of the specified CSS property.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
StaleElementReference - If the element referenced by :id is no longer attached to the page's DOM.
/session/:sessionId/orientation
GET /session/:sessionId/orientation
Get the current browser orientation. The server should return a valid orientation value as defined in
ScreenOrientation: {LANDSCAPE|PORTRAIT}.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The current browser orientation corresponding to a value defined in ScreenOrientation:
{LANDSCAPE|PORTRAIT}.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
POST /session/:sessionId/orientation
Set the browser orientation. The orientation should be specified as defined in ScreenOrientation:
{LANDSCAPE|PORTRAIT}.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
orientation - {string} The new browser orientation as defined in ScreenOrientation:
{LANDSCAPE|PORTRAIT}.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/alert_text
GET /session/:sessionId/alert_text
Gets the text of the currently displayed JavaScript alert(), confirm(), or prompt() dialog.
https://www.selenium.dev/documentation/_print/ 365/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{string} The text of the currently displayed alert.
Potential Errors:
NoAlertPresent - If there is no alert displayed.
POST /session/:sessionId/alert_text
Sends keystrokes to a JavaScript prompt() dialog.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
text - {string} Keystrokes to send to the prompt() dialog.
Potential Errors:
NoAlertPresent - If there is no alert displayed.
/session/:sessionId/accept_alert
POST /session/:sessionId/accept_alert
Accepts the currently displayed alert dialog. Usually, this is equivalent to clicking on the 'OK' button in
the dialog.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoAlertPresent - If there is no alert displayed.
/session/:sessionId/dismiss_alert
POST /session/:sessionId/dismiss_alert
Dismisses the currently displayed alert dialog. For confirm() and prompt() dialogs, this is equivalent to
clicking the 'Cancel' button. For alert() dialogs, this is equivalent to clicking the 'OK' button.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoAlertPresent - If there is no alert displayed.
/session/:sessionId/moveto
POST /session/:sessionId/moveto
Move the mouse by an offset of the specificed element. If no element is specified, the move is relative to
the current mouse cursor. If an element is provided but no offset, the mouse will be moved to the center
of the element. If the element is not visible, it will be scrolled into view.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
element - {string} Opaque ID assigned to the element to move to, as described in the WebElement
JSON Object. If not specified or is null, the offset is relative to current position of the mouse.
xoffset - {number} X offset to move to, relative to the top-left corner of the element. If not specified,
the mouse will move to the middle of the element.
yoffset - {number} Y offset to move to, relative to the top-left corner of the element. If not specified,
the mouse will move to the middle of the element.
https://www.selenium.dev/documentation/_print/ 366/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
/session/:sessionId/click
POST /session/:sessionId/click
Click any mouse button (at the coordinates set by the last moveto command). Note that calling this
command after calling buttondown and before calling button up (or any out-of-order interactions
sequence) will yield undefined behaviour).
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
button - {number} Which button, enum: {LEFT = 0, MIDDLE = 1 , RIGHT = 2}. Defaults to the left
mouse button if not specified.
/session/:sessionId/buttondown
POST /session/:sessionId/buttondown
Click and hold the left mouse button (at the coordinates set by the last moveto command). Note that the
next mouse-related command that should follow is buttonup . Any other mouse command (such as click
or another call to buttondown) will yield undefined behaviour.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
button - {number} Which button, enum: {LEFT = 0, MIDDLE = 1 , RIGHT = 2}. Defaults to the left
mouse button if not specified.
/session/:sessionId/buttonup
POST /session/:sessionId/buttonup
Releases the mouse button previously held (where the mouse is currently at). Must be called once for
every buttondown command issued. See the note in click and buttondown about implications of out-of-
order commands.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
button - {number} Which button, enum: {LEFT = 0, MIDDLE = 1 , RIGHT = 2}. Defaults to the left
mouse button if not specified.
/session/:sessionId/doubleclick
POST /session/:sessionId/doubleclick
Double-clicks at the current mouse coordinates (set by moveto).
URL Parameters:
:sessionId - ID of the session to route the command to.
/session/:sessionId/touch/click
POST /session/:sessionId/touch/click
Single tap on the touch enabled device.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
element - {string} ID of the element to single tap on.
/session/:sessionId/touch/down
https://www.selenium.dev/documentation/_print/ 367/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
POST /session/:sessionId/touch/down
Finger down on the screen.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
x - {number} X coordinate on the screen.
/session/:sessionId/touch/up
POST /session/:sessionId/touch/up
Finger up on the screen.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
x - {number} X coordinate on the screen.
session/:sessionId/touch/move
POST session/:sessionId/touch/move
Finger move on the screen.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
x - {number} X coordinate on the screen.
session/:sessionId/touch/scroll
POST session/:sessionId/touch/scroll
Scroll on the touch screen using finger based motion events. Use this command to start scrolling at a
particular screen location.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
element - {string} ID of the element where the scroll starts.
session/:sessionId/touch/scroll
POST session/:sessionId/touch/scroll
Scroll on the touch screen using finger based motion events. Use this command if you don't care where
the scroll starts on the screen.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
xoffset - {number} The x offset in pixels to scrollby.
https://www.selenium.dev/documentation/_print/ 368/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
session/:sessionId/touch/doubleclick
POST session/:sessionId/touch/doubleclick
Double tap on the touch screen using finger motion events.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
element - {string} ID of the element to double tap on.
session/:sessionId/touch/longclick
POST session/:sessionId/touch/longclick
Long press on the touch screen using finger motion events.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
element - {string} ID of the element to long press on.
session/:sessionId/touch/flick
POST session/:sessionId/touch/flick
Flick on the touch screen using finger motion events. This flickcommand starts at a particulat screen
location.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
element - {string} ID of the element where the flick starts.
session/:sessionId/touch/flick
POST session/:sessionId/touch/flick
Flick on the touch screen using finger motion events. Use this flick command if you don't care where the
flick starts on the screen.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
xspeed - {number} The x speed in pixels per second.
/session/:sessionId/location
GET /session/:sessionId/location
Get the current geo location.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{latitude: number, longitude: number, altitude: number} The current geo location.
https://www.selenium.dev/documentation/_print/ 369/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
POST /session/:sessionId/location
Set the current geo location.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
location - {latitude: number, longitude: number, altitude: number} The new location.
/session/:sessionId/local_storage
GET /session/:sessionId/local_storage
Get all keys of the storage.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{Array.<string>} The list of keys.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
POST /session/:sessionId/local_storage
Set the storage item for the given key.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
key - {string} The key to set.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
DELETE /session/:sessionId/local_storage
Clear the storage.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/local_storage/key/:key
GET /session/:sessionId/local_storage/key/:key
Get the storage item for the given key.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
DELETE /session/:sessionId/local_storage/key/:key
Remove the storage item for the given key.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
https://www.selenium.dev/documentation/_print/ 370/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
/session/:sessionId/local_storage/size
GET /session/:sessionId/local_storage/size
Get the number of items in the storage.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{number} The number of items in the storage.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/session_storage
GET /session/:sessionId/session_storage
Get all keys of the storage.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{Array.<string>} The list of keys.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
POST /session/:sessionId/session_storage
Set the storage item for the given key.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
key - {string} The key to set.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
DELETE /session/:sessionId/session_storage
Clear the storage.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/session_storage/key/:key
GET /session/:sessionId/session_storage/key/:key
Get the storage item for the given key.
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
DELETE /session/:sessionId/session_storage/key/:key
Remove the storage item for the given key.
https://www.selenium.dev/documentation/_print/ 371/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
URL Parameters:
:sessionId - ID of the session to route the command to.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/session_storage/size
GET /session/:sessionId/session_storage/size
Get the number of items in the storage.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{number} The number of items in the storage.
Potential Errors:
NoSuchWindow - If the currently selected window has been closed.
/session/:sessionId/log
POST /session/:sessionId/log
Get the log for a given log type. Log buffer is reset after each request.
URL Parameters:
:sessionId - ID of the session to route the command to.
JSON Parameters:
type - {string} The log type. This must be provided.
Returns:
{Array.<object>} The list of log entries.
/session/:sessionId/log/types
GET /session/:sessionId/log/types
Get available log types.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{Array.<string>} The list of available log types.
/session/:sessionId/application_cache/status
GET /session/:sessionId/application_cache/status
Get the status of the html5 application cache.
URL Parameters:
:sessionId - ID of the session to route the command to.
Returns:
{number} Status code for application cache: {UNCACHED = 0, IDLE = 1, CHECKING = 2, DOWNLOADING
= 3, UPDATE_READY = 4, OBSOLETE = 5}
https://www.selenium.dev/documentation/_print/ 372/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Grid Specific
Key Type Description
Selenium RC Specific
Key Type Description
https://www.selenium.dev/documentation/_print/ 373/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
dontInjectRegex javascript Regular expression that proxy injection mode can use to
RegExp know when to bypss injection. Ignored if not in proxy
injection mode.
userJSInjection boolean ??? Whether to inject user JS. Ignored if not in proxy
injection mode.
Selenese-Backed-WebDriver specific
Key Type Description
Firefox specific
Key Type Description
FirefoxProfile settings
Preferences accepted by the FirefoxProfile with special meaning, in the WebDriver API:
https://www.selenium.dev/documentation/_print/ 374/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
IE specific
Key Type Description
killProcessesByName boolean Whether to try to kill processes by name, instead (or addition) to
killing processes we happen to have handles to.
ensureCleanSession boolean Whether to make sure the session has no cookies or temporary
internet files on Windows. I believe this is passed to the IEDriver
as well, but ignored by it.
Safari specific
Key Type Description
ensureCleanSession boolean Whether to make sure the session has no cookies, cache entries.
And that any registry and proxy settings are restored after the
session.
https://www.selenium.dev/documentation/_print/ 375/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
WebDriver is a large project: if we tried to push everything into a single monolithic build file it eventually
becomes unmanageable. We know this. We’ve tried it. So we broke the single Rakefile into a series of
build.desc files. Each of these describe a part of the build.
Let’s take a look at a build.desc file. This is part of the main test build.desc:
java_test(name = "single",
srcs = [
"SingleTestSuite.java",
],
deps = [
":tests",
"//java/server/src/org/openqa/selenium/server",
"//java/client/test/org/openqa/selenium/v1:selenium-backed-webdriver-test",
"//java/client/test/org/openqa/selenium/firefox:test",
] ])
Targets
This highlights most of the key concepts. Firstly, it declares target, in this case there is a single
java_test target. Each target has a name attribute.
Target Names
The combination of the location of the “build.desc” file and the name are used to derive the rake tasks
that are generated. All task names are prefixed with “//” followed by the path to the directory containing
the “build.desc” file relative to the Rakefile , followed by a “:” and then the name of the target within
the “build.desc”. An example makes this far clearer :)
Implicit Targets
Some build rules supply implicit targets, and provide related extensions to a normal build target.
Examples include generating archives of source code, or running tests. These are declared by appending
a further colon and the name of the implicit target to the full name of a build rule. In our example, you
could run the tests using “//java/client/test/org/openqa/selenium:single:run”
Each of the rules described below have a list of implicit targets that are associated with them.
https://www.selenium.dev/documentation/_print/ 376/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Outputs
Each target specified in a “build.desc” file produces one and only one output. This is important. Keep it in
mind. Generally, all output files are placed in the “build” directory, relative to the rake task name. In our
example, the output of “//java/org/openqa/selenium/server” would be found in
“build/java/org/openqa/selenium/server.jar”. Build rules should output the names and locations of any
files that they generate.
Dependencies
Take a look at the “deps” section of the “single” target above. The ":tests" is a reference to a target in
the current “build.desc” file, in this case, it’s a “java_library” target immediately above. You’ll also see
that there’s a reference to several full paths. For example
"//java/server/src/org/openqa/selenium/server" This refers to another target defined in a crazy
fun build.desc file.
Browsers
The py_test and js_test rules have special handling for running the same tests in multiple browsers.
Relevant browser-specific meta-data is held in rake-tasks/browsers.rb. The general way to use this is to
append _ browsername to the target name; without the _ browsername suffix, the tests will be run
for all browsers.
As an example, if we had a js_test rule //foo/bar, we would run its tests in firefox by running the target
//foo/bar_ff:run or we would run in all available browsers by running the target //foo/bar:run
Build Targets
You can list all the build targets using the -T option. e.g.
./go -T
Being a brief description of the available targets that you can use.
Common Attributes
The following attributes are required for all build targets:
Attribute
Name Type Meaning
name string Used to derive the rake target and (often) the name of the generated
binary
java_library
Output: JAR file named after the “name” attribute if the “srcs” attribute is set.
Implicit Targets: run (if “main” attribute specifiec), project, project-srcs, uber, zip
Required Attributes: “name” and at least one of “srcs” or “deps”.
https://www.selenium.dev/documentation/_print/ 377/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Attribute
Name Type Meaning
resources array Any resources that should be copied into the jar file.
main string The full classname of the main class of the jar (used for creating
executable jars)
java_test
Output: JAR file named after the “name” attribute if the “srcs” attribute is set.
Implicit Targets: run, project, project-srcs, uber, zip
Required Attributes: “name” and at least one of “srcs” or “deps”.
resources array Any resources that should be copied into the jar file.
main string The alternative class to use for running these tests.
sysproperties array An array of maps containing System properties that should be set
js_deps
Output: Marker file to indicate task is up to date.
Implicit Targets: None
Required Attributes: “name” and “srcs”
js_binary
Output: A monolithic JS file containing all dependencies and sources compiled using the closure
compiler without optimizations.
Implicit Targets: None
Required Attributes: At least one of srcs or deps.
https://www.selenium.dev/documentation/_print/ 378/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
js_fragment
Output: Source of an anonymous function representing the exported function, compiled by the
closure compiler with all optimizations turned on.
Implicit Targets: None
Required Attributes: name, module, function, deps
js_fragment_header
Output: A C header file with all js_fragment dependencies declared as constants.
Implicit Targets: None
Required Attributes: name, deps
js_test
Output:
Implicit Targets: _ BROWSER:run, run
Required Attributes: None.
Attribute
Name Type Meaning
path string The path at which to expect the test files to be hosted on the test server.
browsers array List of browsers, from rake_tasks/browsers.rb, to run the tests in. Will only
attempt to run tests in those browsers which are available on the system. If
absent, defaults to all browsers on the system.
Assuming browsers = [‘ff’, ‘chrome’], for target //foo, the implicit targets: //foo_ff:run and
//foo_chrome:run will be generated, which run the tests in each of those browsers, and the implicit
target //foo:run will be generated, which runs the tests in both ff and chrome.
https://www.selenium.dev/documentation/_print/ 379/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
py_test
Output: Creates the directory structure required to run the listed python tests.
Implicit Targets: _ BROWSER:run, run
Required Attributes: name.
deps array Other py_test rule(s), whose tests should also be run.
common_tests array Test file(s) to be run in all browsers. These tests will be passed
through a template, with browser-specific substitutions, so
that they are laid out properly for each browser in the python
output file tree.
rake_task
Output: A crazy fun build rule that can be referred to “blow the escape” hatch and use ordinary
rake targets.
Implicit Targets: None
Required Attributes: name, task_name, out.
gcc_library
Output: Shared library file named after the “name” attribute if the “srcs” attribute is set.
Implicit Targets: None.
Required Attributes: “name” and “srcs”.
arch string “amd64” for 64-bit builds, “i386” for 32-bit builds.
Note: When building a new library for the first time, the build will succeed but copying to pre-built will
fail with a similar message:
https://www.selenium.dev/documentation/_print/ 380/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
cp build/cpp/amd64/libimetesthandler64.so
go aborted!
can't convert nil into String
Solution: Copy the just-built library to the appropriate prebuilt folder (cpp/prebuilt/arch/).
https://www.selenium.dev/documentation/_print/ 381/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Checkout the source to Buck and build the PEX: buck build --show-output buck
Figure out the git hash of the version you’ve just built. Normally that’ll be the HEAD of master. Put
that full hash into the .buckversion of the main selenium project.
Put the md5 hash of the PEX into the .buckhash file in the main selenium project.
Create a new release of SeleniumHQ’s Buck fork on GitHub. The name is buck-
release-$VERSION , where $VERSION is whatever’s in .buckversion in the main selenium
project.
Upload the PEX to the release, and make the release public.
Commit the changes to the main selenium project and push them.
https://www.selenium.dev/documentation/_print/ 382/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
WebDriver has a comprehensive suite of tests that describe the expected behavior of a new
implementation. We’ll assume that you’re implementing the driver in Java for the sake of simplicity, but
you can take a look at any of the existing implementations for how we handle more complex builds or
other languages once you’ve read this.
Once you’ve added the test suite, add a “build.desc” CrazyFunBuild file in the top level of your project.
Model it after the one in the “htmlunit” directory. You should then be able to run your tests from the
command line using the “go” script.
At this point, we expect total and catastrophic failure when tests are being run.
Start Implementing
If your browser runs out of process, it is strongly encouraged to make use of the JsonWireProtocol. This
will make the client-side (the APIs that users use) relatively cheap to implement, and means that you
get Java, C#, Ruby and Python support for significantly less effort since you can extend the remote
client.
Implementation Tips
Where to Start
As mentioned, has a suite of tests. The suggested order to make these pass is roughly:
At this point, you’ll have a reasonably complete working driver. After that, it’s probably best to get the
user interactions correct:
https://www.selenium.dev/documentation/_print/ 383/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
1. CorrectEventFiringTest
2. TypingTest
1. AlertsTest
It’s not necessary to get every test working in a class before moving on. I tend to go as far down a class
as I can, and then switch to the next class on the list when the going gets tough. This allows you to
maintain reasonable velocity and still cover the basics.
Ignoring Tests
At some point you’ll want to stop running tests on an ad-hoc basis and make use of a continuous build
product to ensure that you’re not introducing regressions. At this point, the process is to run the tests
from the command line. This will generate a list of failing tests. Go through each of these tests and add
or modify the “@Ignore” associated with the test. Re-run the tests. It may take a few iterations, but
your build will eventually go green. Nice.
The build makes use of ant behind the scenes and stores logs in “build/build_log.xml” and the test logs
in “build/test_logs”
https://www.selenium.dev/documentation/_print/ 384/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
General architecture
We have a number of Google Compute Engine virtual machines running Ubuntu, currently hosted at
{0..29}.ci.seleniumhq.org - they have publicly addressable DNS set up to point ab.
{0..29}.ci.seleniumhq.org pointing at them as well, so that cookie tests can do subdomain lookups.
One of these machines, ci.seleniumhq.org, is running jenkins. If you want a login on jenkins, get in touch
with juangj. The Build All Java job polls SCM for changes, and does the following:
Does a clean build of the ‘release’ target, any tests which are going to be run, and any artifacts
(e.g. the IEDriverServer executable) which will be required to run those tests
Tars up the entire built working directory and publishes it to http://ci.seleniumhq.org/selenium-
trunk-r${REVISION}.tgz - this is used later by test runs
Publishes the selenium-server-standalone jar to http://ci.seleniumhq.org/selenium-server-
standalone-r${REVISION}.tgz - this is copied down directly by SauceLabs when running tests.
Zips up the IEDriverServer and publishes it to http://ci.seleniumhq.org/IEDriverServer-Win32-
r${REVISION}.zip - this is copied down directly by SauceLabs to run IE tests This machine is backed
by a 1TB persistent disk, which can hold many build artifacts, but they should be cleared out
occasionally (particularly when moving disk between zones).
When this build is successful, it triggers downstream builds for each OS/browser/test combination we
care about. It also triggers a downstream clean build to ensure our maven poms are still in order
(“Maven build”).
Apart from “Maven build” which runs on the same build node as the compile (a beefy, 8-CPU machine
with 32GB RAM), all downstream builds run on separate build nodes.
The downstream builds are configured using environment variables, as per the SauceDriver class. The
downstream builds download the selenium-trunk tar from the build master, and then run tests (which
should already have been compiled by the Build All Java rule). Two of these downstream builds are
special; “HtmlUnit Java Tests” and “Small Tests” just run headless locally. The others use SauceLabs.
A note about networking: The build nodes are set up on an internal network 10.1.0/24, so network
communication between them is incredibly fast and free.
When a non-headless browser test is running, the test-file servlet hosts the test files on ports
determined by an environment variable (231${EXECUTOR_NUMBER} and 241${EXECUTOR_NUMBER} -
EXECUTOR_NUMBER is currently always equal to 0). The hostname used by tests is set by an
environment variable (ab.${NODE_NAME}.ci.seleniumhq.org where NODE_NAME in {0..29}). A browser
is requested from SauceLabs using our credentials (stored in jenkins-wide environment variables, set on
the System Configuration page). Jenkins is currently set to run three test-classes at a time in parallel, per
test run, again on the System Configuration page.
The tests are run, and the results get notified to IRC.
Thanks to SauceLabs and Google for donating the infrastructure to run all of these tests.
FAQ
https://www.selenium.dev/documentation/_print/ 385/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
I want to run my tests on Sauce like Jenkins does (my tests are failing
on CI, but work fine on my machine!)
See the SauceDriver page
Find the most similar config(s) you want to copy. If it’s a new Firefox release, find the latest firefox
(which should have roughly 6 builds associated with it: Javascript + Java {Windows,Linux} **
{Native,Synthesized}
For each of those builds, create a New Job (menu on the left hand side of the home page, when
logged in)
Name the job in the style of the others. Select “Copy existing job”, and enter the job you’re copying.
Scroll through the job it’s pre-populated. Replace the version numbers, browser name, and any
other details that need replacing. For firefox updates, there are currently three places you should
be replacing the number (the “browser_version” field, and two in the Build Execute Shell)
Save
Go to the Build All Java task, configure it, add your new build to the “Projects to build” field where
there are many others listed.**
If it’s a firefox update, you probably also want to delete an existing build.
https://www.selenium.dev/documentation/_print/ 386/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Google will pay successful student contributors a $5000 USD stipend, enabling them to focus on their
coding projects for three months. The deadline for application is April 8, 2011.
When participating in the Selenium - Google Summer of Code program, students will learn that testing,
and building automated testing tools, can be both fun and an integral part of delivering high quality
software. The collaborative effort with Selenium contributors can provide you with a new toolset to
develop and document a set of components used by thousands of people. You will gain valuable
professional experience towards your career development and ultimately help drive higher quality web
applications everywhere.
Student Eligibility
18 years of age or older by April 26, 2010
Currently enrolled in an accredited institution such as colleges, university, master programs, PhD
programs and undergraduate programs
Residents and nationals of countries other than Iran, Syria, Cuba, Sudan, North Korea and
Myanmar (Burma) with whom we are prohibited by U.S. law from engaging in commerce
Strong skills in some or more of the following: Web Application Development, JavaScript, Python,
Flash, iPhone / Android
Self-directed, resourceful, responsible, communicative
Ability to work full-time from May 24 – August 20, 2010 (students residing in SF Bay Area may
have an opportunity to work on-site from time to time with some of our mentors)
More info on Student Eligibility can be found here
If you meet the above requirements, we’d love to have you apply to Selenium for this year’s Google
Summer of Code.
https://www.selenium.dev/documentation/_print/ 387/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
5. Selenium GSoC team will finish reviewing applications and match students with mentors by April
23, 2011.
6. Google announces accepted students on April 26, 2011.
Project Ideas
These are project ideas proposed by mentors. Please send a post to the developer mailing list if you are
interested in it or email GSoC coordinator Adam Goucher.
A Scriptable Proxy
Mentor Patrick Lightbody(?)
Difficulty
<unknown>
Description Selenium is a browser control framework, but sometimes you want to do things to/with
the traffic generates. The ‘right’ way to do this is to put a proxy in the middle and use its API to do get /
fiddle with the traffic information. This project extends the BrowserMob proxy to add the APIs that
users of Selenium would need.
<unknown>
Difficulty
<unknown>
Description Sikuli gets a lot of play for its ability to interact with items on the page based on Images.
This project would add Image Based Locators to the list of available ones.
Selenese Runner
Mentor Adam Goucher
Difficulty
<unknown>
Description It is possible to run Selenese scripts outside of Se-IDE with the -htmlSuite option on the
server. There are a number of downsides to this, like the need to start/stop the server constantly. This
project will create a standalone ‘runner’ for Selenese scripts to interact with the server – and remove the
related code from the server.
Perspective mentors
It’s not too late to apply to be a mentor, if you are interested, please add your project idea here and
discuss logistics with Adam Goucher
Expectations
https://www.selenium.dev/documentation/_print/ 388/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Summary
This page covers, in detail, the expectations for Google Summer of Code students in regards to
communication. This is useful for Selenium projects which haven’t codified their expectations–they can
point to this document and use it as is.
The Google Summer of Code coding period is very short. On top of that, many students haven’t done a
lot of real-world development/engineering work previously; one of the primary purposes of the program
is to introduce students to F/OSS and real-world development scenarios. On top of that, most mentors
and students are in different locations–so face-to-face time is difficult. Because of this, it’s vitally
important to the success of the GSoC project for all expectations to be specified before students begin
coding on May 26th. This should be the first step in a long series of frequent communication between
student and mentor(s).
This document walks through various expectations for students and mentors, as well as addressing
various ways to communicate effectively.
the chance to become part of a project community over the long term–this can lead to involvement
with other projects, social network, good friends, valuable resources, …
the chance to work with real developers on a real project
the end result of the student’s project can be used for resume material that is available for all
future employers to see
The final point is an important one for a beginning developer. Employers greatly appreciate having a
referenceable body of work when looking at potential employees. Your code says more about your
abilities than any amount of algorithms on a whiteboard can.
And of course, the program will provide you with 5000 USD in income and a really cool t-shirt.
Some GsoC students have become prominent technology bloggers, committers to open source projects,
speakers at conferences, mentors for other students, and more…
Regular weekly meeting with your mentor is a must. The planned meeting should cover:
The mentor is one of the most valuable resources for GSoC projects. The mentor is both a solid
developer and a solid engineer. The mentor likely has worked on the project for long enough to know
the history of decisions, how things are architected, the other people involved, the process for doing
https://www.selenium.dev/documentation/_print/ 389/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
things, and all other cultural lore that will help the student be most successful.
Before the GSoC project starts, the mentor and student should iron out answers to the following
questions:
1. When is the regular, scheduled communication scheduled? Weekly? Every two days? Mondays,
Wednesdays, Fridays?
2. What is the best medium to use for regular, scheduled communication? VOIP? Telephone call?
Face-to-face?
3. What is the best medium to use for non-scheduled communication? Email? Instant messenger?
DO:
be considerate of your time and your mentor’s time and plan for your regular meeting
Consider emailing the answers to the above agenda ahead of time so you can spend your
time productively on coming up with solutions, code reviews, and planning for the next
milestones.
talk to your mentors and developers on the mailing list / IRC frequently, outside of your planned
meeting
your mentor is not the only person that can help you out and keep you stay on track,
Selenium has a nice community and you will learn a lot from the other people as well.
let your mentor know what your schedule is
Are you going on vacation, moving, writing papers for class? If your mentor doesn’t know
where you’ll be or to expect a lag in your productivity, your mentor can’t help you course
correct or plan accordingly.
AVOID:
going for more than a week without communicating with your mentor
The project timeline doesn’t allow for unplanned gaps in communication.
Version control
Students should be using version control for their project.
DO:
commit-early/commit-often
This allows issues to be caught quickly and prevents the dreaded one-massive-commit-
before-deadline.
use quality commit messages
Good examples: Fixed a memory leak where the thingamajig wasn’t getting freed after the parent
doohicky was freed. Fixed bug #902 (on Google Code) by changing the comparison used for duplicate
removal. Implemented Joe’s good idea about rendering in a separate buffer and then swapping the
buffer in after rendering is complete. Improved HTML by simplifying tables.
AVOID:
may be a good sounding board for figuring out the specific behavior for features. You are assigned a
mentor, but the whole community is there to help you learn. Make use of all the resources at your
disposal.
Shyness is a common problem for students who are new to open source development. At the beginning
of the project, the student is encouraged to send a “Hello! I’m … and I’m working on a GSoC project on …
and here’s a link to the proposal.” email to project mailing lists and encouraged to log in and say “hi” on
IRC. Break the ice early–it makes the rest of the project easier. If you don’t know where you announce
yourself, ask your mentor.
Often mailing lists are archived and the archives are a rich source of information regarding prior
discussions, decisions, and technical errata.
DO:
search through the archives for answers before asking on the list
be courteous at all times
be specific
Cite data, references, and use links wherever possible when discussing technical things.
be patient
Don’t expect an answer within minutes or hours; people often read their mailing-list
messages once per day.
AVOID:
being rude
Since most mailing lists are archived or recorded, it’s likely anything you say will be available
for everyone to see forever; exercise good manners in all aspects of life.
saying things with all capital letters and excessive punctuation
This is perceived as shouting
getting into heated arguments
If someone insults you, it’s best to ignore it.
IRC
Most F/OSS projects have an IRC channel and some have more than one. People from the project and its
community “hang out” on these channels and talk about various things. Some projects have regularly
scheduled meetings to cover the status of the project, how development is going, status of major
blocking bugs, map out future plans, …
If the project has an IRC channel, it’s a good idea to hang out there. This allows the student to interact
with the community and also a forum for working out problems and ideas in real time.
DO:
hang out on the project IRC channels when you’re working on the project
take time to interact with people who are on the IRC channel This builds community and it’s
easier to get help from people who are familiar with you than people who aren’t.
AVOID:
saying things with all capital letters and excessive punctuation This is perceived as shouting.
poor grammar It makes it harder for other people to understand what you’re trying to say.
being rude
We’re all real people with real feelings and if you’re rude it’s likely people will interact with you and help
you less; also it’s not uncommon for IRC history to be recorded and archived for all to see forever.
See:
http://www.linuxchix.org/irc-basics.html
http://en.wikipedia.org/wiki/Internet_Relay_Chat
https://www.selenium.dev/documentation/_print/ 391/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Design documents
It’s a good idea for the student to maintain design documents during the course of the GSoC project.
These design documents should cover:
1. the project plan, with additional detail to flesh out the original program application
2. deviations from the project plan and how and why the original design plan changed
3. any issues that could not be worked out or overcome
4. possible future directions
5. any resources used or relevant specifications
The student and mentor should work out what design documents should be maintained during the
course of the GSoC.
One thing to note is that the student shouldn’t spend all his/her time doing design documents. It’s
important to keep track of the design, but it’s also important to get some code done. The mentor should
be able to help the student strike a balance between these two goals.
Blogging
Students should get in the habit of blogging about about his/her work at least once every two weeks.
Historically, students who do learn much faster, are more productive, and develop a stronger tie to the
community. Some have gone on to become contributors, others have given talks / presentations at
conferences. How would you like to see your career grow?
Application
Evaluation Criteria
We recognized that very few students have exposures to Selenium during their studies and will
therefore evaluate you based on your:
As long as you get your application in before April 9, you will have until April 18 to fine-tune your
proposal with our mentors.
Feel free to include anything else you feel is important. One liner answers are not likely going to be
considered. In the meanwhile, do feel free to introduce yourself to the community and discuss your
project proposal by writing to our developer mailing list.
General Questions:
Your Experience:
1. How did you get started with programming? How long have you been doing it? Why do you love
it? Any personal projects you can show us? Have you participated in coding contests / taught /
mentor other students?
https://www.selenium.dev/documentation/_print/ 392/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
2. What are your programming interests? Are you a C guy - do you like to get down and dirty with
the linux kernel? Do you know more about Java than your peers? Or are you more of a python/ruby
person? What about JavaScript? You know, what’s your style?
3. Have you worked for a sofware company as a programmer before?
4. Have you worked on an open source project before? Which ones? Describe your participation
5. Do you have a blog? A resume?
6. What makes you a good person for Google Summer of Code? What do you want to get out of it?
Project Questions:
Name and Contact Information. Include email, phone(s), IM, Skype, etc.
Title. One liner on the goal to your project.
Synopsis. Short summary, what would your project do?
Benefits to Community. Why would Google and Selenium be proud to sponsor this work? How
would open source or society as a whole benefit?
Deliverables. We want to know that you have a plan and that at the end of the summer,
something get delivered. :-) Give a brief, clear work breakdown structure with milestones and
deadlines. Make sure to label deliverables as optional or required. You may want plan to start by
producing some kind of whitepaper, or planning the project in traditional Software Engineering
style. It’s OK to include thinking time (“investigation”) in your work schedule. Work should include:
investigation
programming
documentation
dissemination
Description. A small list of project details. Your mentors can give you some guidance on this, but
start by letting us know you are thinking :-)
rough architecture
links to parallel projects that you may get insights from
what version control and build system do you plan to use
how do you plan to test
best practices to get your code accepted, etc.
Bio. Who are you? What makes you the best person to work on this project?
Summarize your education, work, and open source experience.
List your skills and give evidence of your qualifications. Convince us that you can do the
work.
Any published papers, successful open source projects, etc? Please tell us!
Please list any non-Summer-of-Code plans you have for the Summer, especially employment
and class-taking. Be specific about schedules and time commitments.
https://www.selenium.dev/documentation/_print/ 393/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
You can run all the tests in a given test class this way:
You can also run a single test directly from the command line by typing:
Using Rake
Rake is very similar to using other build tools such as “make” or “ant”. You can specify a “target” to run
by adding it as a parameter, and you can add more than one target at a time. Note that since WebDriver
does not rely on ruby being installed and uses JRuby, rake should not be involved directly - use the go
script instead. For example, in order to clean the build and then build and run the HtmlUnitDriver tests:
The default target that’s used will compile the code and run all the tests. More interesting targets are:
Target Description
clean Delete the contents of the build directory, removing all compiled artifacts
test Compile the dependencies of and run all the tests for the HtmlUnitDriver,
FirefoxDriver, and InternetExplorerDriver as well as the support library’s tests
https://www.selenium.dev/documentation/_print/ 394/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Target Description
test_htmlunit Compile the dependencies and then run the tests for the HtmlUnitDriver. The same
“test_x” pattern can be followed for all the compilation targets in this table.
Logger.dumpn() - Logs a string into console (and converts arguments to strings). For example:
Logger.dumpn("Found element: " + node) .
Logger.dump() - Gets a single argument, an object, and dumps its entire contents: implemented
interfaces, data fields, methods, etc.
The webdriver.log.file preference will instruct the Logger to dump all contents of the console to
the specified file. webdriver.log.file
export NSPR_LOG_MODULES=all:3
https://www.selenium.dev/documentation/_print/ 395/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Setting this environment variable will cause Firefox to log additional messages to the console. Use this
environment variable together with webdriver.firefox.logfile to get a hold of Firefox’s output to
the console.
Adding a test
Most of WebDriver’s test cases live under java/client/test/org/openqa/selenium. For example, to
demonstrate an issue with clicking on elements, a test case should be added to ClickTest. The test cases
already have a driver instance - no need to create one. The test use pages that are served by an in-
process server, served from common/src/web. Their URLs are provided by the Pages class, so when
adding a page and add it to the Pages class as well.
We can use a web browser or tools such as telnet to interact with a RemoteWebDriverServer e.g. to
debug the JSON protocol. Here’s a simple example of checking the status of a server installed on the local
machine
In a web browser
http://localhost:8080/wd/hub/status/
In telnet
curl http://localhost:8080/wd/hub/status
wget http://localhost:8080/wd/hub/status
{status:0}
https://www.selenium.dev/documentation/_print/ 396/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
A final release will be made once these are implemented in Firefox, IE and at least one webkit-based
browser.
The Future
The following are also planned:
https://www.selenium.dev/documentation/_print/ 397/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Clean up
Using WebDriver after quit() should be an IllegalStateException
Actions to have a single end point
Capabilities to be the same as the spec
Multiple calls to WebDriver.quit() should still be safe.
Clean up WebDriver constructors, pulling heavy initialization logic into a Builder class
Migrate to Netty or webbit server
Delete unnecessary cruft
Land a cleaner end point for the rc emulation
https://www.selenium.dev/documentation/_print/ 398/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
If there is an issue with the documentation, we want to know! The best way to communicate an issue is
to visit https://github.com/seleniumhq/seleniumhq.github.io/issues and search to see whether or not the
issue has been filed already. If not, feel free to open one!
Many members of the community are present at the #selenium Libera chat at Libera.chat. Feel free to
drop in and ask questions and if you get help which you think could be of use within these documents,
be sure to add your contribution! We can update these documents, but it is much easier for everyone
when we get contributions from outside the normal committers.
https://www.selenium.dev/documentation/_print/ 399/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Attributions
Selenium Main Repository
@shs96c 5115 commits @barancev 3352 commits
https://www.selenium.dev/documentation/_print/ 400/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 401/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 402/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 403/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium IDE
@corevo 2445 commits @toddtarsi 161 commits
https://www.selenium.dev/documentation/_print/ 404/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 405/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Docker Selenium
@diemol 502 commits @ddavison 134 commits
https://www.selenium.dev/documentation/_print/ 406/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 407/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 408/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 409/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 410/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 411/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 412/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 413/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 414/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 415/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 416/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 417/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 418/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 419/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 420/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
@zeljkofilipin 1 commits
https://www.selenium.dev/documentation/_print/ 421/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
License
All code and documentation originating from the Selenium project is licensed under the Apache 2.0
license, with the Software Freedom Conservancy as the copyright holder.
The license is included here for convenience, but you can also find it on the Apache Foundation’s
websites:
https://www.selenium.dev/documentation/_print/ 422/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
https://www.selenium.dev/documentation/_print/ 424/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
https://www.selenium.dev/documentation/_print/ 425/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
http://www.apache.org/licenses/LICENSE-2.0
https://www.selenium.dev/documentation/_print/ 426/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Selenium is a big software project, its site and documentation are key to understanding how things
work and learning effective ways to exploit its potential.
This project contains both Selenium’s site and documentation. This is an ongoing effort (not targeted at
any specific release) to provide updated information on how to use Selenium effectively, how to get
involved and how to contribute to Selenium.
Contributions toward the site and docs follow the process described in the below section about
contributions.
The Selenium project welcomes contributions from everyone. There are a number of ways you can help:
Report an issue
When reporting a new issues or commenting on existing issues please make sure discussions are related
to concrete technical issues with the Selenium software, its site and/or documentation.
All of the Selenium components change quite fast over time, so this might cause the documentation to
be out of date. If you find this to be the case, as mentioned, don’t hesitate to create an issue for that. It
also might be possible that you know how to bring up to date the documentation, so please send us a
pull request with the related changes.
If you are not sure about what you have found is an issue or not, please ask through the communication
channels described at https://selenium.dev/support.
Contributions
The Selenium project welcomes new contributors. Individuals making significant and valuable
contributions over time are made Committers and given commit-access to the project.
Step 1: Fork
Fork the project on Github and check out your copy locally.
Dependencies: Hugo
We use Hugo and the Docsy theme to build and render the site. You will need the “extended” Sass/SCSS
version of the Hugo binary to work on this site. We recommend to use Hugo 0.101.0 or higher.
Step 2: Branch
Create a feature branch and start hacking:
https://www.selenium.dev/documentation/_print/ 427/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
We practice HEAD-based development, which means all changes are applied directly on top of dev .
See Style Guide for more information on our conventions for contribution
Step 4: Commit
First make sure git knows your name and email address:
Writing good commit messages is important. A commit message should describe what changed,
why, and reference issues fixed (if any). Follow these guidelines when writing one:
1. The first line should be around 50 characters or less and contain a short description of the change.
2. Keep the second line blank.
3. Wrap all other lines at 72 columns.
4. Include Fixes #N , where N is the issue number the commit fixes, if any.
Fixes #141
The first line must be meaningful as it’s what people see when they run git shortlog or git log --
oneline .
Step 5: Rebase
Use git rebase (not git merge ) to sync your work from time to time.
https://www.selenium.dev/documentation/_print/ 428/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Step 6: Test
Always remember to run the local server, with this you can be sure that your changes have not broken
anything.
Step 7: Push
Pull requests are usually reviewed within a few days. If there are comments to address, apply your
changes in new commits (preferably fixups) and push to the same branch.
Step 8: Integration
When code review is complete, a committer will take your PR and integrate it on the repository’s trunk
branch. Because we like to keep a linear history on the trunk branch, we will normally squash and rebase
your branch history.
Communication
All details on how to communicate with the project contributors and the community overall can be
found at https://selenium.dev/support
https://www.selenium.dev/documentation/_print/ 429/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Read our contributing documentation for complete instructions on how to add content to this
documentation.
Alerts
Alerts have been added to direct potential contributors to where specific help is needed.
When code examples are needed, this code has been added to the site:
Coding Help ×
Note: This section could use some updated code examples
Check our contribution guidelines and code example formats if you’d like to
help.
To specify what code is needed, you can pass information inside the tag:
Coding Help ×
Check our contribution guidelines and code example formats if you’d like to
help.
or
https://www.selenium.dev/documentation/_print/ 430/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Content Help ×
Note: This section needs additional and/or updated content
Capitalization of titles
Our documentation uses Title Capitalization for linkTitle which should be short and Sentence
capitalization for title which can be longer and more descriptive. For example, a linkTitle of
Special Heading might have a title of The importance of a special heading in documentation
Line length
When editing the documentation’s source, which is written in plain HTML, limit your line lengths to
around 100 characters.
Some of us take this one step further and use what is called semantic linefeeds, which is a technique
whereby the HTML source lines, which are not read by the public, are split at ‘natural breaks’ in the
prose. In other words, sentences are split at natural breaks between clauses. Instead of fussing with the
lines of each paragraph so that they all end near the right margin, linefeeds can be added anywhere that
there is a break between ideas.
This can make diffs very easy to read when collaborating through git, but it is not something we enforce
contributors to use.
Translations
Selenium now has official translators for each of the supported languages.
If you make text changes in the English version, just make a Pull Request. The new process is for
issues to be created and tagged as needs translation based on changes made in a given PR.
Code examples
All references to code should be language independent, and the code itself should be placed inside code
tabs.
To generate the above tabs, this is what you need to write. Note that the tabpane includes
langEqualsHeader=true . This auto-formats the code in each tab to match the header name, but more
importantly it ensures that all tabs on the page with a language are set to the same thing, so we always
https://www.selenium.dev/documentation/_print/ 431/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
This code can be automatically displayed in the documentation using the gh-codeblock shortcode. The
shortcode automatically generates its own html, so if any tab is using this shortcode, set text=true in
the tabpane / tab to prevent the auto-formatting, and add code=true in any tab that still needs to
get formatted with code. Either way, set langEqualsHeader=true to keep the language tabs
synchronized throughout the page. Note that the gh-codeblock line can not be indented at all.
One great thing about using gh-codeblock is that it adds a link to the full example. This means you
don’t have to include any additional context code, just the line(s) that are needed, and the user can
navigate to the repo to see how to use it.
https://www.selenium.dev/documentation/_print/ 432/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
This produces:
Java
driver.get("https://www.selenium.dev/selenium/web/we
driver.quit();
This is preferred to writing code comments because those will not be translated. Only include the code
that is needed for the documentation, and avoid over-explaining. Finally, remember not to indent plain
text or it will rendered as a codeblock.
https://www.selenium.dev/documentation/_print/ 433/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Introduction
This is a work in progress. Feel free to add things you know or remember.
“What I wanted to ask you about was the history of the automation atoms. I seem to remember
them springing fully formed, as if from the head of Zeus, and I’m sure that wasn’t the case. Can you
refresh my memory as to how the concept happened?”
Sure. Are we sitting comfortably? Then I’ll begin. (Brit joke, there)
Imagine wavy lines as the screen dissolves and we’re transported back to when selenium and
webdriver were different projects. Before the projects merged, there was an awful lot of congruent
code in webdriver. Congruent, but not shared. The Firefox driver was in JS. The IE driver was mostly
C++. The Chrome driver was mostly JS, but different JS from the Firefox driver. And HtmlUnit was
unique.
We then added Selenium Core to the mix. Yet more JS that did basically the same thing.
Within Google, I was becoming the TL of the browser automation team. And was corralling a
framework of our own into the mix. Which was written in JS, and had once been based on Core
before it span off on its own path.
So: multiple codebases, lots of JS doing more or less the same thing. And loads of bugs. Weird
mismatches of behaviour in edge-cases.
*shudder*
So I had a bit of a think. (Dangerous, I know) The idea was to extract the “best of breed” code from
all three frameworks (Core, WebDriver and the Google tool). Break them down into code that could
be shared. “The smallest, indivisible unit of browser automation” .
These could be used as the basis the everything. Consistent behaviour between browsers. and apis.
The other important point was that the JS code in webdriver and core was grown organically. Which
is a polite way of saying “I’d rather never edit it again”. Which is a polite way of saying that it was of
dubious quality . In places.
So: high quality was important. And I wanted the code broken up into modules. Because editing a
10k LOC file isn’t a bright idea.
https://www.selenium.dev/documentation/_print/ 434/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
Within Google we had a library called Closure. Which not only allowed modularization, but
“denormalization” of modules into a single file via compilation. And I knew it was being open sourced.
So we started building the library in the google codebase. (Where we had access to the unreleased
library, code review tools and our amazing testing infrastructure). Using Closure Library.
“dom.js” was probably the first file I wrote. (We can check). Greg Dennis and Jason Leyba joined in
the fun. And the atoms have been growing ever since.
Technically, we should be calling anything outside of “javascript/atoms” molecules. But then we can’t
say that we have atomic drivers. and use imagery from the 50s to describe them.
*sigh*
Indeed :) The idea is that the atoms are the lowest level. And we compose the atoms to conform to
the WebDriver or RC apis in “javascript/{selenium,webdriver}-atoms” respecitively. And then suck
those in as necessary.
A Story of Crazy-Fun
Simon Stewart :
https://www.selenium.dev/documentation/_print/ 435/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
https://www.selenium.dev/documentation/_print/ 436/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
jimevans
noob_einsteinsfo: alright, story time, then. are we sitting comfortably? then we'll begin.
noob_einsteinsfo: back when i first started working on the project (circa 2010), the drivers for all of
the browsers were built and maintained by the project.
at the time, that meant IE, firefox, and chrome.
all of those drivers were packaged as part of the selenium standalone server, and were also
packaged in with the various language bindings.
this was a conscious decision, so that if one were running locally, there would be no need for the java
runtime on the machine just to automate a given browser.
there were two factors that led to the development of browser drivers as separate executables.
as a quick aside, remember that the webdriver philosophy is to automate the browser using the
"best-fit" mechanism for that particular browser.
for IE, that means using the COM interfaces; for firefox at the time, that meant using a browser
extension; for chrome, it also meant a browser extension.
so that meant that the IE driver was developed as a DLL in C++ that was loaded by the language
bindings, and communicated with via whatever native-code mechanism was provided by the
language (JNI for java, P/Invoke for .NET, ctypes for python, etc.).
it also meant that the firefox driver was developed as a browser extension that was packaged inside
the various language bindings, and extracted, and used in a profile in firefox.
as i said, the IE driver was implemented as a DLL, loaded and communicated with using different
mechanisms for different language bindings.
the problem is that each of those language-specific mechanisms had different load/unload semantics.
ruby, for example, would never call the windows FreeLibrary API after loading the DLL into memory,
making multiple instances really challenging.
*process* semantics, however, as in, starting, stopping, and managing the lifetime of a process on
the OS, whatever the OS, are remarkably similar across all languages.
so when the IE driver rewrite was completed in 2010, the development team (me) decided to make it
a separate executable, so that the load/unload semantics could be consistent no matter what
language bindings one was using.
concurrently with this, the chromium team made the decision to follow opera's lead and provide a
driver implementation for chrome.
an implementation that they would develop, enhance, and maintain going forward, relieving the
selenium project of the burden of maintaining a chrome driver.
XgizmoX
and that driver is part of the browser?
jimevans
XgizmoX: not really, but i believe there may be some smarts built into chrome itself that knows when
it's being automated via chromedriver. one of the googlers would be a better person to ask about
that.
anyway, knowing the different in shared library (.dll/.so/.dynlib) loading semantics, the chromium
team (with my encouragement) decided to release their chromedriver implementation as a separate
executable.
fast-forward a couple of years, and you begin to see the effort to make webdriver a w3c standard.
a working group with the w3c created a specification (still in progress, but getting close to finished
with the first version), which codified the behavior of webdriver, and how a browser should react to
its methods. furthermore, it standardized the protocol used to communicate between language
bindings and a driver for a particular browser.
i can't emphasize how important and groundbreaking this was.
because the w3c and the webdriver working group within it are made up of representatives from the
browser vendors themselves, it ensures that the solution will be supported directly by the browser
vendors.
mozilla created their webdriver implementation (geckodriver) for firefox.
the most efficient mechanism for distribution of that browser driver, while maintaining the proper
semantics for the language bindings, was to ship as a separate executable.
note, this is a gross oversimplification of the geckodriver architecture; the actual executable acts as a
relatively thin shim, translating from the wire protocol of the spec to their internal marionette
protocol
but the point still stands.
https://www.selenium.dev/documentation/_print/ 437/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
TheSchaf
so i guess there is no other choice than to use the old FF as long as required features are missing
WhereIsMySpoon
TheSchaf: if you need those features, yes
or use another browser
TheSchaf
well, moveTo and sendKeys should be pretty basic :p
jimevans
TheSchaf: element.sendKeys works just fine. it's Actions.sendKeys that would be broken.
in firefox version fortysomething (i misremember the exact version), there was a feature added that
blocked browser extensions that hadn't been signed by the mozilla security team.
remember that the legacy firefox driver was built as a browser extension? well, with that feature of
the browser enabled, the legacy driver couldn't be loaded by the browser.
now, for several versions of firefox, it was possible to disable this feature of the browser, and allow
unsigned extensions to continue to be loaded.
and selenium did this, by virtue of the settings used in the anonymous profile the bindings created
when launching firefox.
until firefox 48, at which point, it was no longer possible to disable loading of unsigned extensions.
at that point, geckodriver was the only way forward for that.
now, two more slight points, then i'll be done with story time.
first, by nature of what the legacy driver extension does, it's not possible to get it to pass the
certification process of the mozilla security team.
we asked, were denied, and were told it wouldn't happen ever, full stop.
https://www.selenium.dev/documentation/_print/ 438/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
and that's perfectly reasonable, since what that extension does is a security hole big enough to drive
a whole fleet of lorries through.
second, it turns out there may, in fact, be a way to privately sign the legacy extension so that it can
be loaded and used privately by versions of firefox 48 and higher.
that's still a less-than-ideal approach, because there's no way that our merry band of open source
developers can know how to automate firefox better than the development teams at mozilla, who
create the browser in the first place.
i totally get the frustration that geckodriver doesn't have the full feature parity of the legacy
implementation, especially when it feels like one is being forced to move to it.
raging at the selenium project about that decision is directing one's ire in entirely the wrong
direction.
however, before going off and saying horrible things about mozilla's decisions, do know that mozilla
has several people who are constantly engaged in the project, a few of them right here in this very
channel (AutomatedTester, davehunt, to name two).
i'm sure i've glossed over or mischaracterized some of the historical details of these things, and i'm
happy to be corrected. i'm old, after all, and the memory isn't what it used to be.
but that, my friends, is the (not so very) short history of why we have separate executables for
drivers, and why geckodriver is the way forward, and why a move to it was necessary when the
move was made even though some functionality was lacking.
jimevans feels like he's become an unofficial historian of the webdriver project
transcript: https://botbot.me/freenode/selenium/2016-12-21/?msg=78265715&page=6
Selenium RC3 - “the next one is the ‘big’ one” release - http://bit.ly/kpiACx
Selenium 2.1.0 now available (yes, even for maven users now)
Selenium 2.2.0 now available (in nuget .. and yes, even maven)
Selenium 2.4.0 is out – stuff changed, but there is no blog post yet
Selenium 2.6.0 is now available. Switch and save 15% or more on car insurance
Ruby bindings for Selenium 2.7.0 first out of the gate (on twitter at any rate). Jari is a machine…
2.26 is out!
Selenium 2.27 has been released with fixes for Firefox 17. Get it while it’s hot!
https://www.selenium.dev/documentation/_print/ 439/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
BOOM! 2.31 is released with native event support for Firefox 19 even.
“correlation does not imply causation” 2.32.0 released with Firefox 20 support.
the US government is open again! Let’s celebrate with 2.36 newly released, with FF24 support
2.52.0 Released - Now you can disable “all bloody edge cases!”
https://www.selenium.dev/documentation/_print/ 440/441
3/13/23, 5:00 PM The Selenium Browser Automation Project | Selenium
LEARN MORE
https://www.selenium.dev/documentation/_print/ 441/441