Last active

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Exercise on safely waiting for unstable web elements with WebDriver.

View endorsedmethod.java
1 2 3 4 5 6 7 8
// This is the official Selenium documention endorsed method of waiting for elements.
// This method is ineffective because it still suffers from
// the stale element exception.
public static void clickByLocator ( final By locator ) {
WebElement myDynamicElement = ( new WebDriverWait(driver, 10))
.until( ExpectedConditions.presenceOfElementLocated( locator ) );
myDynamicElement.click();
}
View endorsedmethod.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// I gleamed this method from the Selenium Google forum.
// The .ignoring fluent method was a huge hint
// to the eventual solution I found but it still didn't work
// because I needed the ExpectedCondition apply method to give
// me some kind of message on failures.
public void waitForElementPresent(final By by, int timeout){
WebDriverWait wait = (WebDriverWait)new WebDriverWait(driver,timeout)
.ignoring(StaleElementReferenceException.class);
wait.until(new ExpectedCondition<Boolean>(){
@Override
public Boolean apply(WebDriver webDriver) {
WebElement element = webDriver.findElement(by);
return element != null && element.isDisplayed();
}
});
}
View endorsedmethod.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// This was my breakthrough. My first partially working code.
public static void clickByLocator( final By locator ) {
staticlogger.info( "Click by locator: " + locator.toString() );
final long startTime = System.currentTimeMillis();
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(90000, TimeUnit.MILLISECONDS)
.pollingEvery(5500, TimeUnit.MILLISECONDS);
//.ignoring( StaleElementReferenceException.class );
wait.until( new ExpectedCondition<Boolean>() {
@Override
public Boolean apply( WebDriver webDriver ) {
try {
webDriver.findElement( locator ).click();
return true;
} catch ( StaleElementReferenceException e ) {
staticlogger.info( e.getMessage() + "\n");
staticlogger.info("Trying again...");
return false;
}
}
} );
driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
staticlogger.info("Finished click after waiting for " + totalTime + " milliseconds.");
}
View endorsedmethod.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
// An extension of method3 although I am unsure if I trust it
// because it re-gets the element AND the element gets assigned
// again after returning from the method. A few opportunities
// to go stale.
public static WebElement getElementByLocator( final By locator ) {
staticlogger.info( "Get element by locator: " + locator.toString() );
final long startTime = System.currentTimeMillis();
driver.manage().timeouts().implicitlyWait( 5, TimeUnit.SECONDS );
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(90000, TimeUnit.MILLISECONDS)
.pollingEvery(5500, TimeUnit.MILLISECONDS);
wait.until( new ExpectedCondition<Boolean>() {
@Override
public Boolean apply( WebDriver webDriver ) {
try {
webDriver.findElement( locator ).getTagName();
return true;
} catch ( StaleElementReferenceException e ) {
staticlogger.info( e.getMessage() + "\n");
staticlogger.info("Trying again for availability of element...");
return false;
}
}
} );
WebElement we = null;
try {
we = driver.findElement( locator ); // is this error prone?
} catch ( StaleElementReferenceException e ) {
staticlogger.info( "Stale element: \n" + e.getMessage() + "\n");
}
driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
staticlogger.info("Finished click after waiting for " + totalTime + " milliseconds.");
return we;
}
View endorsedmethod.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
// I realized that the try-catch doesn't really need to be within
// the ExpectedCondition final block. By moving the try-catch outside
// I would have access to the WebElement returned from findElement().
// So, I can create my own Boolean expected condition while I loop to
// hopefully accomplish a similar thing as method3.
public static WebElement getElementByLocator( By locator ) {
staticlogger.info( "Get element by locator: " + locator.toString() );
long startTime = System.currentTimeMillis();
driver.manage().timeouts().implicitlyWait( 9, TimeUnit.SECONDS );
WebElement we = null;
boolean unfound = true;
int tries = 0;
while ( unfound && tries < 20 ) {
tries += 1;
staticlogger.info("Locating remaining time: " + (180-(9*(tries-1) )) + " seconds." );
try {
we = driver.findElement( locator );
unfound = false; // FOUND IT
} catch ( StaleElementReferenceException ser ) {
staticlogger.info( "ERROR: Stale element. " + locator.toString() );
unfound = true;
} catch ( NoSuchElementException nse ) {
staticlogger.info( "ERROR: No such element. " + locator.toString() );
unfound = true;
} catch ( Exception e ) {
staticlogger.info( e.getMessage() );
}
}
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
staticlogger.info("Finished click after waiting for " + totalTime + " milliseconds.");
driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
return we;
}
View endorsedmethod.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// Another approach, after everything I have learned, that might
// also be effective. With this method, a wait timeout occurs 3
// times within the 90 second limit. So, the method will run
// between 15-90 seconds, depending on the situation of failure.
public static WebElement getElementByLocator( final By locator ) {
LOGGER.info( "Get element by locator: " + locator.toString() );
final long startTime = System.currentTimeMillis();
Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring( StaleElementReferenceException.class ) ;
int tries = 0;
boolean found = false;
WebElement we = null;
while ( (System.currentTimeMillis() - startTime) < 91000 ) {
LOGGER.info( "Searching for element. Try number " + (tries++) );
try {
we = wait.until( ExpectedConditions.presenceOfElementLocated( locator ) );
found = true;
break;
} catch ( StaleElementReferenceException e ) {
LOGGER.info( "Stale element: \n" + e.getMessage() + "\n");
}
}
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
if ( found ) {
LOGGER.info("Found element after waiting for " + totalTime + " milliseconds." );
} else {
LOGGER.info( "Failed to find element after " + totalTime + " milliseconds." );
}
return we;
}
View endorsedmethod.java
1 2 3 4
// create a demonstration of using a Closure instead of the typical inner class
// pattern for @Override that you see above in method #3
 
wait.until( webDriver -> webDriver.findElement( By.id( "foo" ) ) );
View endorsedmethod.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout( 30, TimeUnit.SECONDS )
.pollingEvery( 5, TimeUnit.SECONDS )
.ignoring( NoSuchElementException.class, StaleElementReferenceException.class );
// using a customized expected condition
WebElement foo1 = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo1"));
}
});
// using a built-in expected condition
WebElement foo2 = wait.until( ExpectedConditions
.presenceOfElementLocated( By.id("foo2") ) );
// careful with this next one. it requires visibility attribute on html tag
WebElement foo3 = wait.until( ExpectedConditions
.visibilityOfElementLocated( By.id("foo3") ) );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.