Bagaimana cara meminta Selenium-WebDriver menunggu beberapa detik di Java?


100

Saya sedang mengerjakan Java Selenium-WebDriver. saya tambahkan

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

dan

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

karena Aplikasi saya memerlukan beberapa detik untuk memuat Antarmuka Pengguna. Jadi saya menetapkan 2 detik implisitwait. tetapi saya tidak dapat menemukan kotak teks elemen

Lalu saya tambahkan Thread.sleep(2000);

Sekarang berfungsi dengan baik. Mana yang lebih baik?


Jawaban:


123

Ada dua jenis penantian: penantian eksplisit dan implisit. Ide menunggu eksplisit adalah

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

Konsep menunggu implisit adalah

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

Anda bisa mendapatkan perbedaan detailnya di sini .

Dalam situasi seperti itu, saya lebih suka menggunakan penantian eksplisit ( fluentWaitkhususnya):

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;
};

fluentWaitfungsi mengembalikan elemen web yang Anda temukan. Dari dokumentasi di fluentWait: Implementasi antarmuka Tunggu yang mungkin memiliki batas waktu dan interval polling yang dikonfigurasi dengan cepat. Setiap instans FluentWait menentukan jumlah waktu maksimum untuk menunggu suatu kondisi, serta frekuensi untuk memeriksa kondisi tersebut. Selain itu, pengguna dapat mengonfigurasi menunggu untuk mengabaikan jenis pengecualian tertentu sambil menunggu, seperti NoSuchElementExceptions saat mencari elemen di halaman. Detailnya bisa Anda dapatkan di sini

Penggunaan fluentWaitdalam kasus Anda adalah sebagai berikut:

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

Pendekatan ini IMHO lebih baik karena Anda tidak tahu persis berapa banyak waktu untuk menunggu dan dalam interval pemungutan suara Anda dapat mengatur nilai waktu sewenang-wenang yang keberadaan elemen akan diverifikasi melalui. Salam.


3
Itu import com.google.common.base.Function;, tidakimport java.util.function.Function;
memeriksa

belum diperiksa, sebenarnya menggunakan intelij IDEA untuk pengembangan, ini membantu impor otomatis (saat bekerja di proyek berbasis maven)
eugene.polschikov

1
Saya baru saja memanggil orang lain yang mungkin bertanya-tanya mana Functionyang sedang digunakan. Awalnya tidak jelas bagi saya. Terima kasih atas jawabannya.
memeriksa

1
Atau Anda bisa menggunakan ekspresi lambda: driver -> driver.findElement(locator). Saat menggunakan ini, Anda tidak memerlukan pernyataan impor sama sekali.
Thibstars

2
Sekarang: .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))sebagai pengganti: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro

16

Utas ini sedikit lebih tua, tetapi saya pikir saya akan memposting apa yang saat ini saya lakukan (pekerjaan sedang dalam proses).

Meskipun saya masih mengalami situasi di mana sistem sedang dalam beban berat dan ketika saya mengklik tombol kirim (misalnya, login.jsp), ketiga kondisi (lihat di bawah) kembali truetetapi halaman berikutnya (misalnya, home.jsp) belum ' t mulai memuat.

Ini adalah metode tunggu umum yang mengambil daftar 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;
}

Saya telah menentukan berbagai ExpectedConditions yang dapat digunakan kembali (tiga di bawah). Dalam contoh ini, tiga kondisi yang diharapkan mencakup document.readyState = 'complete', tidak ada "wait_dialog", dan tidak ada 'spinners' (elemen yang menunjukkan data asinkron sedang diminta).

Hanya yang pertama yang dapat diterapkan secara umum ke semua halaman 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;
    }
};

Bergantung pada halamannya, saya dapat menggunakan salah satu atau semuanya:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

Ada juga ExpectedConditions yang telah ditentukan sebelumnya di kelas berikut: org.openqa.selenium.support.ui.ExpectedConditions


1
Jawaban yang bagus! Saya belum pernah melihat seseorang melewatkan item ExpectedCondition melalui metode konstruktor. Ide yang bagus. +1
djangofan

Jeff Vincent, dapatkah Anda memberi tahu saya apakah ini akan berfungsi untuk halaman menunggu 5 menit jika ya, tolong sarankan parameter tempat mana yang perlu dikirim?
khanam

Ini jawaban yang bagus. Saya memiliki fungsi yang serupa seperti ini, namun saya harus memanggilnya di setiap fungsi sehingga skrip saya menunggu hingga halaman dimuat (spinner). Adakah cara agar saya dapat mengaitkan fungsi waitForSpinner ini secara diam-diam ke ImplicitWait sehingga saya tidak perlu memanggilnya setiap saat dalam fungsi saya? Seperti menentukan fungsinya, kaitkan ke driver sekali dan boom.
Bhuvanesh Mani

13

Jika menggunakan webdriverJs (node.js),

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

Kode di atas membuat browser menunggu selama 5 detik setelah mengklik tombol.


18
Mengapa Anda memposting ini jika pertanyaannya khusus tentang Java, bukan node / JavaScript? Ini di luar topik seperti menjawab bagaimana melakukannya di ruby.
Thor84no

1
rekomendasi untuk menggunakan tidur jelas bukan solusi yang baik
Kiril S.

@ Thor84no Terutama karena beberapa dari kita yang mencari solusi web menemukan jawaban ini
Kitanga Nday

10

Menggunakan Thread.sleep(2000);adalah menunggu tanpa syarat. Jika pengujian Anda memuat lebih cepat, Anda masih harus menunggu. Jadi pada prinsipnya menggunakan implicitlyWaitadalah solusi yang lebih baik.

Namun, saya tidak melihat mengapa implicitlyWaittidak berhasil dalam kasus Anda. Apakah Anda mengukur jika findElementsebenarnya membutuhkan dua detik sebelum melempar pengecualian. Jika demikian, dapatkah Anda mencoba menggunakan tunggu bersyarat WebDriver seperti yang dijelaskan dalam jawaban ini ?


3

Saya suka menggunakan kondisi khusus. Berikut beberapa kode di 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)

Kapan pun Anda perlu menunggu, Anda dapat melakukannya secara eksplisit dengan memeriksa keberadaan elemen tertentu (elemen tersebut dapat bervariasi dari satu halaman ke halaman lain). find_elements_by_iddaftar kembali - kosong atau tidak, Anda baru saja memeriksa.


2

klik tampaknya memblokir? - inilah cara lain untuk menunggu jika Anda menggunakan WebDriverJS:

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

Kode di atas menunggu setelah tombol diklik untuk memuat halaman berikutnya dan kemudian mengambil sumber halaman berikutnya.


1
Apa yang membuat kode menunggu halaman berikutnya dimuat? Apakah hanya panggilan pertama dalam callback adalah getPageSource?
Isochronous

1

Menunggu secara implisit dan Thread.sleep Keduanya digunakan untuk sinkronisasi saja..tetapi perbedaannya adalah kita dapat menggunakan Tunggu secara implisit untuk seluruh program tetapi Thread.sleep hanya akan berfungsi untuk kode tunggal itu .. Di sini saran saya adalah gunakan Tunggu secara implisit sekali dalam program ketika setiap kali halaman web Anda akan di-refresh berarti gunakan Thread.sleep pada saat itu..itu akan jauh lebih baik :)

Ini Kode Saya:

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

Kadang-kadang menunggu tersirat tampaknya diganti dan waktu menunggu dipotong pendek. [@ eugene.polschikov] memiliki dokumentasi yang bagus tentang mengapa. Saya telah menemukan dalam pengujian dan pengkodean saya dengan Selenium 2 bahwa menunggu implisit itu baik tetapi kadang-kadang Anda harus menunggu secara eksplisit.

Lebih baik untuk menghindari secara langsung meminta utas untuk tidur, tetapi terkadang tidak ada cara yang baik. Namun, ada pilihan menunggu lain yang disediakan Selenium yang membantu. waitForPageToLoad dan waitForFrameToLoad terbukti sangat berguna.


0

Penantian Implisit: Selama Penantian implisit jika Pengandar Web tidak dapat segera menemukannya karena ketersediaannya, WebDriver akan menunggu waktu yang disebutkan dan tidak akan mencoba menemukan elemen lagi selama jangka waktu yang ditentukan. Setelah waktu yang ditentukan selesai, itu akan mencoba mencari elemen sekali lagi terakhir kali sebelum melempar pengecualian. Pengaturan default adalah nol. Setelah kami menetapkan waktu, Driver Web menunggu periode instance objek WebDriver.

Penantian Eksplisit: Ada kemungkinan saat elemen tertentu membutuhkan waktu lebih dari satu menit untuk dimuat. Dalam hal ini, Anda pasti tidak suka menyetel waktu yang lama ke Penantian implisit, karena jika Anda melakukan ini, browser Anda akan menunggu waktu yang sama untuk setiap elemen. Untuk menghindari situasi tersebut Anda cukup memberikan waktu tersendiri pada elemen yang dibutuhkan saja. Dengan mengikuti ini, waktu tunggu implisit browser Anda akan menjadi singkat untuk setiap elemen dan akan menjadi besar untuk elemen tertentu.


0

Terkadang menunggu implisit gagal, mengatakan bahwa sebuah elemen ada tetapi sebenarnya tidak.

Solusinya adalah menghindari penggunaan driver.findElement dan menggantinya dengan metode kustom yang menggunakan Explicit Wait secara implisit. Sebagai contoh:

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;
}

Ada alasan tambahan untuk menghindari menunggu implisit selain kegagalan yang sesekali dan sporadis (lihat tautan ini ).

Anda dapat menggunakan metode "elemen" ini dengan cara yang sama seperti driver.findElement. Sebagai contoh:

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

Jika Anda benar-benar ingin menunggu beberapa detik untuk memecahkan masalah atau kejadian langka lainnya, Anda dapat membuat metode jeda yang mirip dengan yang ditawarkan oleh selenium IDE:

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

0

Jawaban : tunggu beberapa detik sebelum visibilitas elemen menggunakan Selenium WebDriver melalui metode di bawah ini.

implicitlyWait () : Instance WebDriver menunggu hingga halaman penuh dimuat. Anda perlu menggunakan 30 hingga 60 detik untuk menunggu pemuatan halaman penuh.

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

ExplicitlyWait WebDriverWait () : Instance WebDriver menunggu hingga halaman penuh dimuat.

WebDriverWait wait = new WebDriverWait(driver, 60);

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

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

Catatan : Gunakan ExplicitlyWait WebDriverWait () untuk menangani WebElement tertentu.



-1

Saya lebih suka kode berikut menunggu selama 2 detik.

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

-1
Thread.sleep(1000);

lebih buruk: menunggu statis, itu akan membuat skrip pengujian lebih lambat.

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

ini adalah penantian yang dinamis

  • Ini berlaku sampai driver web ada atau memiliki ruang lingkup sampai masa pakai driver
  • kita juga bisa menunggu secara implisit.

Akhirnya, yang saya sarankan adalah

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

dengan beberapa kondisi standar:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • Itu juga menunggu dinamis
  • dalam hal ini penantian hanya akan berlangsung dalam beberapa detik
  • kita harus menggunakan menunggu eksplisit untuk elemen web tertentu yang ingin kita gunakan.

-4
Thread.Sleep(5000);

Ini memang membantu saya tetapi pengecualian InterruptedException perlu ditangani. Jadi lebih baik mengelilinginya dengan mencoba dan menangkap:

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

ATAU

Tambahkan deklarasi lemparan:

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

Saya lebih suka yang kedua karena seseorang kemudian dapat menggunakan sleep()sebanyak yang diinginkan dan menghindari pengulangan trydan catchblokir setiap kali sleep()digunakan.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.