How to synchronise on application state? How to Wait with WebDriver? Thread.sleep is not the answer, so what is?
Avoid Thread.sleep
The main thing we want to avoid is a Thread.sleep
If you do use Thread.sleep
make it obvious what you are doing.
But do not rely on this for strategic automating.
private void pauseToAllowVisibility() {
try{
Thread.sleep(1000);
}catch(Exception e){
// ignore
}
}
For more information about Thread.sleep, check this blog post.
Waiting
Waiting in WebDriver uses a WebDriverWait
driver.get("https://testpages.herokuapp.com/styled/calculator");
new WebDriverWait(driver,10).
until(
// some ExpectedCondition to wait for
);
And the WebDriverWait
can be assigned to a variable for re-use.
e.g.
WebDriverWait wait = new WebDriverWait(driver,10);
ExpectedConditions
I remember back in 2012 reading through the WebDriver code and finding a support class for ExpectedConditions
class which exposes a bunch of static methods to save me having to write code.
ExpectedConditions
contains a lot of common waiting conditions.
The ExpectedConditions
class has a method waiting for a page title to contain some text.
driver.get("https://testpages.herokuapp.com/styled/calculator");
new WebDriverWait(driver,10).
until(ExpectedConditions.titleContains("Selenium"));
Creating Your Own ExpectedCondition
I can create and use my own ExpectedCondition
classes:
driver.get("https://testpages.herokuapp.com/styled/calculator");
new WebDriverWait(driver,10).
until(new TitleContainsCondition("Selenium"));
This opens the driver to the page and waits until the Title contains the text “Selenium”.
And I would write code to support this i.e. my TitleContainsCondition
class:
public class TitleContainsCondition implements ExpectedCondition {
private String subMenuText;
public TitleContainsCondition(final String subMenuText) {
this.subMenuText=subMenuText;
}
@Override
public Boolean apply(@Nullable WebDriver driver) {
return driver.getTitle().contains(this.subMenuText);
}
}
Create Your Own ExpectedConditions
If I want a custom ExpectedConditions
then I can create my own ‘factory’ class to return ExpectedCondition
driver.get("https://testpages.herokuapp.com/styled/calculator");
new WebDriverWait(driver,10).
until(WaitFor.titleContainsCondition("Selenium"));
I do occasionally write a WaitFor
Class to add application or non-standard conditions, since we test applications which are domain specific.
And the WaitFor
would look like:
public class WaitFor {
public static ExpectedCondition<Boolean> titleContainsCondition(String titleMustContain) {
return new TitleContainsCondition(titleMustContain);
}
}
Inline
If I really wanted to I could use a WebDriverWait
without a separate class.
@Test
public void useInLineExpectedCondition(){
driver.get("https://testpages.herokuapp.com/styled/calculator");
new WebDriverWait(driver,10)
.until(
new ExpectedCondition<Boolean>(){
@Override
public Boolean apply(WebDriver driver) {
return driver.getTitle().startsWith("Selenium");
}
}
);
}
But I haven’t written any code like this for some time. If I use a wait then I would refactor it into a class of its own, or wrap it as a factory method e.g. on WaitFor
Lambda
With Java 8 it is now possible to use waits in closure/lambda expressions.
@Test
public void useViaLambdaExpressions(){
driver.get("https://testpages.herokuapp.com/styled/calculator");
WebDriverWait wait = new WebDriverWait(driver,10);
ExpectedCondition<Boolean> titleStartsWithSelenium = mydriver ->
{ return mydriver.getTitle().startsWith("Selenium");};
wait.until(titleStartsWithSelenium);
}
I rarely use this, but sometimes for adhoc experimentation or workarounds I do.
Historical Note
WebDriver
initial implementation of waiting was much more basic.
e.g. here is some code from 2011(ish)
new Wait("JS Page title did not change"){
@Override
public boolean until() {
try{
return driver.getTitle().startsWith("Selenium"));
}catch(Exception e){
// ignore not found exception
}
return false;
}
};
Note: this post was originally written in 2011, hence the ‘historical note’ example, and updated on 20200603.
Wait Before or Wait After
In one of my early WebDriver training courses I had an exercise which involved waiting for an element to have clickability. It existed in the DOM, visible, and all other rendered event style isCondition()s. But when clicked on, it could not respond to events.
The initial approach involved trying to fix the problem at the point my code encountered it, i.e. when trying to click on it in the Page Object.
private void clickSubMenuItem(String subMenuText) {
// insert lots of banging of head with failed automation code here
// because the element below is visible but isn’t responding to clicks yet
// can’t figure out how to detect if the element is responding to clicks
// before I click on it because click doesn’t throw an exception
// because it is there to click on
String xpathExpression = “//div[@class=\“GALD-WOBF\” and .=\“” + subMenuText + “\“]”;
driver.findElement(By.xpath(xpathExpression)).click();
wait.until(weCanSee.GWTTitleMatches(subMenuText));
}
The most robust solution for the automation issue by waiting, at the point my code puts the system into the state of unclickability, and waiting until it re-enters a state of clickability.
public void openClose() {
WebDriverWait wait = new WebDriverWait(driver,20);
ExpectedConditionFactory weCanSee = new ExpectedConditionFactory();
By imageLocator = By.xpath(“//div[.=\“”+ this.menuHeading + “\“]/../div/img”);
driver.findElement(imageLocator).click();
// This is the wait I needed in the code above, but it only made sense here
// do not consider it open or closed until the menu stops growing,
By parentDiv = By.xpath(“//div[.=\“”+ this.menuHeading + “\“]/../../..”);
wait.until(weCanSee.elementStopsGrowing(parentDiv, driver));
}
Both waiting styles offer valid automation choices.
I found it interesting that I defaulted to the first style and that caused intermittency issues. I don’t think I’ve used the second style as much.
You can imagine more trade-offs associated with each style:
1st Style – Before Follow On Actions
- Tests might go faster because, follow on actions may not require earlier waits as guard conditions
- Page objects become more complicated because we have to remember to check for all guard conditions before taking action
- Guard checking happens in multiple places
- Risk of test intermittency because of emergent behaviour which we might find hard to debug
2nd Style – Immediately After triggering condition
- Exit condition checks in single place
- Less chance of exposing emergent behaviour as application keeps synchronised to a ‘good’ state
- Leads to doSomething and doSomethingAndWait style methods
For some reason my approach to automation defaulted to the first style.
This post should act as a reminder to consider both styles.
Full Source
The full source for this is in my Webdriver Java FAQs project:
Specifically:
If you want to learn how to use Selenium WebDriver with Java then check out our online courses. We have course dedicated to Advanced Synchronisation, and one dedicated to the Support Classes.