Answers:
另外,您可以使用隐式等待:
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
隐式等待是告诉WebDriver在尝试查找不立即可用的一个或多个元素时,在一定时间内轮询DOM。默认设置为0。设置后,将在WebDriver对象实例的生存期内设置隐式等待。
Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
使用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();
WebDriverWait
它们来自OpenQA.Selenium.Support.UI
命名空间,并放在一个名为Selenium WebDriver Support Classes
NuGet 的单独程序包中
Selenium WebDriver Support Classes
现在在NuGet上显示为“ Selenium.Support”,当前版本为3.4.0
return wait.Until(ExpectedConditions.ElementToBeClickable(by));
并且现在效果很好。抬起头,以防其他人得到仍然找不到的随机元素。
您也可以使用
ExpectedConditions.ElementExists
因此,您将搜索像这样的元素可用性
new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));
DotNetSeleniumExtras.WaitHelpers
(未由@Dejan引用)”“未维护,问题不会得到解决,PR将不被接受”。(来源:github.com/SeleniumHQ/selenium/issues/…)。它的发行商正在寻找维护者以从他那里接管它。
这是@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);
}
}
受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();
_webDriver.Manage().Timeouts().ImplicitlyWait(Timeout);
那将仍然胜过您在此处设置的超时值。
Stopwatch
在扩展方法周围添加了一个调用,并Console.WriteLine()
在发送给的lambda内部添加了一个Until()
。秒表几乎准确地计时了60秒,仅写了一条信息Console
。我在这里想念什么吗?
您可以在C#中找到类似的内容。
这就是我在JUnit中使用的-Selenium
WebDriverWait wait = new WebDriverWait(driver, 100);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));
导入相关包
在Selenium IDE中选择Webdriver格式时,不会转换clickAndWait命令。这是解决方法。在下面添加等待行。实际上,问题是在我的C#代码的第1行之前发生的点击或事件。但实际上,只要确保在引用“按”对象的任何操作之前都有一个WaitForElement。
HTML代码:
<a href="http://www.google.com">xxxxx</a>
C#/ N单元代码:
driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();
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
试试这个代码:
New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)
使用Rn222和Aknuds1来使用ISearchContext,该ISearchContext返回单个元素或列表。并且可以指定最小数量的元素:
public static class SearchContextExtensions
{
/// <summary>
/// Method that finds an element based on the search parameters within a specified timeout.
/// </summary>
/// <param name="context">The context where this is searched. Required for extension methods</param>
/// <param name="by">The search parameters that are used to identify the element</param>
/// <param name="timeOutInSeconds">The time that the tool should wait before throwing an exception</param>
/// <returns> The first element found that matches the condition specified</returns>
public static IWebElement FindElement(this ISearchContext context, By by, uint timeOutInSeconds)
{
if (timeOutInSeconds > 0)
{
var wait = new DefaultWait<ISearchContext>(context);
wait.Timeout = TimeSpan.FromSeconds(timeOutInSeconds);
return wait.Until<IWebElement>(ctx => ctx.FindElement(by));
}
return context.FindElement(by);
}
/// <summary>
/// Method that finds a list of elements based on the search parameters within a specified timeout.
/// </summary>
/// <param name="context">The context where this is searched. Required for extension methods</param>
/// <param name="by">The search parameters that are used to identify the element</param>
/// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
/// <returns>A list of all the web elements that match the condition specified</returns>
public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
var wait = new DefaultWait<ISearchContext>(context);
wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
return wait.Until<IReadOnlyCollection<IWebElement>>(ctx => ctx.FindElements(by));
}
return context.FindElements(by);
}
/// <summary>
/// Method that finds a list of elements with the minimum amount specified based on the search parameters within a specified timeout.<br/>
/// </summary>
/// <param name="context">The context where this is searched. Required for extension methods</param>
/// <param name="by">The search parameters that are used to identify the element</param>
/// <param name="timeoutInSeconds">The time that the tool should wait before throwing an exception</param>
/// <param name="minNumberOfElements">
/// The minimum number of elements that should meet the criteria before returning the list <para/>
/// If this number is not met, an exception will be thrown and no elements will be returned
/// even if some did meet the criteria
/// </param>
/// <returns>A list of all the web elements that match the condition specified</returns>
public static IReadOnlyCollection<IWebElement> FindElements(this ISearchContext context, By by, uint timeoutInSeconds, int minNumberOfElements)
{
var wait = new DefaultWait<ISearchContext>(context);
if (timeoutInSeconds > 0)
{
wait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
}
// Wait until the current context found the minimum number of elements. If not found after timeout, an exception is thrown
wait.Until<bool>(ctx => ctx.FindElements(by).Count >= minNumberOfElements);
//If the elements were successfuly found, just return the list
return context.FindElements(by);
}
}
用法示例:
var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://localhost");
var main = driver.FindElement(By.Id("main"));
// It can be now used to wait when using elements to search
var btn = main.FindElement(By.Id("button"),10);
btn.Click();
//This will wait up to 10 seconds until a button is found
var button = driver.FindElement(By.TagName("button"),10)
//This will wait up to 10 seconds until a button is found, and return all the buttons found
var buttonList = driver.FindElements(By.TagName("button"),10)
//This will wait for 10 seconds until we find at least 5 buttons
var buttonsMin= driver.FindElements(By.TagName("button"), 10, 5);
driver.Close();
由于我使用已经发现的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;
}
};
}
这是可重用的函数,可以使用显式等待来等待DOM中存在的元素。
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;
}
});
}
我们可以这样实现:
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;
}
}
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已过时'。
我自己正在使用,FindElements
并检查是否为Count == 0
true await Task.Delay
。确实效率不高。
我看到已经发布了多种解决方案,效果很好!但是,以防万一有人需要其他东西,我想我会发布两个我自己在硒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;
}
}
第一个答案是好的,我的问题是未处理的异常无法正确关闭Web驱动程序并且它保持与我使用的相同的第一个值(即1秒)。
如果遇到同样的问题
restart you visual studio
并确保all the exceptions are handled
正确。
TimeSpan.FromSeconds(5)
。海事组织(IMO)