要素はページオブジェクトクラスで定義する必要があり、テストクラスは要素、セレクターなどを何も知らない必要があるため、テストクラスではなくページオブジェクトクラスの要素を待つ必要があります。テスト、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
によってスローされる可能性のあるものと、要素への参照が現在「古い」ことを示すを無視することは理にかなっています-要素はページのDOMに表示されなくなりました. これは通常、何か (最も一般的には JS) が DOM を変更し、参照が無効になったことを意味します。そのため、再度参照する必要があります。findElement
StaleElementException
WebDriver
もちろん、次のような短いコードもトリックになります。
new WebDriverWait(driver, 60)
.until(ExpectedConditions.visibilityOf(someWebElement));
ドキュメントは実際にはこれについてかなり良いです。
編集:コメントへの回答:
はい、分かりました。しかし、ボタンなどをクリックした後に要素が存在する場合はどうなりますか?
ボタンがあり、そのボタンをクリックするとテキストボックスが表示され、それを操作したいというシナリオがあるとします。
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();
}
}