5

页面包含一些数据(有几行的表)。有一个“刷新”按钮,可以重新加载和重绘页面上的一些元素,而无需重新加载静态数据(ajax)。

我正在尝试为该页面创建适当的测试,但有时会收到 StaleElementReferenceException。

我的代码(python):

from selenium import webdriver
browser=webdriver.Firefox()
browser.get('http://mytisite')
browser.implicitly_wait(10)
browser.find_element_by_id('start').click()
while browser.find_element_by_id('status').text!='Done':
    browser.find_element_by_id('refresh').click()
    for row in browser.find_elements_by_class_name('datarow'):
        if not is_correct(row.text):
           print "incorrect"
    time.sleep(10)

5 次迭代中有 1 次在“if not is_correct(row.text)”行失败:

selenium.common.exceptions.StaleElementReferenceException: 
 Message: u'Element not found in the cache - perhaps the page 
 has changed since it was looked up' ; Stacktrace: Method 
 fxdriver.cache.getElementAt threw an error in 
 resource://fxdriver/modules/web_element_cache.js 

主要问题:页面已经包含以前的数据,所以我在 ajax 刷新和 webdriver 的find_elements_by_class_name('datarow').

如何正确解决 ajax 刷新和 webdriver 之间的竞争?谢谢。

4

2 回答 2

4

恐怕,我无法帮助您进行 python 绑定。但是,我可以为您提供有关 WebDriver 和一些 Java 代码片段的一般建议,这些建议可以帮助您(其他人)找到他们的 Python 等价物。在 Selenium 中,您可以做很多事情来处理 AJAX。

1. 隐式等待 -这将告诉 Web 驱动程序轮询 DOM 一段时间。

driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);

2. 显式等待- 我更喜欢这些!可以将这些与隐式等待结合使用。您可以告诉 WebDriver 等待特定条件。您需要使用 WebDriverWait 来使用显式等待。

WebDriverWait wait = new WebDriverWait(driver, 60/*timeout in seconds*/);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("refresh")));

ExpectedConditions免费提供许多等待条件,我觉得它非常有用。

如果我用 Java 编写你上面的代码片段,我会在下面做。注意我在编辑器中写了这个,所以它应该编译。我想这会让你对 WebDriverWait 的使用有所了解。

WebDriverWait wait = new WebDriverWait(driver, 60/*timeout in seconds*/);
ExpectedCondition<Boolean> untilIFindStatus = ExpectedConditions
                    .elementToBeSelected(By.id("status"));
while (wait.until(untilIFindStatus)) {
        WebElement refresh = wait.until(ExpectedConditions
                        .elementToBeClickable(By.id("refresh")));
        refresh.click();
        List<WebElement> allRows = wait.until(ExpectedConditions
                .presenceOfAllElementsLocatedBy(By.className("datarow")));
             for (WebElement row : allRows) {
                if (row.getText().equals("awesome"))
                    System.out.println("do something");
             }
 }

最后,根据我的经验,许多现代 AJAX 应用程序都使用 jQuery。多年来,我已经成功使用 jQuery.active 标志来检查页面是否已加载。您可以将其与纯 javascript 结合使用document.readyState。这是我在每次“点击”我的 AJAX 应用程序后等待的一般方法。

ExpectedCondition<Boolean> jQueryActive_toBeZero = new ExpectedCondition<Boolean>()   {
        public Boolean apply(WebDriver driver) {
           try {
            return ((Long) jsExecutor
                .executeScript("return jQuery.active") == 0) ? true
                            : false;
         } catch (WebDriverException e) {
             log.debug("It looks like jQuery is not available on the page, skipping the jQuery wait, check stack trace for details");
             return true; //skip the wait
         }
           }
       };
ExpectedCondition<Boolean> document_readyState_toBeComplete = new ExpectedCondition<Boolean>() {
        public Boolean apply(WebDriver driver) {
          return jsExecutor.executeScript("return document.readyState")
             .toString().equals("complete") ? true : false;
         }
     };
    wait.until(jQueryActive_toBeZero);
    wait.until(document_readyState_toBeComplete);
于 2013-04-15T16:20:22.283 回答
3

在以下两种情况之一中会引发过时的元素引用异常,第一种比第二种更常见:

  • 该元素已被完全删除。
  • 该元素不再附加到 DOM

请通过以下硒文档了解更多信息

陈旧元素参考异常文档

于 2013-04-15T05:51:43.263 回答