Skip to content

Instantly share code, notes, and snippets.

@djangofan
Last active January 6, 2023 22:05
Show Gist options
  • Save djangofan/5112655 to your computer and use it in GitHub Desktop.
Save djangofan/5112655 to your computer and use it in GitHub Desktop.
Exercise on safely waiting for unstable web elements with WebDriver.
// 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();
}
// 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();
}
});
}
// This is the most effective method I could find for
// locating elements reliably.
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.");
}
// 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;
}
// 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 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( 5, TimeUnit.SECONDS );
WebElement we = null;
boolean unfound = true;
while ( unfound ) {
try {
we = driver.findElement( locator );
unfound = false; // FOUND IT
} catch ( StaleElementReferenceException e ) {
staticlogger.info( "Stale element: \n" + e.getMessage() + "\n");
staticlogger.info("Trying again for availability of element...");
unfound = true;
try {
Thread.sleep(4000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
// and finally the cleanup
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;
}
@karvendhanp
Copy link

Wow.. it works awesome ..used method 5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment