Làm cách nào để yêu cầu Selenium-WebDriver đợi trong vài giây trong Java?


100

Tôi đang làm việc trên Java Selenium-WebDriver. Tôi đã thêm

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

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

vì Ứng dụng của tôi mất vài giây để tải Giao diện Người dùng. Vì vậy, tôi đặt 2 giây ngầm chờ đợi. nhưng tôi không thể định vị hộp văn bản phần tử

Sau đó, tôi thêm Thread.sleep(2000);

Bây giờ nó hoạt động tốt. Cách nào tốt hơn?


Câu trả lời:


123

Có hai loại chờ đợi: chờ đợi rõ ràng và chờ ngầm. Ý tưởng về sự chờ đợi rõ ràng là

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

Khái niệm về sự chờ đợi ngầm là

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

Bạn có thể nhận được sự khác biệt trong chi tiết ở đây .

Trong những tình huống như vậy, tôi thích sử dụng chờ đợi rõ ràng ( fluentWaitcụ thể là):

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

fluentWaithàm trả về phần tử web tìm thấy của bạn. Từ tài liệu trên fluentWait: Việc triển khai giao diện Chờ có thể có thời gian chờ và khoảng thời gian bỏ phiếu được định cấu hình nhanh. Mỗi cá thể FluentWait xác định khoảng thời gian tối đa để đợi một điều kiện, cũng như tần suất để kiểm tra điều kiện. Hơn nữa, người dùng có thể định cấu hình thời gian chờ để bỏ qua các loại ngoại lệ cụ thể trong khi chờ đợi, chẳng hạn như NoSuchElementExceptions khi tìm kiếm một phần tử trên trang. Thông tin chi tiết bạn có thể lấy tại đây

Cách sử dụng fluentWaittrong trường hợp của bạn như sau:

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

Cách tiếp cận này IMHO tốt hơn vì bạn không biết chính xác bao nhiêu thời gian chờ đợi và trong khoảng thời gian bỏ phiếu, bạn có thể đặt giá trị thời gian tùy ý mà sự hiện diện của phần tử sẽ được xác minh thông qua. Trân trọng.


3
Đó là import com.google.common.base.Function;, không phảiimport java.util.function.Function;
kiểm tra vào

haventchecked, thực sự sử dụng intelij IDEA cho sự phát triển, nó giúp với tính năng tự động nhập khẩu (khi làm việc trong maven dựa trên dự án)
eugene.polschikov

1
Tôi chỉ gọi điều đó cho những người khác có thể đang thắc mắc cái nào Functionđang được sử dụng. Ban đầu tôi không thấy rõ điều đó. Cảm ơn vì câu trả lời.
kiểm tra

1
Hoặc bạn chỉ có thể sử dụng một biểu thức lambda: driver -> driver.findElement(locator). Khi sử dụng điều này, bạn sẽ không cần một câu lệnh nhập nào cả.
Thibstars

2
Bây giờ nó là: .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))thay vì: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro

16

Chủ đề này cũ hơn một chút, nhưng tôi nghĩ tôi sẽ đăng những gì tôi hiện đang làm (đang tiến hành).

Mặc dù tôi vẫn gặp phải các tình huống trong đó hệ thống đang tải nặng và khi tôi nhấp vào nút gửi (ví dụ: login.jsp), cả ba điều kiện (xem bên dưới) đều trả về truenhưng trang tiếp theo (ví dụ: home.jsp) thì không ' chưa bắt đầu tải.

Đây là một phương pháp chờ chung sử dụng một danh sách các Điều kiện mong đợi.

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

Tôi đã xác định các Điều kiện mong đợi có thể tái sử dụng khác nhau (ba điều kiện bên dưới). Trong ví dụ này, ba điều kiện mong đợi bao gồm document.readyState = 'complete', không có "wait_dialog" và không có 'spinners' (phần tử cho biết dữ liệu không đồng bộ đang được yêu cầu).

Chỉ cái đầu tiên có thể được áp dụng chung cho tất cả các trang 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;
    }
};

Tùy thuộc vào trang, tôi có thể sử dụng một hoặc tất cả chúng:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

Ngoài ra còn có các Điều kiện mong đợi được xác định trước trong lớp sau: org.openqa.selenium.support.ui.E Dự kiến ​​Điều kiện


1
Câu trả lời chính xác! Tôi chưa bao giờ thấy ai đó chuyển một mục Mong đợi Điều kiện vào thông qua phương thức khởi tạo. Thật là một ý tưởng hay. +1
djangofan

Jeff Vincent, bạn có thể vui lòng cho tôi biết điều này sẽ hoạt động khi trang đợi 5 phút nếu có, sau đó vui lòng đề xuất tham số địa điểm nào cần gửi?
khanam

Đây là một câu trả lời tuyệt vời. Tôi có chức năng tương tự như thế này, tuy nhiên, tôi phải gọi nó trong mọi hàm để tập lệnh của tôi đợi cho đến khi tải trang (spinner). Có cách nào để tôi có thể kết nối hàm waitForSpinner này một cách thầm lặng vào ImplicitWait để tôi không cần phải gọi nó mọi lúc trong hàm của mình không? Giống như xác định chức năng, móc nó vào trình điều khiển một lần và bùng nổ.
Bhuvanesh Mani

13

Nếu sử dụng webdriverJs (node.js),

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

Đoạn mã trên khiến trình duyệt đợi trong 5 giây sau khi nhấp vào nút.


18
Tại sao bạn lại đăng bài này khi câu hỏi đặc biệt là về Java, không phải node / JavaScript? Nó lạc đề như trả lời làm thế nào để làm điều đó trong ruby.
Thor84no

1
khuyến cáo để sử dụng giấc ngủ chắc chắn không phải là một giải pháp tốt
Kiril S.

@ Thor84no Chủ yếu là do một số người trong chúng ta đang tìm kiếm giải pháp trên web tìm thấy câu trả lời này
Kitanga Nday 26/03

10

Sử dụng Thread.sleep(2000);là một sự chờ đợi vô điều kiện. Nếu thử nghiệm của bạn tải nhanh hơn, bạn sẽ vẫn phải đợi. Vì vậy về nguyên tắc sử dụng implicitlyWaitlà giải pháp tốt hơn.

Tuy nhiên, tôi không hiểu tại sao implicitlyWaitkhông hoạt động trong trường hợp của bạn. Bạn đã đo lường nếu findElementthực sự mất hai giây trước khi ném một ngoại lệ. Nếu vậy, bạn có thể thử sử dụng thời gian chờ có điều kiện của WebDriver như được mô tả trong câu trả lời này không?


3

Tôi thích sử dụng các điều kiện tùy chỉnh. Đây là một số mã bằng 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)

Bất cứ khi nào bạn cần đợi, bạn có thể thực hiện điều đó một cách rõ ràng bằng cách kiểm tra sự tồn tại của một phần tử nhất định (phần tử đó có thể khác nhau giữa các trang). find_elements_by_iddanh sách trả về - trống hay không, bạn chỉ cần kiểm tra.


2

nhấp chuột dường như bị chặn? - đây là một cách khác để đợi nếu bạn đang sử dụng WebDriverJS:

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

Đoạn mã trên đợi sau khi nút được nhấp để tải trang tiếp theo và sau đó lấy nguồn của trang tiếp theo.


1
Điều gì khiến mã phải chờ tải trang tiếp theo? Có phải lệnh gọi đầu tiên trong lệnh gọi lại là getPageSource không?
Isochronous

1

Chờ đợi ngầm và Thread.sleep Cả hai đều chỉ được sử dụng để đồng bộ hóa..nhưng sự khác biệt là chúng ta có thể sử dụng Chờ ngầm toàn bộ chương trình nhưng Thread.sleep sẽ chỉ hoạt động cho mã duy nhất. Ở đây đề xuất của tôi là sử dụng Chờ một lần trong chương trình khi mỗi lần trang web của bạn được làm mới có nghĩa là sử dụng Thread.sleep tại thời điểm đó..nó sẽ tốt hơn nhiều :)

Đây là Mã của tôi:

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

Đôi khi, sự chờ đợi ngầm dường như trở nên quá tải và thời gian chờ đợi bị rút ngắn. [@ eugene.polschikov] có tài liệu tốt về lý do. Tôi đã tìm thấy trong quá trình thử nghiệm và viết mã của mình với Selenium 2 rằng việc chờ đợi ngầm là tốt nhưng đôi khi bạn phải đợi rõ ràng.

Tốt hơn là tránh trực tiếp kêu gọi một chuỗi ngủ, nhưng đôi khi không có cách nào tốt để giải quyết vấn đề đó. Tuy nhiên, có các tùy chọn chờ khác được cung cấp bởi Selenium giúp ích. waitForPageToLoadwaitForFrameToLoad đã chứng minh đặc biệt hữu ích.


0

Chờ ngầm định: Trong thời gian chờ ngầm định nếu Trình điều khiển web không thể tìm thấy nó ngay lập tức vì tính khả dụng của nó, thì WebDriver sẽ đợi trong thời gian đã đề cập và nó sẽ không cố gắng tìm lại phần tử trong khoảng thời gian đã chỉ định. Sau khi hết thời gian quy định, nó sẽ cố gắng tìm kiếm lại phần tử lần cuối trước khi ném ra ngoại lệ. Cài đặt mặc định là 0. Sau khi chúng tôi đặt thời gian, Trình điều khiển Web sẽ đợi khoảng thời gian của cá thể đối tượng WebDriver.

Chờ rõ ràng: Có thể có trường hợp khi một phần tử cụ thể mất hơn một phút để tải. Trong trường hợp đó, bạn chắc chắn không muốn đặt một khoảng thời gian lớn để chờ ngầm, vì nếu bạn làm điều này, trình duyệt của bạn sẽ đợi cùng một thời gian cho mọi phần tử. Để tránh tình trạng đó, bạn có thể chỉ cần đặt một khoảng thời gian riêng cho phần tử bắt buộc. Bằng cách làm theo điều này, thời gian chờ ngầm của trình duyệt của bạn sẽ ngắn cho mọi phần tử và nó sẽ lớn đối với phần tử cụ thể.


0

Đôi khi chờ đợi không thành công, nói rằng một phần tử tồn tại nhưng nó thực sự không.

Giải pháp là tránh sử dụng driver.findElement và thay thế nó bằng một phương thức tùy chỉnh sử dụng ngầm định Chờ rõ ràng. Ví dụ:

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

Có những lý do bổ sung để tránh sự chờ đợi ngầm ngoài những lỗi không thường xuyên, lẻ tẻ (xem liên kết này ).

Bạn có thể sử dụng phương thức "phần tử" này theo cách tương tự như driver.findElement. Ví dụ:

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

Nếu bạn thực sự muốn chỉ đợi vài giây để khắc phục sự cố hoặc một số trường hợp hiếm hoi khác, bạn có thể tạo một phương pháp tạm dừng tương tự như những gì selen IDE cung cấp:

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

0

Trả lời : hãy đợi vài giây trước khi hiển thị phần tử bằng Selenium WebDriver, hãy xem các phương pháp dưới đây.

implicitWait () : Phiên bản WebDriver đợi cho đến khi tải toàn bộ trang. Bạn sử dụng 30 đến 60 giây để đợi tải trang đầy đủ.

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

ExplicitWait WebDriverWait () : Phiên bản WebDriver đợi cho đến khi tải toàn bộ trang.

WebDriverWait wait = new WebDriverWait(driver, 60);

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

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

Lưu ý : Vui lòng sử dụng ExplicitWait WebDriverWait () để xử lý bất kỳ WebElement cụ thể nào.



-1

Tôi muốn đoạn mã sau đợi trong 2 giây.

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

-1
Thread.sleep(1000);

tệ hơn: là một chờ đợi tĩnh, nó sẽ làm cho tập lệnh thử nghiệm chậm hơn.

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

đây là một sự chờ đợi năng động

  • nó có giá trị cho đến khi tồn tại webdriver hoặc có phạm vi cho đến thời gian tồn tại của trình điều khiển
  • chúng ta cũng có thể ngầm chờ đợi.

Cuối cùng, những gì tôi đề nghị là

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

với một số điều kiện xác định trước:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • Nó cũng là chờ đợi động
  • trong điều này, sự chờ đợi sẽ chỉ trong vài giây
  • chúng tôi phải sử dụng chờ rõ ràng cho một phần tử web cụ thể mà chúng tôi muốn sử dụng.

-4
Thread.Sleep(5000);

Điều này đã giúp tôi nhưng ngoại lệ InterruptException cần được quan tâm. Vì vậy, tốt hơn hãy bao quanh nó bằng cách thử và nắm bắt:

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

HOẶC LÀ

Thêm khai báo ném:

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

Tôi thích cái thứ hai hơn vì người ta có thể sử dụng sleep()bao nhiêu lần tùy thích và tránh sự lặp lại trycatchchặn mọi lúc mọi nơi sleep()đã được sử dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.