How to add custom ExpectedConditions for Selenium?

Since all of these answers point the OP to use a separate method with a new wait and encapsulate the function instead of actually using a custom expected conditions, I'll post my answer:

  1. Create a class CustomExpectedConditions.cs
  2. Create each one of your conditions as static accessible methods that you can later call from your wait
public class CustomExpectedConditions
{

    public static Func<IWebDriver, IWebElement> ElementExistsIsVisibleIsEnabledNoAttribute(By locator)
    {
        return (driver) =>
        {
            IWebElement element = driver.FindElement(locator);
            if (element.Displayed
            && element.Enabled
            && element.GetAttribute("aria-disabled").Equals(null))
            {
                return element;
            }

            return null;
        };
    }
}

Now you can call it as you would any other expected condition like so:

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(TIMEOUT));
wait.Until(CustomExpectedConditions.ElementExistsIsVisibleIsEnabledNoAttribute(By.Id("someId")));

An "expected condition" is nothing more than an anonymous method using a lambda expression. These have become a staple of .NET development since .NET 3.0, especially with the release of LINQ. Since the vast majority of .NET developers are comfortable with the C# lambda syntax, the WebDriver .NET bindings' ExpectedConditions implementation only has a few methods.

Creating a wait like you're asking for would look something like this:

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until<IWebElement>((d) =>
{
    IWebElement element = d.FindElement(By.Id("myid"));
    if (element.Displayed &&
        element.Enabled &&
        element.GetAttribute("aria-disabled") == null)
    {
        return element;
    }

    return null;
});

If you're not experienced with this construct, I would recommend becoming so. It is only likely to become more prevalent in future versions of .NET.


I understand the theory behind ExpectedConditions (I think), but I often find them cumbersome and difficult to use in practice.

I would go with this sort of approach:

public void WaitForElementPresentAndEnabled(By locator, int secondsToWait = 30)
{
   new WebDriverWait(driver, new TimeSpan(0, 0, secondsToWait))
      .Until(d => d.FindElement(locator).Enabled
          && d.FindElement(locator).Displayed
          && d.FindElement(locator).GetAttribute("aria-disabled") == null
      );
}

I will be happy to learn from an answer that uses all ExpectedConditions here :)