Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Selenium C#WebDriver:等待元素出现_C#_Selenium_Selenium Webdriver_Webdriver_Automated Tests - Fatal编程技术网

Selenium C#WebDriver:等待元素出现

Selenium C#WebDriver:等待元素出现,c#,selenium,selenium-webdriver,webdriver,automated-tests,C#,Selenium,Selenium Webdriver,Webdriver,Automated Tests,我希望在webdriver开始执行操作之前确保元素存在 我正试图让这样的东西发挥作用: WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 5)); wait.Until(By.Id("login")); 我主要在努力设置匿名函数…我把匿名函数和谓词搞混了。这里有一个小助手方法: WebDriverWait wait; private void waitForById(string

我希望在webdriver开始执行操作之前确保元素存在

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

WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 5));
wait.Until(By.Id("login"));
我主要在努力设置匿名函数…

我把匿名函数和谓词搞混了。这里有一个小助手方法:

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

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

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
隐式等待是告诉WebDriver轮询DOM一段时间 尝试查找一个或多个元素(如果有)的时间量 目前还没有。默认设置为0。一旦设置,则 为WebDriver对象实例的生命周期设置隐式等待

使用可能会影响总体测试性能,因为隐式等待将用于所有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();
//等待最长5秒,没有找到UI元素的最小值
WebDriverWait wait=新的WebDriverWait(_pagedriver,TimeSpan.FromSeconds(5));
IWebElement title=等待直到((d)=>
{
返回d.FindElement(按.ClassName(“MainContentHeader”);
});

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

HTML代码:

<a href="http://www.google.com">xxxxx</a>
driver.FindElement(By.LinkText("z")).Click;
driver.WaitForElement(By.LinkText("xxxxx"));
driver.FindElement(By.LinkText("xxxxx")).Click();
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();
以下是一个变体,它也适用于获取多个元素:

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);
    }
}
公共静态类webdrivex
{
公共静态IWebElement FindElement(此IWebDriver驱动程序,By,int timeoutines)
{
如果(超时秒数>0)
{
var wait=new-WebDriverWait(驱动程序,TimeSpan.FromSeconds(timeoutInSeconds));
返回wait.Until(drv=>drv.FindElement(by));
}
返回驱动程序FindElement(通过);
}
public static ReadOnlyCollection FindElements(此IWebDriver驱动程序,By,int timeoutines)
{
如果(超时秒数>0)
{
var wait=new-WebDriverWait(驱动程序,TimeSpan.FromSeconds(timeoutInSeconds));
返回wait.Until(drv=>(drv.FindElements(by).Count>0)?drv.FindElements(by):null;
}
返回驱动程序FindElements(按);
}
}

我看到已经发布了多个解决方案,效果非常好!然而,为了防止任何人需要其他东西,我想我会发布两个解决方案,我个人在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;
    }
}

你可以在C#中找到类似的内容

这就是我用的硒

WebDriverWait wait = new WebDriverWait(driver, 100);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submit")));
导入相关的包。

受其启发,这里有一个扩展方法,它适用于所有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;
        });
    }
}

以下是如何在Selenium中等待条件:

    WebDriverWait wait = new WebDriverWait(m_driver, TimeSpan.FromSeconds(10));
    wait.Until(d => ReadCell(row, col) != "");
ReadCell(行、列)!=“
可以是任何条件。这样做是因为:

  • 是我的
  • 允许内联
    • 您也可以使用

      预期条件。元素存在

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

      new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut)).Until(ExpectedConditions.ElementExists((By.Id(login))));
      

      Python: 从EC(导入预期的_条件)中,您还可以选择其他条件。 尝试以下操作:

      显式等待

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

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

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


      如果遇到相同的问题,请重新启动Visual Studio并确保所有异常都得到正确处理。

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

      WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(2000)); wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.Name("html-name"))); WebDriverWait wait=新的WebDriverWait(驱动程序,TimeSpan.FromMillicles(2000)); wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.Name(“html Name”)); 请尝试以下代码:

       New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)
      
      用于和使用返回单个元素或列表的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);
          }
      
      }
      

      由于我使用已经找到的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;
              }
          };
      }
      
      public static void WaitForElementToBecomeVisibleWithinTimeout(IWebDriver驱动程序、IWebElement元素、int超时)
      {
      新的WebDriverWait(驱动程序,TimeSpan.FromSeconds(超时))。直到(ElementIsVisible(element));
      }
      私有静态Func元素可见(IWebElement元素)
      {
      返回驱动程序=>{
      尝试
      {
      返回元素。显示;
      }
      捕获(例外)
      {
      //如果元素为null、过时或无法定位
      返回false;
      }
      };
      }
      
      这是一个可重用函数,用于使用显式等待等待DOM中存在的元素

      public void WaitForElement(IWebElement元素,int timeout=2)
      {
      WebDriverWait wait=新的WebDriverWait(webDriver,TimeSpan.FromMinutes(超时));
      等等。忽略例外类型(ty)
      WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(2000));
      wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.Name("html-name")));
      
       New WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(Function(d) d.FindElement(By.Id("controlName")).Displayed)
      
      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();
      
      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;
              }
          };
      }
      
      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 wait = new WebDriverWait(driver, new TimeSpan(0,0,5));
      wait.Until(ExpectedConditions.ElementToBeClickable((By.Id("login")));
      
      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;
              }