15

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.

stealthjong
  • 10,858
  • 13
  • 45
  • 84
Rochelle C
  • 928
  • 3
  • 10
  • 22

4 Answers4

36

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.

JeffC
  • 22,180
  • 5
  • 32
  • 55
JimEvans
  • 27,201
  • 7
  • 83
  • 108
2

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

  • so by this way, we can call this method wherever needed? Because in other approach we have to put that as an expression in all places wherever we need. Correct me if am wrong. – user1925406 Oct 20 '15 at 06:07
1

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")));
Barkman
  • 21
  • 3
-1

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")));
OmG
  • 18,337
  • 10
  • 57
  • 90
Alex Z
  • 1