Module 06: Code Review — Checklist và Best Practices¶
🎯 Mục Tiêu Module¶
- Hiểu tại sao Code Review quan trọng
- Nắm được Checklist đánh giá code Playwright
- Thực hành review code AI sinh ra
- Biết cách tối ưu code
6.1. Tại Sao Code Review Quan Trọng?¶
Vấn đề: Code AI sinh ra chỉ là nháp¶
┌─────────────────────────────────────────────────────┐
│ │
│ Code AI sinh ra: │
│ ✅ Chạy được │
│ ❌ Chưa tối ưu │
│ ❌ Có thể có anti-pattern │
│ ❌ Có thể thiếu assertion │
│ ❌ Có thể dùng locator không ổn định │
│ │
│ → Cần QC review trước khi sử dụng chính thức │
└─────────────────────────────────────────────────────┘
Vai trò của QC trong Code Review¶
QC Manual trong Code Review:
1. Đọc code và hiểu logic
2. Kiểm tra locator có ổn định không
3. Kiểm tra có assertion đầy đủ không
4. Kiểm tra có anti-pattern không
5. Duyệt hoặc yêu cầu chỉnh sửa
6.2. Code Review Checklist¶
Checklist đầy đủ¶
# ═══════════════════════════════════════════════════
# CODE REVIEW CHECKLIST — Playwright Test Script
# ═══════════════════════════════════════════════════
## 1. Locator Quality
□ Không dùng waitForTimeout
□ Không dùng locator index (.nth())
□ Locator tuân thủ hierarchy (data-testid > id > aria-label > text > CSS)
□ Không dùng XPath trừ khi bất khả kháng
□ Locator ngắn gọn, dễ đọc
## 2. Assertion
□ Có assertion sau mỗi step quan trọng
□ Assertion cụ thể (không chỉ check visible)
□ Có assertion cho URL khi cần
□ Có assertion cho text khi cần
## 3. Code Structure
□ Test name mô tả được hành động
□ Mỗi test case độc lập (không phụ thuộc test khác)
□ Có comment giải thích logic phức tạp
□ Code dễ đọc, dễ hiểu
## 4. Test Data
□ Không hardcode test data trong script
□ Test data tách riêng (nếu cần)
□ Dùng biến cho giá trị thường dùng
## 5. Error Handling
□ Có screenshot khi fail (nếu cần)
□ Có error message rõ ràng
□ Không swallow error
## 6. Performance
□ Không dùng waitForTimeout
□ Dùng waitForSelector / waitForLoadState
□ Không chờ quá lâu (timeout hợp lý)
## 7. Best Practices
□ Tuân thủ Page Object Model (nếu project lớn)
□ Dùng fixtures (nếu cần)
□ Dùng beforeEach cho setup chung
6.3. Các Anti-Pattern Cần Tránh¶
Anti-Pattern 1: waitForTimeout¶
// ❌ Anti-pattern: Chờ cố định
await page.waitForTimeout(5000);
// ✅ Nên dùng: Chờ element xuất hiện
await page.locator('#result').waitFor({ state: 'visible' });
// ✅ Hoặc: Chờ trang load
await page.waitForLoadState('networkidle');
Anti-Pattern 2: Locator index¶
// ❌ Anti-pattern: Dùng index
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: Không có assertion¶
// ❌ Anti-pattern: Không kiểm tra kết quả
test('test login', async ({ page }) => {
await page.goto('https://example.com/login');
await page.locator('#username').fill('testuser');
await page.locator('#password').fill('Test@123');
await page.locator('#login-btn').click();
// Không có assertion → Không biết pass hay fail
});
// ✅ Nên dùng: Có assertion rõ ràng
test('test login', async ({ page }) => {
await page.goto('https://example.com/login');
await page.locator('#username').fill('testuser');
await page.locator('#password').fill('Test@123');
await page.locator('#login-btn').click();
// Assertion: Kiểm tra đăng nhập thành công
await expect(page.locator('.welcome-message')).toBeVisible();
await expect(page).toHaveURL(/dashboard/);
});
Anti-Pattern 4: Hardcode test data¶
// ❌ Anti-pattern: Hardcode trong code
await page.locator('#username').fill('testuser123');
await page.locator('#password').fill('Test@123456');
// ✅ Nên dùng: Tách riêng test data
const TEST_DATA = {
username: 'testuser123',
password: 'Test@123456',
};
await page.locator('#username').fill(TEST_DATA.username);
await page.locator('#password').fill(TEST_DATA.password);
Anti-Pattern 5: Test phụ thuộc nhau¶
// ❌ Anti-pattern: Test phụ thuộc
test('test 1: login', async ({ page }) => {
// Login
});
test('test 2: add to cart', async ({ page }) => {
// Phụ thuộc test 1 đã login → Có thể fail nếu chạy riêng
});
// ✅ Nên dùng: Mỗi test độc lập
test('test add to cart', async ({ page }) => {
// Login trước khi test
await page.goto('/login');
await page.locator('#username').fill('testuser');
await page.locator('#password').fill('Test@123');
await page.locator('#login-btn').click();
// Test thêm giỏ hàng
await page.goto('/shop');
// ...
});
6.4. Ví Dụ Review Code¶
Code AI sinh ra (trước khi review)¶
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://practice.automationtesting.in/my-account/');
await page.locator('#username').click();
await page.locator('#username').fill('testuser123');
await page.locator('#password').click();
await page.locator('#password').fill('Test@123456');
await page.locator('[name="login"]').click();
await page.waitForTimeout(3000);
await page.locator('text=Orders').click();
});
Review comments¶
Dòng 3: Tên test quá ngắn "test" → Nên đổi thành "test login success"
Dòng 5: Không cần click trước khi fill → Có thể bỏ
Dòng 7: Không cần click trước khi fill → Có thể bỏ
Dòng 9: Dùng waitForTimeout → Nên dùng waitForLoadState hoặc waitForSelector
Dòng 10: Không có assertion → Không biết test pass hay fail
Code sau khi review¶
import { test, expect } from '@playwright/test';
test('test login success', async ({ page }) => {
await page.goto('https://practice.automationtesting.in/my-account/');
await page.locator('#username').fill('testuser123');
await page.locator('#password').fill('Test@123456');
await page.locator('[name="login"]').click();
// Chờ trang load xong
await page.waitForLoadState('networkidle');
// Assertion: Kiểm tra đăng nhập thành công
await expect(page.locator('.woocommerce-MyAccount-content')).toBeVisible();
// Kiểm tra có link Orders
await expect(page.locator('text=Orders')).toBeVisible();
});
6.5. Quy Trình Code Review¶
┌─────────────────────────────────────────────────────┐
│ Quy trình Code Review: │
│ │
│ 1. AI sinh code nháp │
│ ↓ │
│ 2. Skill 2 (Code Reviewer) check tự động │
│ ↓ │
│ 3. QC Manual review chi tiết │
│ ↓ │
│ 4. QC duyệt hoặc yêu cầu chỉnh sửa │
│ ↓ │
│ 5. Code chính thức (Approved) │
└─────────────────────────────────────────────────────┘
📝 Bài Tập¶
Bài Tập 1: Review Code AI¶
Review code sau và tìm tất cả anti-pattern:
import { test, expect } from '@playwright/test';
test('test add to cart', async ({ page }) => {
await page.goto('https://practice.automationtesting.in/shop/');
await page.locator('.product').nth(0).click();
await page.locator('.add_to_cart_button').click();
await page.waitForTimeout(5000);
await page.locator('text=View Basket').click();
});
Bài Tập 2: Viết Code Tốt Hơn¶
Viết lại code bài tập 1 thành code tốt hơn.
Bài Tập 3: Review Code Bạn¶
Trao đổi code với bạn học và review cho nhau.
✅ Checklist Hoàn Thành Module¶
- [ ] Hiểu tại sao Code Review quan trọng
- [ ] Nắm được Checklist đánh giá
- [ ] Biết các anti-pattern cần tránh
- [ ] Thực hành review code
- [ ] Hoàn thành bài tập