WebDriver: check if an element exists?

JavaTestingWebdriverSelenium Webdriver

Java Problem Overview


How to check if an element exist with web driver?

Is using a try catch really the only possible way?

boolean present;
try {
   driver.findElement(By.id("logoutLink"));
   present = true;
} catch (NoSuchElementException e) {
   present = false;
}

Java Solutions


Solution 1 - Java

You could alternatively do:

driver.findElements( By.id("...") ).size() != 0

Which saves the nasty try/catch

p.s.

Or more precisely by @JanHrcek here

!driver.findElements(By.id("...")).isEmpty()

Solution 2 - Java

I agree with Mike's answer but there's an implicit 3 second wait if no elements are found which can be switched on/off which is useful if you're performing this action a lot:

driver.manage().timeouts().implicitlyWait(0, TimeUnit.MILLISECONDS);
boolean exists = driver.findElements( By.id("...") ).size() != 0
driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

Putting that into a utility method should improve performance if you're running a lot of tests

Solution 3 - Java

As the comment stated, this is in C# not Java but the idea is the same. I've researched this issue extensively and ultimately the issue is, FindElement always returns an exception when the element doesn't exist. There isn't an overloaded option that allows you to get null or anything else. Here is why I prefer this solution over others.

  1. Returning a list of elements then checking if the list size is 0 works but you lose functionality that way. You can't do a .click() on a collection of links even if the collection size is 1.

  2. You could assert that the element exists but often that stops your testing. In some cases, I have an extra link to click depending on how I got to that page and I want to click it if it exists or move on otherwise.

  3. It's only slow if you don't set the timeout driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));

  4. It's actually a very simple and elegant once the method is created. By using FindElementSafe instead of FindElement, I don't "see" the ugly try/catch block and I can use a simple Exists method. That would look something like this:

    IWebElement myLink = driver.FindElementSafe(By.Id("myId"));
    if (myLink.Exists)
    {
       myLink.Click();
    }
    

Here is how you extend IWebElement & IWebDriver

IWebDriver.FindElementSafe

    /// <summary>
    /// Same as FindElement only returns null when not found instead of an exception.
    /// </summary>
    /// <param name="driver">current browser instance</param>
    /// <param name="by">The search string for finding element</param>
    /// <returns>Returns element or null if not found</returns>
    public static IWebElement FindElementSafe(this IWebDriver driver, By by)
    {
        try
        {
            return driver.FindElement(by);
        }
        catch (NoSuchElementException)
        {
            return null;
        }
    }

IWebElement.Exists

    /// <summary>
    /// Requires finding element by FindElementSafe(By).
    /// Returns T/F depending on if element is defined or null.
    /// </summary>
    /// <param name="element">Current element</param>
    /// <returns>Returns T/F depending on if element is defined or null.</returns>
    public static bool Exists(this IWebElement element)
    {
        if (element == null)
        { return false; }
        return true;
    }

You could use polymorphism to modify the IWebDriver class instance of FindElement but that's a bad idea from a maintenance standpoint.

Solution 4 - Java

This works for me every time:

    if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
        //THEN CLICK ON THE SUBMIT BUTTON
    }else{
        //DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
    }

Solution 5 - Java

I extended Selenium WebDriver implementation, in my case HtmlUnitDriver to expose a method

public boolean isElementPresent(By by){}

like this:

  1. check if page is loaded within a timeout period.
  2. Once page is loaded, I lower the implicitly wait time of the WebDriver to some milliseconds, in my case 100 mills, probably should work with 0 mills too.
  3. call findElements(By), the WebDriver even if will not find the element will wait only the amount of time from above.
  4. rise back the implicitly wait time for future page loading

Here is my code:

import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

public class CustomHtmlUnitDriver extends HtmlUnitDriver {

    public static final long DEFAULT_TIMEOUT_SECONDS = 30;
    private long timeout = DEFAULT_TIMEOUT_SECONDS;

    public long getTimeout() {
        return timeout;
    }
    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }

    public boolean isElementPresent(By by) {
        boolean isPresent = true;
        waitForLoad();
        //search for elements and check if list is empty
        if (this.findElements(by).isEmpty()) {
            isPresent = false;
        }
        //rise back implicitly wait time
        this.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);
        return isPresent;
    }

    public void waitForLoad() {
        ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver wd) {
                //this will tel if page is loaded
                return "complete".equals(((JavascriptExecutor) wd).executeScript("return document.readyState"));
            }
        };
        WebDriverWait wait = new WebDriverWait(this, timeout);
        //wait for page complete
        wait.until(pageLoadCondition);
        //lower implicitly wait time
        this.manage().timeouts().implicitlyWait(100, TimeUnit.MILLISECONDS);
    }   
}

Usage:

CustomHtmlUnitDriver wd = new CustomHtmlUnitDriver();
wd.get("http://example.org");
if (wd.isElementPresent(By.id("Accept"))) {
    wd.findElement(By.id("Accept")).click();
}
else {
    System.out.println("Accept button not found on page");
}

Solution 6 - Java

Write the following method using Java:

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

Call the above method during assertion.

Solution 7 - Java

you can do an assertion.

see the example

driver.asserts().assertElementFound("Page was not loaded",
By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT);

you can use this this is native :

public static void waitForElementToAppear(Driver driver, By selector, long timeOutInSeconds, String timeOutMessage) {
    try {
      WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
      wait.until(ExpectedConditions.visibilityOfElementLocated(selector));
    } catch (TimeoutException e) {
      throw new IllegalStateException(timeOutMessage);
    }
  }

Solution 8 - Java

String link = driver.findElement(By.linkText(linkText)).getAttribute("href")

This will give you the link the element is pointing to.

Solution 9 - Java

With version 2.21.0 of selenium-java.jar you can do this;

driver.findElement(By.id("...")).isDisplayed()

Solution 10 - Java

As I understand it, this is the default way of using the web driver.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRalphView Question on Stackoverflow
Solution 1 - JavaMike KwanView Answer on Stackoverflow
Solution 2 - JavaEddView Answer on Stackoverflow
Solution 3 - JavaBrantley BlanchardView Answer on Stackoverflow
Solution 4 - JavaAmstel BytesView Answer on Stackoverflow
Solution 5 - JavaLotzyView Answer on Stackoverflow
Solution 6 - JavaRipon Al WasimView Answer on Stackoverflow
Solution 7 - JavaRan AdlerView Answer on Stackoverflow
Solution 8 - Javauser1549161View Answer on Stackoverflow
Solution 9 - Javanu1silvaView Answer on Stackoverflow
Solution 10 - JavaPål BrattbergView Answer on Stackoverflow