使用Selenium使用Webdriver的Timeout的最佳方法是什么?

我遇到了一个问题。 我的网页有一个DropDownList控件。 一旦DropDownList值改变(通过选择不同的值),页面将刷新并呈现内容。

然后我必须使用Thread.Sleep(2000); 在它和FindElement之前。

我的问题:等待页面加载的最佳方法是什么?

我的代码中有很多Thread.Sleep(2000)实例,我开始认为这不是解决问题的最佳方法。

这是我的代码:

 [TestInitialize()] public void Setup() { if (BaseIntegrationTest.browserType.Equals(BaseIntegrationTest.IE)) { driver = new InternetExplorerDriver(); } else if (BaseIntegrationTest.browserType.Equals(BaseIntegrationTest.CHROME)) { //driver = new ChromeDriver(); } else if (BaseIntegrationTest.browserType.Equals(BaseIntegrationTest.FIREFOX)) { driver = new FirefoxDriver(); } } 

第二部分:

 [TestMethod] public void testVerifyData() { // ................... // ................... driver.FindElement(By.XPath("//*[@id='ctl00_NavigationControl1_lnke']")).Click(); Thread.Sleep(2000); //select from the dropdownlist. IWebElement catagory = driver.FindElement(By.Id("ctl00_ContentPlaceHolder1_Filter")); SelectElement selectCatagory = new SelectElement(catagory); selectCatagory.SelectByText("Employee"); Thread.Sleep(2000); // ................... // ................... } 

Thread.Sleep()是一种非常沮丧的实现等待的方法

此代码在selenium文档中列出http://seleniumhq.org/docs/04_webdriver_advanced.html

 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); IWebElement category = wait.Until((d) => { return d.FindElement(By.Id("ctl00_ContentPlaceHolder1_Filter")); }); 

这是一个显式等待的示例,其中selenium在找到元素之前不会执行任何操作

隐式等待的一个例子是:

 driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10)); IWebElement category = driver.FindElement(By.Id("ctl00_ContentPlaceHolder1_Filter")); 

在隐式等待中,驱动程序将等待给定的时间并轮询DOM以查找不存在的任何元素。

编辑

 public WaitForElement(string el_id) { WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); IWebElement category = wait.Until((d) => { return d.FindElement(By.Id(el_id)); }); } 

我也通过使用WebDriverWait来解决这个问题。

但我设置等到显示的最后一个元素(例如:页脚,列表中的最后一项)。

 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); wait.Until(d => d.FindElement(By.Id("footer")).Displayed); 

要么

 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); wait.Until(d => d.FindElements(By.TagName("li")).Last().Displayed); 

在某些情况下,您确实需要等待,在这种情况下,Task.Delay方法将提供比Thread.Sleep更可预测的结果

Task.Delay(1000).Wait(); //等一下

假设由交互引起的刷新是Selenium可以检测到的,那么以下方法可能会满足您的需求:

waitForPageToLoad

据我所知,此方法检查浏览器中的状态以查看浏览器是否认为它正在加载某些内容,并等待直到清除此状态。 但是,这种就绪状态有点旧 – 有很多方法可以动态加载页面或页面的一部分,就绪状态并不总是准确描述正在发生的事情。

如果您知道由于您的操作会发生什么变化 – 也就是说,如果您知道在与下拉列表进行交互后,将出现之前不在页面上的特定UI元素 – 那么您可能会更好等待那些特定的UI元素出现。 您可以通过编写一个重复检查isTextPresent并以小增量等待的方法来执行此操作,直到达到超时或出现预期元素。 还有其他“是X Present”方法可以在这些方法中使用,您可以在我链接到的Selenium接口的其他位置找到这些方法。

如果你想在页面加载或超时到期后获得html:

 using (var chromeDriver = new ChromeDriver()) { chromeDriver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(30)); try { chromeDriver.Navigate().GoToUrl(link); return chromeDriver.PageSource; } catch (WebDriverTimeoutException) { return chromeDriver.PageSource; } } 

我为自己制作了一个自定义function,也许对某人有用:

  public static void waitForPageToBeLoaded(WebDriver driver, int time) { ExpectedCondition expectation = new ExpectedCondition() { public Boolean apply(WebDriver driver) { return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"); } }; Wait wait = new WebDriverWait(driver, Long.valueOf(time)); try { wait.until(expectation); } catch(Throwable error) { System.out.println(error); mainFunctions.reportFailure("[waitForPageToBeLoaded] Page load took longer than " + time/60 + " min."); } } // waitForPageLoaded