Checking an element is present in C# WebDriver

Immediately checking that an element is present and displayed in C# WebDriver is a little more difficult than it initially seems.

The first reason it’s a little tricky is WebDriver throws an exception when an element doesn’t exist in the DOM, so if you’re checking that something doesn’t exist then it won’t work. For example:

[TestMethod]
public void FindVisibleElements()
{
    var driver = new FirefoxDriver();
    driver.Navigate().GoToUrl("data:text/html,<span id=\"hello\">Hello</span>");
    Assert.AreEqual(true,driver.FindElement(By.Id("hello")).Displayed); // Visible Works
    driver.Navigate()
        .GoToUrl(
        "data:text/html,<span id=\"hello\" style=\"position:absolute;left:-9000px;width:0;overflow:hidden;\">Hello</span>");
    Assert.AreEqual(false,driver.FindElement(By.Id("hello")).Displayed); // Not Visible Works
    driver.Navigate().GoToUrl("data:text/html,Hello");
    Assert.AreEqual(false,driver.FindElement(By.Id("hello")).Displayed); // Not Present Throws Exception
    driver.Quit();
}

The finally assertion throws an exception when asserting element with id hello doesn’t exist in the empty html content.

Test method FindVisibleElements threw exception: 
OpenQA.Selenium.NoSuchElementException: Unable to locate element: {"method":"id","selector":"hello"}

A way to get around this is to write a IWebDriver extension method to check the presence of and display of an element, including whether it is actually in the DOM at all:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace WebDriverExtensions
{
    public static class WebElementExtensions
    {
        public static bool ElementIsPresent(this IWebDriver driver, By by)
        {
            try
            {
                return driver.FindElement(by).Displayed;
            }
            catch (NoSuchElementException)
            {
                return false;
            }
        }
    }

    [TestClass]
    public class ExtensionUnitTests
    {
        [TestMethod]
        public void FindVisibleElements()
        {
            var driver = new FirefoxDriver();
            driver.Navigate().GoToUrl("data:text/html,<span id=\"hello\">Hello</span>");
            Assert.AreEqual(true,driver.ElementIsPresent(By.Id("hello"))); // Visible Works
            driver.Navigate()
                .GoToUrl(
                "data:text/html,<span id=\"hello\" style=\"position:absolute;left:-9000px;width:0;overflow:hidden;\">Hello</span>");
            Assert.AreEqual(false,driver.ElementIsPresent(By.Id("hello"))); // Not Visible Works
            driver.Navigate().GoToUrl("data:text/html,Hello");
            Assert.AreEqual(false,driver.ElementIsPresent(By.Id("hello"))); // Not Present Works
            driver.Quit();
        }
    }
}

This does what we want. Hooray. There’s one more thing to be aware of though. It currently runs in 4 seconds total as we’re not specifying an implicit wait. An implicit wait is a way for WebDriver to wait implicitly for elements to appear. It’s often set on the driver to avoid minor timing issues and to avoid having to write explicit waits throughout your code.

If we specify an implicit wait, the test execution time blows out to 14 seconds as the third assertion waits 10 seconds before throwing the exception.

var driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(new TimeSpan(0, 0, 0, 10)); // 10 seconds
driver.Navigate().GoToUrl("data:text/html,<span id=\"hello\">Hello</span>");
Assert.AreEqual(true,driver.ElementIsPresent(By.Id("hello"))); // Visible Works
driver.Navigate().GoToUrl("data:text/html,<span id=\"hello\" style=\"position:absolute;left:-9000px;width:0;overflow:hidden;\">Hello</span>");
Assert.AreEqual(false,driver.ElementIsPresent(By.Id("hello"))); // Not Visible Works
driver.Navigate().GoToUrl("data:text/html,Hello");
Assert.AreEqual(false,driver.ElementIsPresent(By.Id("hello"))); // Not Present Works
driver.Quit();

If you really need to use an implicit wait, what we can do is temporarily disable it when checking for existence of our element:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace WebDriverExtensions
{
    public static class Config
    {
        public static readonly TimeSpan ImplicitWait = new TimeSpan(0, 0, 0, 10);
        public static readonly TimeSpan NoWait = new TimeSpan(0, 0, 0, 0);
    }
    
    public static class WebElementExtensions
    {
        public static bool ElementIsPresent(this IWebDriver driver, By by)
        {
            var present = false;
            driver.Manage().Timeouts().ImplicitlyWait(Config.NoWait);
            try
            {
                present = driver.FindElement(by).Displayed;
            }
            catch (NoSuchElementException)
            {
            }
            driver.Manage().Timeouts().ImplicitlyWait(Config.ImplicitWait);
            return present;
        }
    }

    [TestClass]
    public class ExtensionUnitTests
    {
        [TestMethod]
        public void FindVisibleElements()
        {
            var driver = new FirefoxDriver();
            driver.Manage().Timeouts().ImplicitlyWait(Config.ImplicitWait);
            driver.Navigate().GoToUrl("data:text/html,<span id=\"hello\">Hello</span>");
            Assert.AreEqual(true,driver.ElementIsPresent(By.Id("hello"))); // Visible Works
            driver.Navigate()
                .GoToUrl(
                "data:text/html,<span id=\"hello\" style=\"position:absolute;left:-9000px;width:0;overflow:hidden;\">Hello</span>");
            Assert.AreEqual(false,driver.ElementIsPresent(By.Id("hello"))); // Not Visible Works
            driver.Navigate().GoToUrl("data:text/html,Hello");
            Assert.AreEqual(false,driver.ElementIsPresent(By.Id("hello"))); // Not Present Works
            driver.Quit();
        }
    }
}

This takes our test time back to 4 seconds, whilst allowing us to use an implicit wait for the rest of our test suite.

So, there we have it. A reasonably simple extension method on the IWebDriver class that allows us to check the immediate existance of an element in the DOM and displayed without throwing an exception.

Next I will write about how we can use this to write an extension method to explicitly wait for an element that we are expecting to appear (or disappear).

Author: Alister Scott

Alister is an Excellence Wrangler for Automattic.