Waiting
Available in bb-core
since version 1.6.0
. Mechanism from previous versions: link
Overview
One of the fundamental problems when automating GUI is handling dynamic elements on a website: pop-ups, carousels, menus, lazy-loaded data in various places, etc.
Bobcat utilizes Selenium’s out-of-the-box mechanisms: implicit and explicit waiting. More information about them can be found in official docs.
Implicit waiting
Implicit waiting happens before any lookup of a WebElement
is being executed during your tests. When searching for an element it waits for a specific period of time to actually report the issue in case of the element not being present on the page.
This implicit timeout can be set manually using: webDriver.manage().timeouts().implicitlyWait(<TIMEOUT>, <TIME UNIT>)
.
Bobcat has an in-built modifier that sets that timeout for you, just after the WebDriver
instance is created: ImplicitTimeoutModifier
.
The modifier is enabled by default. It is set to 1 second.
To disable it, put the following property in your config file:
modifier.implicitTimeout: false
To change the value of the timeout to e.g. 5 seconds, put the following property in your config:
timings.implicitTimeout: 5
Explicit waiting
Depending on implicit timeout will solve only a tiny fraction of your problems. That is why, the most recommended approach is to use explicit waiting.
Selenium provides the FluentWait
and its extension, WebDriverWait
. Bobcat wraps the latter with bunch of useful methods in the form of BobcatWait
.
BobcatWait
Explicit waiting relies on evaluating ‘expected conditions’. They are the implementation of ExpectedCondition
interface.
Selenium provides a hefty list of predefined conditions out-of-the-box in the ExpectedConditions
class. This will be your bread-and-butter when working with dynamic elements.
How to wait?
To wait for a specific condition you can use two methods from BobcatWait
:
@Inject
private BobcatWait bobcatWait;
@FindBy(css=".my-element")
private WebElement testedElement;
WebElement element = bobcatWait.until(ExpectedConditions.visibilityOf(testedElement));
boolean result = bobcatWait.isConditionMet(ExpectedConditions.visibilityOf(testedElement));
BobcatWait#until(condition)
:
- if the condition is met, the method will return an object of a type declared in the condition itself.
- if the condition has not been met,
TimeoutException
will be thrown - this behaviour is exactly the same as in Selenium’s
WevDriverWait#until
BobcatWait#isConditionMet(condition)
:
- if the condition is met, the method will return
true
- if the condition has not been met, the method will return
false
Writing your own conditions
When ExpectedConditions
does not provide you a condition suiting your needs, you can always write your own. You can either implement it in a similar way to Selenium, i.e. create a dedicated class where you will keep your conditions, or you can also provide one inline with lamda:
BobcatWait.until(webDriver -> heightOfElement == expectedValue);
.
Fine-tuning your waits
Bobcat takes the following values as defaults:
timings.explicitTimeout: 10 # in seconds
timings.implicitTimeout: 1 # in seconds
timings.pollingInterval: 500 # in milliseconds
You can tweak these in various ways:
- globally, by providing the above properties in your config or via command line
- locally, by using the
BobcatWait.tweak(Timings)
method before theuntil
call- it takes an instance of
Timings
as an argument; use theTimingsBuilder
to create one, e.g.:new TimingsBuilder().explicitTimeout(5).pollingInterval(200).build()
- it takes an instance of
Explicit vs implicit waiting
It is discouraged (also by Selenium maintainers) to use implicit and explicit waiting together, as it may yield unexpected results. That is why Bobcat has an in-built protection against such situations.
After calling BobcatWait#until(condition)
Bobcat will:
- reduce the implicit timing before evaluating the condition,
- evaluate the condition,
- restore the implicit timeout to the default one, or the customized value from config or a
Timings
instance passed toBobcatWait
viatweak(Timings)
method.