Selenium:尽管存在不可见元素,但让 findElements 等待可见元素
Selenium: Let findElements wait for visible element although invisible element exists
我们想将一些键发送到由名称标识的元素。在应用程序中可能有多个具有相同名称的元素,但在这种情况下只有一个元素是可见的。为此,我们有一个这样的代码片段(简单代码,没有生产代码):
List<WebElement> list = driver.findElements(By.xpath("//[@name='title']"));
for (WebElement elem : list) {
try {
elem.sendKeys(value);
break;
} catch (Exception e) {
// ignore
}
}
如果标题元素还不存在,我们使用隐式等待等待它出现。所以通常这会很好用。无论如何,有时我们会遇到这样的情况,即已经有具有该名称的元素(但被隐藏),而正确的元素将由异步代码创建。但在这种情况下,代码将不起作用。由于 findElements()
将 return 立即(没有隐式等待)只是 returning 不可见元素。在这种情况下,sendKeys()
将等待元素变得可见,但这永远不会发生(忽略在 findElements
之后创建的新元素),因此在隐式等待超时后它会失败。
基本上我们需要能够告诉 findElements()
我们只想拥有可见元素。如果没有可见元素,Selenium 应该等待隐式等待时间。这可能吗?
作为您的用例涉及:
- 可能有多个同名元素,但在这种情况下只有一个可见
- 将一些键发送到由名称标识的元素
- 等待出现
- 使用隐式等待
满足上述所有条件的多用途解决方案是使用 WebDriverWait in conjunction with ExpectedConditions 设置为 elementToBeClickable()
。
elementToBeClickable()
: 期望检查元素可见并启用,以便您可以单击它。
代码示例:
try {
new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//button[@class='nsg-button']"))).sendKeys(value);
}
catch (TimeoutException e) {
System.out.println("Desired element was not present");
}
此外,您必须删除
的所有实例
Note: Do not mix implicit and explicit waits
. Doing so can cause unpredictable wait times
. For example setting an implicit wait of 10 seconds and an explicit wait of 15 seconds, could cause a timeout to occur after 20 seconds.
您可以在 Replace implicit wait with explicit wait (selenium webdriver & java)
中找到相关讨论
根据 DebanjanB 和 JeffC 的回答,我能够创建自己的等待实现,它等待第一个可见元素,但也考虑了在等待期间创建的元素:
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
for (WebElement element : elements) {
if (element.isDisplayed()) {
return element;
}
}
return null;
});
或使用流 ;-)
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
return elements.stream()
.filter(WebElement::isDisplayed)
.findFirst()
.orElse(null);
});
我们想将一些键发送到由名称标识的元素。在应用程序中可能有多个具有相同名称的元素,但在这种情况下只有一个元素是可见的。为此,我们有一个这样的代码片段(简单代码,没有生产代码):
List<WebElement> list = driver.findElements(By.xpath("//[@name='title']"));
for (WebElement elem : list) {
try {
elem.sendKeys(value);
break;
} catch (Exception e) {
// ignore
}
}
如果标题元素还不存在,我们使用隐式等待等待它出现。所以通常这会很好用。无论如何,有时我们会遇到这样的情况,即已经有具有该名称的元素(但被隐藏),而正确的元素将由异步代码创建。但在这种情况下,代码将不起作用。由于 findElements()
将 return 立即(没有隐式等待)只是 returning 不可见元素。在这种情况下,sendKeys()
将等待元素变得可见,但这永远不会发生(忽略在 findElements
之后创建的新元素),因此在隐式等待超时后它会失败。
基本上我们需要能够告诉 findElements()
我们只想拥有可见元素。如果没有可见元素,Selenium 应该等待隐式等待时间。这可能吗?
作为您的用例涉及:
- 可能有多个同名元素,但在这种情况下只有一个可见
- 将一些键发送到由名称标识的元素
- 等待出现
- 使用隐式等待
满足上述所有条件的多用途解决方案是使用 WebDriverWait in conjunction with ExpectedConditions 设置为 elementToBeClickable()
。
elementToBeClickable()
: 期望检查元素可见并启用,以便您可以单击它。代码示例:
try { new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//button[@class='nsg-button']"))).sendKeys(value); } catch (TimeoutException e) { System.out.println("Desired element was not present"); }
此外,您必须删除
Note: Do not mix
implicit and explicit waits
. Doing so can causeunpredictable wait times
. For example setting an implicit wait of 10 seconds and an explicit wait of 15 seconds, could cause a timeout to occur after 20 seconds.
您可以在 Replace implicit wait with explicit wait (selenium webdriver & java)
中找到相关讨论根据 DebanjanB 和 JeffC 的回答,我能够创建自己的等待实现,它等待第一个可见元素,但也考虑了在等待期间创建的元素:
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
for (WebElement element : elements) {
if (element.isDisplayed()) {
return element;
}
}
return null;
});
或使用流 ;-)
new WebDriverWait(driver, 5).until(drv -> {
List<WebElement> elements = drv.findElements(By.xpath("//[@name='title']"));
return elements.stream()
.filter(WebElement::isDisplayed)
.findFirst()
.orElse(null);
});