JavaでSelenium-WebDriverに数秒待つように依頼するにはどうすればよいですか?


100

Java Selenium-WebDriverに取り組んでいます。追加した

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

そして

WebElement textbox = driver.findElement(By.id("textbox"));

アプリケーションがユーザーインターフェイスを読み込むのに数秒かかるからです。したがって、2秒の暗黙の待機を設定しました。しかし、要素のテキストボックスを見つけることができませんでした

次に追加します Thread.sleep(2000);

今ではうまくいきます。どちらが良い方法ですか?


回答:


123

待機には、明示的待機と暗黙的待機の2つのタイプがあります。明示的な待機の考え方は

WebDriverWait.until(condition-that-finds-the-element);

暗黙の待機の概念は

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

ここで詳細の違いを得ることができます

このような状況では、明示的な待機(fluentWait特に)を使用したいと思います。

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWait関数は、見つかったWeb要素を返します。のドキュメントからfluentWaitタイムアウトとポーリング間隔をオンザフライで設定できるWaitインターフェースの実装。各FluentWaitインスタンスは、条件を待機する最大時間と、条件をチェックする頻度を定義します。さらに、ユーザーは、ページ上で要素を検索するときのNoSuchElementExceptionsなど、待機中に特定のタイプの例外を無視するように待機を構成できます。ここで 入手できる詳細

fluentWaitあなたの場合の使用法は次のとおりです:

WebElement textbox = fluentWait(By.id("textbox"));

この方法は、待機する時間が正確にわからないため、IMHOの方が適切です。ポーリング間隔では、によって要素の存在を確認する任意のtimevalueを設定できます。よろしく。


3
それはimport com.google.common.base.Function;、ではないimport java.util.function.Function;
16:06の

チェックしていませんが、実際には開発にintelij IDEAを使用しており、自動インポートを支援しています(mavenベースのプロジェクトで作業している場合)
eugene.polschikov

1
どちらFunctionが使用されているのかと不思議に思うかもしれない他の人たちのために、それを呼びかけていました。最初ははっきりしませんでした。答えてくれてありがとう。
2016年

1
または、ラムダ式を使用することもできますdriver -> driver.findElement(locator)。これを使用する場合、インポート文はまったく必要ありません。
Thibstars、2016年

2
今では .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))、代わりに: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro '15

16

このスレッドは少し古いですが、私が現在行っていること(進行中の作業)を投稿したいと思いました。

システムの負荷trueが高く、送信ボタン(login.jspなど)をクリックすると、3つの条件(下記を参照)はすべて戻りますが、次のページ(home.jspなど)には戻りません。 tはまだロードを開始しました。

これは、ExpectedConditionsのリストを受け取る汎用の待機メソッドです。

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

さまざまな再利用可能なExpectedConditionsを定義しました(以下の3つ)。この例では、予期される3つの条件には、document.readyState = 'complete'、 "wait_dialog"の存在、および 'spinners'(非同期データが要求されていることを示す要素)が含まれます。

すべてのWebページに一般的に適用できるのは最初のものだけです。

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

ページによっては、そのうちの1つまたはすべてを使用する場合があります。

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

次のクラスには、事前定義されたExpectedConditionもあります 。org.openqa.selenium.support.ui.ExpectedConditions


1
正解です。誰かがメソッドコンストラクターを介してExpectedConditionアイテムを渡すのを見たことはありません。何て素晴らしいアイデアなんだ。+1
djangofan 2016

ジェフビンセント、このページが5分間待機することを伝えてください。「はい」の場合、送信する必要のある場所のパラメータを提案してください。
2016年

これは素晴らしい答えです。私はこのような類似の関数を持っていますが、スクリプトがページの読み込み(スピナー)まで待機するように、すべての関数でそれを呼び出す必要があります。このwaitForSpinner関数を黙示的にImplicitWaitにフックして、関数で毎回呼び出す必要がないようにする方法はありますか?関数を定義するように、一度ドライバーにフックしてブームにします。
Bhuvanesh Mani

13

webdriverJs(node.js)を使用している場合、

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

上記のコードは、ボタンをクリックした後、ブラウザを5秒間待機させます。


18
質問がノード/ JavaScriptではなく、特にJavaに関するものであるのに、なぜこれを投稿するのですか?それはルビでそれを行う方法に答えるのと同じくらい話題外です。
Thor84no

1
睡眠の使用​​を推奨することは、確かに良い解決策ではありません
Kiril S.

@ Thor84no主にWebソリューションを探している私たちの一部がこの答えを見つけたため
Kitanga Nday

10

使用Thread.sleep(2000);は無条件の待機です。テストの読み込みが速くなった場合でも、待機する必要があります。したがって、原則として、使用implicitlyWaitすることをお勧めします。

しかし、なぜimplicitlyWaitあなたのケースではうまくいかないのかわかりません。がfindElement例外をスローするまでに実際に2秒かかるかどうかを測定しましたか。もしそうなら、この回答で説明されているように、WebDriverの条件付き待機を使用してみることができますか?


3

カスタム条件を使用したい。Pythonのコードは次のとおりです。

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

待つ必要があるときはいつでも、特定の要素の存在を確認することで明示的に行うことができます(このような要素はページごとに異なる場合があります)。find_elements_by_idリストを返します-空かどうか、チェックするだけです。


2

クリックがブロックされているようです?-WebDriverJSを使用している場合に待機する別の方法を次に示します。

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

上記のコードは、ボタンがクリックされた後、次のページが読み込まれるのを待ってから、次のページのソースを取得します。


1
次のページが読み込まれるまでコードを待機させるのはなぜですか?コールバックの最初の呼び出しがgetPageSourceであるだけですか?
アイソクロナス2015

1

暗黙的な待機とThread.sleepの両方が同期にのみ使用されます。ただし、プログラム全体を暗黙的に待機することはできますが、Thread.sleepはその単一のコードに対してのみ機能します。 Webページが更新されるたびに、その時点でThread.sleepを使用することを意味します。

これが私のコードです:

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}

0

暗黙の待機が無効になり、待機時間が短縮される場合があります。[@ eugene.polschikov]は、その理由についての優れたドキュメントを持っていました。Selenium 2を使用したテストとコーディングで、暗黙的な待機が適切であることがわかりましたが、場合によっては明示的に待機する必要があります。

スレッドがスリープ状態になるのを直接呼び出さないようにすることをお勧めしますが、適切な方法がない場合もあります。ただし、他のSelenium提供の待機オプションが役立ちます。waitForPageToLoadwaitForFrameToLoadは特に便利です。


0

暗黙的な待機:暗黙的な待機中に、Webドライバーがその可用性のためにそれをすぐに検出できない場合、WebDriverは指定された時間待機し、指定された期間中に要素を再度検索しようとしません。指定された時間が経過すると、最後に例外をスローする前にもう一度要素を検索しようとします。デフォルト設定はゼロです。時間を設定すると、WebドライバーはWebDriverオブジェクトインスタンスの期間待機します。

明示的な待機:特定の要素の読み込みに1分以上かかる場合があります。その場合、ブラウザーがすべての要素に対して同じ時間待機するようになるので、暗黙の待機に長い時間を設定することは間違いなく嫌です。この状況を回避するには、必要な要素のみに別の時間を設定するだけです。これに従うことにより、ブラウザの暗黙の待機時間はすべての要素で短くなり、特定の要素では長くなります。


0

要素が存在するが実際には存在しないと言って、暗黙の待機が失敗することがあります。

解決策は、driver.findElementの使用を避け、暗黙的な明示的な待機を使用するカスタムメソッドに置き換えることです。例えば:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

散発的な偶発的な失敗以外にも、暗黙的な待機を回避する理由があります(このリンクを参照)。

この「要素」メソッドは、driver.findElementと同じ方法で使用できます。例えば:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

トラブルシューティングやその他のまれな状況で数秒待つだけの場合は、selenium IDEが提供するものと同様のpauseメソッドを作成できます。

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

0

回答:Selenium WebDriverを使用した要素の可視性が以下のメソッドを通過する前に、数秒待ってください。

implicitlyWait():WebDriverインスタンスは、ページ全体が読み込まれるまで待機します。全ページのロードを待機するために、30〜60秒を使用します。

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

ExplicitlyWait WebDriverWait():WebDriverインスタンスは、ページ全体が読み込まれるまで待機します。

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

:特定のWebElementを処理するには、ExplicitlyWait WebDriverWait()を使用してください。


0

アクションを使用-

複雑なユーザージェスチャーをエミュレートするためのユーザー向けAPI。

Actions#pauseメソッドを参照してください 。


-1

私は次のコードが2秒待つのを好みます。

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}

-1
Thread.sleep(1000);

悪いことです。静的な待機であるため、テストスクリプトが遅くなります。

driver.manage().timeouts.implicitlyWait(10,TimeUnit.SECONDS);

これは動的待機です

  • Webドライバーが存在するまで有効であるか、ドライバーの寿命まで有効です
  • 暗黙的に待機することもできます。

最後に、私が提案するのは

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

いくつかの事前定義された条件で:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • 動的待機でもあります
  • この場合、待機時間は数秒です
  • 使用したい特定のWeb要素を明示的に待機する必要があります。

-4
Thread.Sleep(5000);

これは私には役立ちましたが、InterruptedException例外を処理する必要があります。ですから、try and catchで囲んでください。

try {
    Thread.Sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

または

スロー宣言を追加します。

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

1は、その後、使用することができますので、私は2番目のものを好むだろうsleep()、それは望んで何度でもとの重複を避けるtrycatchどこ毎回をブロックsleep()に使用されています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.