Reputation: 20934
With WebDriver
from Selenium 2.0a2 I am having trouble checking if an element is visible.
WebDriver.findElement
returns a WebElement
, which unfortunately doesn't offer an isVisible
method. I can go around this by using WebElement.clear
or WebElement.click
both of which throw an ElementNotVisibleException
, but this feels very dirty.
Any better ideas?
Upvotes: 88
Views: 313381
Reputation: 312
Answer from oligofren - the method isDisplayedInViewport works. Thanks for that. Helped me. Just have a couple of suggestions -
I have used the following code based on what oligofren provided in his answer. I am passing the WebElement as an argument to the selenium execute_script method and reading it as elem
var elem = arguments[0]
const dde = document.documentElement
let isWithinViewport = true
var firstTime = true
while (elem.parentNode && elem.parentNode.getBoundingClientRect) {
const elemDimension = elem.getBoundingClientRect()
const elemComputedStyle = window.getComputedStyle(elem)
const viewportDimension = {
width: dde.clientWidth,
height: dde.clientHeight
}
let dimCondition = true
if (firstTime){
dimCondition = dimCondition && (elemDimension.bottom > 0 &&
elemDimension.right > 0 &&
(elemDimension.top + elemDimension.height) < viewportDimension.height &&
(elemDimension.left + elemDimension.width) < viewportDimension.width)
firstTime = false
}
isWithinViewport = isWithinViewport && dimCondition &&
(elemComputedStyle.display !== 'none' &&
elemComputedStyle.visibility === 'visible' &&
parseFloat(elemComputedStyle.opacity, 10) > 0
)
console.log(isWithinViewport)
console.log(elem.nodeName)
elem = elem.parentNode
}
return isWithinViewport
Upvotes: 1
Reputation: 654
If you are using page factory then you can try the below code for your reference:
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;
}
}
Upvotes: 1
Reputation: 83577
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.
Upvotes: 164
Reputation: 22923
#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 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();
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
opacity
> 0display
property set to something else than none
visibility
prop is set to visible
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']"));
}
}
Upvotes: 24
Reputation: 21
try{
if( driver.findElement(By.xpath("//div***")).isDisplayed()){
System.out.println("Element is Visible");
}
}
catch(NoSuchElementException e){
else{
System.out.println("Element is InVisible");
}
}
Upvotes: -1
Reputation: 37746
I have the following 2 suggested ways:
You can use isDisplayed()
as below:
driver.findElement(By.id("idOfElement")).isDisplayed();
You can define a method as shown below and call it:
public boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
}
catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
}
Now, you can do assertion as below to check either the element is present or not:
assertTrue(isElementPresent(By.id("idOfElement")));
Upvotes: 18
Reputation: 128
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
Upvotes: 0
Reputation: 4594
Here is how I would do it (please ignore worry Logger class calls):
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;
}
Upvotes: -1
Reputation: 1
try this
public boolean isPrebuiltTestButtonVisible() {
try {
if (preBuiltTestButton.isEnabled()) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Upvotes: -3
Reputation: 1423
Verifying ele is visible.
public static boolean isElementVisible(final By by)
throws InterruptedException {
boolean value = false;
if (driver.findElements(by).size() > 0) {
value = true;
}
return value;
}
Upvotes: 1
Reputation: 1071
If you're using C#, it would be driver.Displayed. Here's an example from my own project:
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
Upvotes: 9
Reputation: 31
It is important to see if the element is visible or not as the Driver.FindElement
will only check the HTML source. But popup code could be in the page html, and not be visible. Therefore, Driver.FindElement
function returns a false positive (and your test will fail)
Upvotes: 3