Selenium c#Webdriver:等到元素存在

AyK*_*rsi 173 c# selenium automated-tests webdriver selenium-webdriver

我想确保在webdriver开始执行操作之前存在一个元素.

我正试图让这样的东西起作用:

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(By.Id("login"));
Run Code Online (Sandbox Code Playgroud)

我主要是在努力设置如何设置任何功能..

Lou*_*ier 260

使用Mike Kwan提供的解决方案可能会对整体测试性能产生影响,因为隐式等待将用于所有FindElement调用. 很多时候,当元素不存在时,你会希望FindElement立即失败(你正在测试格式错误的页面,缺少元素等).使用隐式等待,这些操作将在抛出异常之前等待整个超时到期.默认隐式等待设置为0秒.

我已经向IWebDriver写了一个小扩展方法,它为FindElement()方法添加了一个超时(以秒为单位)参数.这是不言自明的:

public static class WebDriverExtensions
{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }
        return driver.FindElement(by);
    }
}
Run Code Online (Sandbox Code Playgroud)

我没有缓存WebDriverWait对象,因为它的创建非常便宜,这个扩展可以同时用于不同的WebDriver对象,我只在最终需要时进行优化.

用法很简单:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost/mypage");
var btn = driver.FindElement(By.CssSelector("#login_button"));
btn.Click();
var employeeLabel = driver.FindElement(By.CssSelector("#VCC_VSL"), 10);
Assert.AreEqual("Employee", employeeLabel.Text);
driver.Close();
Run Code Online (Sandbox Code Playgroud)

  • 如果有人想知道,`WebDriverWait`来自`OpenQA.Selenium.Support.UI`命名空间,并且在NuGet上有一个名为`Selenium WebDriver Support Classes`的独立包 (110认同)
  • @Ved我可以吻你<3在不同的dll中寻找它:D (5认同)
  • `Selenium WebDriver Support Classes`现在在NuGet上出现为**"Selenium.Support"**,当前版本为3.4.0 (5认同)

Mik*_*wan 146

或者,您可以使用隐式等待:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
Run Code Online (Sandbox Code Playgroud)

隐式等待是指在尝试查找一个或多个元素(如果它们不是立即可用)时,WebDriver轮询DOM一段时间.默认设置为0.设置后,将为WebDriver对象实例的生命周期设置隐式等待.

  • @RedaBalkouch,迈克在他的答案中使用的语法是正确的.这是C# (17认同)
  • 现在不推荐使用此方法,您应该使用属性ImplicitWait:`Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);` (6认同)
  • 谢谢,新语法是:driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS); (5认同)
  • 如果您选择使用隐式等待,请注意不要使用显式等待.这可能会导致一些不可预测的行为导致测试结果不佳.一般来说,我建议使用显式等待而不是隐式等待. (3认同)

Zai*_*Ali 81

你也可以使用

ExpectedConditions.ElementExists

因此,您将搜索这样的元素可用性

new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));
Run Code Online (Sandbox Code Playgroud)

资源

  • 虽然这有效.它现在被标记为已弃用,因此应该避免. (5认同)
  • 这是新方法(不建议使用):/sf/answers/3490732381/ (3认同)
  • 请注意,此时,“DotNetSeleniumExtras.WaitHelpers”(上面由 @Dejan 引用)“未得到维护,问题不会得到解决,PR 也不会被接受”。(来源:https://github.com/SeleniumHQ/selenium/issues/4387#issuecomment-370502866)。它的出版商正在寻找一个维护者来从他手中接管它。 (2认同)

Rn2*_*222 30

这是@Loudenvier解决方案的变体,也适用于获取多个元素:

public static class WebDriverExtensions
{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }
        return driver.FindElement(by);
    }

    public static ReadOnlyCollection<IWebElement> FindElements(this IWebDriver driver, By by, int timeoutInSeconds)
    {
        if (timeoutInSeconds > 0)
        {
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => (drv.FindElements(by).Count > 0) ? drv.FindElements(by) : null);
        }
        return driver.FindElements(by);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 太好了!我刚把它添加到我自己的库中!这就是分享代码的美妙! (7认同)
  • 我建议添加一个。您可以捕获 NoSuchElement 解决方案并在该实例中返回 null。然后,您可以创建一个名为 .exists 的扩展方法,除非 IWebElement 为 null,否则该方法返回 true。 (2认同)

akn*_*ds1 16

受Loudenvier解决方案的启发,这是一个适用于所有ISearchContext对象的扩展方法,而不仅仅是IWebDriver,它是前者的特化.此方法还支持等待元素显示.

static class WebDriverExtensions
{
    /// <summary>
    /// Find an element, waiting until a timeout is reached if necessary.
    /// </summary>
    /// <param name="context">The search context.</param>
    /// <param name="by">Method to find elements.</param>
    /// <param name="timeout">How many seconds to wait.</param>
    /// <param name="displayed">Require the element to be displayed?</param>
    /// <returns>The found element.</returns>
    public static IWebElement FindElement(this ISearchContext context, By by, uint timeout, bool displayed=false)
    {
        var wait = new DefaultWait<ISearchContext>(context);
        wait.Timeout = TimeSpan.FromSeconds(timeout);
        wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
        return wait.Until(ctx => {
            var elem = ctx.FindElement(by);
            if (displayed && !elem.Displayed)
                return null;

            return elem;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
var btn = main.FindElement(By.Id("button"));
btn.Click();
var dialog = main.FindElement(By.Id("dialog"), 5, displayed: true);
Assert.AreEqual("My Dialog", dialog.Text);
driver.Close();
Run Code Online (Sandbox Code Playgroud)


AyK*_*rsi 9

我用谓词混淆了任何函数.下面是一个小帮手方法:

   WebDriverWait wait;
    private void waitForById(string id) 
    {
        if (wait == null)            
            wait = new WebDriverWait(driver, new TimeSpan(0,0,5));

        //wait.Until(driver);
        wait.Until(d => d.FindElement(By.Id(id)));
    }
Run Code Online (Sandbox Code Playgroud)


Adi*_*iti 6

你可以在 C# 中找到类似的东西。

这是我在JUnit 中使用的- Selenium

WebDriverWait wait = new WebDriverWait(driver, 100);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));
Run Code Online (Sandbox Code Playgroud)

导入相关包。

  • 我今天尝试使用它,而 VS.net 给了我警告:OpenQA.Selenium.Support.UI.ExpectedConditions 类已被标记为“已弃用”并在 https://github.com/DotNetSeleniumTools 上“迁移到 DotNetSeleniumExtras”存储库 (2认同)