#SeleniumでHTML要素が見つかるまで待機したい
会社で勤怠管理のWebシステムを利用していますが、毎日、手動で入力するのが面倒くさかったのでSelenium(Java)で自動入力するツールを作りました。その際、画面遷移の完了を判断するために、あるHTML要素が見つかるまで待機する処理を作るのに一番、手こずったので内容をメモします。
##Strategyインタフェースを作成
ただ待機するだけではなく、画面によっては見つからなかったら再度、ボタンをクリックするようなことがしたかったので、「どのように待つか」というアルゴリズムを入れ替えられるようにStrategyパターンで作ります。
public interface HtmlElementStrategy {
public boolean isFindElement();
}
##Contextを作成
HtmlElementStrategy#isFindElementがtrueになるまで待機する処理。
waitTimeに待機時間、timeoutCntに待機回数を指定。
public class HtmlElementContext{
public static void waitUntilFindElement(long waitTime, int timeoutCnt,
HtmlElementStrategy t) {
for (int i = 0;; i++) {
try {
if (t.isFindElement()) {
// 要素が見つかったらループを抜ける
break;
}
} catch (NoSuchElementException e) {
if (i > timeoutCnt) {
// timeoutCntを超えたら例外を投げる
throw e;
}
}
try {
// waitTimeの間、待機する
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
##クライアントを作成
実際の使用例。
HtmlElementContext#waitUntilFindElementを呼び出す際に、Strategyを実装する。
HtmlElementContext.waitUntilFindElement(1000, 30,
new TeamSplitStrategy() {
// Strategyの実装
@Override
public boolean isFindElement() {
if (driver.getTitle().contains("HTML要素名")) {
// 画面のタイトルが見つかった
return true;
}
// リンクをクリック
driver.findElement(By.linkText("HTML要素名")).click();
return false;
}
});
##WebDriverWaitクラスを使えばよかった
この記事を書いている最中、SeleniumライブラリのWebDriverWaitクラスを使えば、わざわざ上記のような処理を自作しなくても済むことに気付いてしまいました。
// Waitオブジェクト作成
Wait<WebDriver> wait = new WebDriverWait(driver, 30);
// 待機条件を実装
ExpectedCondition<Boolean> waitCondition= new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
driver.findElement(By.linkText("HTML要素名")).click();
return driver.getTitle().contains("HTML要素名");
}
};
// 条件を満たすまで待つ
wait.until(waitCondition);
つまり、車輪の再発明をする前に、APIを確認しようねというお話でした・・・・・・。