Reputation: 373
driver.findElement(By.xpath(sOptionPath)).click(); //this option button changes contents of page
Thread.sleep(4000);
WebElement combo=driver.findElement(By.xpath(sXpath));
Select dropdownvalue = new Select(combo);
dropdownvalue.selectByVisibleText(sText);
This above code works fine but if I use wait instead of thread.sleep I get StaleElementReferenceException exception. This is the Fluent wait I used :
Wait<WebDriver> newwait=new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class);
WebElement combo=newwait.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(By.xpath(sXpath));
}
});
this finds the combobox, but performing any operation on combobox again gives NoSuchElement or statestate exception. SO I also tried this to select value from combobox :
Wait<WebElement> elwait=new FluentWait<WebElement>(combo).withTimeout(10, TimeUnit.SECONDS).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class,NoSuchElementException.class);
Boolean a=elwait.until(new Function<WebElement,Boolean>(){
@Override
public Boolean apply(WebElement arg0) {
Select dropdownvalue = new Select(arg0);
dropdownvalue.selectByVisibleText(sText);
return true;
}
});
This timeouts and doesnot work !
How can I make this work and why is it not working and thread.sleep working. And why using Thread.sleep a bad practice ?
Upvotes: 1
Views: 2734
Reputation: 1145
I would try to validate that the object I'm returning to 'combo' is not stale using some of the existing checks from ExpectedCondtions class.
Wait<WebDriver> newwait=new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class);
WebElement combo=newwait.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver driver) {
WebElement found = driver.findElement(By.xpath(sXpath));
if (ExpectedConditions.stalenessOf(found).apply(driver)) {
return null;
}
return found;
}
});
I am working off of version 2.47.2, and the FluentWait appears to retry when null is returned from the delegate Function, so I would expect this to retry if you would otherwise get the StaleElementException.
public <V> V until(Function<? super T, V> isTrue) {
long end = clock.laterBy(timeout.in(MILLISECONDS));
Throwable lastException = null;
while (true) {
try {
V value = isTrue.apply(input);
if (value != null && Boolean.class.equals(value.getClass())) {
if (Boolean.TRUE.equals(value)) {
return value;
}
} else if (value != null) {
return value;
}
} catch (Throwable e) {
lastException = propagateIfNotIngored(e);
}
// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!clock.isNowBefore(end)) {
String toAppend = message == null ?
" waiting for " + isTrue.toString() : ": " + message;
String timeoutMessage = String.format("Timed out after %d seconds%s",
timeout.in(SECONDS), toAppend);
throw timeoutException(timeoutMessage, lastException);
}
try {
sleeper.sleep(interval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new WebDriverException(e);
}
}
I had seen something similar in one of my tests, and it took me a while but I finally came to the conclusion that in my case it was a race condition between the implicit wait in the WebDriver configuration and the explicit wait time. I've not made a test that proves this case yet, but here's my current theory...
SLEEP
Explicit Wait <= Implicit Wait
Explicit Wait > Implicit Wait
Working off of that assumption I've not seen this problem recently. I made the Implicit wait value accessible to my test and I now have something calculate the timeframe based on the amount of retries I want to perform.
private final WebElement explicitWait(int retries, Predicate<Boolean> test) {
WebDriverWait wait = new WebDriverWait(driver, retries * getImplicitWait());
return wait.until(test);
}
I completely agree with Vinoth about the use and reliability of Thread.sleep, it's unreliable and can be wasteful if it occurs too often in a large suite of tests. It's better to have a mechanism that can respond as quickly as possible and account for well-typed and meaningful exceptions.
Best of Luck.
Upvotes: 1
Reputation: 15370
Thread.sleep is a bad practice because you are using a hardcoded wait. Even if the element appears within 1 second, you are unncessarily wait for 3 more seconds in your case. Or, Lets say the element appears after 10 seconds. you wait for 4 seconds, after that you are going to get an exception that no such element is present. So use expected conditions which is more reliable. Thread.sleep is not reliable. https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath(sXpath)));
WebElement combo=driver.findElement(By.xpath(sXpath));
Select dropdownvalue = new Select(combo);
dropdownvalue.selectByVisibleText(sText);
Upvotes: 0