Module 04: Locator Strategy — Nghệ Thuật Bắt Element Ổn Định
🎯 Mục Tiêu Module
- Hiểu tại sao Locator quan trọng trong automation test
- Nắm được Locator Hierarchy (thứ tự ưu tiên)
- Thực hành tìm và đánh giá locator trên website thực
- Biết cách fallback khi locator chính không có
4.1. Tại Sao Locator Quan Trong?
Vấn đề: Locator không ổn định
┌─────────────────────────────────────────────────────┐
│ │
│ Locator động (thay đổi mỗi lần load): │
│ <div id="ember123">...</div> │
│ <div id="ember456">...</div> ← ID thay đổi! │
│ │
│ → Code gãy mỗi lần chạy │
│ → Maintenance tốn thời gian │
│ → Test không tin cậy │
└─────────────────────────────────────────────────────┘
Giải pháp: Locator ổn định
┌─────────────────────────────────────────────────────┐
│ │
│ Locator ổn định: │
│ <button data-testid="login-btn">Login</button> │
│ │
│ → Code chạy ổn định │
│ → Maintenance ít │
│ → Test tin cậy │
└─────────────────────────────────────────────────────┘
4.2. Locator Hierarchy — Thứ Tự Ưu Tiên
┌─────────────────────────────────────────────────────┐
│ LOCATOR HIERARCHY │
│ │
│ Ưu tiên 1: [data-testid="xxx"] │
│ → Ổn định cao nhất, dành riêng cho test │
│ │
│ Ưu tiên 2: [data-cy="xxx"] │
│ → Cypress convention, cũng rất ổn │
│ │
│ Ưu tiên 3: [id="xxx"] (cố định) │
│ → Chỉ khi ID không phải dynamic │
│ │
│ Ưu tiên 4: [aria-label="xxx"] │
│ → Accessibility-friendly │
│ │
│ Ưu tiên 5: text content │
│ → Dễ đọc nhưng dễ thay đổi │
│ │
│ Ưu tiên 6: CSS selector │
│ → Class-based, có thể thay khi refactor UI │
│ │
│ Ưu tiên 7: XPath │
│ → Last resort, chỉ dùng khi bất khả kháng │
└─────────────────────────────────────────────────────┘
Bảng chi tiết
| Ưu tiên |
Locator Type |
Ví dụ |
Ổn định |
Dễ đọc |
| 1 |
data-testid |
[data-testid="login-btn"] |
⭐⭐⭐⭐⭐ |
⭐⭐⭐ |
| 2 |
data-cy |
[data-cy="login-btn"] |
⭐⭐⭐⭐⭐ |
⭐⭐⭐ |
| 3 |
id (cố định) |
#login-btn |
⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
| 4 |
aria-label |
[aria-label="Login"] |
⭐⭐⭐⭐ |
⭐⭐⭐⭐ |
| 5 |
text content |
text=Login |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
| 6 |
CSS selector |
.login-button |
⭐⭐ |
⭐⭐⭐ |
| 7 |
XPath |
//button[@type='submit'] |
⭐ |
⭐⭐ |
4.3. Cách Tìm Locator
- Mở DevTools (F12)
- Click vào element
- Xem Attributes trong Elements panel
┌─────────────────────────────────────────────────────┐
│ <button │
│ data-testid="login-btn" ← Ưu tiên 1 │
│ id="login-button" ← Ưu tiên 3 │
│ class="btn btn-primary" ← Ưu tiên 6 │
│ aria-label="Login" ← Ưu tiên 4 │
│ > │
│ Login │
│ </button> │
└─────────────────────────────────────────────────────┘
Cách 2: Dùng Playwright Inspector
- Chạy code với
--debug flag
- Dùng "Pick Locator" để chọn element
- Playwright sẽ gợi ý locator tốt nhất
Cách 3: Dùng Antigravity IDE
- Click vào element trên browser trong IDE
- IDE sẽ hiển thị locator được sử dụng
- Xem và đánh giá locator
4.4. Ví Dụ Thực Tế trên Practice Website
Trang Login: https://practice.automationtesting.in/my-account/
<!-- Ô Username -->
<input
type="text"
name="username"
id="username"
placeholder="Username"
class="input-text"
/>
<!-- Ô Password -->
<input
type="password"
name="password"
id="password"
placeholder="Password"
class="input-text"
/>
<!-- Nút Login -->
<button
type="submit"
name="login"
class="button"
value="Login"
>
Login
</button>
Đánh giá locator cho trang Login
| Element |
Locator tốt nhất |
Tại sao |
| Username |
#username |
ID cố định, dễ tìm |
| Password |
#password |
ID cố định, dễ tìm |
| Nút Login |
[name="login"] |
Name cố định |
Code Playwright cho trang Login
import { test, expect } from '@playwright/test';
test('test login', async ({ page }) => {
await page.goto('https://practice.automationtesting.in/my-account/');
// Dùng ID (ổn định)
await page.locator('#username').fill('testuser123');
await page.locator('#password').fill('Test@123456');
// Dùng name attribute (ổn định)
await page.locator('[name="login"]').click();
// Assertion
await expect(page.locator('.woocommerce-MyAccount-content')).toBeVisible();
});
4.5. Khi Nào Dùng Fallback?
Tình huống: Không có data-testid
Website không có data-testid:
<button class="btn-primary">Add to Cart</button>
Chiến lược Fallback
Không có data-testid?
│
├── Có ID cố định? ──► Dùng ID
│
├── Có aria-label? ──► Dùng aria-label
│
├── Có text content? ──► Dùng text
│ (Chỉ khi text không thay đổi)
│
└── Dùng CSS selector
(Class-based, có thể thay khi refactor)
Ví dụ Fallback
// Ưu tiên 1: data-testid (không có)
// await page.locator('[data-testid="add-to-cart"]').click();
// Ưu tiên 2: ID (không có)
// await page.locator('#add-to-cart').click();
// Ưu tiên 3: aria-label (không có)
// await page.locator('[aria-label="Add to Cart"]').click();
// Ưu tiên 4: text content (có!)
await page.locator('text=Add to basket').click();
// Ưu tiên 5: CSS selector (fallback cuối)
// await page.locator('.add_to_cart_button').click();
4.6. Locator Anti-patterns
❌ Anti-pattern 1: Locator quá dài
// Quá dài, khó maintain
await page.locator('div.container > div.row > div.col-md-6 > form > div.form-group > input#email').fill('test@example.com');
// Nên dùng
await page.locator('#email').fill('test@example.com');
❌ Anti-pattern 2: Dùng index
// Dùng index → Gãy khi thứ tự thay đổi
await page.locator('button').nth(2).click();
// Nên dùng locator cụ thể
await page.locator('button:has-text("Submit")').click();
❌ Anti-pattern 3: Dùng XPath dài
// XPath dài, khó đọc
await page.locator('//div[@class="container"]/div[2]/form//button[@type="submit"]').click();
// Nên dùng CSS hoặc text
await page.locator('button[type="submit"]').click();
❌ Anti-pattern 4: Dùng waitForTimeout
// Chờ cố định → Không ổn định
await page.waitForTimeout(5000);
// Nên chờ element xuất hiện
await page.locator('#result').waitFor({ state: 'visible' });
4.7. Yêu Cầu Dev Thêm data-testid
Khi nào cần yêu cầu?
Website có data-testid? ──► Không cần yêu cầu
Website không có data-testid? ──► Xem xét yêu cầu
Cách yêu cầu
Gửi yêu cầu cho Dev team:
"Để automation test ổn định hơn, cần thêm attribute
data-testid cho các element quan trọng:
- Nút Login: data-testid="login-btn"
- Ô Username: data-testid="username-input"
- Ô Password: data-testid="password-input"
- Form: data-testid="login-form"
Đây là convention tốt cho testing, không ảnh hưởng
đến functionality của website."
Lợi ích
| Bên |
Lợi ích |
| QC |
Test ổn định, ít maintenance |
| Dev |
Không ảnh hưởng code, dễ implement |
| Team |
CI/CD chạy ổn định |
📝 Bài Tập
Bài Tập 1: Tìm Locator trên Practice Website
- Mở https://practice.automationtesting.in/my-account/
- Dùng DevTools tìm locator cho:
- Ô Username
- Ô Password
- Nút Login
- Link "Register"
- Đánh giá ổn định cho mỗi locator
Bài Tập 2: Đánh Giá Locator
Cho đoạn HTML sau, chọn locator tốt nhất:
<button
data-testid="submit-order"
id="btn-submit"
class="btn btn-success"
aria-label="Submit Order"
>
Place Order
</button>
Bài Tập 3: Viết Code với Locator Ưu Tiên
Viết code Playwright cho flow đăng ký tài khoản:
- URL: https://practice.automationtesting.in/my-account/
- Chọn tab "Register"
- Nhập email, password
- Click nút Register
- Tuân thủ Locator Hierarchy
✅ Checklist Hoàn Thành Module
- [ ] Hiểu tại sao Locator quan trọng
- [ ] Nắm được Locator Hierarchy
- [ ] Biết cách tìm locator bằng DevTools
- [ ] Thực hành tìm locator trên Practice Website
- [ ] Biết cách dùng fallback
- [ ] Nắm các anti-pattern cần tránh
- [ ] Hoàn thành bài tập