Taking nilesh's answer a step further, you can also allow finer-tuned searches (eg, within the context of a WebElement) by using the SearchContext interface:
Function<SearchContext, WebElement> elementLocated(final By by) {
return new Function<SearchContext, WebElement>() {
public WebElement apply(SearchContext context) {
return context.findElement(by);
}
};
}
Execution is performed by a FluentWait<SearchContext> instance (instead of WebDriverWait). Give yourself a nice programming interface by wrapping its execution and necessary exception handling in a utility method (the root of your PageObject type hierarchy is a good spot):
/**
* @return The element if found before timeout, otherwise null
*/
protected WebElement findElement(SearchContext context, By by,
long timeoutSeconds, long sleepMilliseconds) {
@SuppressWarnings("unchecked")
FluentWait<SearchContext> wait = new FluentWait<SearchContext>(context)
.withTimeout(timeoutSeconds, TimeUnit.SECONDS)
.pollingEvery(sleepMilliseconds, TimeUnit.MILLISECONDS)
.ignoring(NotFoundException.class);
WebElement element = null;
try {
element = wait.until(elementLocated(by));
}
catch (TimeoutException te) {
element = null;
}
return element;
}
/**
* overloaded with defaults for convenience
*/
protected WebElement findElement(SearchContext context, By by) {
return findElement(context, by, DEFAULT_TIMEOUT, DEFAULT_POLL_SLEEP);
}
static long DEFAULT_TIMEOUT = 3; // seconds
static long DEFAULT_POLL_SLEEP = 500; // milliseconds
Example usage:
WebElement div = this.findElement(driver, By.id("resultsContainer"));
if (div != null) {
asyncSubmit.click();
WebElement results = this.findElement(div, By.id("results"), 30, 500);
if (results == null) {
// handle timeout
}
}