Waits
- Selenium Implicit Waits
- Selenium Explicit Waits
- Selenium Fluent Waits
- Selenium Implicit Waits and Explicit Waits together
- Playwright Waits
Waits bản chất là một tính năng hỗ trợ timing, hiểu nôm na là “đợi”. Trong Browser Automation, chúng ta sẽ sử dụng Waits để đợi cho đến khi một điều kiện nào đó được thoả mãn. Lý do tại sao lại cần waits đó là để tính đến khả năng của đường truyền mạng hoặc tốc độ xử lý của trình duyệt, một trường hợp hay gặp chính là:
Cần xác định xem một element đã hiển thị hay chưa, nhưng do đường truyền mà element đó không hiển thị ngay lập tức, nếu chúng ta không sử dụng waits mà thực hiện kiểm tra ngay lập tức thì sẽ luôn báo lỗi
Có hai hướng Waits hiện nay tuỳ theo kiểu công nghệ mà các framework sử dụng:
- Framework như Selenium sử dụng Web Driver để tương tác với trình duyệt, nó sẽ có một số loại waits như:
- Implicit Waits
- Explicit Waits
- Fluent Waits
- Framework như Puppeteer sử dụng API của trình duyệt (Chrome Dev Tool đối với trình duyệt sử dụng nhân Chromium), nó sẽ cung cấp một số loại waits như:
- waitForSelector
- waitForXPath
- waitForFunction
- Framework như Playwright thì hoàn toàn tự động hóa việc waits, không cần phải quan tâm đến việc waits - sử dụng autowaits
Bài viết này thì mình sẽ nói về waits của Selenium và Playwright
Selenium Implicit Waits
Implicit Waits ở trong Selenium là một loại waits thông qua tương tác với WebDriver, nó sẽ đặt cho session của WebDriver một thời gian chờ trước khi ném ra lỗi NoSuchElementException. Bình thường nếu không đặt implicit waits, khi chúng ta tương tác với một element bằng selector, nếu selector này không tìm thấy element nào thì lỗi trên sẽ được trả ra ngay lập tức.
Implicit Waits cho phép một khoảng thời gian để trang web load hoàn toàn, hoặc cho các code javascript chạy xong, trước khi chúng ta thực hiện tương tác với element.
Trong Selenium, để sử dụng Implicit Waits, chúng ta sẽ sử dụng driver.implicitly_wait(time), với time là thời gian chờ, đơn vị là giây.
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10) # 10 seconds
Trong Robot Framework, library SeleniumLibrary cung cấp keyword Set Browser Implicit Wait để sử dụng Implicit Waits
*** Settings ***
Library SeleniumLibrary
*** Test Cases ***
Example
Set Browser Implicit Wait 10
Open Browser https://google.com chrome
Ngoài ra Robot Framework cũng cung cấp từ khoá mở rộng Set Selenium Implicit Wait để sử dụng Implicit Waits, về cơ bản là có bao nhiêu trình duyệt đang mở thì sẽ được áp dụng Implicit Waits cho tất cả, còn Set Browser Implicit Wait thì chỉ áp dụng cho trình duyệt đang được tập trung
Ngoài ra, nếu chỉ cần quan tâm đến chuyện page load xong thì có thể sử dụng driver.set_page_load_timeout(time), nó sẽ đặt thời gian chờ cho page load xong, nếu quá thời gian chờ mà page chưa load xong thì sẽ ném ra lỗi TimeoutException
Selenium Explicit Waits
Explicit Waits thực chất là một loại waits mà chúng ta sẽ đặt cho một element cụ thể, nó sẽ chờ cho đến khi element đó thoả mãn một điều kiện nhất định. Explicit Waits ám chỉ đến cách chúng ta viết code và handle các hàm assert chứ nó không phải là một function trọn vẹn như Implicit Waits.
Phương pháp sử dụng Explicit Waits trong Selenium là dựa vào hàm wait_until của WebDriverWait và expected_conditions của selenium.webdriver.support.ui để xác định điều kiện cụ thể.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://example.com")
# Create an instance of WebDriverWait with a timeout of 10 seconds
wait = WebDriverWait(driver, 10)
# Wait until the element is visible
element = wait.until(EC.visibility_of_element_located((By.ID, "elementId")))
# Perform actions on the element
element.click()
# Close the browser
driver.quit()
Trong Robot Framework, library SeleniumLibrary cung cấp các keyword Wait Until, về cơ bản cũng chỉ gói lại function wait_until của WebDriverWait và expected_conditions của selenium.webdriver.support.ui
*** Settings ***
Library SeleniumLibrary
*** Test Cases ***
Example Test Case
Open Browser https://example.com chrome
Wait Until Element Is Visible id=elementId 10 seconds
Click Element id=elementId
Close Browser
Nôm na tóm lại, Explicit Waits là việc chúng ta đặt một điều kiện cụ thể cho một element, và chờ cho đến khi điều kiện đó thoả mãn, nếu trong thời gian chờ mà điều kiện không thoả mãn, chúng ta đánh fail. Và Explicit Wait có thể hiểu là nằm ở phía IDE, chứ không phải là một tính năng cụ thể của Web Driver.
Selenium Fluent Waits
Fluent Waits là một loại wait đi ra từ Explicit Waits nhưng với nhiều tuỳ chỉnh thông số: polling interval, timeout , ignore exceptions. Fluent Waits cho phép chúng ta tùy chỉnh thời gian chờ, thời gian polling, loại exception bỏ qua.
Trong Selenium, để sử dụng Fluent Waits, chúng ta sẽ sử dụng WebDriverWait và expected_conditions như trong Explicit Waits, nhưng thêm một số tuỳ chỉnh như poll_frequency, ignored_exceptions
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException
import time
driver = webdriver.Chrome()
driver.get("https://example.com")
# Define a custom wait function
def wait_for_element(driver):
element = driver.find_element(By.ID, "elementId")
if element.is_displayed():
return element
else:
return False
# Create an instance of WebDriverWait with a timeout of 10 seconds and polling every 2 seconds
wait = WebDriverWait(driver, 10, poll_frequency=2, ignored_exceptions=[NoSuchElementException])
# Wait until the element is visible
element = wait.until(wait_for_element)
# Perform actions on the element
element.click()
# Close the browser
driver.quit()
Thực tế mà nói thì cách ứng dụng Fluent Waits trong Selenium Python là kiểu mì ăn liền, còn gốc gác bên java thì phức tạp hơn
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import java.time.Duration;
import java.util.NoSuchElementException;
public class FluentWaitExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
// Create an instance of FluentWait with a timeout of 10 seconds and polling every 2 seconds
FluentWait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofSeconds(2))
.ignoring(NoSuchElementException.class);
// Wait until the element is visible
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("elementId")));
// Perform actions on the element
element.click();
// Close the browser
driver.quit();
}
}
Selenium Implicit Waits and Explicit Waits together
Bản chất Implicit Waits là tính năng thuộc Web Driver, còn Explicit Waits là thuộc về cách code - tức là IDE, vốn không liên quan gì đến nhau. Vì thế, hành vi của bài test khi thực hiện cùng lúc cả hai loại waits này sẽ rơi vào vùng không xác định - tức là nhà phát triển Selenium không hề đặt ra một quy luật cụ thể mà thời gian chờ kết hợp diễn ra đơn thuần do logic của code, tuỳ thuộc vào cách các function liên quan được viết mà nó có thể thay đổi tuỳ theo phiên bản của Selenium.
Hiện tại, với Robot Framework, việc sử dụng cả hai waits sẽ diễn ra như sau:
- Explicit Waits sẽ bọc lấy Implicit Waits
- Trong khoảng thời gian khả dụng của explicit waits, implicit waits sẽ được reset mỗi khi hết hạn
Ví dụ, với một test case trong Robot Framework:
*** Settings ***
Library SeleniumLibrary
*** Test Cases ***
Example Test Case
Set Browser Implicit Wait 8
Open Browser https://example.com chrome
Wait Until Element Is Visible id=elementId 10 seconds
Click Element id=elementId
Close Browser
Điều xảy ra sẽ là:
- Ở 0 giây, implicit waits được set là 8 giây, explicit waits được set là 10 giây
- Ở 8 giây, implicit waits hết hạn và đúng ra sẽ throw
NoSuchElementExceptionnhưng vì explicit waits còn 2 giây nên keywordWait Until Element Is Visiblevẫn chưa fail, implicit waits reset về 0 giây - Ở giây thứ 10, explicit waits hết hạn, nhưng chưa có fail do bước fail do element không tồn tại vẫn đang được chờ bởi implicit waits
- Ở giây thứ 16 (8 + 8), implicit waits hết hạn và throw
NoSuchElementException, bây giờ Explicit waits đã có đủ điều kiện để fail nên cũng fail luôn
Tổng thời gian là 16 giây + thêm vài giây delay và nhảy polling ở giữa.
Tóm lại, không nên sử dụng cả hai loại waits cùng lúc, lý do là vì trong tình huống ở trên, đúng ra test case nên fail trong vòng 10 theo ý tưởng của người code, nhưng do hành vi bất thường của Selenium nên test case fail sau 16 giây, nó sẽ gây ảnh hưởng đến cái nhìn tổng thể về sản phẩm và gây ra kết quả dường như không đáng tin.
Playwright Waits
Playwright là một framework mới ra đời, nó tự động hóa việc waits, không cần phải quan tâm đến việc waits, nó sẽ tự động chờ cho đến khi element được tìm thấy, hoặc một điều kiện nào đó được thoả mãn, ví dụ:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// Wait for the element to be visible
await page.waitForSelector('#elementId');
// Perform actions on the element
await page.click('#elementId');
await browser.close();
})();
Nó được thể hiện ở các function như waitForSelector, waitForXPath, waitForFunction, waitForLoadState, waitForNavigation, waitForRequest, waitForResponse, waitForEvent, waitForTimeout, waitForURL, v.v.. mây mây. Đánh giá sơ bộ của mình là dùng playwright rất sướng, nó tương tác với trình duyệt thông qua CDP nên tốc độ và thời gian waits cũng rất chính xác, đồng thời tránh được những lỗi không mong muốn khi sử dụng Selenium.