Temporarily bypassing implicit waits with WebDriver

倾然丶 夕夏残阳落幕 提交于 2019-12-03 01:24:26
Jonik

Given that Selenium doesn't seem to offer what I want directly (based on what Mike Kwan and Slanec said), this simple helper method is what I went with for now:

protected boolean isElementHiddenNow(String id) {
    turnOffImplicitWaits();
    boolean result = ExpectedConditions.invisibilityOfElementLocated(By.id(id)).apply(driver);
    turnOnImplicitWaits();
    return result;
}

private void turnOffImplicitWaits() {
    driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
}

private void turnOnImplicitWaits() {
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}

If the element is hidden or not present at all, the method returns true; if it is visible, returns false. Either way, the check is done instantly.

Using the above is at least much cleaner than littering the test cases themselves with calls to turnOffImplicitWaits() and turnOnImplicitWaits().

See also these answers for fined-tuned versions of the same approach:

I would also suggest changing the parameter to a "By" locator for more flexibility when looking for the element.

protected boolean isElementHiddenNow(By locator) {
    turnOffImplicitWaits();
    boolean result = false;
    try {
       result = ExpectedConditions.invisibilityOfElementLocated(locator).apply(driver);
    }
    finally {
       turnOnImplicitWaits();
    }
    return result;
}

That way, you could search by css if needed rather than just id:

By PartLinkLocator = By.cssSelector("div.search-result div.row a");

'Course, your locator should probably be designed to return only one element (unlike the "By" example I quickly grabbed, which returns all part links in a css table of rows...) So, an "id" example would look like

By usernameLocator = By.id("inputEmail");
myResult = isElementHiddenNow(usernameLocator);

My implementation:

using (driver.NoImplicitWait())
{
    ....
}

With extension method:

public static NoImplicitWait NoImplicitWait(this IWebDriver driver)
{
    return new NoImplicitWait(driver);
}

And class:

public sealed class NoImplicitWait : IDisposable
{
    private readonly IWebDriver _driver;

    public NoImplicitWait(IWebDriver driver)
    {
        _driver = driver;
        _driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0));
    }

    public void Dispose()
    {
        _driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(30));
    }
}
3urdoch

@Jonic's answer helped me, however I would add a try { } finally { } and call turnOnImplicitWaits() in the finally block to make sure it always turns back on.

protected boolean isElementHiddenNow(String id) {
    turnOffImplicitWaits();
    boolean result = false;
    try {
       result = ExpectedConditions.invisibilityOfElementLocated(By.id(id)).apply(driver);
    }
    finally {
       turnOnImplicitWaits();
    }
    return result;
}

My approach was to bypass Implicit wait entirely and reimplement it (with an addition of a visibility check etc.) in my own findElement() and findElements() methods which I now use by default. This way, when I want to check something instantly, I can call the original WebDriver method which does, of course, not wait.

In an existing code relying a lot on implicit wait way of thinking, and without CSS to the rescue, I found a way out nfor that kind of things, complementing it with Jsoup, and going on with Jsoup:

# this is straightforward Scala... put the types and it is Java.
val innerHtml = seleniumWebElementFatherInstance.getAttribute("innerHTML")
val jsoupElements = Jsoup.parse(innerHtml).select("div.your.css.selector")
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!