Xử lý chờ trong Selenium: Chiến lược tối ưu cho kiểm thử tự động

Trong kiểm thử tự động với Selenium, mã thường thực thi nhanh hơn trình duyệt kịp render nội dung. Để xử lý các trường hợp này mà không gây ra lỗi sai, chúng ta có ba cơ chế chờ chính.

1. Chờ ngầm định (Implicit Wait)

Cơ chế này hoạt động ở phạm vi toàn cục. Khi được thiết lập, WebDriver sẽ đợi một khoảng thời gian nhất định khi tìm kiếm phần tử, nếu chưa tìm thấy thì tiếp tục thử cho tới khi hết thời gian quy định.

Trường hợp sử dụng:

  • Khi tốc độ tải trang không ổn định, phần tử có thể xuất hiện muộn.
  • Phù hợp khi không cần kiểm soát thời gian chờ cho từng phần tử cụ thể.

from selenium import webdriver

# Khởi tạo trình duyệt
driver = webdriver.Chrome()

# Thiết lập chờ ngầm định 10 giây
driver.implicitly_wait(10)

# Mở trang
driver.get("https://example.com")

# Tìm phần tử, nếu chưa có thì sẽ đợi tối đa 10 giây
element = driver.find_element("id", "someElement")

# Đóng trình duyệt
driver.quit()

Lưu ý:

  • Chỉ cần thiết lập một lần cho toàn bộ vòng đời của WebDriver.
  • Áp dụng cho mọi lệnh find_element.
  • Không thể tùy chỉnh thời gian chờ riêng cho từng phần tử.

2. Chờ tường minh (Explicit Wait)

Cơ chế này chỉ tác động lên một phần tử hoặc một điều kiện cụ thể. Trong khoảng thời gian chờ, nó liên tục kiểm tra điều kiện cho đến khi thỏa mãn.

Trường hợp sử dụng:

  • Chỉ muốn chờ một phần tử cụ thể, không ảnh hưởng đến các phần tử khác.
  • Điều kiện chờ phức tạp: phần tử hiển thị, có thể click, hoặc văn bản đã thay đổi.

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

# Khởi tạo trình duyệt
driver = webdriver.Chrome()
driver.get("https://example.com")

# Chờ tối đa 10 giây cho đến khi phần tử hiển thị
element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "someElement"))
)

element.click()
driver.quit()

3. Chờ linh hoạt (Fluent Wait) & Chờ cứng (time.sleep)

Chờ linh hoạt (Fluent Wait)

Cho phép tùy chỉnh tần suất kiểm tra và bỏ qua các ngoại lệ không mong muốn. Phù hợp với các trường hợp tải không ổn định, cần kiểm tra nhiều lần.


from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

# Thiết lập chờ linh hoạt: tối đa 10 giây, mỗi 0.5 giây kiểm tra một lần
wait = WebDriverWait(driver, 10, poll_frequency=0.5, ignored_exceptions=[Exception])

element = wait.until(
    EC.presence_of_element_located((By.ID, "someElement"))
)

Chờ cứng (time.sleep) - Không khuyến nghị

Dùng time.sleep(5) để dừng chương trình bất kể phần tử đã xuất hiện hay chưa. Chỉ nên dùng trong gỡ lỗi hoặc khi không còn giải pháp khác.


import time
time.sleep(5)  # Chờ 5 giây dù phần tử đã có hay chưa

Các điều kiện chờ phổ biến (Expected Conditions)

Thư viện expected_conditions cung cấp nhiều điều kiện kiểm tra. Dưới đây là các điều kiện thông dụng:

presence_of_element_located - Kiểm tra sự tồn tại

Chờ cho đến khi phần tử có mặt trong DOM (dù có thể ẩn).

wait.until(EC.presence_of_element_located((By.ID, "myId")))

visibility_of_element_located - Kiểm tra khả năng hiển thị

Chờ cho đến khi phần tử vừa tồn tại trong DOM vừa hiển thị (không ẩn).

wait.until(EC.visibility_of_element_located((By.ID, "myId")))

element_to_be_clickable - Kiểm tra khả năng tương tác

Chờ cho đến khi phần tử hiển thị và có thể click.

wait.until(EC.element_to_be_clickable((By.ID, "myButton"))).click()

invisibility_of_element_located - Kiểm tra sự biến mất

Chờ cho đến khi phần tử không còn xuất hiện hoặc bị ẩn.

wait.until(EC.invisibility_of_element_located((By.ID, "loadingSpinner")))

text_to_be_present_in_element - Kiểm tra văn bản

Chờ cho đến khi phần tử chứa văn bản mong muốn.

wait.until(EC.text_to_be_present_in_element((By.ID, "status"), "Hoàn thành"))

presence_of_all_elements_located - Kiểm tra nhiều phần tử

Chờ cho đến khi tất cả các phần tử phù hợp xuất hiện trong DOM.

elements = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "item")))

new_window_is_opened - Chờ cửa sổ mới

Chờ cho đến khi một cửa sổ mới được mở.

wait.until(EC.new_window_is_opened)
driver.switch_to.window(driver.window_handles[-1])

alert_is_present - Chờ hộp thoại Alert

Chờ cho đến khi hộp thoại alert xuất hiện.

alert = wait.until(EC.alert_is_present())
alert.accept()

Ví dụ kết hợp nhiều điều kiện


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")

wait = WebDriverWait(driver, 10)

# Bước 1: Chờ nút có thể click
button = wait.until(EC.element_to_be_clickable((By.ID, "confirmButton")))

# Bước 2: Chờ văn bản thay đổi
wait.until(EC.text_to_be_present_in_element((By.ID, "statusText"), "Hoàn thành"))

# Bước 3: Click
button.click()

driver.quit()

Kinh nghiệm thực tế: Sử dụng WebDriverWait + expected_conditions là cách tối ưu. Ưu tiên element_to_be_clickable thay vì presence_of_element_located để tránh lỗi khi tương tác. Có thể kết hợp nhiều điều kiện chờ khác nhau để kiểm soát chính xác luồng kiểm thử.

Thẻ: selenium automation-testing webdriverwaits explicit-wait implicit-wait

Đăng vào ngày 26 tháng 6 lúc 01:48