web-dev-qa-db-ja.com

要素を待つ-WebDriver-PageObjectパターン

PageObjectパターンを使用している限り、動的ページの要素をどこで待つべきか疑問に思いました。テストメソッドとpageObjectクラスがあると仮定します。私は(テスト方法で)次のようなことをする必要があります:

  1. ボタンをクリックします
  2. 要素が表示されるのを待つ
  3. 要素を確認します(例:メソッドisElementDisplayed()を含む)

それとも、要素を待つための他の良い習慣がありますか?たぶん、PageObject.classにあるメソッドisElementDisplayedの要素を待つ必要がありますか?

10
Robert

要素はページオブジェクトクラスで定義する必要があるため、テストクラスではなく、ページオブジェクトクラスの要素を待つ必要があります。テストクラスは、要素やセレクターなどを何も知らないはずです。テスト、IMHOには、テストフローを説明するメソッド呼び出しのチェーンのみを含める必要があります。Webサイトおよび基盤となるDOMとのすべての対話は、ページオブジェクトクラスで行う必要があります。

したがって、ある要素が表示されるのを待つ過度に冗長なメソッドは、次のようになります。

_private final By yourElement = By.id("id");
@Override
public void isLoaded() throws Error {
    new FluentWait<WebDriver>(driver)
            .withTimeout(60, TimeUnit.SECONDS)
            .pollingEvery(1, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class)
            .ignoring(StaleElementReferenceException.class)
            .until(new Function<WebDriver, Boolean>() {
                @NotNull
                @Override
                public Boolean apply(WebDriver webDriver) {
                    WebElement element = driver.findElement(yourElement);
                    return element != null && element.isDisplayed();
                }
            });
}
_

簡単に言うと、DOMを60秒(1秒ごと)ポーリングして、要素がDOMに存在し、表示されているかどうかを確認する場合の関数(つまり、高さと幅が1pxより大きい)。要素が存在する(そして表示される)場合、関数は見つかった要素を返し、ポーリングを停止します(ただし、この特定の場合、isLoaded()メソッドは要素を返しません)。

要素が見つからない場合にNoSuchElementExceptionメソッドによってスローされる可能性のあるfindElementと、要素への参照が現在 "であることを示すStaleElementExceptionを無視することは理にかなっています。 stale」-要素はページのDOMに表示されなくなりました。これは通常、何か(最も一般的にはJS)がDOMを変更し、参照が無効になったことを意味します。したがって、WebDriverはそれを再度検索する必要があります。

もちろん、より短いコードもトリックになります。

_    new WebDriverWait(driver, 60)
            .until(ExpectedConditions.visibilityOf(someWebElement));
_

documentation は、実際にはこれでかなり良いです。

編集:コメントへの回答:

はい、分かりました。しかし、ボタンなどをクリックした後に要素が存在する場合はどうなりますか?

ボタンがあり、そのボタンをクリックした後にテキストボックスが表示され、それを操作したいというシナリオがあるとします。

_public class PageObject extends LoadableComponent<PageObject>{

    public PageObject() throws Exception {
        driver = getWebDriver();
        PageFactory.initElements(driver, this);
        isLoaded();
    }
    private WebDriver driver = null;

    @FindBy(id = "yourButton")
    private WebElement button;

    @FindBy(id = "textBoxThatAppears")
    private WebElement txtBox;

    @Override
    public void isLoaded() throws Error {
        // Initial loading, called when creating the page object to make sure that the page is loaded to a state where it is ready to interact with us, in our case it means that button is present in DOM and visible.
        waitForVisibility(button);
    }

    private void waitForVisibility(WebElement element) throws Error{
           new WebDriverWait(driver, 60)
                .until(ExpectedConditions.visibilityOf(element));
    }

    public void clickButton(){
        button.click();

    }

    public void interactWithTextbox(String text){
        // Wait for txtBox to be visible, then send text
        waitForVisibility(txtBox);
        txtBox.sendKeys(text);

       // EDIT 27.04.14: 
       // Actually you should not do the assertion here or anywhere in 
       // the pageObject, because when reusing the method in some other test, you might
       // not want to assert, you might wonder that why wouldn't you assert some 
       // specific condition every time, but I would throw that question right back 
       // to you and ask: What is the point of checking the exact same thing over and 
       // over again. There are 2 things, firstly the assertion takes resources (and
       // that can become important when test suite grows, secondly your tests can 
       // simply start failing at the same point when one little condition is not as
       // it should be. Also, having the asserts in the test, makes the test more
       // readable and understandable for others.
         // end edit 27.04.14
        // Next line is no longer recommended by this answer.
         // assert that something happened that you expected.
    }

}
_

そして今あなたのテストクラス:

_public void TestClass {

     @Test
     public void testClickButtonAndInteractWithTextbox(){
         // Initiate the page object
         Pageobject po = new PageObject();
         po.clickButtonAndWaitForTextbox();
         po.interactWithTextbox("blabla");
         // edit 27.04.14
         assertSomethingGoodHappened();
     }
}
_
17
Erki M.

Selenium tests-frameworks - [〜#〜] isfw [〜#〜] のいずれかからのテストページ(Selenium 1以降)の別の効率的な概念は、ここで利用できます。 。遅延ロードされた要素、カスタムコンポーネント機能、自動待機(パフォーマンスを低下させる暗黙的な待機ではない)、要素を備えた組み込みの待機メソッド、およびajaxベースアプリケーションに非常に役立つその他の機能があります。

テストケースを開発するための次のビルディングブロックを提供します。

  1. テストページ
  2. 成分
  3. テストステップ

さらに レポート も説明的です。

0
user861594