- Tác giả

- Name
- Nguyễn Đức Xinh
- Ngày xuất bản
- Ngày xuất bản
Tổng Hợp Các Method Của Locator Trong Playwright - Hướng Dẫn Chi Tiết
Giới Thiệu
Locator là thành phần cốt lõi trong Playwright, cung cấp khả năng auto-waiting và retry tự động. Locator đại diện cho cách tìm element trên page tại bất kỳ thời điểm nào. Các method của Locator đóng vai trò quan trọng trong việc tương tác với trang web, cho phép bạn thực hiện mọi thao tác từ cơ bản đến phức tạp như click, điền form, kiểm tra trạng thái, và xử lý các tình huống đặc biệt. Hiểu và sử dụng thành thạo các method này là chìa khóa để viết test automation hiệu quả và ổn định.
1. Các Method Tương Tác Với Element
1.1. Click và Double Click
| Method | Mô Tả | Ví Dụ |
|---|---|---|
click() |
Click vào element | await page.getByRole('button').click() |
dblclick() |
Double-click element | await locator.dblclick() |
tap() |
Thao tác tap (cho thiết bị cảm ứng) | await locator.tap() |
Ví dụ click với options:
// Click với modifier key
await page.locator('canvas').click({
button: 'right',
modifiers: ['Shift'],
position: { x: 23, y: 32 }
});
1.2. Nhập Liệu (Input)
| Method | Mô Tả | Sử Dụng Khi |
|---|---|---|
fill() |
Điền giá trị vào input field | Nhập văn bản nhanh vào form |
type() (deprecated) |
Gõ từng ký tự | Không nên dùng, dùng pressSequentially() |
pressSequentially() |
Gõ từng ký tự (như người dùng thật) | Cần trigger keyboard events |
press() |
Nhấn một phím cụ thể | Nhấn Enter, Backspace, v.v. |
Ví dụ:
// Fill - Cách nhanh nhất
await page.getByRole('textbox').fill('example value');
// Press sequentially - Gõ từng ký tự
await locator.pressSequentially('Hello', { delay: 100 });
// Press - Nhấn phím đặc biệt
await page.getByRole('textbox').press('Backspace');
await locator.press('Control+A'); // Shortcut
1.3. Xóa và Clear
// Clear input field
await page.getByRole('textbox').clear();
// Blur - Remove focus
await locator.blur();
1.4. Hover và Focus
// Hover over element
await page.getByRole('link').hover();
// Focus vào element
await locator.focus();
// Scroll element vào view
await locator.scrollIntoViewIfNeeded();
2. Checkbox và Radio Button
| Method | Mô Tả | Return |
|---|---|---|
check() |
Đảm bảo checkbox/radio được checked | Promise<void> |
uncheck() |
Đảm bảo checkbox/radio không được checked | Promise<void> |
setChecked(checked) |
Set trạng thái checked (true/false) | Promise<void> |
isChecked() |
Kiểm tra xem có được checked không | Promise<boolean> |
Ví dụ:
// Check checkbox
await page.getByRole('checkbox').check();
// Uncheck
await page.getByRole('checkbox').uncheck();
// Set checked state
await locator.setChecked(true);
// Kiểm tra trạng thái
const checked = await page.getByRole('checkbox').isChecked();
3. Select Options và File Upload
3.1. Select Option
// Select single option bằng value
await locator.selectOption('blue');
// Select bằng label
await locator.selectOption({ label: 'Blue' });
// Select multiple options
await locator.selectOption(['red', 'green', 'blue']);
// Select bằng index
await locator.selectOption({ index: 0 });
3.2. File Upload
// Upload một file
await page.getByLabel('Upload file').setInputFiles(
path.join(__dirname, 'myfile.pdf')
);
// Upload nhiều files
await page.getByLabel('Upload files').setInputFiles([
path.join(__dirname, 'file1.txt'),
path.join(__dirname, 'file2.txt')
]);
// Upload từ buffer
await page.getByLabel('Upload file').setInputFiles({
name: 'file.txt',
mimeType: 'text/plain',
buffer: Buffer.from('this is test')
});
// Clear files
await page.getByLabel('Upload file').setInputFiles([]);
4. Lấy Thông Tin Từ Element
4.1. Text Content
| Method | Return | Ghi Chú |
|---|---|---|
textContent() |
Promise<string | null> |
Lấy node.textContent |
innerText() |
Promise<string> |
Lấy element.innerText |
innerHTML() |
Promise<string> |
Lấy element.innerHTML |
allTextContents() |
Promise<string[]> |
Lấy textContent của tất cả matching elements |
allInnerTexts() |
Promise<string[]> |
Lấy innerText của tất cả matching elements |
Ví dụ:
const text = await locator.textContent();
const inner = await locator.innerText();
const html = await locator.innerHTML();
// Lấy text của tất cả elements
const texts = await page.getByRole('link').allTextContents();
4.2. Input Value và Attributes
// Lấy value của input/textarea/select
const value = await page.getByRole('textbox').inputValue();
// Lấy attribute
const href = await locator.getAttribute('href');
const title = await locator.getAttribute('title');
// Lấy bounding box
const box = await locator.boundingBox();
// Returns: { x, y, width, height } hoặc null
5. Kiểm Tra Trạng Thái Element
5.1. Visibility và Display
| Method | Kiểm Tra | Return |
|---|---|---|
isVisible() |
Element có visible không | Promise<boolean> |
isHidden() |
Element có hidden không | Promise<boolean> |
isEnabled() |
Element có enabled không | Promise<boolean> |
isDisabled() |
Element có disabled không | Promise<boolean> |
isEditable() |
Element có editable không | Promise<boolean> |
Ví dụ:
const visible = await page.getByRole('button').isVisible();
const disabled = await page.getByRole('button').isDisabled();
const editable = await page.getByRole('textbox').isEditable();
// Lưu ý: isVisible() và isHidden() không wait
// Nên dùng expect() cho assertions
await expect(page.getByRole('button')).toBeVisible();
5.2. Count và Bounding Box
// Đếm số lượng matching elements
const count = await page.getByRole('listitem').count();
// Lấy bounding box coordinates
const box = await page.getByRole('button').boundingBox();
if (box) {
await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
}
6. Filter và Chọn Element
6.1. Filter Locators
const rows = page.locator('tr');
// Filter theo text
await rows
.filter({ hasText: 'text in column 1' })
.filter({ has: page.getByRole('button', { name: 'column 2 button' }) })
.screenshot();
// Filter theo điều kiện phủ định
await rows.filter({ hasNotText: 'excluded text' });
await rows.filter({ hasNot: page.locator('.hidden') });
// Filter theo visibility
await rows.filter({ visible: true });
6.2. Chọn Element Cụ Thể
| Method | Mô Tả | Ví Dụ |
|---|---|---|
first() |
Element đầu tiên | locator.first() |
last() |
Element cuối cùng | await page.getByRole('listitem').last() |
nth(index) |
Element thứ n (index từ 0) | await page.getByRole('listitem').nth(2) |
Ví dụ:
// Lấy element đầu tiên
const firstButton = await page.getByRole('button').first();
// Lấy element cuối
const lastItem = await page.getByRole('listitem').last();
// Lấy element thứ 3 (index = 2)
const thirdItem = await page.getByRole('listitem').nth(2);
7. Locator Nâng Cao
7.1. Kết Hợp Locators
// AND - Kết hợp 2 locators
const button = page.getByRole('button').and(page.getByTitle('Subscribe'));
// OR - Match một trong hai
const newEmail = page.getByRole('button', { name: 'New' });
const dialog = page.getByText('Confirm security settings');
await expect(newEmail.or(dialog).first()).toBeVisible();
7.2. Nested Locators
// Locator trong locator
const article = page.locator('article');
const content = article.locator('.content');
// Frame locator
const frameLocator = page.frameLocator('iframe');
await frameLocator.getByRole('button').click();
// Content frame (cho iframe)
const locator = page.locator('iframe[name="embedded"]');
const frameLocator = locator.contentFrame();
await frameLocator.getByRole('button').click();
8. Wait và Assertions
8.1. Wait For Element
// Wait for element state
await locator.waitFor({ state: 'visible' });
await locator.waitFor({ state: 'hidden' });
await locator.waitFor({ state: 'attached' });
await locator.waitFor({ state: 'detached' });
// Wait for element state (các state: visible, hidden, stable, enabled, disabled, editable)
await locator.waitForElementState('visible');
await locator.waitForElementState('enabled');
8.2. Wait For Selector
await page.setContent(`<div><span></span></div>`);
const div = await page.$('div');
const span = await div.waitForSelector('span', { state: 'attached' });
9. Advanced Operations
9.1. Drag and Drop
const source = page.locator('#source');
const target = page.locator('#target');
await source.dragTo(target);
// Với positions cụ thể
await source.dragTo(target, {
sourcePosition: { x: 34, y: 7 },
targetPosition: { x: 10, y: 20 }
});
9.2. Screenshot
// Screenshot element
await page.getByRole('link').screenshot();
// Screenshot với options
await page.getByRole('link').screenshot({
animations: 'disabled',
path: 'link.png',
mask: [page.locator('.sensitive-data')],
maskColor: '#FF0000'
});
9.3. Evaluate JavaScript
// Execute JS trên element
const result = await page.getByTestId('myId').evaluate((element, [x, y]) => {
return element.textContent + ' ' + x * y;
}, [7, 8]);
// Evaluate all matching elements
const moreThanTen = await locator.evaluateAll(
(divs, min) => divs.length > min,
10
);
// Evaluate và return JSHandle
const handle = await locator.evaluateHandle(element => element);
9.4. Dispatch Events
// Dispatch custom event
await locator.dispatchEvent('click');
// Với event init properties
await locator.dispatchEvent('dragstart', { dataTransfer });
10. Locator Selectors
10.1. Get By Methods
| Method | Mô Tả | Ví Dụ |
|---|---|---|
getByRole() |
Tìm theo ARIA role | page.getByRole('button', { name: 'Submit' }) |
getByText() |
Tìm theo text content | page.getByText('Hello') |
getByLabel() |
Tìm theo label text | page.getByLabel('Username') |
getByPlaceholder() |
Tìm theo placeholder | page.getByPlaceholder('name@example.com') |
getByAltText() |
Tìm theo alt text | page.getByAltText('Playwright logo') |
getByTitle() |
Tìm theo title attribute | page.getByTitle('Issues count') |
getByTestId() |
Tìm theo test id | page.getByTestId('directions') |
Ví dụ Get By Role:
// Basic role
await page.getByRole('button', { name: 'Submit' }).click();
// Với các options
await page.getByRole('heading', { name: 'Sign up' });
await page.getByRole('checkbox', { name: 'Subscribe' }).check();
await page.getByRole('button', { name: /submit/i }).click();
// Role với state
await page.getByRole('button', {
name: 'Save',
disabled: false,
pressed: true
});
11. Utility Methods
11.1. Các Method Hỗ Trợ
// Lấy page từ locator
const page = locator.page();
// Highlight element (debugging)
await locator.highlight();
// Get all matching locators
const allButtons = await page.getByRole('button').all();
for (const button of allButtons) {
await button.click();
}
// Mô tả locator (cho trace/report)
const button = page.getByTestId('btn-sub').describe('Subscribe button');
await button.click();
// Select text
await locator.selectText();
// Aria snapshot
const snapshot = await page.getByRole('link').ariaSnapshot();
12. Bảng Tổng Hợp Nhanh
12.1. Các Method Thường Dùng Nhất
| Category | Methods | Frequency |
|---|---|---|
| Click | click(), dblclick() |
⭐⭐⭐⭐⭐ |
| Input | fill(), press(), pressSequentially() |
⭐⭐⭐⭐⭐ |
| Get Text | textContent(), innerText() |
⭐⭐⭐⭐⭐ |
| Checkbox | check(), uncheck(), isChecked() |
⭐⭐⭐⭐ |
| Visibility | isVisible(), isHidden() |
⭐⭐⭐⭐ |
| Select | first(), last(), nth() |
⭐⭐⭐⭐ |
| Filter | filter(), locator() |
⭐⭐⭐ |
| Wait | waitFor(), waitForElementState() |
⭐⭐⭐ |
12.2. So Sánh Text Methods
| Method | Khi Nào Dùng | Assertion Tốt Hơn |
|---|---|---|
textContent() |
Lấy raw text content | expect(locator).toHaveText() |
innerText() |
Lấy visible text (như user thấy) | expect(locator).toHaveText({ useInnerText: true }) |
innerHTML() |
Lấy HTML content | Ít khi cần assert |
12.3. So Sánh Input Methods
| Method | Tốc Độ | Use Case |
|---|---|---|
fill() |
⚡⚡⚡ Nhanh nhất | Điền form thông thường |
pressSequentially() |
⚡⚡ Chậm hơn | Cần trigger keyboard events |
press() |
⚡⚡⚡ | Nhấn phím đặc biệt, shortcuts |
13. Best Practices
13.1. Nên Dùng
- ✅ Dùng
fill()thay vìtype()hoặcpressSequentially()cho input thông thường - ✅ Dùng expect() assertions thay vì
isVisible(),isDisabled()để tránh flakiness - ✅ Dùng role-based selectors (
getByRole) khi có thể - ✅ Dùng
waitFor()thay vì hard-coded timeout
13.2. Không Nên
- ❌ Không dùng
type()- đã deprecated, dùngpressSequentially()hoặcfill() - ❌ Không dùng
elementHandle()- racy, dùng locator - ❌ Không dùng
isVisible()cho assertions - dùngexpect(locator).toBeVisible() - ❌ Không quên set
timeoutcho các operations lâu
13.3. Tips và Tricks
// 1. Chain operations
await page.getByRole('textbox')
.fill('test')
.press('Enter');
// 2. Reuse locators
const submitButton = page.getByRole('button', { name: 'Submit' });
await expect(submitButton).toBeVisible();
await submitButton.click();
// 3. Wait cho element trước khi interact
await locator.waitFor({ state: 'visible' });
await locator.click();
// 4. Dùng force cho edge cases
await locator.click({ force: true }); // Bypass actionability checks
14. Xử Lý Các Trường Hợp Đặc Biệt
14.1. Element Trong Frame
// Cách 1: Frame locator
const frame = page.frameLocator('iframe');
await frame.getByRole('button').click();
// Cách 2: Content frame
const iframeLocator = page.locator('iframe[name="embedded"]');
const frame = iframeLocator.contentFrame();
await frame.getByRole('button').click();
14.2. Dynamic Content
// Wait for element appear
await page.getByText('Loading...').waitFor({ state: 'hidden' });
await page.getByText('Content loaded').waitFor({ state: 'visible' });
// Wait for text change
await expect(locator).toHaveText('New text');
14.3. Multiple Elements
// Get all và iterate
const buttons = await page.getByRole('button').all();
for (const button of buttons) {
if (await button.isVisible()) {
await button.click();
}
}
// Count before processing
const count = await page.getByRole('listitem').count();
for (let i = 0; i < count; i++) {
await page.getByRole('listitem').nth(i).click();
}
Kết Luận
Playwright Locator cung cấp một bộ API phong phú và mạnh mẽ để tương tác với web elements. Hiểu rõ và sử dụng đúng các method sẽ giúp bạn:
- Viết test code ngắn gọn, dễ đọc hơn
- Giảm flakiness trong tests
- Tận dụng auto-waiting và retry mechanism
- Xử lý các trường hợp phức tạp một cách dễ dàng
Hãy bookmark bài viết này để tra cứu khi cần và thực hành thường xuyên để thành thạo Playwright!
