Wiki

← Tất cả bài wiki

Tương tác phần tử cơ bản (Click, Fill, Press, Check, Select...)

automationplaywright

Bộ API tương tác cơ bản của Locator: click, dblclick, fill, press, check/uncheck, selectOption, hover, clear, type. Tất cả đều đi qua actionability checks tự động (visible, stable, enabled, nhận event) nên viết xong là dùng được — nhưng cần hiểu khác biệt fill vs pressSequentially, click vs dispatchEvent, và các option force/noWaitAfter để không lạm dụng.

Khái niệm & Bản chất

  • Actionability checks trước mọi action: trước khi click, Playwright chờ element: attached vào DOM → visible → stable (không di chuyển/animation) → enabled → receives events (không bị overlay che). Fail điều kiện nào thì retry tới timeout.
  • fill vs gõ phím: fill() set value + phát input event 1 lần — nhanh, chuẩn cho form. pressSequentially() gõ từng ký tự như người thật — cần khi field có mask/auto-suggest listen keydown.
  • check/uncheck/setChecked: cho checkbox/radio — setChecked(true) idempotent (click nếu chưa đúng trạng thái, không toggle mù).
  • selectOption cho <select> native: chọn theo value, label hoặc index; hỗ trợ multi-select bằng mảng. Dropdown custom (div-based) KHÔNG dùng được — phải click từng item.
  • Trial run của click: click({ trial: true }) chạy actionability checks nhưng không thực hiện click — dùng kiểm tra element có clickable không.
  • Mọi action trả Promise: luôn await; quên await = action chạy lơ lửng, test pass ảo hoặc race với step sau.

Cách hoạt động & API chính

  • click(options): button (left/right/middle), clickCount, delay (giữa mousedown/up), position {x,y}, modifiers (Shift/Ctrl...), force, trial, noWaitAfter, timeout. dblclick() là double click — test edit inline, chọn text block.
  • fill(value): input/textarea/contenteditable; tự focus + clear cũ + set mới + phát event. clear() (v1.44+) = fill('') đọc rõ nghĩa hơn.
  • press(key): phím đơn trên element đang focus ('Enter', 'Tab', 'Escape', 'ArrowDown', 'Control+A'); pressSequentially(text, { delay }) gõ chuỗi từng phím.
  • check()/uncheck()/setChecked(bool): checkbox & radio; toggle() KHÔNG nên dùng vì phụ thuộc trạng thái đầu.
  • selectOption(value | {value} | {label} | {index} | mảng): chỉ cho <select> thật.
  • hover(): di chuột qua element (mở menu, tooltip); tự scroll vào view; dùng dispatchEvent('mouseover') chỉ khi hover thật không trigger được (hiếm).

Ví dụ & Cú pháp thực tế

  • Form đăng ký đầy đủ: ``ts import { test, expect } from '@playwright/test'; test('điền form đăng ký', async ({ page }) => { await page.goto('/register'); await page.getByLabel('Họ tên').fill('Nguyễn Văn A'); await page.getByLabel('Email').fill('a@hoctest.com'); // select native await page.getByLabel('Tỉnh thành').selectOption({ label: 'Hà Nội' }); // checkbox theo trạng thái mong muốn — không toggle mù await page.getByRole('checkbox', { name: 'Đồng ý điều khoản' }).setChecked(true); await page.getByRole('button', { name: 'Đăng ký' }).click(); await expect(page.getByText('Đăng ký thành công')).toBeVisible(); }); ``
  • Bàn phím & nhập có mask: ``ts // Ô OTP/ngày tháng có mask — fill không phát keydown từng ký tự await page.getByPlaceholder('MM/YY').pressSequentially('1226', { delay: 50 }); // Phím tắt & điều hướng await page.getByRole('textbox').press('Control+A'); await page.getByRole('textbox').press('Backspace'); await page.getByRole('combobox').press('ArrowDown'); await page.keyboard.press('Enter'); // page.keyboard cho phím không gắn element ``
  • Hover, double click, modifier: ``ts await page.getByRole('button', { name: 'Tài khoản' }).hover(); // mở dropdown await page.getByRole('menuitem', { name: 'Đăng xuất' }).click(); await page.getByText('cell-42').dblclick(); // edit inline // Ctrl+Click chọn nhiều item await page.locator('.file').first().click({ modifiers: ['Control'] }); ``
  • Clear & select multi: ``ts await page.getByLabel('Số điện thoại').clear(); // v1.44+, = fill('') await page.getByLabel('Tags').selectOption(['js', 'ts']); // multi-select ``

Best practices & Khi nào dùng

  • Mặc định: click + fill là đủ 90%: chỉ đụng press/keyboard khi test phím tắt, autocomplete, mask; đụng hover khi menu tooltip; đừng "giả lập người thật" quá mức — test cần ổn định hơn cần giống người.
  • setChecked > check/uncheck > toggle: nói rõ trạng thái cuối mong muốn → test idempotent, chạy lại vẫn đúng dù state ban đầu khác.
  • fill rỗng bằng clear(): fill('') hoạt động nhưng clear() đọc là hiểu ý đồ xoá ngay.
  • Chờ điều hướng đúng cách sau click submit: bọc await Promise.all([page.waitForURL('**/done'), btn.click()]) hoặc assert URL sau — đừng waitForTimeout.
  • Dropdown custom: đừng cố selectOption — click mở, rồi click option (thường getByRole('option', {name}) hoặc listbox pattern).

Gotchas, So sánh & Lưu ý

  • force: true là cờ cưỡng bức: bỏ qua receives-events/stability check — chỉ dùng khi hiểu rõ overlay/animation không phải bug; lạm dụng force = tự vứt bỏ lớp bảo vệ flake.
  • noWaitAfter bị phản đối: cũ hay dùng để không chờ navigation; nay waitForURL/Promise.all chuẩn hơn — noWaitAfter chỉ còn trong API vì backward compat.
  • fill không gây keydown/keyup: framework validate per-keystroke (React controlled + input mask) có thể lỗi → dấu hiệu: value có nhưng form báo invalid → chuyển pressSequentially.
  • click() vào element bị che: Playwright retry tới timeout rồi báo "element intercepts pointer events" — thường là overlay/spinner/cookie banner; fix bằng đóng overlay chứ KHÔNG phải force.
  • So sánh Selenium sendKeys: sendKeys = gõ từng phím luôn → chậm + hay lỗi mask; Playwright fill nhanh gọn, pressSequentially khi cần — linh hoạt hơn.
  • hover trên trang có :hover race: một số UI đóng menu khi mất hover — sau hover() mà click con bị timeout, thử hover() trên vùng cha rồi expect(menu).toBeVisible() trước khi click. Cũng nhớ: trong form native, press('Enter') trigger submit — test cả hai path nếu nghiệp vụ cho phép, vì người dùng thật hay gõ Enter.