In Selenium (or at least its C# bindings), WebDriverWait is a class that sees a lot of use. In fact, the pattern of explicit waits, which is recommended over the alternative of implicit waits, relies on this class. However, it has a limitation that becomes glaring as your page objects become more deeply nested. In fact, it’s all there in the name: WebDriverWait can only be used with IWebDriver.

Let me provide an example to illustrate how this might become a problem. Say you have a class representing a Bootstrap modal, that starts out something like this:

public class Modal
{
    private readonly IWebElement _root;

    public Modal(IWebElement root)
    {
        _root = root;
    }
    
    // other modal contents (subclass?)
}

In fact, this is how I start out a lot of page objects (I’ll save any further detail for another article).

Nearly every Bootstrap modal has a “x” button in the top-right corner for closing the modal. To be able to close modals from this page object, we’ll add a Close() method that clicks on that button and waits for the modal to not be displayed. We want it to look something like this:

public void Close()
{
    _root.FindElement(By.ClassName("close")).Click();
    // uh-oh...
    new WebDriverWait(_root, TimeSpan.FromSeconds(1)).Until(e => !e.Displayed);
}

But, of course, we can’t use WebDriverWait with anything other than an IWebDriver, and to make the IWebDriver accessible by the Modal class isn’t the greatest ever for separation of concerns under this way of organizing page objects. hence our problem. In addition, IWebDriver and IWebElement both implement a common ISearchContext interface which provides, among other things, the FindElement(By) and FindElements(By) methods that can be used with both interfaces, and the code for WebDriverWait doesn’t appear to use anything IWebDriver-specific, either. So why can’t we use WebDriverWait, or even a generally-applicable SearchContextWait?

A bit of Google-fu brought me to this Github issue opened by NickAb in 2015 which asked the same question. The issue was ultimately closed in 2016 by Jim Evans, due to the amount of “dependent code in the ecosystem” to change WebElementWait’s signature to take ISearchContexts instead of IWebDrivers. However, it’s easy to implement one’s own WebElementWait, and Evans even provides a code snippet (reproduced here, without comments, for convenience) detailing this:

public class WebElementWait : DefaultWait<IWebElement>
{
    public WebDriverWait(IWebElement element, TimeSpan timeout)
        : base(element, new SystemClock())
    {
        this.Timeout = timeout;
        this.IgnoreExceptionTypes(typeof(NotFoundException));
    }
}

To make a SearchContextWait instead of a WebElementWait, simply change IWebElement to ISearchContext wherever it appears.

However, this isn’t exactly idiomatic Selenium. Although it barely adds any extra code on top of the framework, it’s still something that isn’t included by default with the framework itself. If you want to use something that already exists in Selenium, you may want to look into FluentWaits as well, which use more of a fluent API approach to waiting for things in Selenium. For the curious, StackExchange SQA user LittlePanda details the differences differences between implicit, explicit and fluent waits here, and Github user up1 has some code snippets if you just want to see what they look like in practice.