3

「Book of Geb」に従って、ポータルの Web ページのマッピングを開始しました。私は、静的コンテンツ クロージャ ブロック内で定義された変数を使用し、後でページ メソッドでそれらにアクセスすることを好みます。

static content = {
    buttonSend { $("input", type: "submit", nicetitle: "Senden") }
}
def sendLetter() {
    waitFor { buttonSend.isDisplayed() }
    buttonSend.click()
}

残念ながら、Geb 待機タイムアウト例外 (60 秒後) が発生したり、さらに悪いことに、よく知られている "StaleElementReferenceException" が発生したりすることがあります。

「isDisplayed」の代わりに「isEnabled」を使用すると、待機タイムアウトを回避できましたが、「StaleElementReferenceException」については、以下の解決策しか適用できませんでした。

def sendLetter() {
    waitFor { buttonSend.isEnabled() }
    try {
        buttonSend.click()
    } catch (StaleElementReferenceException e) {
        log.info(e.getMessage())
        buttonSend.click()
    }
}

この解決策はあまり良くないと思いますが、別の記事で説明されているように、明示的に待機することはできませんでした。したがって、いくつかの一般的な質問があります。

  • ページが動的である場合、静的コンテンツ定義の使用を避けるべきですか?
  • Geb が DOM をリフレッシュするのはいつですか? DOM リフレッシュをトリガーするにはどうすればよいですか?
  • CSS セレクターを使用しているときに「StaleElementReferenceException」が引き続き発生するのはなぜですか?

この問題を理解または解決するのに役立つすべてのヒントをいただければ幸いです。私はまだ初心者なので、簡単なコード例を用意するのが最善です。ありがとうございました!

4

3 に答える 3

4

twinj の回答に加えて、StaleElementReferenceException が発生した場合に備えて、他のいくつかの回避策を指摘したいと思います。

  1. 多くの場合、ページで定義されているコンテンツに依存するよりも、セレクターを手動で書き出す方が良いことがわかります。あなたのページのコンテンツはデフォルトでキャッシュされるべきではありませんが、それでも時々私から離れてしまいます. これは、動的なコンテンツや反復を扱う場合に特によく見られます。

    例: 動的に作成されたドロップダウンから要素をクリックしたいとしましょう。

    通常、次のようなことをしたいかもしれません...

    static content = {
         dropdown { $("#parentDiv").find("ul") }
    }
    
    void clickDesiredElement(String elementName) {
         dropdown.click()
         def desiredElement = dropdown.find("li", text:elementName)
         waitFor { desiredElement.displayed }
         desiredElement.click()
    }
    

    これがうまくいかない場合は、コンテンツを完全に削除して、セレクターを手動で書き出すことを試みてください...

    void clickDesiredElement(String elementName) {
         $("#parentDiv").find("ul").click()
         def desiredElement = $("#parentDiv").find("ul").find("li", text:elementName)
         waitFor { desiredElement.displayed }
         desiredElement.click()
    }
    

    本当に厄介なケースでは、この回答で指摘されているように、手動タイマーを使用する必要がある場合があり、コードは次のようになります...

    void clickDesiredElement(String elementName) {
         $("#parentDiv").find("ul").click()
         sleepForNSeconds(2)
         def desiredElement = $("#parentDiv").find("ul").find("li", text:elementName)
         waitFor { desiredElement.displayed }
         desiredElement.click()
    }
    

    これは回避策であることを覚えておいてください:)

  2. each{} や collect{} などの大規模な反復と便利なクロージャー メソッドについては、反復ごとに waitFor{} を追加することをお勧めします。

    例: 大きなテーブルのすべての行を取得したいとしましょう

    通常、次のようなことをしたいかもしれません...

    def rows = $("#table1").find("tr").collect {
       [
          name: it.find("td",0),
          email: it.find("td",1)
       ]
    }
    

    StaleElementReferentException を回避するために、各反復の間に waitFor{} を使用して、これを反復的に実行する必要がある場合があります。こんな感じかも…。

    def rows = []
    int numRows = $("#table1").find("tr").size()
    int i
    for(i=0; i < numRows; i++) {
        waitFor {
          def row = $("#table1").find("tr",i)
          rows << [
              name: row.find("td",0),
              email: row.find("td",1)
          ]
        }
    }
    
于 2015-07-09T15:07:57.213 に答える