How to check if an element is visible with WebDriver How to check if an element is visible with WebDriver java java

How to check if an element is visible with WebDriver


Even though I'm somewhat late answering the question:

You can now use WebElement.isDisplayed() to check if an element is visible.

Note:

There are many reasons why an element could be invisible. Selenium tries cover most of them, but there are edge cases where it does not work as expected.

For example, isDisplayed() does return false if an element has display: none or opacity: 0, but at least in my test, it does not reliably detect if an element is covered by another due to CSS positioning.


element instanceof RenderedWebElement should work.


Short answer: use #visibilityOfElementLocated

None of the answers using isDisplayed or similar are correct. They only check if the display property is not none, not if the element can actually be seen! Selenium had a bunch of static utility methods added in the ExpectedConditions class. Two of them can be used in this case:

Usage

@Test// visibilityOfElementLocated has been statically importedpublic 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();

Custom visibility check running on the client

This was my answer before finding out about the utility methods on ExpectedConditions. It might still be relevant, as I assume it does more than the method mentioned above, which only checks the element has a height and a width.

In essence: this cannot be answered by Java and the findElementBy* methods and WebElement#isDisplayed alone, as they can only tell you if an element exists, not if it is actually visible. The OP hasn't defined what visible means, but it normally entails

  • it has an opacity > 0
  • it has the display property set to something else than none
  • the visibility prop is set to visible
  • there are no other elements hiding it (it's the topmost element)

Most people would also include the requirement that it is actually within the viewport as well (so a person would be able to see it).

For some reason, this quite normal need is not met by the pure Java API, while front-ends to Selenium that builds upon it often implements some variation of isVisible, which is why I knew this should be possible. And after browsing the source of the Node framework WebDriver.IO I found the source of isVisible, which is now renamed to the more aptly name of isVisibleInViewport in the 5.0-beta.

Basically, they implement the custom command as a call that delegates to a javascript that runs on the client and does the actual work! This is the "server" bit:

export default function isDisplayedInViewport () {    return getBrowserObject(this).execute(isDisplayedInViewportScript, {        [ELEMENT_KEY]: this.elementId, // w3c compatible        ELEMENT: this.elementId // jsonwp compatible    })}

So the interesting bit is the javascript sent to run on the client:

/** * 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}

This piece of JS can actually be copied (almost) verbatim into your own codebase (remove export default and replace const with var in case of non-evergreen browsers)! To use it, read it from File into a String that can be sent by Selenium for running on the client.

Another interesting and related script that might be worth looking into is selectByVisibleText.

If you haven't executed JS using Selenium before you could have a small peek into this or browse the JavaScriptExecutor API.

Usually, try to always use non-blocking async scripts (meaning #executeAsyncScript), but since we already have a synchronous, blocking script we might as well use the normal sync call. The returned object can be many types of Object, so cast approprately. This could be one way of doing it:

/**  * 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']"));    }}