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)

「if not is_correct(row.text)」行で 5 回の反復のうち 1 回が失敗します。

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 refresh と webdriver の間の競合を適切に解決するにはどうすればよいですか? ありがとう。

4

2 に答える 2

4

申し訳ありませんが、Python バインディングについてはお手伝いできません。ただし、WebDriver に関する一般的なアドバイスと、(他の) 人が同等の Python を見つけるのに役立つ Java スニペットを提供することはできます。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

古い要素参照の例外は、次の 2 つのケースのいずれかでスローされます。最初のケースは 2 番目のケースよりも一般的です。

  • 要素は完全に削除されました。
  • 要素が DOM に関連付けられなくなった

詳細については、以下のセレンのドキュメントを参照してください

古い要素参照の例外に関するドキュメント

于 2013-04-15T05:51:43.263 に答える