WebDriver does not reliably click links or buttons
I have been desperately trying to get WebDriver to click a button or link reliably, but it just does not want to cooperate. I have tried different methods from setting an implicit timeout, to the below code which is suppose to click and wait for the element to appear.
The below snippet of code was found somewhere on the internet,开发者_Python百科 and it the closest I have come to reliably getting a button or link to click. Except it does not work the same in debug mode as it does when executed during my nightly regression testing.
Does anyone know of another method to click a button or link in a browser? Or should I be using Selenium 1 and not WebDriver as it is too new to be used reliably.
public void waitAndClick(WebDriver driver, By by) {
WebDriverWait wait = new WebDriverWait(driver, 10000, 2000);
Function<WebDriver, Boolean> waitForElement = new waitForElement(by);
wait.until(waitForElement);
Actions builder = new Actions(driver);
builder.click(driver.findElement(by))
.perform();
}
private class waitForElement implements Function<WebDriver, Boolean> {
private final By by;
private String text = null;
public waitForElement(By by) {
this.by = by;
}
public waitForElement(By by, String text) {
this.by = by;
this.text = text;
}
@Override
public Boolean apply(WebDriver from) {
if (this.text != null) {
for (WebElement e : from.findElements(this.by)) {
if (e.getText().equals(this.text)) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
} else {
try {
driver.switchTo().defaultContent().switchTo().frame("top");
from.findElement(this.by);
} catch (Exception e) {
logger.error("Unable to find \"" + this.by.toString() + "\". Retrying....");
return Boolean.FALSE;
}
logger.info("Found \"" + this.by.toString() + "\".");
return Boolean.TRUE;
}
}
}
Console out in Eclipse Debug mode:
16:07:08,109 INFO WebDriverUtility: apply Found "By.linkText: Classes".
16:07:10,514 INFO WebDriverUtility: apply Found "By.linkText: Reports".
16:07:17,028 ERROR WebDriverUtility: apply Unable to find "By.linkText: Users". Retrying....
16:07:26,369 INFO WebDriverUtility: apply Found "By.linkText: Users".
16:07:38,272 ERROR WebDriverUtility: apply Unable to find "By.linkText: System". Retrying....
16:07:41,334 INFO WebDriverUtility: apply Found "By.linkText: System".
16:07:47,722 ERROR WebDriverUtility: apply Unable to find "By.linkText: Schools". Retrying....
16:07:50,565 INFO WebDriverUtility: apply Found "By.linkText: Schools".
Console out when running from Eclipse:
16:14:04,179 INFO WebDriverUtility: apply Found "By.linkText: Classes".
16:14:04,726 INFO WebDriverUtility: apply Found "By.linkText: Reports".
16:14:09,771 INFO PageAPITesting: login org.openqa.selenium.NoSuchElementException: Unable to find element with link text == Reports (WARNING: The server did not provide any stacktrace information)
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
Build info: version: '2.0rc3', revision: '12536', time: '2011-06-20 18:19:52'
System info: os.name: 'Windows XP', os.arch: 'x86', os.version: '5.1', java.version: '1.6.0_24'
Driver info: driver.version: RemoteWebDriver
16:14:09,865 INFO PageAPITesting: login current tabs is Classes
16:14:09,958 INFO WebDriverUtility: apply Found "By.linkText: Schools".
16:14:10,240 INFO PageAPITesting: login java.lang.IllegalStateException: Unable to navigate to the ca.schoolspecialty.qa.api.pages.schools.MenuSchoolPage page
I don't see any strange behavior,
The wait.until method, what it does is to call the apply method on the function until it returns something or there is a Time Out.
It's expected to receive NotFoundExceptions sometimes if the element hasn't been created yet, actually if you look in the code you'll see this:
while (clock.isNowBefore(end)) {
try {
T value = isTrue.apply(driver);
if (value != null && Boolean.class.equals(value.getClass())) {
if (Boolean.TRUE.equals(value)) {
return value;
}
} else if (value != null) {
return value;
}
} catch (NotFoundException e) {
// Common case in many conditions, so swallow here, but be ready to
// rethrow if it the element never appears.
lastException = e;
}
sleep();
It catches the exception and does nothing with it, the problem is that you overwrote the apply to catch and logs that exception, so what you are seeing is the expected behavior, there's no other way to check if the element has been created that continuously asking for it.
I myself I'm using this code for the Function generator:
public static Function<WebDriver, WebElement> presenceOfElementLocated(
final By locator) {
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
Is a lot simpler and you can use for any Locator
精彩评论