You can try making a custom ExpectedCondition that will repeat whatever process you find unreliable. It works just like any other wait; it just repeats some function until it returns true or times out.
Don't be intimidated by how much code there is. Like most java, it's mostly all just boilerplate you copy/paste :P
In your case you want to click the element and then check if another element changes. If the change occurs, then stop trying and move on.
This is an inelegant example I whipped up to give you the idea.
So in your test you will wait for the click to succeed like so:
By elementToClick = By.cssSelector("foo");
By elementAfterClick = By.cssSelector("bar");
WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds, attemptIntervalInSeconds);
wait.until(CustomExpectedConditions.ClickSucceeds(elementToClick, elementAfterClick));
Your custom expected conditions class will look like this:
public class CustomExpectedConditions {
public static ExpectedCondition<Boolean> ClickSucceeds(By preLocator, By postLocator) {
//use this when you can't trust the the click to always succeed
return new ClickSucceeds(preLocator, postLocator);
}
Finally your actual expected condition will look like this: (note: in my example I'm checking if the element exists. You may need to only check isDisplayed())
public class ClickSucceeds implements ExpectedCondition<Boolean> {
private By locatorToClick;
private By postClickSuccessLocator;
public ClickSucceeds(By locatorToClick, By postClickSuccessLocator) {
this.locatorToClick = locatorToClick;
this.postClickSuccessLocator = postClickSuccessLocator;
}
@Override
public Boolean apply(WebDriver driver) {
//todo: make this cleaner
Boolean success = false;
if (!success) {
try {
WebElement targetElement = driver.findElement(this.locatorToClick);
targetElement.click();
success = !(driver.findElements(this.postClickSuccessLocator).isEmpty());
//or success = driver.findElement(postClickSuccessLocator).isDisplayed();
} catch (NoSuchElementException e) {
return null;
}
}
else {
return success;
}
return null;
}
}
Cheers, hope that helps!
explicit
wait when finding the element