NỘI DUNG BÀI HỌC
🧠 Nắm vững tư duy bất đồng bộ: Hiểu rõ vì sao phải "Wait" và sự tiến hóa của các cơ chế chờ trong ngành Automation.
🛠️ Thành thạo bộ thư viện Actions: Làm chủ các thao tác tương tác Form, chuột nâng cao và phím tắt bàn phím.
⚙️ Hiểu rõ Actionability Checks: Biết cách Playwright tự động kiểm tra trạng thái phần tử trước khi hành động.
🚧 Biết cách xử lý ngoại lệ: Vận dụng các lệnh Wait chủ động khi gặp các kịch bản Single Page Application (SPA) phức tạp.
⏳ I. Khái Niệm Về Wait (Chờ Đợi)
Vì sao cần Wait?
Tưởng tượng bạn gọi điện cho một người bạn và ngay lập tức hỏi "Bạn nghe rõ không?" mà không chờ họ nhấc máy. Script automation cũng vậy. Nó thực thi lệnh nhanh hơn rất nhiều so với tốc độ trình duyệt tải trang, render các phần tử JavaScript, hay thực hiện một API call.
➡️ Wait chính là cơ chế giúp script đồng bộ hóa, "chờ" cho ứng dụng web sẵn sàng trước khi thực hiện hành động tiếp theo, tránh các lỗi "Element not found" hay "Element not interactable".
1. Ba loại Wait chính trong Automation truyền thống (như Selenium)
Đây là 3 khái niệm nền tảng mà bạn cần hiểu để thấy được sự đột phá của Playwright.
a. Implicit Wait (Chờ đợi Ngầm định)
-
Khái niệm: Là thiết lập cấu hình toàn cục (Global setting). Nó ra lệnh: "Nếu không tìm thấy Element, hãy thử lại liên tục cho đến khi hết X giây rồi mới báo lỗi."
-
Cách hoạt động: Bạn chỉ cần cài đặt một lần duy nhất ở đầu script.
# Ví dụ trong Selenium driver.implicitly_wait(10) # Thiết lập chờ ngầm định là 10 giây # Từ đây trở đi, mọi lệnh find_element đều sẽ tự động chờ tối đa 10s driver.find_element(By.ID, "username") driver.find_element(By.ID, "password") -
Tình huống sử dụng: Thường được dùng trong các dự án nhỏ, đơn giản để tiết kiệm việc viết code wait lặp đi lặp lại. Tuy nhiên, đây được coi là một thói quen không tốt vì nó thiếu linh hoạt và có thể che giấu các vấn đề về hiệu năng của trang web.
b. Explicit Wait (Chờ đợi Tường minh)
-
Khái niệm: Đây là một lệnh chờ cụ thể và có điều kiện. Giống như bạn ra lệnh: "Hãy chờ tối đa X giây cho đến khi CỤ THỂ cái nút 'Login' này có thể được click".
-
Cách hoạt động: Bạn phải viết lệnh chờ cho từng tình huống cụ thể mà bạn muốn.
# Ví dụ trong Selenium from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait = WebDriverWait(driver, 10) # Tạo một đối tượng chờ tối đa 10s # Chỉ chờ cho element 'login-button' được phép click login_button = wait.until(EC.element_to_be_clickable((By.ID, "login-button"))) login_button.click() -
Tình huống sử dụng: Đây là phương pháp chuẩn và được khuyến khích nhất trong Selenium. Nó được dùng khi bạn cần chờ một element xuất hiện, biến mất, có thể click, hoặc có một thuộc tính nào đó thay đổi. Nó chính xác và đáng tin cậy
-
Hạn chế: Code cực kỳ dài dòng, lặp đi lặp lại.
c. Fluent Wait
-
Khái niệm: Đây là một phiên bản nâng cao của Explicit Wait, cho phép bạn tùy chỉnh sâu hơn, ví dụ như tần suất kiểm tra (polling time) và bỏ qua một số loại lỗi nhất định trong khi chờ.
-
Tình huống sử dụng: Rất hiếm khi cần đến. Chỉ dùng trong các kịch bản cực kỳ phức tạp, ví dụ như một element thỉnh thoảng xuất hiện rồi biến mất (flashing) và bạn muốn script bỏ qua các lỗi "không tìm thấy" tạm thời.
Trong các framework truyền thống như Selenium, việc quản lý Wait là một kỹ năng quan trọng.
2. Wait trong Playwright Python: Cuộc cách mạng "Auto-Waiting" 🎯
Đây là tính năng thay đổi cuộc chơi của Playwright. Bạn không cần phải lo lắng về việc thêm wait một cách thủ công trong hầu hết các trường hợp.
👉 Cơ chế: Mặc định, MỌI lệnh tương tác như .click(), .fill(), .check()... đều được tích hợp sẵn một loạt các bước kiểm tra (Actionability Checks). Playwright sẽ tự động chờ cho đến khi tất cả các điều kiện này được đáp ứng.
-
Các kiểm tra tự động bao gồm:
-
📎 Attached: Phần tử đã được gắn vào cây DOM.
-
👁️ Visible: Phần tử phải hiển thị trên màn hình.
-
🧘 Stable: Phần tử đứng yên, không bị dính hiệu ứng chuyển động (animation).
-
🟢 Enabled: Phần tử không bị khóa (
disabled). -
🖱️ Receiving Events: Phần tử không bị che khuất bởi Popup hay Loading overlay.
-
✅ Ví dụ thực tế:
from playwright.sync_api import sync_playwright, expect
def test_auto_wait_in_playwright(page):
# Giả sử trang này có 1 nút "Load Data" và sau 3 giây mới hiện ra bảng dữ liệu
page.goto("https://www.your-dynamic-page.com")
page.get_by_role("button", name="Load Data").click()
# BẠN KHÔNG CẦN VIẾT BẤT KỲ LỆNH WAIT NÀO Ở ĐÂY
# Playwright sẽ tự động chờ cho đến khi element '#data-table' xuất hiện và sẵn sàng
first_row = page.locator("#data-table tbody tr:first-child")
# expect cũng có cơ chế auto-waiting tích hợp!
expect(first_row).to_be_visible(timeout=5000) # Chờ tối đa 5 giây
3. So sánh trực tiếp Wait với Selenium
| Tình huống | Code Selenium (Cần Explicit Wait) | Code Playwright (Tự động) |
| Click một nút xuất hiện sau 2s | login_button = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "loginBtn"))) login_button.click() |
page.get_by_role("button", name="Login").click() |
4. Khi nào cần "Wait" tường minh trong Playwright?
Dù auto-waiting rất mạnh mẽ, bạn vẫn cần các lệnh wait tường minh cho các sự kiện không phải là tương tác trực tiếp với element.
🖱️ II. Thư viện Hành động (Actions) Toàn diện
Đây là bộ công cụ để bạn mô phỏng mọi hành vi mà người dùng có thể thực hiện.
1. Tương tác với Form (Form Interactions)
.fill() - Điền dữ liệu nhanh
-
Khái niệm: Lệnh này sẽ xóa sạch nội dung cũ trong
inputrồi mới điền nội dung mới. Đây là lựa chọn hàng đầu và nhanh nhất cho việc điền form. -
Ví dụ HTML:
<div class="form-group"> <label>Email</label> <input id="email-field" type="text" value="old-email@example.com"> </div> -
Ví dụ Automation:
email_input = page.locator("#email-field") email_input.fill("new-email@example.com") # Kết quả: value của input sẽ là "new-email@example.com"
.select_option() - Chọn từ Dropdown
-
Khái niệm: Chọn một tùy chọn từ thẻ
<select>. Cực kỳ linh hoạt, cho phép chọn theovalue(ổn định nhất),label(text người dùng thấy), hoặcindex. -
Ví dụ HTML:
<select id="country-selector"> <option value="">-- Select Country --</option> <option value="vn">Vietnam</option> <option value="us">United States</option> </select> -
Ví dụ Automation:
country_dropdown = page.locator("#country-selector") # Cách 1: Chọn theo value (khuyến khích) country_dropdown.select_option("vn") # Cách 2: Chọn theo label (text hiển thị) country_dropdown.select_option(label="United States")
.set_input_files() - Upload File
-
Khái niệm: Mô phỏng việc người dùng chọn một file để tải lên. Nó hoạt động ngay lập tức mà không cần mở hộp thoại file của hệ điều hành.
-
Ví dụ HTML:
<label>Choose your avatar:</label> <input type="file" id="avatar-uploader"> -
Ví dụ Automation:
# Giả sử bạn có file "my-avatar.png" trong thư mục project page.locator("#avatar-uploader").set_input_files("my-avatar.png")
.check() & .uncheck() - Tích và Bỏ tích
-
Khái niệm: Dùng để tích (
.check()) hoặc bỏ tích (.uncheck()) các ôcheckboxhoặcradio button. Các lệnh này an toàn, nếu checkbox đã được tích,.check()sẽ không làm gì cả. -
Ví dụ HTML:
<label><input type="checkbox" id="agree-terms"> Tôi đồng ý</label> <label><input type="checkbox" id="newsletter" checked> Đăng ký nhận tin</label> -
Ví dụ Automation:
# Tích vào ô điều khoản page.locator("#agree-terms").check() # Bỏ tích nhận tin page.locator("#newsletter").uncheck()
2. Tương tác Chuột Nâng cao (Advanced Mouse Interactions)
.hover() - Di chuột lên trên
-
Khái niệm: Dùng để kích hoạt các menu ẩn, tooltip, hoặc các hiệu ứng CSS chỉ xuất hiện khi người dùng di chuột lên một element.
-
Ví dụ HTML:
<div class="dropdown"> <button class="dropbtn">User Menu</button> <div class="dropdown-content" style="display: none;"> <a href="/profile">Profile</a> <a href="/logout">Logout</a> </div> </div> -
Ví dụ Automation:
# Di chuột vào menu để nó hiện ra page.locator(".dropdown").hover() # Bây giờ có thể click vào link "Logout" đã hiển thị page.locator("a[href='/logout']").click()
.dblclick() - Nhấp đúp chuột
-
Khái niệm: Dùng cho các chức năng yêu cầu double-click, ví dụ như mở một mục trong danh sách hoặc vào chế độ chỉnh sửa.
-
Ví dụ HTML:
<div id="item-123" class="list-item">Double-click to edit</div> -
Ví dụ Automation:
list_item = page.locator("#item-123") list_item.dblclick() # Sau đó có thể kiểm tra xem ô input edit có xuất hiện không
3. Tương tác Bàn phím (Keyboard Interactions)
.press() - Nhấn một phím
-
Khái niệm: Mô phỏng việc nhấn và thả một phím duy nhất trên bàn phím. Cực kỳ hữu ích để submit form, điều hướng, hoặc dùng phím tắt.
-
Ví dụ HTML:
<input id="search-box" placeholder="Search..."> -
Ví dụ Automation:
search_box = page.locator("#search-box") search_box.fill("Playwright automation") # Nhấn phím Enter để thực hiện tìm kiếm search_box.press("Enter") -
Các phím khác:
'Tab','Escape','ArrowDown','Control+A','Shift+Click'.
🧩 III. Bài Tập Thực Hành (Focus vào Hành Động)
Kịch bản: Tương tác nâng cao trên trang tài nguyên khóa học
Thao tác trên lớp:
-
Ví dụ: Dropdown
-
Arrange: Truy cập
https://the-internet.herokuapp.com/dropdown. -
Act & Assert:
-
Dùng
.select_option(label="Option 2"). -
Dùng
expect(page.locator("option:checked")).to_have_text("Option 2")để xác nhận lựa chọn thành công.
-
-
-
Ví dụ: Hovers
-
Arrange: Truy cập
https://the-internet.herokuapp.com/hovers. -
Act & Assert:
-
Dùng
.hover()để di chuột lên ảnh đại diện thứ ba (div.figure:nth-child(5)). -
Dùng
expect(page.get_by_text("name: user3")).to_be_visible()để xác nhận thông tin đã hiện ra.
-
-
-
Ví dụ: File Upload
-
Arrange: Truy cập
https://the-internet.herokuapp.com/upload. Tạo một file text rỗng tên làmy_test_file.txt. -
Act & Assert:
-
Dùng
.set_input_files()để chọn file đó. -
Click nút "Upload".
-
Dùng
expect(page.locator("#uploaded-files")).to_contain_text("my_test_file.txt")để xác nhận upload thành công.
-
-
