WebDriver: check if an element exists?

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.


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()

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
    }

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