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:
- Create a class CustomExpectedConditions.cs
- 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 :)