C# Selenium 'ExpectedConditions is obsolete'
Asked Answered
N

10

104

When trying to explicitly wait for an element to become visible using ExpectedConditions, Visual Studio warns me that it is now obsolete and will be removed from Selenium soon.

What is the current/new method to achieve the same result?

var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 30));
var element = wait.Until(ExpectedConditions.ElementIsVisible(By.Id("content-section")));
Nowlin answered 16/4, 2018 at 21:14 Comment(1)
What was the Selenium version that you used?Understate
N
158

How to resolve this with the latest version of Selenium.

Using NuGet, search for DotNetSeleniumExtras.WaitHelpers, and import that namespace into your class. Now you can do this:

var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 30));
var element = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.Id("content-section")));

And the warning in the IDE will be gone.

Nowlin answered 16/4, 2018 at 23:23 Comment(3)
Note that there is no owner to the project. I dont know why they cut it out from Selenium but for now there will be no updates to the DotNetSeleniumExtras repo.Scintilla
They cut it out because it was a copy of the Java implementation that was hard to maintain and poorly implemented. jimevansmusic.blogspot.com/2018/03/…Waldo
It also come with a great tool called "PageObjects". It is good to used.Oncoming
I
46

If you don't want to download an extra NuGet package, it is quite easy to declare your own function (or condition), especially using a lambda expression, e.g.

var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 30));
var element = wait.Until(condition =>
{
    try
    {
        var elementToBeDisplayed = driver.FindElement(By.Id("content-section"));
        return elementToBeDisplayed.Displayed;
    }
    catch (StaleElementReferenceException)
    {
        return false;
    }
    catch (NoSuchElementException)
    {
        return false;
    }
});

This is also very versatile, since it is now possible to evaluate any kind of Boolean expression.

Interrogative answered 30/5, 2018 at 11:53 Comment(6)
I like the versatility, but if I am using multiple waits, this could be alot more lines of code.Nowlin
Surely not a lot more code if you wrap that in a function?Secretary
Terrific! @Stevieboy84, how does one wrap this into a function?Saltire
how do you wrap this to a function and apply it to multiple waits on different elements?Tic
Create a function that recieves a By as parameter and returns a boolHeighttopaper
It seems that your lambda should use the parameter that was passed in, and not a global "driver" object. The "condition" is the lambda, not the first parameter to the lambda. which is the IWebDriver object.Salaried
H
16

It's very simple. Just change Wait.Until(ExpectedConditions.ElementIsVisible(By.Id("content-section")));

to

Wait.Until(c => c.FindElement(By.Id("content-section")));
Hsu answered 3/10, 2018 at 12:21 Comment(3)
While the replacement will work there is a difference. Using ElementIsVisible waits without throwing any exceptions. The FindElement version throws an internal NoSuchElementException which can complicate debugging if your IDE breaks on thrown exceptions.Craps
On a side note, wait utility ignores NoSuchElementException by default. selenium.dev/documentation/en/webdriver/waitsNevil
@rohim-chou No wonder I still get NoSuchElementException even after I added wait.IgnoreExceptionTypes(typeof(NoSuchElementException));.Apiculate
F
15

The answers to change to an anonymous function is the most correct one. Or write your own class of your own, needed, wait conditions.

An example of using an anonymous function for the explicit scenario above would be something like:

var wait = new WebDriverWait(driver, new TimeSpan(0, 0, 30));
wait.IgnoreExceptionTypes(typeof(NoSuchElementException), typeof(ElementNotVisibleException));
var element = wait.Until(() =>
{
    var e = Driver.FindElement(By.Id("content-section"));
    if(e.Displayed)
        return e;
});

And at that point, the function itself could be off on its own in some class in your solution that you can call. The nice thing with this is that you can modify as needed; I have seen several cases where really poorly made websites end up breaking how the ExpectedConditions work, and that was solved with the team writing our own function.

As per the C# contributor:

With respect to ExpectedConditions, again, this was an addition that was created in .NET solely because "Java has it." At the time the ExpectedConditions class in Java was created, the syntax for creating a lambda function (or something that acted like one) was particularly arcane and difficult to understand. In that case, a helper class made lots of sense for the Java bindings. However, C# isn't Java. In C#, the syntax for creating lambda functions ("anonymous methods" in the language of Microsoft's documentation) has been well understood by C# developers for many years, and is a standard tool in their arsenal.

In this case, the question of code verbosity does have some merit, but since wait conditions are rarely one-size-fits-all, it would be a much cleaner approach for users to develop their own conditions class that has the wait conditions they're interested in. This, however, is something users have an aversion to. Additionally, the thought of a 'standard' collection of implementations of specific wait conditions seems to be a good idea on its face, but there is a great deal of variation on the way users want any given condition to work. Having a collection of wait conditions might be a good thing, but the Selenium project is not the place for it.

Rantings of a Selenium Contributor

Faun answered 28/3, 2019 at 17:29 Comment(1)
Thank you. Clearly - for several different reasons - importing "DotNetSeleniumExtras.WaitHelpers" is NOT the best solution. Your example - or Everton Rocha's example above should be the "preferred" approach.Commencement
W
12

Based on Rob F.'s answer, I added extension methods to my project. (Actually I added two, WaitUntilVisible(...) and WaitUntilClickable(...).)

These return the element, instead of a bool, so it is more like the Wait.Until(ExpectedConditions...)

// use: element = driver.WaitUntilVisible(By.XPath("//input[@value='Save']"));
public static IWebElement WaitUntilVisible(
    this IWebDriver driver,
    By itemSpecifier,
    int secondsTimeout = 10)
{
    var wait = new WebDriverWait(driver, new TimeSpan(0, 0, secondsTimeout));
    var element = wait.Until<IWebElement>(driver =>
    {
        try
        {
            var elementToBeDisplayed = driver.FindElement(itemSpecifier);
            if(elementToBeDisplayed.Displayed)
            {
                return elementToBeDisplayed;
            }
            return null;
        }
        catch (StaleElementReferenceException)
        {
            return null;
        }
        catch (NoSuchElementException)
        {
            return null;
        }
    });
    return element;
}
Wingfooted answered 8/9, 2019 at 22:45 Comment(0)
M
9

NuGet is required - DotNetSeleniumExtras.WaitHelpers

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementToBeClickable(By.XPath("")));

I just demonstrated the element clickable event. Similarly, other events can be used with the required parameters.

Mojave answered 24/6, 2019 at 18:18 Comment(0)
V
5

The following C# code works for me:

new WebDriverWait(webDriver, TimeSpan.FromSeconds(10)).Until(c => c.FindElement(By.Id("name")));
Vocalize answered 11/5, 2021 at 18:0 Comment(2)
Yeah, the simplest solution.Pathology
@leo-barbas I thought the Until method would force selenium to wait until the element is found. But I get an exception in Visual Studio (C#) which says: {"no such element: Unable to locate element: {\"method\":\"xpath\",\"selector\":\"(//body[@id=\"ctl00_body\"]//div[@class=\"my-css-class\"])[1]\"}\n (Session info: chrome=99.0.4844.82)"}. This issue occurs even after I added wait.IgnoreExceptionTypes(typeof(NoSuchElementException));. Any idea on how to solve this? Note that my xpath is correct, I'm able to locate the element using the xpath.Apiculate
S
1

Check which version of the Selenium.Support and Selenium.WebDriver NuGet package you have installed.

I got the same issue now with the latest version, 3.11.2. I downgraded to 3.10.0 and it fixed the problem.

Slipover answered 16/4, 2018 at 22:55 Comment(5)
Yeah I am using the latest version, I just added it with NuGet last night. Same thing with Selenium.Support. I'd rather not downgrade, I want to learn what the new method is so I can use future releases in my projects.Nowlin
I figured it out if you want to see my answer, if you want to use the new and future releases.Nowlin
If its obsolete downgrading isnt really a good solution. Ideally you'd be using new way of doing it.Immunoreaction
Downgrading actually is an acceptable solution if one does not have time at the moment to rewrite the code.Fruition
Behaving like an ostrich is also sometimes a good solution.Integrant
U
1

you can import a library like this

using ExpectedConditions = SeleniumExtras.WaitHelpers.ExpectedConditions;

then the warning will be disappeared.

Unspotted answered 22/2, 2023 at 8:41 Comment(0)
S
0

You can use the NuGet package Gravity.Core - it is maintained by Gravity API community and it contains A LOT more than just the ExpectedConditions class.

How to use

  1. Download the NuGet using NuGet package manager.
  2. Add using OpenQA.Selenium.Extensions
Semen answered 3/6, 2021 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.