196

Is there a way how to test if an element is present? Any findElement method would end in an exception, but that is not what I want, because it can be that an element is not present and that is okay. That is not a fail of the test, so an exception can not be the solution.

I've found this post: Selenium C# WebDriver: Wait until element is present.

But this is for C#, and I am not very good at it. What would the code be in Java? I tried it out in Eclipse, but I didn't get it right into Java code.

This is the code:

public static class WebDriverExtensions{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds){

        if (timeoutInSeconds > 0){
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }

        return driver.FindElement(by);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tester
  • 3,977
  • 5
  • 39
  • 59
  • I have a couple of methods that work very effectively at checking for an object but it depends on what you are wanting to do with it. for example do you want to look for the element until it exists, do you want to look for it until it no longer exists or do you want to just try to to find it? – CBRRacer Nov 03 '11 at 17:10
  • 2
    Java is very similar to C# I think one of the main problems you are running into here is in java it's WebElement instead of IWebElement – CBRRacer Nov 03 '11 at 17:12
  • 1
    Do you know about the implicit wait method? By setting this up at the start of the test you never have to check for an element's existence as it is uses the implicit wait value to poll, however if it exceeds that value it will throw an exception – Bob Evans Nov 03 '11 at 18:56
  • 1
    Here is my post about WebDriverWait in Java: [WebDriverWait](http://ksblog.org/index.php?q=WebDriverWait-ajax-javascript-asynchronized-refresh&id=31) –  Nov 15 '11 at 14:36
  • If either case is ok, this can be problematic for test performance, as the wait time associated for waiting for an element that you don't expect to exist really adds up. I've used a few hacks to get around wait time, but have yet to find a truly clean solution for this. – mrfreester Nov 03 '14 at 22:26
  • The only save way is: static bool isElementPresent(dynamic element, By by) { try { element.FindElement(by); return true; } catch (NoSuchElementException e) { return false; } } – Andreas Karz Mar 14 '18 at 11:03
  • Related (affects many of the answers here): *[find_element_by_\* commands are deprecated in Selenium](https://stackoverflow.com/questions/69875125/)*. See also [this comment](https://stackoverflow.com/questions/30002313/selenium-finding-elements-by-class-name-in-python#comment128785684_30025430). – Peter Mortensen Nov 13 '22 at 22:05

21 Answers21

330

Use findElements instead of findElement.

findElements will return an empty list if no matching elements are found instead of an exception.

To check that an element is present, you could try this

Boolean isPresent = driver.findElements(By.yourLocator).size() > 0

This will return true if at least one element is found and false if it does not exist.

The official documentation recommends this method:

findElement should not be used to look for non-present elements, use findElements(By) and assert zero length response instead.

Raedwald
  • 46,613
  • 43
  • 151
  • 237
el roso
  • 3,586
  • 1
  • 16
  • 12
  • 40
    This will add a lot of time it takes to run your tests. You can't use this technique everywhere. – yurisich Oct 25 '12 at 15:13
  • I understand that it might not be the best solution for all scenarios but it works well in my case where I have to use a do-while loop to judge if every time an element can be located or not. – Chen Xie Dec 18 '14 at 23:45
  • 13
    @Droogans - I will not add time to your tests. The reason it wont is because the default implicit wait is still 0. If you increased the default implicit wait, then I agree that it would , but it doesn't appear to be the case here. – djangofan Jan 14 '15 at 18:56
  • 2
    Good call djangofan! I successfully used this strategy by changing the driver timeouts' implicit wait to zero, then changing it back to its previous value. – emery May 27 '15 at 17:18
  • 3
    This gave a NoSuchElementFound exception, which is a shame as I was hoping to use this to avoid catching that exception in a given instance. –  Aug 04 '15 at 08:54
  • 3
    Much easier way is to use: if(driver.getPageSource().contains("A text in page")){} If the page contains this text then the condition will be true, or else it will be false and you can code accordingly. – pradyot Nov 20 '18 at 10:01
  • 2
    Can someone explain to me why do we even need the `presenceOfElementLocated()` method if it throws the `NoSuchElementException` (according to the answers below). What is the point of this method then if it cannot even normally check the presence of an element ? – LexSav Nov 08 '19 at 17:16
  • Great answer ! I was using findelement in a try catch that was quite slow ! Thanks for sharing ! – Carl Verret Feb 18 '22 at 17:52
  • From [a comment](https://stackoverflow.com/questions/30002313/selenium-finding-elements-by-class-name-in-python#comment128785684_30025430): *"`find_element_by_*` and `find_elements_by_*` are removed in Selenium 4.3.0. Use `find_element` instead."*. Though it doesn't really answer the question what can be done if the number of elements is different from exactly one. – Peter Mortensen Nov 11 '22 at 17:38
  • I have `Error: Object of class Facebook\WebDriver\Remote\RemoteWebElement could not be converted to string` :( – Denis Chenu Apr 03 '23 at 07:15
  • @pradyot ... AND it's much faster! – Arash Kamangir Apr 04 '23 at 12:53
64

Use a private method that simply looks for the element and determines if it is present like this:

private boolean existsElement(String id) {
    try {
        driver.findElement(By.id(id));
    } catch (NoSuchElementException e) {
        return false;
    }
    return true;
}

This would be quite easy and does the job.

You could even go further and take a By elementLocator as a parameter, eliminating problems if you want to find the element by something other than an id.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dennis
  • 1,061
  • 10
  • 21
  • 5
    Yep, this is the way to go. Don't understand why people are ignoring this way, and counting matching elements, seeing if the result is 0. – Ralph Lavelle Aug 14 '14 at 05:54
  • 48
    Well, I must say using Exceptions to regulate the program flow is not the best way to go. – Dennis Aug 14 '14 at 11:13
  • 2
    Huh? It was your suggestion! It is a good way to go if your test expects not to find the element. As you show, just return null and assert.isnull or isnotnull, which is a meaningful way to test if a thing exists. – Ralph Lavelle Aug 14 '14 at 22:56
  • 2
    In case I misinterpreted the question "is there a way how to test if an element is present?" wrong, I will be glad to learn why your opinion differs on whether or not this is a legitimate answer. – Dennis Jan 12 '15 at 20:32
  • might want to reduce the wait time. Right now, if the element doesn't exist you must wait "30 seconds" before the function returns false – Jason Smiley Oct 05 '15 at 19:06
  • @Dennis - Why not use exceptions to regulate program flow in this case ? – MasterJoe Sep 01 '16 at 21:47
  • It is simply a slow way if you base your program flow on handling exceptions. It's not wrong but takes some time. You might want to look at [this question](http://stackoverflow.com/questions/299068/how-slow-are-java-exceptions) for a more general answer. – Dennis Sep 03 '16 at 08:45
15

I found that this works for Java:

WebDriverWait waiter = new WebDriverWait(driver, 5000);
waiter.until( ExpectedConditions.presenceOfElementLocated(by) );
driver.FindElement(by);
Len
  • 2,093
  • 4
  • 34
  • 51
Tango Ben
  • 169
  • 1
  • 4
  • 21
    `presenceOfElementLocated` will throw an Exception if the element is not found on any particular attempt. To avoid this, add a `wait.ignoring(NoSuchElementException.class);` statement between the first and second line. – Steve Chambers Jan 22 '14 at 14:03
10
public static WebElement FindElement(WebDriver driver, By by, int timeoutInSeconds)
{
    WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
    wait.until( ExpectedConditions.presenceOfElementLocated(by) ); //throws a timeout exception if element not present after waiting <timeoutInSeconds> seconds
    return driver.findElement(by);
}
RedDeckWins
  • 2,111
  • 14
  • 16
7

I had the same issue. For me, depending on a user's permission level, some links, buttons and other elements will not show on the page. Part of my suite was testing that the elements that should be missing, are missing. I spent hours trying to figure this out. I finally found the perfect solution.

It tells the browser to look for any and all elements based specified. If it results in 0, that means no elements based on the specification was found. Then I have the code execute an *if statement to let me know it was not found.

This is in C#, so translations would need to be done to Java. But it shouldn’t be too hard.

public void verifyPermission(string link)
{
    IList<IWebElement> adminPermissions = driver.FindElements(By.CssSelector(link));
    if (adminPermissions.Count == 0)
    {
        Console.WriteLine("User's permission properly hidden");
    }
}

There's also another path you can take depending on what you need for your test.

The following snippet is checking to see if a very specific element exists on the page. Depending on the element's existence I have the test execute an if else.

If the element exists and is displayed on the page, I have console.write let me know and move on. If the element in question exists, I cannot execute the test I needed, which is the main reasoning behind needing to set this up.

If the element does not exist and is not displayed on the page, I have the else in the if else execute the test.

IList<IWebElement> deviceNotFound = driver.FindElements(By.CssSelector("CSS LINK GOES HERE"));
// If the element specified above results in more than 0 elements and is displayed on page execute the following, otherwise execute what’s in the else statement
if (deviceNotFound.Count > 0 && deviceNotFound[0].Displayed){
    // Script to execute if element is found
} else {
    // Test script goes here.
}

I know I'm a little late on the response to the OP. Hopefully this helps someone!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tasha
  • 73
  • 1
  • 5
6

Try this:

Call this method and pass three arguments:

  1. WebDriver variable. Assuming driver_variable as the driver.
  2. The element which you are going to check. It should provide a from By method. Example: By.id("id")
  3. Time limit in seconds.

Example: waitForElementPresent(driver, By.id("id"), 10);

public static WebElement waitForElementPresent(WebDriver driver, final By by, int timeOutInSeconds) {

    WebElement element;

    try{
        driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); // Nullify implicitlyWait()

        WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
        element = wait.until(ExpectedConditions.presenceOfElementLocated(by));

        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Reset implicitlyWait
        return element; // Return the element

    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prabu Ananthakrishnan
  • 4,139
  • 1
  • 12
  • 16
3

This works for me:

if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
    // Then click on the submit button
}
else{
    // Do something else as submit button is not there
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amstel Bytes
  • 177
  • 1
  • 8
  • 3
    the same problem exist here: what if the element "//*[@id='submit']" does not exist? then an exception will be thrown, thus the if conditional never evaluates – Bryan_C Aug 14 '17 at 18:54
3

You can make the code run faster by shorting the Selenium timeout before your try-catch statement.

I use the following code to check if an element is present.

protected boolean isElementPresent(By selector) {
    selenium.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
    logger.debug("Is element present"+selector);
    boolean returnVal = true;
    try{
        selenium.findElement(selector);
    } catch (NoSuchElementException e) {
        returnVal = false;
    } finally {
        selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
    }
    return returnVal;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aaron Levenstein
  • 385
  • 2
  • 12
  • This is what I use in my code. I leave the Selenium timeout at the default and then use this. – Nicholas DiPiazza Jan 11 '15 at 17:05
  • 3
    Since writing this answer I learned that using ExpectedConditions is considered better form but using a try catch statement is still useful when attempting to determine if an element is not present. – Aaron Levenstein Apr 01 '15 at 15:31
  • I'm stuck on an old version of selenium becuase i have to test IE8. but i will try that when i can upgrade – Nicholas DiPiazza Apr 02 '15 at 11:53
  • Each time your method will set implicit wait timeout, but logically we should set implicit wait only once after initializing driver object and timeout is set to the driver session. – Chandrashekhar Swami Apr 11 '16 at 13:14
  • What is the normal penalty? [3 seconds](https://stackoverflow.com/questions/6521270/webdriver-check-if-an-element-exists/8790334#8790334)? – Peter Mortensen Nov 15 '22 at 22:07
3

Write the following function/methods using Java:

protected boolean isElementPresent(By by){
    try{
        driver.findElement(by);
        return true;
    }
    catch(NoSuchElementException e){
        return false;
    }
}

Call the method with the appropriate parameter during the assertion.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ripon Al Wasim
  • 36,924
  • 42
  • 155
  • 176
2

If you are using rspec-Webdriver in Ruby, you can use this script, assuming that an element should really not be present, and it is a passed test.

First, write this method first from your class RB file:

class Test
  def element_present?
      begin
          browser.find_element(:name, "this_element_id".displayed?
          rescue Selenium::WebDriver::Error::NoSuchElementError
          puts "this element should not be present"
      end
end

Then, in your spec file, call that method.

before(:all) do
    @Test= Test.new(@browser)
end

@Test.element_present?.should == nil

If your element is not present, your spec will pass, but if the element is present, it will throw an error, and the test failed.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
grayshell
  • 21
  • 2
1

Personally, I always go for a mixture of the above answers and create a reusable static utility method that uses the size() > 0 suggestion:

public Class Utility {
   ...
   public static boolean isElementExist(WebDriver driver, By by) {
      return driver.findElements(by).size() > 0;
   ...
}

This is neat, reusable, maintainable, etc.—all that good stuff ;-)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Charlie S
  • 4,366
  • 6
  • 59
  • 97
1
public boolean isElementDisplayed() {
    return !driver.findElements(By.xpath("...")).isEmpty();
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
helloWorld
  • 219
  • 2
  • 11
0

The simplest way I found in Java was:

List<WebElement> linkSearch=  driver.findElements(By.id("linkTag"));
int checkLink = linkSearch.size();

if(checkLink!=0) {
    // Do something you want
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
back2back
  • 113
  • 11
0

To find if a particular Element is present or not, we have to use the findElements() method instead of findElement()...

int i = driver.findElements(By.xpath(".......")).size();
if(i=0)
    System.out.println("Element is not present");
else
    System.out.println("Element is present");

This is worked for me...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Subbarao Gaddam
  • 131
  • 1
  • 3
  • 13
0

This should do it:

try {
    driver.findElement(By.id(id));
} catch (NoSuchElementException e) {
    //do what you need here if you were expecting
    //the element wouldn't exist
}
Scott Helme
  • 4,786
  • 2
  • 23
  • 35
0

You can try implicit wait:

WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));

Or you can try explicit wait one:

IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
    {
        return d.FindElement(By.Id("someDynamicElement"));
    });

Explicit will check if the element is present before some action. Implicit wait could be called in every place in the code. For example, after some Ajax actions.

More you can find at SeleniumHQ page.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
streser
  • 49
  • 2
0

I am giving my snippet of code. So, the below method checks if a random web element 'Create New Application' button exists on a page or not. Note that I have used the wait period as 0 seconds.

public boolean isCreateNewApplicationButtonVisible(){
    WebDriverWait zeroWait = new WebDriverWait(driver, 0);
    ExpectedCondition<WebElement> c = ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@value='Create New Application']"));
    try {
        zeroWait.until(c);
        logger.debug("Create New Application button is visible");
        return true;
    } catch (TimeoutException e) {
        logger.debug("Create New Application button is not visible");
        return false;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rambo7
  • 1,175
  • 1
  • 10
  • 18
0

I would use something like (with Scala [the code in old "good" Java 8 may be similar to this]):

object SeleniumFacade {

  def getElement(bySelector: By, maybeParent: Option[WebElement] = None, withIndex: Int = 0)(implicit driver: RemoteWebDriver): Option[WebElement] = {
    val elements = maybeParent match {
      case Some(parent) => parent.findElements(bySelector).asScala
      case None => driver.findElements(bySelector).asScala
    }
    if (elements.nonEmpty) {
      Try { Some(elements(withIndex)) } getOrElse None
    } else None
  }
  ...
}

so then,

val maybeHeaderLink = SeleniumFacade getElement(By.xpath(".//a"), Some(someParentElement))
ses
  • 13,174
  • 31
  • 123
  • 226
0

In 2022 this can now be done without an annoying delay, or affecting your current implicit wait value.

First bump your Selenium driver to latest (currently 4.1.2).

Then you can use getImplicitWaitTimeout then set timeout to 0 to avoid a wait then restore your previous implicit wait value whatever it was:

Duration implicitWait = driver.manage().timeouts().getImplicitWaitTimeout();
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(0));
final List<WebElement> signOut = driver.findElements(By.linkText("Sign Out"));
driver.manage().timeouts().implicitlyWait(implicitWait); // Restore implicit wait to previous value

if (!signOut.isEmpty()) {
    ....
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
slonik
  • 1,144
  • 11
  • 13
0

Try the below code using the isDispplayed() method to verify if the element is present or not:

WebElement element = driver.findElements(By.xpath(""));
element.isDispplayed();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
arpita biswas
  • 144
  • 1
  • 6
  • 1
    This code does not work: `findElements` return a list but not a single `WebElement`. And if the element is not present then `findElements` will not return that element, therefore one can not invoke any method on it. – Ralph Mar 31 '22 at 20:03
  • I think for that can iterate with loop all elements and one by one can check each element displayed or not – arpita biswas Apr 01 '22 at 05:02
  • 1
    I don't think this was tested. The function name `isDispplayed` is very unlikely to exist (so much for quality assurance). *[displayed](https://en.wiktionary.org/wiki/display#Verb)* – Peter Mortensen Nov 13 '22 at 21:51
0

There could be multiple reasons due to which you might observe exceptions while locating a WebElement using Selenium driver.

I would suggest you to apply the below suggestions for different scenarios:

Scenario 1: You just want to find out if a certain WebElement is present on the screen or not. For example, the Save button icon will only appear until the form is fully filled and you may want to check if Save button is present or not in your test.

Use the below code -

public Boolean isElementLoaded(By locator){
    return !getWebElements(this.driver.findElements(locator), locator).isEmpty();
}

Scenario 2: You want to wait before a WebElement becomes visible in the UI

public List<WebElement> waitForElementsToAppear(By locator) {
    return wait.until(visibilityOfAllElementsLocatedBy(by));
}

Scenario 3: Your test is flaky because the WebElement becomes stale sometimes and gets detached from the DOM.

protected final List<Class<? extends WebDriverException>> exceptionList =
    List.of(NoSuchWindowException.class,
            NoSuchFrameException.class,
            NoAlertPresentException.class,
            InvalidSelectorException.class,
            ElementNotVisibleException.class,
            ElementNotSelectableException.class,
            TimeoutException.class,
            NoSuchSessionException.class,
            StaleElementReferenceException.class);

    public WebElement reactivateWebElement(By by, WebElement element){
        try {
            wait.ignoreAll(exceptionList)
                    .until(refreshed(visibilityOf(element)));
            logger.info(("Element is available.").concat(BLANK).concat(element.toString()));
        } catch (WebDriverException exception) {
            logger.warn(exception.getMessage());
        } return this.driver.findElement(by);
    }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131