Selenium c#Webdriver:等到元素存在

时间:2011-08-09 07:49:06

标签: c# selenium selenium-webdriver webdriver automated-tests

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

我正试图让这样的事情发挥作用:

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(By.Id("login"));

我主要是在努力设置无关功能..

24 个答案:

答案 0 :(得分:251)

使用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);
    }
}

我没有缓存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();

答案 1 :(得分:140)

或者你可以使用隐式等待:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
  

隐式等待是告诉WebDriver对DOM进行轮询   尝试查找一个或多个元素的时间量   没有立即可用。默认设置为0.一旦设置,   隐式等待是为WebDriver对象实例的生命周期设置的。

答案 2 :(得分:80)

您也可以使用

<强> ExpectedConditions.ElementExists

因此,您将搜索类似

的元素可用性
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));

Source

答案 3 :(得分:29)

这是@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);
    }
}

答案 4 :(得分: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;
        });
    }
}

用法示例:

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();

答案 5 :(得分: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)));
    }

答案 6 :(得分:3)

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

这就是我在JUnit中使用的 - Selenium

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

导入相关的包

答案 7 :(得分:2)

//wait up to 5 seconds with no minimum for a UI element to be found
WebDriverWait wait = new WebDriverWait(_pagedriver, TimeSpan.FromSeconds(5));
IWebElement title = wait.Until<IWebElement>((d) =>
{
    return d.FindElement(By.ClassName("MainContentHeader"));
});

答案 8 :(得分:2)

在Selenium IDE中选择Webdriver格式时,不会转换clickAndWait命令。这是解决方法。添加下面的等待行。实际上,问题是在我的C#代码中的第1行之前发生的点击或事件。但实际上,只需确保在引用“By”对象的任何操作之前都有WaitForElement。

HTML code:

<a href="http://www.google.com">xxxxx</a>

C#/ NUnit代码:

driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();

答案 9 :(得分:2)

试试这段代码:

 New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)

答案 10 :(得分:2)

的Python:

from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By

driver.find_element_by_id('someId').click()

WebDriverWait(driver, timeout).until(EC.presence_of_element_located((By.ID, 'someAnotherId'))
来自EC的

您也可以选择其他条件 试试这个:http://selenium-python.readthedocs.org/api.html#module-selenium.webdriver.support.expected_conditions

答案 11 :(得分:1)

由于我使用已经发现的IWebElement来提高可见性,从而分隔了页面元素定义和页面测试方案,所以可以这样做:

public static void WaitForElementToBecomeVisibleWithinTimeout(IWebDriver driver, IWebElement element, int timeout)
{
    new WebDriverWait(driver, TimeSpan.FromSeconds(timeout)).Until(ElementIsVisible(element));
}

private static Func<IWebDriver, bool> ElementIsVisible(IWebElement element)
{
    return driver => {
        try
        {
            return element.Displayed;              
        }
        catch(Exception)
        {
            // If element is null, stale or if it cannot be located
            return false;
        }
    };
}

答案 12 :(得分:1)

您不希望在元素更改之前等待太久。在此代码中,webdriver在继续之前等待最多2秒钟。


WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(2000));
wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.Name("html-name")));

答案 13 :(得分:1)

显式等待

public static  WebDriverWait wait = new WebDriverWait(driver, 60);

示例:

wait.until(ExpectedConditions.visibilityOfElementLocated(UiprofileCre.UiaddChangeUserLink));

答案 14 :(得分:0)

我们可以这样实现:

public static IWebElement WaitForObject(IWebDriver DriverObj, By by, int TimeOut = 30)
{
    try
    {
        WebDriverWait Wait1 = new WebDriverWait(DriverObj, TimeSpan.FromSeconds(TimeOut));
        var WaitS = Wait1.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.PresenceOfAllElementsLocatedBy(by));
        return WaitS[0];
    }
    catch (NoSuchElementException)
    {
        Reports.TestStep("Wait for Element(s) with xPath was failed in current context page.");
        throw;
    }
}

答案 15 :(得分:0)

This is the reusable function to wait for an element present in DOM using Explicit Wait. Public void WaitForElement(IWebElement element, int timeout = 2){ WebDriverWait wait = new WebDriverWait(webDriver, TimeSpan.FromMinutes(timeout)); wait.IgnoreExceptionTypes(typeof(NoSuchElementException)); wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException)); wait.Until<bool> (driver => { try { return element.Displayed; } catch(Exception) { return false; } }); }

答案 16 :(得分:0)

WebDriverWait无效。

var driver = new FirefoxDriver(
    new FirefoxOptions().PageLoadStrategy = PageLoadStrategy.Eager
);
driver.Navigate().GoToUrl("xxx");
new WebDriverWait(driver, TimeSpan.FromSeconds(60))
    .Until(d => d.FindElement(By.Id("xxx"))); // a tag that close to the end

一旦页面“交互式”,这将立即引发异常。我不知道为什么,但是超时似乎不存在。

也许SeleniumExtras.WaitHelpers可以工作,但是我没有尝试。它是官方的,但被拆分为另一个nuget程序包。您可以参考C# Selenium 'ExpectedConditions is obsolete'

我自己正在使用FindElements,并检查Count == 0是否为真,请使用await Task.Delay。确实效率不高。

答案 17 :(得分:0)

您可以使用以下

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
wait.Until(ExpectedConditions.ElementToBeClickable((By.Id("login")));

答案 18 :(得分:0)

使用C#扩展方法:我们可以解决等待元素可见的问题。
特定元素的最大返回值为 100。

public static bool WaitForElementToBeVisible(IWebDriver browser, By by)
        {
            int attemptToFindElement = 0;
            bool elementFound = false;
            IWebElement elementIdentifier = null;
            do
            {
                attemptToFindElement++;
                try
                {
                    elementIdentifier = browser.FindWebElement(by);
                    elementFound = (elementIdentifier.Displayed && elementIdentifier.Enabled) ? true : false;
                }
                catch (Exception)
                {
                    elementFound = false;
                }

            }
            while (elementFound == false && attemptToFindElement < 100);

            return elementFound;
        }

答案 19 :(得分:0)

public bool doesWebElementExist(string linkexist)
{
     try
     {
        driver.FindElement(By.XPath(linkexist));
        return true;
     }
     catch (NoSuchElementException e)
     {
        return false;
     }
}

答案 20 :(得分:0)

我看到已发布的多个解决方案效果很好!但是,如果有人需要别的东西,我想我会发布两个我个人在selenium C#中使用的解决方案来测试一个元素是否存在!希望它有所帮助,欢呼!

public static class IsPresent
{
    public static bool isPresent(this IWebDriver driver, By bylocator)
    {

        bool variable = false;
        try
        {
            IWebElement element = driver.FindElement(bylocator);
            variable = element != null;
        }
       catch (NoSuchElementException){

       }
        return variable; 
    }

}

这是第二个

    public static class IsPresent2
{
    public static bool isPresent2(this IWebDriver driver, By bylocator)
    {
        bool variable = true; 
        try
        {
            IWebElement element = driver.FindElement(bylocator);

        }
        catch (NoSuchElementException)
        {
            variable = false; 
        }
        return variable; 
    }

}

答案 21 :(得分:-1)

第一个答案是好的,我的问题是未处理的异常没有正确关闭网页驱动程序,它保持了我使用的第一个值,即1秒。

如果你遇到同样的问题

restart you visual studio并确保all the exceptions are handled正确。

答案 22 :(得分:-1)

var re = /\|((?:(?!<br\s*\/?>)[^\r\n|])*)\|/ig; 
var str = 'test1 | test2 | test3<br>| test4<br>| test5 |<br>test6|';
var res = [];
while ((m = re.exec(str)) !== null) {
  res.push(m[1]); // Grab Group 1 value only
}
console.log(res);

答案 23 :(得分:-1)

正在搜索如何在Selenium中等待条件,登陆这个帖子,这就是我现在使用的内容:

    WebDriverWait wait = new WebDriverWait(m_driver, TimeSpan.FromSeconds(10));
    wait.Until(d => ReadCell(row, col) != "");

ReadCell(row, col) != ""可以是任何条件。喜欢这种方式因为:

  • 这是我的
  • 允许内联