我如何在Selenium中使用Wait机制?

时间:2014-03-15 08:40:15

标签: selenium selenium-webdriver

  1. 我正在为JSF的J2EE应用程序编写Selenium 2 + C#和Nunit。
  2. 可能由于它是基于Ajax或网络延迟,Selenium会失败,除非我保留一些“等待”机制。我列出了我尝试它们的4种方法。但是,仍有一些情况下测试挂起,或说它无法获取元素,或者元素是陈旧的。这些错误是随机的,不一致。
  3. 所以我一直在减少等待以减轻陈旧性,或增加等待以启用元素处理。当然有时我会等很长时间。
  4. 我一直在混合各种各样的方式,因为它们对我来说是黑色艺术。下面列出的方法有什么问题吗?
  5. 感谢。

    A)等待进度条

    public void WaitForProgressBar(ref Screenshot ss, WebDriverWait wait, ref IWebElement progressBar, ref IWebDriver _driver)
                {
                try
                    {
                    progressBar = wait.Until<IWebElement>((d) =>
                    {
                        return d.FindElement(By.XPath("//span[@id='_viewRoot:status.start']/img[@src='images/pleasewait.gif']"));
                    });
                    }
                catch
                    {
                    _logger.Debug("Could not locate progress bar");
                    }
    
                progressBar = _driver.FindElement(By.XPath("//span[@id='_viewRoot:status.start']/img[@src='images/pleasewait.gif']"));
                while (progressBar.Displayed)
                    System.Threading.Thread.Sleep(100);
    
                _logger.Debug("Sleeping");
    
                while (progressBar.Displayed)
                    System.Threading.Thread.Sleep(300);
    
                ss = ((ITakesScreenshot)_driver).GetScreenshot();
                ss.SaveAsFile("C:/WaitingForProgressBar.png", System.Drawing.Imaging.ImageFormat.Png);
                }
    

    B)睡眠然后调用WaitForProgressBar()

    System.Threading.Thread.Sleep(2500);
    logInAndConfigureHospital.WaitForProgressBar(ref ss, wait, ref progressBar, ref _driver);
    

    C)调用WaitForProgressBar()然后再睡眠

    logInAndConfigureHospital.WaitForProgressBar(ref ss, wait, ref progressBar, ref _driver);
    System.Threading.Thread.Sleep(250);
    

    D)使用Wait Until

    IWebElement checkBoxSelectAll = wait.Until<IWebElement>((d) =>
            {
                return d.FindElement(By.XPath("//div[@id='convertHandlerForm:ConvertHandlerLines_header']/table/tbody/tr/td/input"));
            });
            checkBoxSelectAll.Click(); 
    

1 个答案:

答案 0 :(得分:1)

这两个陈述

while (progressBar.Displayed)

会在进度条消失后立即抛出StaleElementReferenceException,因为DOM已更改。

在尝试检查进度条可见性时,您需要一个处理不同异常的方法。下面的扩展方法就是这样,如果找不到元素,或者抛出异常,则返回null值。

public static class WebDriverExtensions
{
    /// <summary>
    /// Wait Get an element. 
    /// </summary>
    /// <param name="driver"></param>
    /// <param name="by"></param>
    /// <param name="timeout">timeout in seconds to wait for element</param>
    /// <returns>the element, else null</returns>
    public static IWebElement WaitGetElement(this IWebDriver driver, By by, 
            int timeout = 10, bool checkForVisibility=false)
    {
        IWebElement element;
        WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
        wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException));
        wait.Message = string.Format("Timed out after waiting {0} seconds for the {1} field ", timeout, by.ToString());
        try
        {
            if (checkForVisibility)
            {
                element = wait.Until(ExpectedConditions.ElementIsVisible(by));
            }
            else
            {
                element = wait.Until(ExpectedConditions.ElementExists(by));
            }
        }
        catch (NoSuchElementException) { element = null; }
        catch (WebDriverTimeoutException) { element = null; }
        catch (TimeoutException) { element = null; }

        return element;
    }
}

现在您可以使用上面的扩展方法使用以下方法等待进度条。这将等待至少1秒,以使进度条消失。

public bool WaitForProgressComplete(int waitTimeoutInSecs = 60)
{
   bool isComplete = false;
   var sw = new Stopwatch();
   sw.Start();
   while (!isComplete && sw.Elapsed.TotalSeconds < waitTimeoutInSecs)
   {
      //try locate the progress bar, checking for max 1 sec(internally polls every 500ms) 
      //Check for visibility true (last param)
   progressBar = this.Driver.WaitGetElement(By.XPath("//span[@id='_viewRoot:status.start']/img[@src='images/pleasewait.gif']"), 1, true);
      isComplete = (progressBar == null);
   }

   sw.Stop();
   return isComplete;
}

这里唯一需要注意的是,如果进度条最初显示的时间不到1秒,则此方法将在显示条形图之前返回。在这种情况下,您可以在WaitGetElement调用中增加等待超时,或预先设置静态等待。