Các kiểu “đợi chờ” trong Selenium Webdriver: Implicit wait, Explicit wait và Fluent wait

Bài viết được sự cho phép của tác giả To Thi Van Anh

Trong Selenium – Wait là một yếu tố đóng vai trò rất quan trọng khi thực thi các test case. Vì thế hôm nay trong bài viết này mình sẽ nói về một vài kiểu wait được nhắc đến khá nhiều trong Selenium webdriver, để mọi người cùng hiểu và áp dụng nhé! 😀

  6 lý do Async/Await của Javascript đánh bại Promises
  Phân biệt sự khác nhau giữa await-return-return await

Tại sao cần sử dụng Wait?

Đã bao giờ bạn sử dụng Selenium IDE để record một vài thao tác nào đó, bạn đã chắc chắn là các key như bạn đã get như id/name chuẩn như Lê Duẩn rồi, sau đấy còn xem đi xem lại là không thể sai ở chỗ nào được mà khi run script vẫn báo fail? Điên đầu là lúc mà lâu lắm thì tự dưng với vẫn script đấy nó lại chạy pass được một lần! Nếu bạn đã từng làm với IDE thì đảm bảo là bạn đã từng gặp vấn đề này rồi!

Hoặc khi sử dụng Selenium Webdriver, bạn cũng đã rà soát kỹ lắm rồi, chắc nhẩm mình không thể nhầm lẫn ở đâu được ấy thế mà console vẫn ra dòng exception này “ElementNotVisibleException“, quái lạ, rõ ràng cái id/name/xpath của nó là như thế rồi mà, sao lại không tìm thấy được nhỉ?

Sau nhiều lần gặp phải, cũng đi tìm khắp nơi mới phát hiện nguyên nhân là do script của mình cứ đi tìm phần tử web ấy, trong khi trang web nó chưa tải được xong, lúc này thì tất nhiên là nó không thể tìm được phần tử web kia rồi. Vấn đề ở đây có thể do mạng kém, hay dữ liệu cần load lên quá lớn, trong một khoảng thời gian ngắn không thể load kịp với tốc độ của script test được.

Ngoài ra nó còn vì một số nguyên nhân chính khác liên quan đến việc xử lý các phần tử web, Ajax và Javascript ở phía ứng dụng web, nên việc load các phần tử không thể diễn ra cùng một lúc được.

Để giải quyết vấn đề này, lời khuyên dành cho bạn là hãy sử dụng Waits!

Selenium waits bao gồm một số loại như:

  1. Implicit wait
  2. Explicit wait
  3. Fluent wait

Implicit wait

Sử dụng implicit wait khi run test script, nó sẽ yêu cầu web driver tạm dừng một khoảng thời gian nhất định mà mình đã thiết lập ban đầu, trước khi bật ra một exception có nội dung giống như này: “No Such Element Exception”.

Ví dụ đơn giản như sau, khi run 1 test script, trình duyệt được bật lên, đường dẫn ứng dụng được mở ra, theo tiến trình script sẽ tự động dừng lại 5 giây – do trước đó ta đã set implicit wait = 5 giây, rồi sau đó mới thực hiện tiếp thao tác tiếp theo là click vào login. Thay vì trước đây nếu không sử dụng wait, sau khi mở link, script sẽ run luôn bước tiếp theo là click vào nút login, và ở đoạn này có thể xảy ra trường hợp là code chạy nhanh quá, nút login chưa kịp hiển thị thì sẽ không tìm thấy element này để click, vì vậy sẽ có exception được trả về thôi.

Giá trị mặc định của khoảng thời gian này là 0. Ta có thể set các giá trị này tùy ý.

Cú pháp:

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

Ta có ví dụ:

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

Như ví dụ trên, thì ta set thời gian chờ trước khi bật ra expeption là 10 giây, chỗ TimeUnit, bạn có thể thay đổi thành SECONDS, MINUTES, MILISECOND, MICROSECONDS, NANOSECONDS, DAYS, HOURS,… tùy theo yêu cầu của bạn.

Explicit Wait

Khác với implicit wait, khi sử dụng explicit wait nó sẽ đi kèm với một điều kiện nào đó, tức là thay vì chờ đợi một khoảng thời gian được thiết lập sẵn thì ở đây chúng sẽ chờ một điều kiện cụ thể nào đó hay kiểm tra khi việc wait đã vượt qua khoảng thời gian maximum nào đó, trước khi output ra một exception có nội dung kiểu như là “ElementNotVisibleException”.

Ví dụ như là wait cho đến khi phần tử A có thể click được, hay phần tử B được enable, hoặc visible. Trong khi bình thường, nếu không sử dụng explicit wait, thì mặc dù phần tử A chưa click được, nhưng script của mình vẫn chạy, chưa click được nhưng cố click thì tất nhiên là ra exception thôi. 😀 Dễ hình dung đúng không nào!

Đây được đánh giá là một kiểu wait rất là thông minh, nhưng nó chỉ có thể sử dụng được cho một số các element cụ thể nào đó thôi kiểu như trong trường hợp clickable, visible, invisible, display… . Và nó khá phù hợp trong những case mà có element động được load bằng Ajax.

Để sử dụng explicit wait thì có nhiều cách khác nhau, nhưng mình thì thích cách viết luôn cái này thành một method, và để nó vào một common nào đó, khi nào cần thì chỉ cần gọi ra và dùng thôi:

public void waitForElement(int seconds, String waitConditionLocator){
    WebDriverWait wait = new WebDriverWait(driver, seconds);
    wait.until(ExpectedConditions.visibilityOfElementLocated
              (By.xpath(waitConditionLocator)));
}

Bạn cũng có thể sử dụng trực tiếp như ví dụ dưới đây:

WebDriver driver = new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
                        .until(ExpectedConditions.presenceOfElementLocated
                        (By.id("myDynamicElement")));

Thêm ví dụ với điều kiện là element có thể click được hay display và enable như sau:

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable
                     (By.id("idOfElementToBeClicked")));

Ngoài ra các bạn có thể tham khảo thêm một số ví dụ khác về sử dụng wait theo link mình để phía cuối bài viết nhé!

Fluent wait

Sử dụng Fluent wait trong những trường hợp kiểu như, đôi khi là ta gặp những phần tử mà cần từ một đến hai giây để load, nhưng khi khác có khi lại cần nhiều thời gian hơn đến tận mấy chục giây chẳng hạn. Fluent wait sẽ tìm kiếm đi tìm kiếm lại cho đến khi tìm được phần tử đó hoặc đến khi time out thì thôi.

Ví dụ khi dùng Fluent wait, nó sẽ chờ phần tử A một khoảng thời gian cho đến khi nó xuất hiện, trong mỗi khoảng thời gian nào đó nó lại thực hiện kiểm tra xem phần tử này đã xuất hiện chưa, nếu chưa thì qua khoảng thời gian đó nó lại check lại, nếu đã tìm được thì nó sẽ đi bước tiếp theo. Hoặc đến khi vượt quá khoảng thời gian time out đã set thì lúc này mới bật ra exception.

Ta có cú pháp như sau:

Wait wait = new FluentWait(WebDriver reference)
.withTimeout(timeout, SECONDS)
.pollingEvery(timeout, SECONDS)
.ignoring(Exception.class);

Các bạn có thể tham khảo ví dụ dưới đây nhé:

// Sẽ chờ 30 giây để mỗi element hiển thị trên page 
// và sẽ thực hiện lặp lại mỗi 5 giây nếu chưa tìm thấy phần tử đó
 
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
 .withTimeout(30, SECONDS)
 .pollingEvery(5, SECONDS)
 .ignoring(NoSuchElementException.class);

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

Trên đây là một vài cơ bản về các wait hay gặp và một số ví dụ chung chung một chút. 😀 Chi tiết hơn mình sẽ tìm hiểu thêm và hẹn các bạn trong bài viết khác nhé! hehe

Nguồn tham khảo:

https://www.guru99.com/implicit-explicit-waits-selenium.html#2

http://toolsqa.com/selenium-webdriver/implicit-explicit-n-fluent-wait/

https://www.testingexcellence.com/webdriver-implicit-explicit-and-fluent-wait-examples/

https://loadfocus.com/blog/2016/11/07/how-to-use-explicit-and-implicit-waits-in-selenium-webdriver-with-java/

Bài viết gốc được đăng tải tại vananhtooo.wordpress.com

Có thể bạn quan tâm:

Xem thêm các việc làm Developer hấp dẫn tại TopDev