Tìm hiểu về Playwright Config
Cách sử dụng file playwright.config.(ts|js)
Hướng dẫn Cấu hình Playwright (playwright.config.ts)
📚 Mục lục
- Giới thiệu
- Cấu hình cơ bản
- Cấu hình Projects
- Global Setup & Teardown
- Cấu hình Use Options
- Recording Options
- Network Options
- Emulation Options
- Ví dụ hoàn chỉnh
Giới thiệu
File playwright.config.ts (hoặc .js) là nơi cấu hình toàn bộ test runner của Playwright. Đây là file quan trọng nhất để điều khiển cách thức chạy test của bạn.
Cấu trúc cơ bản
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Cấu hình test runner ở đây (top-level)
testDir: 'tests',
timeout: 30000,
use: {
// Cấu hình browser/context ở đây
baseURL: 'http://localhost:3000',
},
projects: [
// Cấu hình các project/browser khác nhau
],
});
⚠️ Lưu ý quan trọng: Các tùy chọn test runner đặt ở top-level, KHÔNG đặt trong section use.
Cấu hình cơ bản
1. Thư mục test và file patterns
export default defineConfig({
// Thư mục chứa file test
testDir: 'tests',
// Pattern để tìm file test (mặc định: *.spec.ts, *.test.ts)
testMatch: '*todo-tests/*.spec.ts',
// Pattern để bỏ qua file test
testIgnore: '*test-assets',
});
📌 Giải thích:
testDir: Thư mục gốc chứa các file testtestMatch: Chỉ chạy các file khớp với pattern nàytestIgnore: Bỏ qua các file khớp với pattern này
2. Timeout và Retries
export default defineConfig({
// Timeout cho mỗi test (mặc định: 30 giây)
timeout: 30000,
// Số lần retry khi test fail (0 = không retry)
retries: process.env.CI ? 2 : 0,
expect: {
// Timeout cho các assertion (mặc định: 5 giây)
timeout: 5000,
},
});
💡 Best Practice:
- Trên CI: nên set
retries: 2để tránh false negative - Local development:
retries: 0để phát hiện vấn đề sớm
3. Parallel và Workers
export default defineConfig({
// Chạy tất cả test song song
fullyParallel: true,
// Số worker process (default: 50% số CPU cores)
workers: process.env.CI ? 1 : undefined,
// Ngăn test.only trên CI
forbidOnly: !!process.env.CI,
});
🚀 Performance Tips:
- Local: để
workers: undefined(sẽ dùng 50% cores) - CI: set
workers: 1nếu CI server yếu, hoặc2-4nếu mạnh
4. Reporter
export default defineConfig({
// Reporter để hiển thị kết quả test
reporter: [
['html'], // HTML report
['list'], // Console output
['json', { outputFile: 'test-results.json' }],
],
// Thư mục lưu kết quả test
outputDir: 'test-results',
});
📊 Reporter phổ biến:
html: Báo cáo HTML đẹp mắt (khuyên dùng)list: In ra console, phù hợp cho CIdot: Compact formatjson: Export JSON để xử lý tiếpjunit: Tích hợp với Jenkins/CI tools
Cấu hình Projects
Projects cho phép chạy test trên nhiều browser/môi trường khác nhau.
Ví dụ: Multi-browser testing
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
// Desktop Chrome
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
},
},
// Desktop Firefox
{
name: 'firefox',
use: {
...devices['Desktop Firefox'],
},
},
// Desktop Safari
{
name: 'webkit',
use: {
...devices['Desktop Safari'],
},
},
// Mobile Chrome
{
name: 'Mobile Chrome',
use: {
...devices['Pixel 5'],
},
},
// Mobile Safari
{
name: 'Mobile Safari',
use: {
...devices['iPhone 12'],
},
},
],
});
Project với cấu hình riêng
projects: [
{
name: 'staging',
use: {
baseURL: 'https://staging.example.com',
screenshot: 'only-on-failure',
},
},
{
name: 'production',
use: {
baseURL: 'https://example.com',
screenshot: 'off',
},
},
],
🎯 Chạy project cụ thể:
# Chỉ chạy trên Chrome
npx playwright test --project=chromium
# Chạy nhiều project
npx playwright test --project=chromium --project=firefox
Global Setup & Teardown
Khi nào cần dùng?
- Khởi tạo database trước khi test
- Login và lưu authentication state
- Start/stop services
- Cleanup sau khi test xong
Cấu hình
export default defineConfig({
// File setup chạy TRƯỚC tất cả test
globalSetup: require.resolve('./global-setup.ts'),
// File teardown chạy SAU tất cả test
globalTeardown: require.resolve('./global-teardown.ts'),
});
Ví dụ: Global Setup
global-setup.ts:
import { chromium, FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
console.log('🚀 Starting global setup...');
// 1. Khởi tạo database
await setupDatabase();
// 2. Login và lưu auth state
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com/login');
await page.fill('input[name="username"]', 'admin');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
// Lưu storage state
await page.context().storageState({
path: 'auth-state.json'
});
await browser.close();
console.log('✅ Global setup completed');
}
export default globalSetup;
global-teardown.ts:
import { FullConfig } from '@playwright/test';
async function globalTeardown(config: FullConfig) {
console.log('🧹 Starting cleanup...');
// Cleanup database, services, etc.
await cleanupDatabase();
console.log('✅ Cleanup completed');
}
export default globalTeardown;
Sử dụng Auth State trong test
export default defineConfig({
use: {
// Tất cả test sẽ dùng auth state này
storageState: 'auth-state.json',
},
});
Cấu hình Use Options
Section use chứa các options áp dụng cho browser và context.
Base URL
use: {
// Base URL cho tất cả các page.goto()
baseURL: 'http://localhost:3000',
},
Sử dụng trong test:
// Thay vì:
await page.goto('http://localhost:3000/products');
// Chỉ cần:
await page.goto('/products');
Action Timeout
use: {
// Timeout cho mỗi action (click, fill, v.v.)
actionTimeout: 10000, // 10 giây
},
Browser Options
use: {
// Chọn browser
browserName: 'chromium', // hoặc 'firefox', 'webkit'
// Channel (Chrome/Edge variants)
channel: 'chrome', // 'chrome', 'msedge', 'chrome-beta'
// Chạy browser có UI (không headless)
headless: false,
// Bypass CSP
bypassCSP: true,
},
Test ID Attribute
use: {
// Thay đổi attribute mặc định từ data-testid
testIdAttribute: 'data-test-id',
},
Sử dụng trong test:
// HTML: <button data-test-id="submit-btn">Submit</button>
await page.getByTestId('submit-btn').click();
Recording Options
Ghi lại screenshots, videos và traces để debug.
Cấu hình Screenshot
use: {
screenshot: 'only-on-failure',
// Options: 'off' | 'on' | 'only-on-failure'
},
📸 Screenshot modes:
off: Không chụp screenshoton: Chụp screenshot sau mỗi testonly-on-failure: Chỉ chụp khi test fail ✅ Recommended
Cấu hình Video
use: {
video: 'retain-on-failure',
// Options: 'off' | 'on' | 'retain-on-failure' | 'on-first-retry'
},
🎥 Video modes:
off: Không record videoon: Record tất cả testretain-on-failure: Chỉ giữ video của test fail ✅ Recommendedon-first-retry: Chỉ record lần retry đầu tiên
Cấu hình Trace
use: {
trace: 'on-first-retry',
// Options: 'off' | 'on' | 'retain-on-failure' | 'on-first-retry'
},
🔍 Trace modes:
off: Không thu thập traceon: Thu thập trace cho tất cả testretain-on-failure: Chỉ giữ trace của test failon-first-retry: Chỉ thu thập khi retry ✅ Recommended
Xem trace:
npx playwright show-trace trace.zip
Cấu hình Visual Comparison
expect: {
toHaveScreenshot: {
// Số pixel khác biệt tối đa
maxDiffPixels: 100,
},
toMatchSnapshot: {
// Tỷ lệ % pixel khác biệt tối đa
maxDiffPixelRatio: 0.1, // 10%
},
},
Ví dụ config hoàn chỉnh cho Recording
export default defineConfig({
use: {
// Screenshot khi fail
screenshot: 'only-on-failure',
// Video khi fail
video: 'retain-on-failure',
// Trace khi retry
trace: 'on-first-retry',
},
// Thư mục lưu artifacts
outputDir: 'test-results',
expect: {
toHaveScreenshot: {
maxDiffPixels: 100,
},
},
});
Network Options
Accept Downloads
use: {
// Tự động tải file về
acceptDownloads: true,
},
HTTP Headers
use: {
// Header gửi kèm mọi request
extraHTTPHeaders: {
'X-API-Key': 'your-api-key',
'Accept-Language': 'vi-VN',
},
},
HTTP Authentication
use: {
// Basic authentication
httpCredentials: {
username: 'admin',
password: 'secret123',
},
},
Ignore HTTPS Errors
use: {
// Bỏ qua lỗi SSL certificate
ignoreHTTPSErrors: true,
},
Offline Mode
use: {
// Emulate network offline
offline: true,
},
Proxy
use: {
proxy: {
server: 'http://myproxy.com:3128',
bypass: 'localhost,*.example.com',
username: 'user',
password: 'pass',
},
},
Emulation Options
Viewport
use: {
// Kích thước màn hình
viewport: { width: 1280, height: 720 },
// Hoặc null để dùng kích thước thật
viewport: null,
},
User Agent
use: {
userAgent: 'My Custom User Agent',
},
Geolocation
use: {
// Vị trí địa lý
geolocation: {
longitude: 106.6297,
latitude: 10.8231
}, // Tọa độ TP.HCM
// Cần grant permission
permissions: ['geolocation'],
},
Locale & Timezone
use: {
// Ngôn ngữ/vùng
locale: 'vi-VN',
// Múi giờ
timezoneId: 'Asia/Ho_Chi_Minh',
},
Color Scheme
use: {
// Dark mode / Light mode
colorScheme: 'dark', // 'light' | 'dark'
},
Permissions
use: {
// Cấp quyền cho browser
permissions: ['geolocation', 'notifications', 'camera'],
},
Device Emulation
import { devices } from '@playwright/test';
use: {
// Emulate iPhone 12
...devices['iPhone 12'],
// Hoặc custom
viewport: { width: 375, height: 667 },
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0...)',
deviceScaleFactor: 2,
isMobile: true,
hasTouch: true,
},
Ví dụ hoàn chỉnh
Config cho dự án thực tế
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
// ============ TEST RUNNER CONFIG ============
testDir: './tests',
testMatch: '**/*.spec.ts',
testIgnore: '**/node_modules/**',
// Timeout
timeout: 30000,
// Parallel
fullyParallel: true,
workers: process.env.CI ? 2 : undefined,
// Retries
retries: process.env.CI ? 2 : 0,
// CI
forbidOnly: !!process.env.CI,
// Reporter
reporter: [
['html', { open: 'never' }],
['list'],
['json', { outputFile: 'test-results.json' }],
],
// Output
outputDir: 'test-results',
// Expect
expect: {
timeout: 5000,
toHaveScreenshot: {
maxDiffPixels: 100,
},
},
// ============ USE OPTIONS ============
use: {
// Base URL
baseURL: process.env.BASE_URL || 'http://localhost:3000',
// Action timeout
actionTimeout: 10000,
// Recording
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'on-first-retry',
// Network
extraHTTPHeaders: {
'Accept-Language': 'vi-VN',
},
ignoreHTTPSErrors: true,
// Emulation
locale: 'vi-VN',
timezoneId: 'Asia/Ho_Chi_Minh',
viewport: { width: 1280, height: 720 },
// Storage state (auth)
storageState: 'auth-state.json',
},
// ============ PROJECTS ============
projects: [
// Setup: Login trước
{
name: 'setup',
testMatch: '**/*.setup.ts',
},
// Desktop Chrome
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
},
dependencies: ['setup'],
},
// Desktop Firefox
{
name: 'firefox',
use: {
...devices['Desktop Firefox'],
},
dependencies: ['setup'],
},
// Mobile Chrome
{
name: 'mobile-chrome',
use: {
...devices['Pixel 5'],
},
dependencies: ['setup'],
},
// API Testing (không cần browser)
{
name: 'api',
testMatch: '**/*.api.spec.ts',
use: {
baseURL: process.env.API_URL || 'http://localhost:3001',
},
},
],
// ============ GLOBAL SETUP ============
globalSetup: require.resolve('./global-setup.ts'),
globalTeardown: require.resolve('./global-teardown.ts'),
// ============ WEB SERVER ============
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120000,
},
});
📋 Tổng kết
Checklist cho Config tốt
- ✅ Cấu hình
retriescho CI - ✅ Sử dụng
fullyParallelđể tăng tốc - ✅ Bật recording (
screenshot,video,trace) với mode thông minh - ✅ Cấu hình
baseURLđể code ngắn gọn - ✅ Setup projects cho multi-browser testing
- ✅ Dùng
globalSetupcho authentication - ✅ Cấu hình
webServernếu cần start dev server - ✅ Set
forbidOnly: truetrên CI
Câu lệnh hữu ích
# Chạy tất cả test
npx playwright test
# Chạy test trên một project
npx playwright test --project=chromium
# Chạy test với UI mode
npx playwright test --ui
# Debug một test
npx playwright test --debug
# Xem HTML report
npx playwright show-report
# Xem trace
npx playwright show-trace trace.zip
Tài liệu tham khảo
🎉 Chúc bạn viết test thành công với Playwright!