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.
This is the multi-page printable view of this section. Click here to print.
Support features
- 1: Waiting with Expected Conditions
- 2: Command Listeners
- 3: Working With Colors
- 4: Working with select list elements
- 5: ThreadGuard
1 - Waiting with Expected Conditions
Expected Conditions are used with Explicit Waits. Instead of defining the block of code to be executed with a lambda, an expected conditions method can be created to represent common things that get waited on. Some methods take locators as arguments, others take elements as arguments.
These methods can include conditions such as:
- element exists
- element is stale
- element is visible
- text is visible
- title contains specified value
2 - Command Listeners
These allow you to execute custom actions in every time specific Selenium commands are sent
3 - Working With Colors
You will occasionally want to validate the colour of something as part of your tests; the problem is that colour definitions on the web are not constant. Would it not be nice if there was an easy way to compare a HEX representation of a colour with a RGB representation of a colour, or a RGBA representation of a colour with a HSLA representation of a colour?
Worry not. There is a solution: the Color class!
First of all, you will need to import the class:
import org.openqa.selenium.support.Color;
from selenium.webdriver.support.color import Color
include Selenium::WebDriver::Support
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:
private final Color HEX_COLOUR = Color.fromString("#2F7ED8");
private final Color RGB_COLOUR = Color.fromString("rgb(255, 255, 255)");
private final Color RGB_COLOUR = Color.fromString("rgb(40%, 20%, 40%)");
private final Color RGBA_COLOUR = Color.fromString("rgba(255, 255, 255, 0.5)");
private final Color RGBA_COLOUR = Color.fromString("rgba(40%, 20%, 40%, 0.5)");
private final Color HSL_COLOUR = Color.fromString("hsl(100, 0%, 50%)");
private final Color HSLA_COLOUR = Color.fromString("hsla(100, 0%, 50%, 0.5)");
HEX_COLOUR = Color.from_string('#2F7ED8')
RGB_COLOUR = Color.from_string('rgb(255, 255, 255)')
RGB_COLOUR = Color.from_string('rgb(40%, 20%, 40%)')
RGBA_COLOUR = Color.from_string('rgba(255, 255, 255, 0.5)')
RGBA_COLOUR = Color.from_string('rgba(40%, 20%, 40%, 0.5)')
HSL_COLOUR = Color.from_string('hsl(100, 0%, 50%)')
HSLA_COLOUR = Color.from_string('hsla(100, 0%, 50%, 0.5)')
HEX_COLOUR = Color.from_string('#2F7ED8')
RGB_COLOUR = Color.from_string('rgb(255, 255, 255)')
RGB_COLOUR = Color.from_string('rgb(40%, 20%, 40%)')
RGBA_COLOUR = Color.from_string('rgba(255, 255, 255, 0.5)')
RGBA_COLOUR = Color.from_string('rgba(40%, 20%, 40%, 0.5)')
HSL_COLOUR = Color.from_string('hsl(100, 0%, 50%)')
HSLA_COLOUR = Color.from_string('hsla(100, 0%, 50%, 0.5)')
private val HEX_COLOUR = Color.fromString("#2F7ED8")
private val RGB_COLOUR = Color.fromString("rgb(255, 255, 255)")
private val RGB_COLOUR_PERCENT = Color.fromString("rgb(40%, 20%, 40%)")
private val RGBA_COLOUR = Color.fromString("rgba(255, 255, 255, 0.5)")
private val RGBA_COLOUR_PERCENT = Color.fromString("rgba(40%, 20%, 40%, 0.5)")
private val HSL_COLOUR = Color.fromString("hsl(100, 0%, 50%)")
private val HSLA_COLOUR = Color.fromString("hsla(100, 0%, 50%, 0.5)")
The Color class also supports all of the base colour definitions specified in http://www.w3.org/TR/css3-color/#html4.
private final Color BLACK = Color.fromString("black");
private final Color CHOCOLATE = Color.fromString("chocolate");
private final Color HOTPINK = Color.fromString("hotpink");
BLACK = Color.from_string('black')
CHOCOLATE = Color.from_string('chocolate')
HOTPINK = Color.from_string('hotpink')
BLACK = Color.from_string('black')
CHOCOLATE = Color.from_string('chocolate')
HOTPINK = Color.from_string('hotpink')
private val BLACK = Color.fromString("black")
private val CHOCOLATE = Color.fromString("chocolate")
private val HOTPINK = Color.fromString("hotpink")
Sometimes browsers will return a colour value of “transparent” if no colour has been set on an element. The Color class also supports this:
private final Color TRANSPARENT = Color.fromString("transparent");
TRANSPARENT = Color.from_string('transparent')
TRANSPARENT = Color.from_string('transparent')
private val TRANSPARENT = Color.fromString("transparent")
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:
Color loginButtonColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("color"));
Color loginButtonBackgroundColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("background-color"));
login_button_colour = Color.from_string(driver.find_element(By.ID,'login').value_of_css_property('color'))
login_button_background_colour = Color.from_string(driver.find_element(By.ID,'login').value_of_css_property('background-color'))
login_button_colour = Color.from_string(driver.find_element(id: 'login').css_value('color'))
login_button_background_colour = Color.from_string(driver.find_element(id: 'login').css_value('background-color'))
val loginButtonColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("color"))
val loginButtonBackgroundColour = Color.fromString(driver.findElement(By.id("login")).getCssValue("background-color"))
You can then directly compare colour objects:
assert loginButtonBackgroundColour.equals(HOTPINK);
assert login_button_background_colour == HOTPINK
assert(login_button_background_colour == HOTPINK)
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, 180, 1)");
assert loginButtonBackgroundColour.asRgb().equals("rgb(255, 105, 180)");
assert login_button_background_colour.hex == '#ff69b4'
assert login_button_background_colour.rgba == 'rgba(255, 105, 180, 1)'
assert login_button_background_colour.rgb == 'rgb(255, 105, 180)'
assert(login_button_background_colour.hex == '#ff69b4')
assert(login_button_background_colour.rgba == 'rgba(255, 105, 180, 1)')
assert(login_button_background_colour.rgb == 'rgb(255, 105, 180)')
assert(loginButtonBackgroundColour.asHex().equals("#ff69b4"))
assert(loginButtonBackgroundColour.asRgba().equals("rgba(255, 105, 180, 1)"))
assert(loginButtonBackgroundColour.asRgb().equals("rgb(255, 105, 180)"))
Colours are no longer a problem.
4 - Working with select list elements
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 count, apparently</option>
</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.
<select name="multi" id="multi" multiple="multiple">
<option selected="selected" value="eggs">Eggs</option>
<option value="ham">Ham</option>
<option selected="selected" value="sausages">Sausages</option>
<option value="onion gravy">Onion gravy</option>
</select>
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.
WebElement selectElement = driver.findElement(By.name("selectomatic"));
Select select = new Select(selectElement);
select_element = driver.find_element(By.NAME, 'selectomatic')
select = Select(select_element)
var selectElement = driver.FindElement(By.Name("selectomatic"));
var select = new SelectElement(selectElement);
select_element = driver.find_element(name: 'selectomatic')
select = Selenium::WebDriver::Support::Select.new(select_element)
const selectElement = await driver.findElement(By.name('selectomatic'))
const select = new Select(selectElement)
val selectElement = driver.findElement(By.name("selectomatic"))
val select = Select(selectElement)
List options
There are two lists that can be obtained:
All options
Get a list of all options in the <select>
element:
List<WebElement> optionList = select.getOptions();
option_list = select.options
IList<IWebElement> optionList = select.Options;
option_list = select.options
const optionList = await select.getOptions()
val optionList = select.getOptions()
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.
List<WebElement> selectedOptionList = select.getAllSelectedOptions();
selected_option_list = select.all_selected_options
IList<IWebElement> selectedOptionList = select.AllSelectedOptions;
selected_option_list = select.selected_options
const selectedOptionList = await select.getAllSelectedOptions()
val selectedOptionList = select.getAllSelectedOptions()
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");
select.select_by_visible_text('Four')
select.SelectByText("Four");
select.select_by(:text, 'Four')
await select.selectByVisibleText('Four')
select.selectByVisibleText("Four")
Value
Select the option based on its value attribute
select.selectByValue("two");
select.select_by_value('two')
select.SelectByValue("two");
select.select_by(:value, 'two')
await select.selectByValue('two')
select.selectByValue("two")
Index
Select the option based on its position in the list
select.selectByIndex(3);
select.select_by_index(3)
select.SelectByIndex(3);
select.select_by(:index, 3)
await select.selectByIndex(3)
select.selectByIndex(3)
Disabled options
Options with a disabled
attribute may not be selected.
<select name="single_disabled">
<option id="sinlge_disabled_1" value="enabled">Enabled</option>
<option id="sinlge_disabled_2" value="disabled" disabled="disabled">Disabled</option>
</select>
Assertions.assertThrows(UnsupportedOperationException.class, () -> {
select.selectByValue("disabled");
});
with pytest.raises(NotImplementedError):
select.select_by_value('disabled')
Assert.ThrowsException<InvalidOperationException>(() => select.SelectByValue("disabled"));
expect {
select.select_by(:value, 'disabled')
}.to raise_exception(Selenium::WebDriver::Error::UnsupportedOperationError)
await assert.rejects(async () => {
await select.selectByValue("disabled")
}, {
name: 'UnsupportedOperationError',
Assertions.assertThrows(UnsupportedOperationException::class.java) {
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");
select.deselect_by_value('eggs')
select.DeselectByValue("eggs");
select.deselect_by(:value, 'eggs')
await select.deselectByValue('eggs')
select.deselectByValue("eggs")
5 - ThreadGuard
This class is only available in the Java Binding
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.
The following example simulate a clash of threads:
public class DriverClash {
//thread main (id 1) created this driver
private WebDriver protectedDriver = ThreadGuard.protect(new ChromeDriver());
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();
}
public static void main(String[] args) {
new DriverClash().runThreads();
}
}
The result shown below:
Exception in thread "Thread-1" org.openqa.selenium.WebDriverException:
Thread safety error; this instance of WebDriver was constructed
on thread main (id 1)and is being accessed by thread Thread-1 (id 24)
This is not permitted and *will* cause undefined behaviour
As seen in the example:
protectedDriver
Will be created in Main thread- We use Java
Runnable
to spin up a new process and a newThread
to run the process - Both
Thread
will clash because the Main Thread does not haveprotectedDriver
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.