NỘI DUNG BÀI HỌC

☑️ Dùng setChecked() cho checkbox/radio (role=checkbox) và click() cho element "giả".

⬇️ Phân biệt selectOption() (cho ) và click() (cho custom dropdowns).

⚠️ Xử lý alert, confirm của trình duyệt bằng page.on('dialog') (lắng nghe trước).

🖥️ Tương tác với HTML Modals (React/AntD) bằng locator (ví dụ: getByRole('dialog')).

🔄 Dùng page.once để xử lý nhiều dialogs (OK/Cancel) trong cùng một test.



✅ Phần 1: Checkbox và Radio Button

 

Playwright có các phương thức "thông minh" ổn định hơn click(). Vấn đề của click() là nó lật trạng thái (toggle), nên khi trạng thái ban đầu không chắc chắn thì test rất dễ flaky.

Vì vậy hãy ưu tiên các phương thức idempotent (đảm bảo trạng thái cuối cùng, chạy nhiều lần vẫn ra một kết quả):

 

  • locator.check() - đảm bảo phần tử được chọn.
  • locator.uncheck() - đảm bảo phần tử bị bỏ chọn.
  • locator.setChecked(boolean) - linh hoạt nhất, nên dùng khi trạng thái lấy từ data.

 

const shouldBeChecked = true; // Giá trị lấy từ file data

// setChecked nhận cả true và false với checkbox
await page.getByLabel("Đồng ý").setChecked(shouldBeChecked);

 

🔹 1. Radio Button khác Checkbox ở điểm nào?

 

Với radio, check() hoặc setChecked(true) hoạt động bình thường, nhưng setChecked(false) sẽ báo lỗi. Lý do là người dùng không thể tự bỏ chọn một radio, chỉ có thể chọn một radio khác trong cùng nhóm.

 

// Chọn tùy chọn "Medium"
await page.getByLabel("Medium").check();

// Kiểm tra "Medium" đã được chọn
await expect(page.getByLabel("Medium")).toBeChecked();

// Xác nhận "Low" không được chọn
await expect(page.getByLabel("Low")).not.toBeChecked();

 

🔹 2. Khi gặp checkbox "giả" không đúng chuẩn

 

Các phương thức thông minh chỉ chạy trên phần tử có "trạng thái được chọn" thật: input[type="checkbox"]input[type="radio"], hoặc phần tử custom có role="checkbox" đúng chuẩn ARIA.

Với "checkbox giả" chỉ là một div không có role ARIA, setChecked() sẽ báo lỗi Element is not a checkbox or radio button. Lúc này phải quay về click() và tự kiểm tra thuộc tính.

 

<div class="my-custom-checkbox" data-checked="false"></div>

 

const fakeCheckbox = page.locator(".my-custom-checkbox");

// 1. Bắt buộc dùng click() vì không phải checkbox thật
await fakeCheckbox.click();

// 2. Tự kiểm tra trạng thái qua thuộc tính data-*
await expect(fakeCheckbox).toHaveAttribute("data-checked", "true");

Thứ tự ưu tiên tìm phần tử vẫn là: getByLabel → getByRole('checkbox'|'radio') → getByTestId → CSS/XPath, và luôn kiểm tra bằng toBeChecked().

 

📥 Phần 2: Dropdown (Select gốc và Custom)

 

Có hai loại dropdown hoàn toàn khác nhau, cách xử lý cũng khác nhau. Nhận diện đúng loại là bước quan trọng nhất.

 

🔹 1. Dropdown HTML gốc với thẻ <select>

 

Nhận biết qua thẻ <select> và <option>. Loại này không cần click(), chỉ cần dùng selectOption().

 

const colorSelect = page.locator("#select-color");

// Cách 1: Chọn bằng text hiển thị (dễ đọc, nên dùng)
await colorSelect.selectOption("Màu Xanh");

// Cách 2: Chọn bằng value (ổn định nhất vì value ít đổi)
await colorSelect.selectOption({ value: "red" });

// Cách 3: Chọn bằng index (không khuyến khích vì dễ gãy)
await colorSelect.selectOption({ index: 2 });

// Với <select multiple>: truyền một mảng
await colorSelect.selectOption(["Màu Đỏ", "Màu Xanh Dương"]);

 

🔹 2. Custom Dropdown (React, AntD, react-select)

 

Loại này được dựng bằng div/span/input cộng JavaScript, không có thẻ <select>. Bắt buộc phải click() để mở rồi mới chọn.

 

// Chiến lược 1: Click để mở rồi chọn (mô phỏng người dùng)
const countrySelect = page.locator(".ant-select-selector");
await countrySelect.click(); // Mở dropdown
await page.getByRole("option", { name: "Vietnam" }).click(); // Chọn option

// Chiến lược 2: Gõ để lọc rồi nhấn Enter (nếu dropdown có tìm kiếm)
const countryInput = page.locator("#country-input");
await countryInput.fill("Vietnam");
await countryInput.press("Enter");

 

Khi dropdown có infinite scroll hoặc virtualization, option cần tìm có thể chưa render. Lúc đó cuộn dần cho tới khi thấy rồi mới click.

 

await page.locator(".ant-select-selector").click();

const targetOption = page.getByRole("option", { name: "Vietnam" });
const dropdownMenu = page.locator(".ant-select-dropdown");

// Cuộn tối đa 10 lần, dừng ngay khi option đã hiển thị
for (let i = 0; i < 10; i++) {
  if (await targetOption.isVisible()) break;
  await dropdownMenu.dispatchEvent("wheel", { deltaY: 500 });
  await page.waitForTimeout(200);
}

await targetOption.click();

 

🔔 Phần 3: Browser Dialog (alert, confirm, prompt)

 

Dialog trình duyệt (alertconfirmprompt) không phải HTML, không tìm bằng locator được và nó chặn cả trang. Phải dùng page.on('dialog', ...) với quy tắc vàng: lắng nghe trước, hành động sau.

 

test("Xử lý Alert", async ({ page }) => {
  // 1. Lắng nghe TRƯỚC: cài trình xử lý dialog
  page.on("dialog", async (dialog) => {
    console.log("Loại:", dialog.type());
    console.log("Nội dung:", dialog.message());
    await dialog.accept(); // alert chỉ có thể accept()
  });

  // 2. Hành động SAU: click nút gây ra alert
  await page.getByRole("button", { name: "Hiện Alert" }).click();
  await expect(page.locator("#alert-result")).toHaveText("Đã nhấn OK");
});

 

confirm cho phép accept() hoặc dismiss()prompt cho phép accept('text') để điền chữ hoặc dismiss().

 

// confirm: nhấn Hủy
page.on("dialog", async (dialog) => {
  await dialog.dismiss(); // Bấm "Hủy"
});
await page.getByRole("button", { name: "Hiện Confirm" }).click();

// prompt: nhấn OK kèm nội dung nhập
page.on("dialog", async (dialog) => {
  await dialog.accept("Tên của tôi"); // Điền text rồi bấm OK
});
await page.getByRole("button", { name: "Hiện Prompt" }).click();

 

💡 Mẹo: Nếu một test cần xử lý nhiều dialog khác nhau (vừa OK vừa Hủy), hãy dùng page.once('dialog', ...) để mỗi handler chỉ lắng nghe một lần cho một hành động.

 

🪟 Phần 4: HTML Modal xử lý như phần tử thường

 

HTML Modal chỉ là một div được style thành pop-up, nằm trong DOM. Tuyệt đối không dùng page.on('dialog') cho loại này. Thay vào đó xử lý như phần tử HTML bình thường bằng locator.

Thuật toán: mở modal → chờ visible → tương tác bên trong → đóng → chờ biến mất.

 

test("Xử lý HTML Modal", async ({ page }) => {
  // 1. Click để mở
  await page.getByRole("button", { name: "Mở Modal" }).click();

  // 2. Tìm và chờ modal xuất hiện
  const modal = page.getByRole("dialog");
  await expect(modal).toBeVisible();

  // 3. Tương tác BÊN TRONG modal
  await expect(modal).toContainText("Đây là nội dung modal");
  await modal.locator("#username-in-modal").fill("Tên đăng nhập");

  // 4. Đóng modal
  await modal.getByRole("button", { name: "Đồng ý" }).click();

  // 5. Chờ modal biến mất
  await expect(modal).not.toBeVisible();
});

 

🔹 Ghi nhớ nhanh cho Tester

 

  • Ưu tiên setChecked()/check()/uncheck() thay cho click() với checkbox và radio thật.
  • Radio không bỏ chọn được bằng setChecked(false), hãy chọn radio khác trong nhóm.
  • Checkbox "giả" không đúng ARIA thì dùng click() và tự kiểm tra thuộc tính data-*.
  • Thẻ <select> dùng selectOption(); custom dropdown phải click() mở rồi chọn.
  • Browser dialog: lắng nghe trước bằng page.on('dialog'), hành động sau.
  • HTML Modal: dùng locator như phần tử thường, không dùng page.on('dialog').

 

✅ Kết luận: Chìa khóa của bài này là nhận diện đúng bản chất phần tử. Checkbox thật hay giả, select gốc hay custom, browser dialog hay HTML modal đều có cách xử lý riêng. Chọn đúng công cụ ngay từ đầu sẽ giúp test ổn định và dễ đọc hơn nhiều.

Teacher

Teacher

Nguyên Hoàng

Automation Engineer

With 7+ years of hands-on experience across multiple languages and frameworks. I'm here to share knowledge, helping you turn complex processes into simple and effective solutions.

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