前提
・selenium-java version 2.44.0
WebDriverWaitについて
WebDriverWaitは描画処理などの関係でwaitをかけることに特化したクラス。
waitを使うときには以下のように書く。
WebDriverWait wait = new WebDriverWait(driver, 10); wait.until(ExpectedConditions.alertIsPresent()); // 処理 doSomething(); ・・・・
WebDriverWaitのインスタンスを生成し、untilメソッドで引数で
渡した条件(ExceptedCondtionインスタンス)がtrueになるまで待つ。
(正確に言えば、untilメソッドの引数は
com.google.common.base.Functionインターフェースか
com.google.common.base.Predicateの具象クラスインスタンス。
ExceptedCondtionはFunctionを継承している)
ExpectedConditionsはExpectedConditionインターフェース型の
無名クラスインスタンスを生成するstaticメソッドを持っているのでこのような記述になる。
(ExpectedConditionsクラスとExpectedConditionクラスって紛らわしい)
なぜカスタムコンディションを作るのか
ExpectedConditionsで提供されているメソッドは以下に記載するが、割と豊富で実用性が高い。
ただ、必ずしも僕の要件を満たしてくれるわけではなく
エレメントのinnerHTML属性にテキスト出力するJavaScriptの処理に対して
直接的にwaitをかける方法がなかった(たぶん)
static ExpectedCondition<Alert> alertIsPresent() アラートが表示されているか static ExpectedCondition<java.lang.Boolean> elementSelectionStateToBe(By locator, boolean selected) static ExpectedCondition<java.lang.Boolean> elementSelectionStateToBe(WebElement element, boolean selected) 指定された要素が選択されているか static ExpectedCondition<WebElement> elementToBeClickable(By locator) static ExpectedCondition<WebElement> elementToBeClickable(WebElement element) エレメントが表示され、かつクリック可能か static ExpectedCondition<java.lang.Boolean> elementToBeSelected(By locator) static ExpectedCondition<java.lang.Boolean> elementToBeSelected(WebElement element) 指定された要素が選択されているかどうか static ExpectedCondition<WebDriver> frameToBeAvailableAndSwitchToIt(By locator) static ExpectedCondition&;ltWebDriver> frameToBeAvailableAndSwitchToIt(java.lang.String frameLocator) フレームを切り替え可能であるかどうか static ExpectedCondition<java.lang.Boolean> invisibilityOfElementLocated(By locator) static ExpectedCondition<java.lang.Boolean> invisibilityOfElementWithText(By locator, java.lang.String text) エレメントが非表示であるか、存在しないか static ExpectedCondition<java.lang.Boolean> not(ExpectedCondition<?> condition) 与えられた条件の論理的な反対の条件か。つまり逆か static ExpectedCondition<java.util.List<WebElement>> presenceOfAllElementsLocatedBy(By locator) static ExpectedCondition<WebElement> presenceOfElementLocated(By locator) ウェブページ上に存在する少なくとも1つエレメントがあるか static <T> ExpectedCondition<T> refreshed(ExpectedCondition<T> condition) エレメントがページ再描画によって更新可能な状態かを確認するラッパー static ExpectedCondition<java.lang.Boolean> stalenessOf(WebElement element) エレメントはもうDOMにアタッチされないかどうか static ExpectedCondition<java.lang.Boolean> textToBePresentInElement(By locator, java.lang.String text) 非推奨のため省略。textToBePresentInElementLocatedにかわっている static ExpectedCondition<java.lang.Boolean> textToBePresentInElement(WebElement element, java.lang.String text) 引数のテキストは、引数のエレメントに存在しているかどうか static ExpectedCondition<java.lang.Boolean> textToBePresentInElementLocated(By locator, java.lang.String text) 引数のテキストは、引数のロケータから取得できるエレメントに存在しているかどうか (対象エレメントに対してWebElement#getTextでチェックをする) static ExpectedCondition<java.lang.Boolean> textToBePresentInElementValue(By locator, java.lang.String text) static ExpectedCondition<java.lang.Boolean> textToBePresentInElementValue(WebElement element, java.lang.String text) 引数のテキストは、引数のエレメントのvalue属性に存在しているかどうか (対象エレメントに対してWebElement#getAttribute("value")でチェックをする) static ExpectedCondition<java.lang.Boolean> titleContains(java.lang.String title) ページのタイトルに引数の文字が含まれているかどうか(大文字と小文字を区別する) static ExpectedCondition<java.lang.Boolean> titleIs(java.lang.String title) ページのタイトルに引数の文字と一致するか(大文字と小文字を区別する) static ExpectedCondition<WebElement> visibilityOf(WebElement element) ページ上でエレメントが認識され、かつ表示されているか static ExpectedCondition<java.util.List<WebElement>> visibilityOfAllElements(java.util.List<WebElement> elements) 引数で渡されたリストの全てのエレメントがページ上に表示されているか static ExpectedCondition<java.util.List<WebElement>> visibilityOfAllElementsLocatedBy(By locator) ロケータと一致する全てのエレメントがページ上に存在する表示されているか static ExpectedCondition<WebElement> visibilityOfElementLocated(By locator) エレメントがページ上に存在し、表示されているか
カスタム方法
実際にExcepectedConditionを実装してあげればおっけー。
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedCondition; public class AttributeCondition implements ExpectedCondition<Boolean> { private WebElement element; private String attributeName; private String expectedValue; public AttributeCondition(WebElement element, String attributeName, String expectedValue) { this.element = element; this.attributeName = attributeName; this.expectedValue = expectedValue; } public Boolean apply(WebDriver driver) { return element.getAttribute(attributeName).equals(expectedValue); } }
このクラスをこんな感じで使ってあげる
@Test public void testUpdate() { // 更新処理とかする update(); WebDriverWait waitForUpdate = new WebDriverWait(driver, 10); WebElement hoge = driver.findElement(By.id("hoge")); waitForUpdate.until(new AttributeCondition(hoge, "innerHTML","更新が完了しました")); assertThat("keyDown", hoge.getAttribute("innerHTML"), is("更新が完了しました")); } @Test public void testSearch() { // 検索処理とかする search(); WebDriverWait waitForSearch = new WebDriverWait(driver, 10); WebElement fuga = driver.findElement(By.id("fuga")); waitForSearch.until(new AttributeCondition(fuga, "messageArgs","更新が完了しました")); assertThat("keyDown", fuga.getAttribute("disabled"), is("更新が完了しました")); }
無事にinnerHTMLのテキストに対してのwaitをかけることが出来ました!
まとめ
なるべくなら車輪の再発明はしたくないところ。
どうしても、かゆいところに手が届かない感じなら
作っちゃってもいいんじゃないでしょうか?ということで作りました。
おそらく、関連する他のエレメントの状態を監視してwaitをかければ
waitの条件満たせる場合があるかもしれません。
ですが、個人的には間接的なwait(※1)は推奨しません。
ページの変更に弱くなりテスト失敗の原因になりかねません。
だったらカスタムコンディションのクラスを作った方が良いんではないかなぁと。
数が増えてきたら、WebDriverのAPIに倣って、オレオレExpectedConditionsクラスを作ると良いと思います。
>2015年3月1日追記
実装方法について少し考えなおしましたので
オレオレExpectedConditionsクラスに関して以下の記事を確認ください。
続編記事
※1.例えば、対象 A B Cがある場合Cが表示されていれば、AのinnerHTMLが表示されていると判断するなど
0 件のコメント:
コメントを投稿