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")));
JohnWick
  • 4,929
  • 9
  • 37
  • 74

10 Answers10

156

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JohnWick
  • 4,929
  • 9
  • 37
  • 74
  • 5
    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. – Flipbed Jul 05 '18 at 11:59
  • 7
    They cut it out because it was a copy of the Java implementation that was hard to maintain and poorly implemented. http://jimevansmusic.blogspot.com/2018/03/deprecating-parts-of-seleniums-net.html – Harv Jan 23 '19 at 18:58
  • It also come with a great tool called "PageObjects". It is good to used. – Sovandara LENG Sep 06 '19 at 04:26
45

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob F.
  • 451
  • 3
  • 2
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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
PandaMagnus
  • 251
  • 2
  • 6
  • 1
    Thank you. Clearly - for several different reasons - importing "DotNetSeleniumExtras.WaitHelpers" is *NOT* the best solution. Your example - or Everton Rocha's example [above](https://stackoverflow.com/a/52626929/421195) should be the "preferred" approach. – paulsm4 Sep 24 '21 at 22:40
14

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

to

Wait.Until(c => c.FindElement(By.Id("content-section")));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Everton Rocha
  • 165
  • 1
  • 4
  • 10
    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. – Donald Rich Mar 11 '19 at 12:39
  • 1
    On a side note, wait utility **ignores** `NoSuchElementException` by default. https://www.selenium.dev/documentation/en/webdriver/waits/ – Rohim Chou Aug 21 '20 at 06:59
  • 1
    @rohim-chou No wonder I still get `NoSuchElementException` even after I added `wait.IgnoreExceptionTypes(typeof(NoSuchElementException));`. – Stack0verflow May 22 '22 at 18:19
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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jamie F
  • 23,189
  • 5
  • 61
  • 77
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Krunal Patel
  • 257
  • 3
  • 10
5

The following C# code works for me:

new WebDriverWait(webDriver, TimeSpan.FromSeconds(10)).Until(c => c.FindElement(By.Id("name")));
C. Peck
  • 3,641
  • 3
  • 19
  • 36
Leo Barbas
  • 109
  • 1
  • 4
  • Yeah, the simplest solution. – fragg Apr 24 '22 at 16:10
  • @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. – Stack0verflow May 22 '22 at 18:14
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
martin pb
  • 105
  • 1
  • 1
  • 6
  • 2
    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. – JohnWick Apr 16 '18 at 23:06
  • I figured it out if you want to see my answer, if you want to use the new and future releases. – JohnWick Apr 16 '18 at 23:24
  • 6
    If its obsolete downgrading isnt really a good solution. Ideally you'd be using new way of doing it. – Festivejelly Apr 24 '18 at 12:28
  • 1
    Downgrading actually is an acceptable solution if one does not have time at the moment to rewrite the code. – brianc May 07 '18 at 14:02
  • Behaving like an ostrich is also sometimes a good solution. – Bolt Thunder May 26 '21 at 10:30
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
Gravity API
  • 680
  • 8
  • 16
0

you can import a library like this

using ExpectedConditions = SeleniumExtras.WaitHelpers.ExpectedConditions;

then the warning will be disappeared.

Sess2504
  • 11
  • 2