NỘI DUNG BÀI HỌC

Nắm vững sự khác biệt giữa các cơ chế "Wait" trong automation truyền thống và "Auto-Waiting" thông minh của Playwright.
Thành thạo kỹ năng phân tích DOM và viết Locators ổn định bằng CSS Selector và XPath.
Ưu tiên sử dụng các locator hiện đại và bền vững của Playwright (get_by_role, get_by_text, get_by_label).
Thực hành viết một kịch bản test hoàn chỉnh, áp dụng cả Wait và Locator để đảm bảo tính ổn định.
So sánh trực tiếp với Selenium để thấy rõ sức mạnh và sự tinh gọn mà Playwright mang lại.



🧠 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: Đây là một thiết lập toàn cục, giống như bạn ra lệnh: "Này script, từ giờ trở đi, mỗi khi mày tìm một element nào đó mà không thấy ngay, hãy kiên nhẫn chờ tối đa X giây trước khi 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ể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.


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

Loại Mô tả Cách hoạt động Hạn chế
Implicit Wait Chờ đợi ngầm định. Thiết lập một lần, áp dụng cho TẤT CẢ các lệnh tìm kiếm element. driver.implicitly_wait(10) → Nếu không tìm thấy element ngay lập tức, Selenium sẽ thử lại liên tục trong tối đa 10 giây trước khi báo lỗi. Không linh hoạt, làm chậm toàn bộ test suite. Là một anti-pattern (không nên dùng) trong automation hiện đại.
Explicit Wait Chờ đợi tường minh. Chờ một điều kiện cụ thể xảy ra trên một element cụ thể. WebDriverWait(driver, 10).until(EC.visibility_of_element_located(...)) → Chỉ chờ tối đa 10s cho ĐÚNG element này trở nên visible. Chính xác, đáng tin cậy. Đây là phương pháp chuẩn trong Selenium nhưng làm code dài và phức tạp hơn.
Fluent Wait Dạng nâng cao của Explicit Wait. Tương tự Explicit Wait nhưng cho phép tùy chỉnh tần suất kiểm tra (polling) và bỏ qua một số loại lỗi nhất định. Mạnh mẽ nhưng rất dài dòng và hiếm khi cần thiết.


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:

    • Element đã được gắn vào cây DOM.

    • Element đang hiển thị (visible).

    • Element ổn định (stable - không bị che bởi element khác, không có animation).

    • Element có thể nhận tương tác (enabled).

    • Element có thể chỉnh sửa (editable - đối với .fill()).

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. LOCATORS – CÁCH XÁC ĐỊNH PHẦN TỬ TRÊN TRANG


1️⃣ Khái niệm Locators

Locator là một chuỗi truy vấn hoạt động như một "địa chỉ" để Playwright tìm thấy một (hoặc nhiều) phần tử trên trang web. Việc chọn đúng locator quyết định 80% sự ổn định của test case.

2️⃣ Các loại Locator phổ biến (Truyền thống)

a. CSS Selector

  • Mô tả: Cú pháp mạnh mẽ để chọn element dựa trên ID, class, thuộc tính và mối quan hệ cha-con.

    Ký hiệu Ý nghĩa Ví dụ HTML Ví dụ Locator (trong Playwright) Diễn giải chi tiết
    # ID <input id="user-login"> page.locator("#user-login") Dấu # có nghĩa là "Tìm element có ID chính xác là 'user-login'". ID là duy nhất trên một trang, nên đây là cách tìm kiếm nhanh và đáng tin cậy nhất.
    . Class <button class="btn btn-primary"> page.locator(".btn-primary") Dấu . có nghĩa là "Tìm element có chứa class là 'btn-primary'". Một element có thể có nhiều class, và nhiều element có thể chung một class.
    [] Thuộc tính (Attribute) <input name="password"> page.locator("[name='password']") Dấu ngoặc vuông [] dùng để tìm theo bất kỳ thuộc tính nào. [name='password'] có nghĩa là "Tìm element có thuộc tính name với giá trị là 'password'".
    (không có) Tên thẻ (Tag Name) <h1>Welcome</h1> page.locator("h1") Viết thẳng tên thẻ có nghĩa là "Tìm tất cả các element có thẻ là h1".
    > Con trực tiếp <div> <p>Text</p> </div> page.locator("div > p") Dấu > có nghĩa là "Tìm thẻ p là con trực tiếp (nằm ngay bên trong) của thẻ div".
    (dấu cách) Con cháu <div> <span> <p>Text</p> </span> </div> page.locator("div p") Dấu cách có nghĩa là "Tìm thẻ p nằm bên trong (bất kể cấp nào) của thẻ div".

  • Ví dụ:

    • Theo ID (duy nhất): page.locator("#username")

    • Theo Class: page.locator(".btn-primary")

    • Theo thuộc tính: page.locator("input[name='password']")

    • Theo quan hệ cha-con: page.locator("div.form-group > input")

b. XPath

Hãy coi XPath như hệ thống định vị GPS, nó có thể đi theo những con đường phức tạp hơn.

  • Khái niệm: XPath cho phép bạn duyệt cây DOM theo cấu trúc của nó. Nó mạnh hơn CSS nhưng cú pháp cũng phức tạp hơn.

  • Ví dụ đơn giản:

    • Tìm theo text chính xác:
      🧪 HTML:

      <button>Đăng nhập</button>
      # "Tìm thẻ button có nội dung text chính xác là 'Đăng nhập'"
      page.locator("//button[text()='Đăng nhập']")

      Tìm theo một phần text:

      🧪 HTML:
      <h3>Chào mừng trở lại, Lan Hà!</h3>
      # "Tìm thẻ h3 có nội dung text chứa chuỗi 'Chào mừng'"
      page.locator("//h3[contains(text(), 'Chào mừng')]")
  •  


3️⃣ Các Locator hiện đại trong Playwright (Best Practices)

Playwright khuyến khích sử dụng các locator ngữ nghĩa, giúp test case của bạn dễ đọc như văn xuôibền vững hơn khi giao diện thay đổi.

Kim tự tháp ưu tiên:

  1. Role (Vai trò người dùng)

  2. Label / Text (Văn bản nhìn thấy)

  3. Test ID (Thuộc tính dành riêng cho test)

  4. CSS / XPath (Khi các cách trên thất bại)

 
Method Ý nghĩa Ví dụ Khi nào dùng tốt nhất?
get_by_role() Xác định phần tử theo vai trò người dùng (nút, link, checkbox...). Ưu tiên số 1. page.get_by_role("button", name="Login") Nút, link, checkbox, heading, radio button...
get_by_text() Tìm theo văn bản hiển thị trên màn hình. page.get_by_text("Forgot password?") Các đoạn text, tiêu đề, thông báo lỗi.
get_by_label() Tìm một ô input dựa vào thẻ <label> của nó. Rất hiệu quả cho form. page.get_by_label("Email Address") Các ô input, textarea, select trong form.
get_by_placeholder() Tìm một ô input dựa vào văn bản gợi ý (placeholder). page.get_by_placeholder("Enter your name") Các ô input trong form.
get_by_test_id() Tìm theo thuộc tính data-testid. Cần sự phối hợp của team dev. page.get_by_test_id("cart-icon-badge") Các element khó xác định, cần độ ổn định tuyệt đối.


4️⃣ Ví dụ tổng hợp

🧪 HTML:

<div class="form-group">
  <label for="email-input">Email Address</label>
  <input id="email-input" placeholder="Enter your email" data-testid="email-field" />
  <button class="btn-primary">Submit</button>
</div>


🧩 Playwright Python (Nhiều cách để chọn cùng 1 element):

def test_all_locators(page):
    page.goto("https://example.com")
    email_input = page.locator("#email-input") # Cách 1: CSS theo ID
    email_input = page.locator("[placeholder='Enter your email']") # Cách 2: CSS theo thuộc tính
    
    # Cách 3 (Tốt hơn): Dùng get_by_label
    email_input = page.get_by_label("Email Address")
    
    # Cách 4 (Tốt nhất nếu có): Dùng get_by_test_id
    email_input = page.get_by_test_id("email-field")
    email_input.fill("lanha.tester@example.com")
    
    # Click nút Submit
    page.get_by_role("button", name="Submit").click()

 

🧩 BÀI TẬP THỰC HÀNH


🧠 Bài 1: Đăng nhập thành công

  1. Truy cập trang https://www.saucedemo.com/

  2. Sử dụng page.get_by_placeholder("Username") để điền standard_user.

  3. Sử dụng page.get_by_placeholder("Password") để điền secret_sauce.

  4. Click nút Login bằng page.get_by_role("button", name="Login").

  5. Dùng expect để chờ và xác nhận tiêu đề "Products" xuất hiện: expect(page.get_by_text("Products")).to_be_visible().

  6. In ra số lượng sản phẩm có trên trang (gợi ý: locator là .inventory_item).


🧠 Bài 2: Xử lý đăng nhập thất bại

  1. Cũng tại trang trên, cố tình nhập sai password.

  2. Click nút Login.

  3. Sử dụng page.locator("[data-test='error']") kết hợp với expect().to_contain_text() để chờ và xác minh thông báo lỗi "Username and password do not match" xuất hiện.


🔍 TÓM TẮT KIẾN THỨC

Chủ đề Ghi nhớ cốt lõi Lời khuyên vàng
Wait Playwright có Auto-Waiting mạnh mẽ, bạn không cần thêm wait thủ công cho các hành động tương tác. Chỉ dùng wait tường minh (wait_for_*, expect) khi chờ các sự kiện (URL, response, load state). Tránh xa wait_for_timeout.
Locators Có 2 nhóm: Truyền thống (CSS, XPath) và Hiện đại (get_by_*). Ưu tiên tuyệt đối cho các locator hiện đại theo thứ tự: Role -> Label/Text -> Test ID. Chỉ dùng CSS/XPath khi thực sự cần thiết.

Teacher

Teacher

Hà Lan

QA Automation

With over 5 years of experience in web, API, and mobile test automation, built strong expertise in designing and maintaining automation frameworks across various domains and international projects. Committed to mentoring and knowledge sharing, I provide practical guidance and proven techniques to help aspiring testers develop their skills and succeed in the automation field.

Cộng đồng Automation Testing Việt Nam:

🌱 Telegram Automation Testing:   Cộng đồng Automation Testing
🌱 
Facebook Group Automation: Cộng đồng Automation Testing Việt Nam
🌱 
Facebook Fanpage: Cộng đồng Automation Testing Việt Nam - Selenium
🌱 Telegram
Manual Testing:   Cộng đồng Manual Testing
🌱 
Facebook Group Manual: Cộng đồng Manual Testing Việt Nam

Chia sẻ khóa học lên trang

Bạn có thể đăng khóa học của chính bạn lên trang Anh Tester để kiếm tiền

Danh sách bài học