80

WebDriverSelenium 2.0a2 开始,我无法检查元素是否可见。

WebDriver.findElement返回 a WebElement,不幸的是它不提供isVisible方法。我可以通过使用WebElement.clearWebElement.click两者都抛出一个来解决这个问题ElementNotVisibleException,但这感觉很脏。

有更好的想法吗?

4

12 回答 12

154

即使我回答这个问题有点晚了:

您现在可以使用WebElement.isDisplayed()来检查元素是否可见。

注意

元素不可见的原因有很多。Selenium 尝试覆盖其中的大部分,但在某些极端情况下它不能按预期工作。

例如,如果一个元素有or ,isDisplayed() 它会返回,但至少在我的测试中,它不能可靠地检测一个元素是否由于 CSS 定位而被另一个元素覆盖。falsedisplay: noneopacity: 0

于 2011-09-23T07:31:19.740 回答
24

element instanceof RenderedWebElement应该管用。

于 2010-04-15T15:55:32.617 回答
20

简短的回答:使用#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> 0
  • 它的display属性设置为none
  • visibility道具设置为visible
  • 没有其他元素隐藏它(它是最顶层的元素)

大多数人还会要求它实际上也在视口内(这样人们就可以看到它)。

出于某种原因,纯 Java API 无法满足这种非常正常的需求,而基于它的 Selenium 前端通常会实现一些变体isVisible,这就是为什么我知道这应该是可能的。在浏览了 Node 框架WebDriver.IO的源代码后,我找到了 的源代码isVisible,现在它被重命名为isVisibleInViewport5.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并替换constvar)!要使用它,请将其从Selenium 发送的Filea中读取,以便在客户端上运行。String

另一个可能值得研究的有趣且相关的脚本是selectByVisibleText

如果您还没有使用 Selenium 执行过 JS,那么您可以稍微了解一下或浏览JavaScriptExecutor API

通常,尝试始终使用非阻塞异步脚本(意思是#executeAsyncScript),但由于我们已经有一个同步的阻塞脚本,我们不妨使用正常的同步调用。返回的对象可以是多种类型的对象,因此请适当地进行转换。这可能是一种方法:

/** 
 * 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']"));
    }
}
于 2018-09-10T15:26:32.760 回答
16

我有以下两种建议的方式:

  1. 您可以使用isDisplayed()如下:

    driver.findElement(By.id("idOfElement")).isDisplayed();
    
  2. 您可以定义如下所示的方法并调用它:

    public boolean isElementPresent(By by) {
      try {
        driver.findElement(by);
        return true;
      }
    catch (org.openqa.selenium.NoSuchElementException e) {
        return false;
      }
    }
    

现在,您可以进行如下断言来检查元素是否存在:

assertTrue(isElementPresent(By.id("idOfElement")));
于 2012-10-11T04:25:48.867 回答
9

如果您使用的是 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
于 2012-11-27T15:21:19.330 回答
2

查看元素是否可见很重要,因为它Driver.FindElement只会检查 HTML 源。但是弹出代码可能在页面 html 中,并且不可见。因此,Driver.FindElement函数返回误报(您的测试将失败)

于 2011-08-18T21:36:34.493 回答
1

验证 ele 是可见的。

public static boolean isElementVisible(final By by)
    throws InterruptedException {
        boolean value = false;

        if (driver.findElements(by).size() > 0) {
            value = true;
        }
        return value;
    }
于 2014-06-12T14:06:07.250 回答
1

如果您使用的是页面工厂,那么您可以尝试以下代码供您参考:

public static boolean isElementVisible(WebElement webElement, int timeOut) {
    try {
      WebDriverWait wait = new WebDriverWait(driver, timeOut);
      wait.until(ExpectedConditions.visibilityOf(webElement));
      return true;
    } catch (org.openqa.selenium.NoSuchElementException e) {
      return false;
    }
  }
于 2021-05-12T13:26:04.407 回答
0
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
于 2017-02-14T10:55:04.597 回答
-1

这是我的做法(请忽略担心 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;
}
于 2015-05-22T11:02:18.707 回答
-1
    try{
        if( driver.findElement(By.xpath("//div***")).isDisplayed()){
          System.out.println("Element is Visible");
        }
}
catch(NoSuchElementException e){
   else{
     System.out.println("Element is InVisible");
        }
}
于 2018-04-18T05:29:11.533 回答
-2

试试这个

public boolean isPrebuiltTestButtonVisible() {
    try {

        if (preBuiltTestButton.isEnabled()) {

            return true;

        } else {

            return false;
        }

    } catch (Exception e) {

        e.printStackTrace();
        return false;
    }
}
于 2014-10-18T10:26:29.530 回答