Basically I'm trying to see if a button is able to be clicked at the moment. If not I would like to try again. So I need some kind of a goto function to return to an earlier line of my code. Although I suspect I written this extremely poorly and it could have been done much easier.
try {
driver.findElement(By.xpath("//button[@id='btn_ok']")).click();
}catch (Exception e) {
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
for context, here is the button culprit in question.
<button type="submit" value="ok" name="s1" id="btn_ok" class="green">
You can use fluent wait for this. This will check for the button to be clickable at every 5 seconds for 30 seconds. You can adjust the time according to your need. Try this code and give feedback whether it worked or not.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement clickseleniumlink = wait.until(new Function<WebDriver, WebElement>(){
public WebElement apply(WebDriver driver ) {
return driver.findElement(By.xpath("//button[@id='btn_ok']"));
}
});
clickseleniumlink.click();
Try this way.see if it helps.
int size=driver.findElements(By.xpath("//button[@id='btn_ok']")).size();
if (size>0)
{
driver.findElement(By.xpath("//button[@id='btn_ok']")).click();
}
else
{
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
int size1=driver.findElements(By.xpath("//button[@id='btn_ok']")).size();
if (size1>0)
{
driver.findElement(By.xpath("//button[@id='btn_ok']")).click();
}
}
You can use explicit wait to wait for the button to be clickable. It will test the button every 500 ms for maximum of specified time until it's clickable
WebDriverWait wait = new WebDriverWait(driver, 5); // maximum wait time is 5 here, can be set to longer time
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("btn_ok")));
button.click();
As a side note, implicitlyWait
set the max time the driver will search for an element, it doesn't delay the script.
I prefer this, as it can take literally any boolean condition to "wait until".
public static void WaitUntil(this IWebDriver driver, Func<bool> Condition, float timeout = 10f)
{
float timer = timeout;
while (!Condition.Invoke() && timer > 0f) {
System.Threading.Thread.Sleep(500);
timer -= 0.5f;
}
System.Threading.Thread.Sleep(500);
}
driver.WaitUntil(() => driver.FindElements(By.XPath("some xpath...").Length == 0);
//Here is the particular benefit over normal Selenium waits. Being able to wait for things that have utterly nothing to do with Selenium, but are still sometimes valid things to wait for.
driver.WaitUntil(() => "Something exists in the database");
I find that the implicit waiting causes me more trouble than it is worth. And I find explicit selenium waiting can get a bit verbose, and it doesn't cover everything I need from it in my framework, so I've made a good number of extensions. Here is one of them. Note, I use the FindElements for the example above because I do not want an exception thrown if nothing is found. This should work for you.
Note: This is C#, but it shouldn't be difficult to modify this for any language (especially Java). If your language does not allow extensions like this, simply call the method directly in a class. You will need to put this in a static class to be functional. Be careful when extending existing classes like this in logic, as it can confuse others when they are trying to determine where the methods are defined.
Quick answer
Please checkout below piece of code and lets know if it resolved your problem.
public synchronized boolean clickOnButtonWhenItBecomesClickable() {
boolean buttonClicked=false;
try {
List<WebElement> element = driver.findElements(By.xpath("//button[@id='btn_ok']"));
while(element.size()!=0) {
// if any action needed to perform to display button, please do it.
element = driver.findElements(By.xpath("//button[@id='btn_ok']"));
if(element.size()!=0) {
wait = new FluentWait<WebDriver>((WebDriver) driver).withTimeout(30, TimeUnit.SECONDS).pollingEvery(5,
TimeUnit.SECONDS);
wait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.xpath("//button[@id='btn_ok']"))));
buttonClicked=true;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return buttonClicked;
}