随着WebDriver
硒2.0a2我有麻烦检查如果一个元素是可见的。
WebDriver.findElement
返回WebElement
,不幸的是没有提供isVisible
方法。我可以使用WebElement.clear
或WebElement.click
两者都抛出一个来解决这个问题ElementNotVisibleException
,但这感觉很脏。
还有更好的主意吗?
Answers:
element instanceof RenderedWebElement
应该管用。
RemoteWebElement
。但是,是的,如@sleske所写WebElement.isDisplayed
,现在可以使用,并且它可能会在此用例中正常工作(我再也没有可用的代码了,因此无法测试)。
isDisplayed()
对于所讨论的版本,使用不是正确的答案。
即使我回答这个问题有些晚:
现在,您可以WebElement.isDisplayed()
用来检查元素是否可见。
注意事项:
元素不可见的原因有很多。Selenium尝试涵盖了大多数尝试,但是在某些极端情况下,Selenium无法按预期工作。
例如,如果某个元素具有或,isDisplayed()
则返回,但是至少在我的测试中,由于CSS定位,它不能可靠地检测到某个元素是否被另一个元素覆盖。false
display: none
opacity: 0
display
设置道具仅覆盖了部分可能的状态,并且在很多情况下会返回误报。
isDisplayed()
则返回false
true。当然,在某些极端情况下,它无法按预期运行,但通常可以运行,除非您在页面中做一些非常漂亮的事情。答案已更新。
我有以下2种建议的方式:
您可以isDisplayed()
如下使用:
driver.findElement(By.id("idOfElement")).isDisplayed();
您可以定义如下所示的方法并调用它:
public boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
}
catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
}
现在,您可以按以下方式进行断言以检查元素是否存在:
assertTrue(isElementPresent(By.id("idOfElement")));
#visibilityOfElementLocated
使用isDisplayed
或类似的答案均不正确。他们只检查display
属性是否不是none
,而不检查元素是否实际可见!Selenium在ExpectedConditions
类中添加了一堆静态实用程序方法。在这种情况下,可以使用其中两个:
用法
@Test
// visibilityOfElementLocated has been statically imported
public demo(){
By searchButtonSelector = By.className("search_button");
WebDriverWait wait = new WebDriverWait(driver, 10);
driver.get(homeUrl);
WebElement searchButton = wait.until(
visibilityOfElementLocated
(searchButtonSelector));
//clicks the search button
searchButton.click();
这是我的答案,然后才了解关于的实用方法ExpectedConditions
。它可能仍然很重要,因为我认为它的作用不止上述方法,后者仅检查元素的高度和宽度。
本质上:这不能由Java和findElementBy*
方法WebElement#isDisplayed
来解决,而且不能单独解决,因为它们只能告诉您元素是否存在,而不是元素是否实际可见。OP尚未定义可见的含义,但通常需要
opacity
> 0display
属性设置为除none
visibility
道具设为visible
大多数人也会要求它实际上也必须在视口内(这样一个人就能看到它)。
出于某种原因,纯Java API无法满足这种非常正常的需求,而基于Selenium构建的Selenium的前端通常会实现的某些变体isVisible
,这就是为什么我知道这是可能的。浏览Node框架WebDriver.IO的源代码后isVisible
,我找到的源代码,现在isVisibleInViewport
在5.0-beta中将其重命名为更恰当的名称。
基本上,它们将自定义命令作为调用来实现,该调用委托给在客户端上运行的javascript并完成实际工作!这是“服务器”位:
export default function isDisplayedInViewport () {
return getBrowserObject(this).execute(isDisplayedInViewportScript, {
[ELEMENT_KEY]: this.elementId, // w3c compatible
ELEMENT: this.elementId // jsonwp compatible
})
}
因此,有趣的是发送到客户端上运行的javascript:
/**
* check if element is visible and within the viewport
* @param {HTMLElement} elem element to check
* @return {Boolean} true if element is within viewport
*/
export default function isDisplayedInViewport (elem) {
const dde = document.documentElement
let isWithinViewport = true
while (elem.parentNode && elem.parentNode.getBoundingClientRect) {
const elemDimension = elem.getBoundingClientRect()
const elemComputedStyle = window.getComputedStyle(elem)
const viewportDimension = {
width: dde.clientWidth,
height: dde.clientHeight
}
isWithinViewport = isWithinViewport &&
(elemComputedStyle.display !== 'none' &&
elemComputedStyle.visibility === 'visible' &&
parseFloat(elemComputedStyle.opacity, 10) > 0 &&
elemDimension.bottom > 0 &&
elemDimension.right > 0 &&
elemDimension.top < viewportDimension.height &&
elemDimension.left < viewportDimension.width)
elem = elem.parentNode
}
return isWithinViewport
}
这片JS的其实是可以复制的(几乎)逐字到您自己的代码库(删除export default
和替换const
用var
在非常绿浏览器的情况下)!要使用它,请将其读File
入String
Selenium可以发送的,以在客户端上运行。
另一个值得研究的有趣且相关的脚本是selectByVisibleText。
如果您尚未使用Selenium执行JS,则可以对此进行一小步浏览或浏览JavaScriptExecutor API。
通常,尝试始终使用非阻塞的异步脚本(即#executeAsyncScript),但是由于我们已经有一个同步的阻塞脚本,因此我们也可以使用普通的同步调用。返回的对象可以是许多类型的Object,因此请适当地进行转换。这可能是这样做的一种方式:
/**
* Demo of a java version of webdriverio's isDisplayedInViewport
* https://github.com/webdriverio/webdriverio/blob/v5.0.0-beta.2/packages/webdriverio/src/commands/element/isDisplayedInViewport.js
* The super class GuiTest just deals with setup of the driver and such
*/
class VisibleDemoTest extends GuiTest {
public static String readScript(String name) {
try {
File f = new File("selenium-scripts/" + name + ".js");
BufferedReader reader = new BufferedReader( new FileReader( file ) );
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
} catch(IOError e){
throw new RuntimeError("No such Selenium script: " + f.getAbsolutePath());
}
}
public static Boolean isVisibleInViewport(RemoteElement e){
// according to the Webdriver spec a string that identifies an element
// should be deserialized into the corresponding web element,
// meaning the 'isDisplayedInViewport' function should receive the element,
// not just the string we passed to it originally - how this is done is not our concern
//
// This is probably when ELEMENT and ELEMENT_KEY refers to in the wd.io implementation
//
// Ref https://w3c.github.io/webdriver/#dfn-json-deserialize
return js.executeScript(readScript("isDisplayedInViewport"), e.getId());
}
public static Boolean isVisibleInViewport(String xPath){
driver().findElementByXPath("//button[@id='should_be_visible']");
}
@Test
public demo_isVisibleInViewport(){
// you can build all kinds of abstractions on top of the base method
// to make it more Selenium-ish using retries with timeouts, etc
assertTrue(isVisibleInViewport("//button[@id='should_be_visible']"));
assertFalse(isVisibleInViewport("//button[@id='should_be_hidden']"));
}
}
如果您使用的是C#,它将是driver.Displayed。这是我自己的项目中的一个示例:
if (!driver.FindElement(By.Name("newtagfield")).Displayed) //if the tag options is not displayed
driver.FindElement(By.Id("expand-folder-tags")).Click(); //make sure the folder and tags options are visible
display
属性设置为以外的其他属性none
。它仍然可能被其他元素隐藏,高度为零,等等。
请务必查看该元素是否可见,因为Driver.FindElement
只会检查HTML源。但是弹出代码可能在页面html中,并且不可见。因此,Driver.FindElement
函数返回假阳性(您的测试将失败)
验证ele是否可见。
public static boolean isElementVisible(final By by)
throws InterruptedException {
boolean value = false;
if (driver.findElements(by).size() > 0) {
value = true;
}
return value;
}
这是我的操作方法(请忽略担心的Logger类调用):
public boolean isElementExist(By by) {
int count = driver.findElements(by).size();
if (count>=1) {
Logger.LogMessage("isElementExist: " + by + " | Count: " + count, Priority.Medium);
return true;
}
else {
Logger.LogMessage("isElementExist: " + by + " | Could not find element", Priority.High);
return false;
}
}
public boolean isElementNotExist(By by) {
int count = driver.findElements(by).size();
if (count==0) {
Logger.LogMessage("ElementDoesNotExist: " + by, Priority.Medium);
return true;
}
else {
Logger.LogMessage("ElementDoesExist: " + by, Priority.High);
return false;
}
}
public boolean isElementVisible(By by) {
try {
if (driver.findElement(by).isDisplayed()) {
Logger.LogMessage("Element is Displayed: " + by, Priority.Medium);
return true;
}
}
catch(Exception e) {
Logger.LogMessage("Element is Not Displayed: " + by, Priority.High);
return false;
}
return false;
}
public boolean isElementFound( String text) {
try{
WebElement webElement = appiumDriver.findElement(By.xpath(text));
System.out.println("isElementFound : true :"+text + "true");
}catch(NoSuchElementException e){
System.out.println("isElementFound : false :"+text);
return false;
}
return true;
}
text is the xpath which you would be passing when calling the function.
the return value will be true if the element is present else false if element is not pressent
try{
if( driver.findElement(By.xpath("//div***")).isDisplayed()){
System.out.println("Element is Visible");
}
}
catch(NoSuchElementException e){
else{
System.out.println("Element is InVisible");
}
}
尝试这个
public boolean isPrebuiltTestButtonVisible() {
try {
if (preBuiltTestButton.isEnabled()) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}