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átinputevent 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 listenkeydown. - 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,labelhoặcindex; 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ưngclear()đọ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 — đừngwaitForTimeout. - 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.allchuẩn hơn —noWaitAfterchỉ 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ồiexpect(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.
