15
votes

I'm trying to write my own ExpectedConditions for Selenium but I don't know how to add a new one. Does anyone have an example? I can't find any tutorials for this online.

In my current case I want to wait until an element exists, is visible, is enabled AND doesn't have the attr "aria-disabled". I know this code doesn't work:

var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(seconds));
return wait.Until<IWebElement>((d) =>
    {
        return ExpectedConditions.ElementExists(locator) 
        && ExpectedConditions.ElementIsVisible 
        &&  d.FindElement(locator).Enabled 
         && !d.FindElement(locator).GetAttribute("aria-disabled")
    }

EDIT: A little additional info: the problem I am running into is with jQuery tabs. I have a form on a disabled tab and it will start filling out fields on that tab before the tab becomes active.

4

4 Answers

36
votes

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.

2
votes

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

0
votes

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")));
-1
votes

I've converted an example of WebDriverWait and ExpectedCondition/s from Java to C#.

Java version:

WebElement table = (new WebDriverWait(driver, 20))  
.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("table#tabletable")));

C# version:

IWebElement table = new WebDriverWait(driver, TimeSpan.FromMilliseconds(20000))
.Until(ExpectedConditions.ElementExists(By.CssSelector("table#tabletable")));