- Tác giả
- Name
- Nguyễn Đức Xinh
- Ngày xuất bản
- Ngày xuất bản
Giới thiệu về Playwright: Công cụ Testing hiện đại cho ứng dụng Web
Playwright là gì?
Playwright là một framework automation testing mã nguồn mở được phát triển bởi Microsoft, chuyên dùng để thực hiện end-to-end testing cho các ứng dụng web. Ra mắt vào năm 2020, Playwright nhanh chóng trở thành một công cụ phổ biến trong cộng đồng phát triển phần mềm nhờ khả năng chạy test trên nhiều trình duyệt (cross-browser) và nhiều nền tảng một cách đáng tin cậy.
Không giống như các framework testing truyền thống, Playwright được thiết kế để làm việc hiệu quả với các ứng dụng web hiện đại, đặc biệt là các ứng dụng single-page (SPA), progressive web apps (PWA), và các ứng dụng web phức tạp khác. Playwright cung cấp một API mạnh mẽ, cho phép tự động hóa hầu hết mọi hành động mà người dùng có thể thực hiện trên trình duyệt web.
Những đặc điểm nổi bật của Playwright
1. Hỗ trợ đa trình duyệt (Cross-browser support)
Một trong những ưu điểm lớn nhất của Playwright là khả năng chạy các test case trên nhiều trình duyệt khác nhau một cách nhất quán. Playwright hỗ trợ:
- Chromium: Bao gồm Google Chrome và Microsoft Edge
- Firefox
- WebKit: Sử dụng trong Safari
Điều này cho phép các developer và QA engineer đảm bảo rằng ứng dụng của họ hoạt động đồng nhất trên các trình duyệt phổ biến mà không cần phải viết các bộ test riêng biệt.
2. Hỗ trợ đa ngôn ngữ lập trình
Playwright hỗ trợ nhiều ngôn ngữ lập trình phổ biến, giúp các team có thể sử dụng ngôn ngữ phù hợp với stack công nghệ của họ:
- JavaScript
- TypeScript
- Python
- Java
- C#/.NET
Sự linh hoạt này làm cho Playwright dễ dàng tích hợp vào các dự án hiện có, bất kể ngôn ngữ lập trình nào đang được sử dụng.
3. Auto-waiting và tính năng chống flakiness
Playwright được thiết kế để giảm thiểu các test case không ổn định (flaky tests) - một vấn đề phổ biến trong automated testing. Framework này:
- Tự động đợi các element trở nên sẵn sàng trước khi tương tác
- Đợi các animation hoàn thành
- Đợi network requests hoàn tất
- Đợi các thay đổi DOM
Nhờ vậy, các test case ít bị ảnh hưởng bởi vấn đề timing, tốc độ mạng hay hiệu suất máy tính.
4. Powerful API và khả năng mô phỏng người dùng
Playwright cung cấp một API mạnh mẽ cho phép mô phỏng hầu hết mọi tương tác của người dùng:
- Click, hover, và tap
- Điền form và tương tác với input fields
- Nhấn phím và kết hợp phím
- Tùy chọn upload file
- Tương tác với dialog và alert
- Và nhiều tính năng khác
5. Debug và Tracing
Playwright cung cấp các công cụ debug mạnh mẽ:
- Trace Viewer: Ghi lại toàn bộ quá trình thực thi test với screenshots, DOM snapshots và network logs
- Inspector Mode: Cho phép kiểm tra các element và thực hiện các bước test một cách tương tác
- Debug logs: Chi tiết về các hành động được thực hiện và các lỗi xảy ra
So sánh Playwright với các framework testing khác
Tính năng | Playwright | Selenium | Cypress | Puppeteer |
---|---|---|---|---|
Hỗ trợ trình duyệt | Chromium, Firefox, WebKit | Chrome, Firefox, Safari, Edge, IE | Chrome, Firefox, Edge | Chủ yếu Chromium |
Ngôn ngữ lập trình | JavaScript, TypeScript, Python, Java, C# | Nhiều ngôn ngữ | JavaScript, TypeScript | JavaScript, TypeScript |
Kiến trúc | Modern, sử dụng DevTools Protocol | WebDriver protocol | Chạy trong browser | DevTools Protocol |
Auto-waiting | Có | Không (cần explicit waits) | Có | Hạn chế |
Parallel testing | Có | Có | Giới hạn trong Cypress Cloud | Cần cấu hình thêm |
Hỗ trợ iframes | Tốt | Phức tạp | Hạn chế | Hạn chế |
Mobile testing | Mô phỏng | Appium | Giới hạn | Không |
Community & Support | Đang phát triển | Rất lớn | Lớn | Trung bình |
Cài đặt và thiết lập Playwright
Cài đặt Playwright
Để bắt đầu với Playwright, bạn cần cài đặt nó thông qua npm (Node Package Manager). Dưới đây là các bước cơ bản:
# Tạo một project mới
mkdir playwright-demo
cd playwright-demo
npm init -y
# Cài đặt Playwright
npm init playwright@latest
Khi chạy lệnh cài đặt, Playwright sẽ hỏi một số câu hỏi cấu hình như:
- Bạn muốn sử dụng JavaScript hay TypeScript
- Thư mục test sẽ nằm ở đâu
- Bạn có muốn thêm GitHub Actions workflow không
- Bạn muốn cài đặt trình duyệt nào
Sau khi hoàn tất, Playwright sẽ tạo cấu trúc project ban đầu, cài đặt các trình duyệt cần thiết, và thêm các test ví dụ.
Cấu trúc project
Một project Playwright điển hình có cấu trúc thư mục như sau:
playwright-demo/
├── package.json
├── playwright.config.ts // Hoặc .js tùy vào lựa chọn ngôn ngữ
├── tests/
│ ├── example.spec.ts // Các file test
│ └── ...
└── node_modules/
File playwright.config.ts
chứa các cấu hình cho project của bạn, bao gồm:
- Trình duyệt sẽ sử dụng cho testing
- Timeout settings
- Cấu hình parallel testing
- Các tùy chọn khác như screenshots, video recording, etc.
Viết test case đầu tiên với Playwright
Hãy tạo một test case đơn giản để kiểm tra việc đăng nhập vào một website:
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
test('Successful login', async ({ page }) => {
// Điều hướng đến trang đăng nhập
await page.goto('https://example.com/login');
// Điền thông tin đăng nhập
await page.fill('input[name="email"]', 'user@example.com');
await page.fill('input[name="password"]', 'password123');
// Click vào nút đăng nhập
await page.click('button[type="submit"]');
// Kiểm tra xem đã đăng nhập thành công chưa
// bằng cách xác minh sự hiện diện của một element chỉ xuất hiện sau khi đăng nhập
await expect(page.locator('.dashboard-welcome')).toBeVisible();
// Kiểm tra URL sau khi đăng nhập
expect(page.url()).toContain('/dashboard');
});
Giải thích code:
- Import cần thiết: Import các module
test
vàexpect
từ Playwright - Tạo test case: Sử dụng hàm
test
và đặt tên cho test case - Page fixture: Playwright tự động cung cấp một
page
object để tương tác với trình duyệt - Navigation: Điều hướng đến URL cần test
- Tương tác: Điền form và nhấn nút submit
- Assertions: Kiểm tra kết quả mong đợi
expect()
: API để kiểm tra các điều kiệntoBeVisible()
: Kiểm tra element có hiển thị khôngtoContain()
: Kiểm tra string có chứa substring
Các kỹ thuật chọn element trong Playwright
Playwright cung cấp nhiều cách để chọn các element trên trang web:
1. CSS Selectors
// Sử dụng CSS selector
await page.click('button.login-button');
await page.fill('input#username', 'testuser');
2. Text content
// Tìm element bằng text
await page.click('text=Login');
await page.click('button:has-text("Submit")');
3. Locator API (Khuyến nghị)
// Sử dụng Locator API
const loginButton = page.locator('button[type="submit"]');
await loginButton.click();
// Kết hợp nhiều điều kiện
const submitButton = page.locator('button').filter({ hasText: 'Submit' });
await submitButton.click();
4. XPath (Nếu cần thiết)
// Sử dụng XPath
await page.click('xpath=//button[contains(text(), "Login")]');
Kiểm tra các element trên trang
Playwright cung cấp nhiều phương thức để kiểm tra trạng thái của các element:
// Kiểm tra một element có visible không
await expect(page.locator('.success-message')).toBeVisible();
// Kiểm tra text content
await expect(page.locator('.greeting')).toHaveText('Welcome back, User!');
// Kiểm tra giá trị của input
await expect(page.locator('input[name="email"]')).toHaveValue('user@example.com');
// Kiểm tra thuộc tính của element
await expect(page.locator('img.avatar')).toHaveAttribute('alt', 'User profile picture');
// Kiểm tra element có bị disabled không
await expect(page.locator('button[type="submit"]')).not.toBeDisabled();
// Kiểm tra element có tồn tại trong DOM
await expect(page.locator('.error-message')).toBeAttached();
Xử lý các tình huống phổ biến trong testing
1. Xử lý Dialog và Alerts
// Đăng ký event listener trước khi dialog xuất hiện
page.on('dialog', dialog => {
console.log(`Dialog message: ${dialog.message()}`);
dialog.accept(); // hoặc dialog.dismiss()
});
// Thực hiện hành động gây ra dialog
await page.click('#show-dialog-button');
2. Xử lý các request network
// Chặn (mock) một API request
await page.route('**/api/users', route => {
route.fulfill({
status: 200,
body: JSON.stringify([{ id: 1, name: 'Mocked User' }])
});
});
// Đợi cho một request hoàn thành
const responsePromise = page.waitForResponse('**/api/login');
await page.click('#login-button');
const response = await responsePromise;
expect(response.status()).toBe(200);
3. Upload file
// Upload một file
await page.setInputFiles('input[type="file"]', 'path/to/file.jpg');
// Upload nhiều file
await page.setInputFiles('input[type="file"]', ['file1.jpg', 'file2.jpg']);
4. Xử lý iframes
// Tương tác với element trong iframe
const frame = page.frameLocator('#my-iframe');
await frame.locator('button.submit').click();
5. Mobile testing và responsive design
// Cấu hình chế độ mobile
await page.setViewportSize({ width: 375, height: 812 }); // iPhone X
// Mô phỏng device cụ thể
await page.emulate({
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15A372 Safari/605.1.15',
viewport: { width: 375, height: 812 },
deviceScaleFactor: 3,
isMobile: true,
hasTouch: true
});
Các kỹ thuật nâng cao trong Playwright
1. Parallel testing
Playwright cho phép chạy các test parallel để tiết kiệm thời gian. Cấu hình trong playwright.config.ts
:
export default defineConfig({
// Số lượng worker để chạy các test song song
workers: 5,
// Hoặc sử dụng % số CPU
// workers: '50%',
});
2. Test grouping và tagging
import { test } from '@playwright/test';
// Grouping các test liên quan
test.describe('Authentication flows', () => {
test('User can login', async ({ page }) => {
// test login
});
test('User can logout', async ({ page }) => {
// test logout
});
});
// Tagging
test('User can purchase a product @smoke @e2e', async ({ page }) => {
// test purchase flow
});
// Chạy test với tag cụ thể
// npx playwright test --grep @smoke
3. Testing with authentication
import { test as base, expect } from '@playwright/test';
// Định nghĩa fixture cho authenticated state
const test = base.extend({
authenticatedPage: async ({ page }, use) => {
// Login logic
await page.goto('/login');
await page.fill('[name=email]', 'user@example.com');
await page.fill('[name=password]', 'password123');
await page.click('button[type=submit]');
await page.waitForURL('/dashboard');
// Chuyển page đã đăng nhập cho test sử dụng
await use(page);
}
});
// Sử dụng authenticated fixture
test('User can view profile', async ({ authenticatedPage }) => {
await authenticatedPage.click('text=My Profile');
await expect(authenticatedPage.locator('h1')).toHaveText('User Profile');
});
4. Visual testing với Screenshot comparison
import { test, expect } from '@playwright/test';
test('homepage looks correct', async ({ page }) => {
await page.goto('https://example.com');
// So sánh toàn bộ trang với screenshot chuẩn
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixelRatio: 0.01 // Cho phép sai khác 1%
});
// So sánh chỉ một vùng cụ thể
await expect(page.locator('.navbar')).toHaveScreenshot('navbar.png');
});
Best Practices khi sử dụng Playwright
1. Tổ chức test code
- Page Object Model (POM): Tạo các class cho mỗi page để encapsulate các selector và logic
- Fixture sử dụng lại: Tạo các fixture cho những tác vụ thường xuyên thực hiện
- Tách biệt test data: Đặt test data trong các file riêng biệt
Ví dụ về Page Object Model:
// models/LoginPage.ts
export class LoginPage {
constructor(private page) {}
async navigate() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.page.fill('[name=email]', email);
await this.page.fill('[name=password]', password);
await this.page.click('button[type=submit]');
}
async getErrorMessage() {
return this.page.locator('.error-message').textContent();
}
}
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../models/LoginPage';
test('User can login with valid credentials', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
await loginPage.login('valid@example.com', 'correctpassword');
await expect(page).toHaveURL('/dashboard');
});
2. Giữ test độc lập
- Mỗi test case nên hoàn toàn độc lập, không phụ thuộc vào các test case khác
- Sử dụng
test.beforeEach()
để thiết lập trạng thái ban đầu - Cleanup sau mỗi test bằng
test.afterEach()
3. Tối ưu hiệu suất test
- Sử dụng authentication state storage thay vì đăng nhập lại mỗi test
- Sử dụng mock API cho những request không cần thiết
- Chọn selector tối ưu, ưu tiên
data-testid
hoặc các attribute có mục đích test
Tích hợp Playwright vào CI/CD pipeline
Playwright có thể dễ dàng tích hợp vào các hệ thống CI/CD phổ biến:
Tài liệu tham khảo và cộng đồng
Tổng kết
Playwright đang nhanh chóng trở thành một công cụ automation testing ưa thích của nhiều developer và QA engineer nhờ khả năng cross-browser testing đáng tin cậy, API mạnh mẽ và dễ sử dụng, cùng nhiều tính năng hiện đại giúp giảm thiểu "flaky tests".
Với khả năng hoạt động trên nhiều trình duyệt và hỗ trợ nhiều ngôn ngữ lập trình, Playwright phù hợp với nhiều dự án khác nhau, từ các ứng dụng web nhỏ đến các hệ thống phức tạp với nhiều thành phần.
Trong bối cảnh các ứng dụng web ngày càng phức tạp và yêu cầu về chất lượng ngày càng cao, Playwright cung cấp một giải pháp testing hiệu quả, giúp các team phát hiện và khắc phục các vấn đề sớm, từ đó cải thiện trải nghiệm người dùng và giảm chi phí khắc phục lỗi trong các giai đoạn sau của dự án.
Hãy bắt đầu với Playwright ngay hôm nay và khám phá cách nó có thể cải thiện quy trình testing của bạn!