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();
}
// This method is not effective. The while loop wont throw an error but
// findElements is not guaranteed to return a non-stale element.
public static WebElement safeGetElementByLocator( By locator ) {
int weWait = 10;
int cycle = 1; // 10 cycles is 280
List<WebElement> weList = driver.findElements( locator );
while ( weList.size()==0 && weWait <= 280 ) {
staticlogger.info("DOM not ready. Trying again for " + weWait + " more seconds.");
staticlogger.info( "[" + cycle + "] Searching for element...");
driver.manage().timeouts().implicitlyWait( weWait, TimeUnit.SECONDS );
weList = driver.findElements( locator );
weWait +=30;
cycle +=1;
}
if ( weList.size() > 1 ) staticlogger.info("WARNING: Locator matched more elements than expected.");
WebElement we = null;
try {
we = weList.get(0);
} catch ( Exception e ) {
staticlogger.info( e.getMessage() );
}
return we;
}
// This method is not effective. I had mixed results with this.
// I didn't stay with this long enough to determine the actual problem.
public static void clickByLocator( By locator ) {
boolean search = true;
int weWait = 30;
int cycle = 1;
while ( search && cycle <= 3 ) {
try {
driver.findElement( locator ).click();
search = false; // stop searching if no error
} catch ( StaleElementReferenceException sere ) {
staticlogger.info( "\n\n\nElement was stale. Trying again.\n" + sere.getMessage() + "\n" +
sere.getCause().getLocalizedMessage() + "\n\n" );
//sere.printStackTrace();
}
weWait +=30; // increase wait value for next cycle
cycle +=1;
driver.manage().timeouts().implicitlyWait( weWait, TimeUnit.SECONDS );
}
driver.manage().timeouts().implicitlyWait( DEFAULT_IMPLICIT_WAIT, TimeUnit.SECONDS );
staticlogger.info("Finished safe 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 method4 although I am unsure if I trust it
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;
}
@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