如何使用 WebDriver 检查元素是不是可见

Posted

技术标签:

【中文标题】如何使用 WebDriver 检查元素是不是可见【英文标题】:How to check if an element is visible with WebDriver如何使用 WebDriver 检查元素是否可见 【发布时间】:2011-02-08 10:13:22 【问题描述】:

使用 Selenium 2.0a2 中的 WebDriver,我无法检查元素是否可见。

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

有更好的想法吗?

【问题讨论】:

【参考方案1】:

element instanceof RenderedWebElement 应该可以工作。

【讨论】:

这不起作用,但此接口委托方法 isDisplayed 并且它有效。感谢您的提示。 (+1) 这仍然与 selenium 2.0 相关吗?我认为不需要 RenderedWebElement(类本身已经消失)。 @Eugen 我认为它已更改为RemoteWebElement。但是,正如@sleske 所写,WebElement.isDisplayed 现在可用,它可能会在这个用例中工作(我没有该代码可用,因此无法测试)。 真的吗?问题是关于 Selenium (2.0a2) 的特定版本。因此,使用isDisplayed() 并不是所讨论版本的正确答案。 isDisplayed 不起作用。即使元素明显未显示,它也表示正确。【参考方案2】:

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

【讨论】:

如果元素存在于 HTML 代码中,那么即使元素被隐藏,findElement 也会通过。或者说不可见(如下拉菜单)。问题是找出元素是否可见。 @CallumRogers 检查我的答案。它展示了基于 Selenium 的 Webdriver.io NodeJS 框架的 Java 版本。基本上你需要在客户端运行JS来确定。【参考方案3】:

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

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

注意

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

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

【讨论】:

isDisplayed 即使元素不可见也会返回 true。 我被告知这不是一个错误,并且它可以按预期工作。显示对他们的意义与对英语世界的其他人不同。 这并不是说元素是否可见,只有当它存在于页面上时。它可能被其他元素隐藏和/或在视口之外。 display 属性是否设置仅涵盖可能状态的一小部分,并且在很多情况下会返回误报。 @oligofren:是的,元素不可见的原因有很多——Selenium 确实涵盖了其中的大部分。例如,isDisplayed()确实返回false,如果元素在视口之外,或者不透明度=0。当然,在某些极端情况下它不能按预期工作,但它通常可以工作,除非你在页面中做了非常花哨的事情。答案已更新。 @RamzanMahmood:是的,这是设计使然。您不能在不再位于 DOM 中的元素上调用 isDisplayed()【参考方案4】:

我有以下两种建议方式:

    您可以使用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")));

【讨论】:

但这会一直等到超时发生 @Anna:我很高兴 - 谢谢。 这并不是说元素是否可见,只有当它存在于页面上时。它可能被其他元素隐藏和/或在视口之外,因此会产生误报。【参考方案5】:

如果您使用的是 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

【讨论】:

可见与显示不一样。这只是检查元素是否将 css prop display 设置为 none 以外的其他值。它仍然可能被其他元素隐藏,高度为零等。这不会捕捉到。【参考方案6】:

验证 ele 是否可见。

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

        if (driver.findElements(by).size() > 0) 
            value = true;
        
        return value;
    

【讨论】:

与OP无关,但可以简化功能。怎么样:返回 driver.findElements(by).size() > 0; 只检查你是否能找到它,而不是它是否可见。它会找到一个隐藏的元素。【参考方案7】:

试试这个

public boolean isPrebuiltTestButtonVisible() 
    try 

        if (preBuiltTestButton.isEnabled()) 

            return true;

         else 

            return false;
        

     catch (Exception e) 

        e.printStackTrace();
        return false;
    

【讨论】:

【参考方案8】:

我会这样做(请忽略担心 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;

【讨论】:

我也在做同样的事情。直接使用 isDisplayed() 会抛出异常,所以可以作为检查,但不能作为这样驱动工作流的条件。【参考方案9】:
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

【讨论】:

请提供更多详细信息来回答您的问题。这是如何工作的,这如何解决 OP 的问题? 不是检查一个元素是否存在,而是检查它是否可见【参考方案10】:
    try
        if( driver.findElement(By.xpath("//div***")).isDisplayed())
          System.out.println("Element is Visible");
        

catch(NoSuchElementException e)
   else
     System.out.println("Element is InVisible");
        

【讨论】:

虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。 这并不是说元素是否可见,只有当它存在于页面上时。它可能被其他元素隐藏和/或位于视口之外。【参考方案11】:

简答:使用#visibilityOfElementLocated

使用isDisplayed 或类似名称的答案均不正确。他们只检查display 属性是否不是none,而不检查元素是否真的可以看到! Selenium 在ExpectedConditions 类中添加了一堆静态实用程序方法。在这种情况下可以使用其中两个:

visibilityOfElementLocated(允许元素不存在) visibilityOf(元素必须存在)

用法

@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 没有定义 visible 的含义,但它通常需要

它有一个opacity > 0 它的display 属性设置为none 以外的其他值 visibility 属性设置为 visible 没有其他元素隐藏它(它是最顶层的元素)

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

出于某种原因,纯 Java API 无法满足这种非常正常的需求,而基于它的 Selenium 前端通常会实现 isVisible 的一些变体,这就是为什么我知道这应该是可能的。在浏览了 Node 框架 WebDriver.IO 的源代码后,我发现了 isVisible 的 the source,现在在 5.0-beta 中更贴切地改名为 isVisibleInViewport。 p>

基本上,他们将自定义命令实现为一个调用,委托给在客户端运行的 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,您可以拥有 a small peek into this 或浏览 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']"));
    

【讨论】:

【参考方案12】:

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

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;
    
  

【讨论】:

以上是关于如何使用 WebDriver 检查元素是不是可见的主要内容,如果未能解决你的问题,请参考以下文章

Selenium C# Webdriver如何检测元素是不是可见

Selenium Webdriver Python - 检查元素是不是可见/检测到/存在[重复]

如何使用 Selenium WebDriver 检查元素是不是可点击

WebDriver:检查元素是不是存在? [复制]

如何使用 Puppeteer 和纯 JavaScript 检查元素是不是可见?

如何使用 selenium webdriver 检查按钮是不是可点击