Hướng dẫn cài đặt và triển khai dự án Playwright với TypeScript từ A-Z
Giới thiệu về Playwright và TypeScript
Playwright là một framework testing end-to-end mạnh mẽ do Microsoft phát triển, cho phép thực hiện automated testing trên nhiều trình duyệt khác nhau như Chromium, Firefox và WebKit với một API thống nhất. Kết hợp với TypeScript, Playwright trở thành công cụ testing mạnh mẽ với khả năng type-checking, giúp code trở nên an toàn và dễ bảo trì hơn.
Trong bài viết này, chúng ta sẽ tìm hiểu cách cài đặt và cấu hình một dự án Playwright với TypeScript từ đầu. Chúng ta sẽ đi qua các bước chi tiết, bao gồm cài đặt các dependency cần thiết, tạo cấu trúc dự án, viết test cơ bản, và chạy các test case đầu tiên.
Tại sao nên chọn Playwright với TypeScript?
- Cross-browser testing: Playwright hỗ trợ đầy đủ các trình duyệt chính (Chromium, Firefox, WebKit) với một API thống nhất.
- Auto-waiting: Tự động đợi cho đến khi các element sẵn sàng để tương tác.
- Type safety: TypeScript giúp phát hiện lỗi ngay trong quá trình phát triển.
- Network interception: Khả năng chặn và sửa đổi các network request.
- Mobile emulation: Hỗ trợ testing trên các thiết bị di động thông qua device emulation.
- Parallel execution: Khả năng chạy test đồng thời để tối ưu thời gian.
Yêu cầu hệ thống
Trước khi bắt đầu, hãy đảm bảo máy tính của bạn đáp ứng các yêu cầu sau:
- Node.js (phiên bản 14 hoặc cao hơn)
- npm hoặc yarn (trình quản lý package)
- Editor code như Visual Studio Code (khuyến nghị)
Để kiểm tra phiên bản Node.js đã cài đặt:
node -v
Để kiểm tra phiên bản npm:
npm -v
Cài đặt dự án Playwright với TypeScript
Bước 1: Tạo dự án mới
Đầu tiên, chúng ta cần tạo một thư mục mới cho dự án và khởi tạo một dự án Node.js:
mkdir awesome-playwright-typescript
cd awesome-playwright-typescript
Bước 2: Cài đặt Playwright và TypeScript
Cài đặt Playwright cùng với các dependencies cần thiết cho TypeScript:
npm init playwright@latest
Trong quá trình cài đặt, bạn sẽ được hỏi một số câu hỏi về cấu hình. Hãy chọn các tùy chọn phù hợp:
- Do you want to use TypeScript or JavaScript? » TypeScript
- Where to put your end-to-end tests? » tests
- Add a GitHub Actions workflow? » Yes/No (tùy theo nhu cầu)
- Install Playwright browsers (can be done manually via 'npx playwright install')? » Yes
Quá trình cài đặt sẽ tạo ra cấu trúc dự án ban đầu với các file cấu hình cần thiết.
Bước 3: Kiểm tra cấu trúc dự án
Sau khi cài đặt hoàn tất, cấu trúc dự án của bạn sẽ có dạng như sau:
playwright-typescript-project/
├── node_modules/
├── package.json
├── package-lock.json
├── playwright.config.ts
├── tests/
│ └── example.spec.ts
├── tests-examples/
│ └── demo-todo-app.spec.ts
└── tsconfig.json
./tests/example.spec.ts
: Đây là file test end-to-end mẫu../tests-examples/demo-todo-app.spec.ts
- Đây là file test end-to-end mẫu cho ứng dụng Todo.
Bước 4: Tìm hiểu các file cấu hình
File playwright.config.ts
File này chứa cấu hình chính cho Playwright, bao gồm các thiết lập về trình duyệt, timeout, và các tùy chọn khác:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
File tsconfig.json
File này chứa cấu hình TypeScript cho dự án:
{
"compilerOptions": {
"target": "ES2021",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"noImplicitAny": true,
"baseUrl": ".",
"paths": {
"*": ["node_modules/*"]
},
"esModuleInterop": true
}
}
Viết test đầu tiên với Playwright và TypeScript
Để hiểu cách Playwright hoạt động, chúng ta sẽ viết một test đơn giản để kiểm tra trang chủ của Google.
Tạo file test mới
Trong thư mục tests
, tạo một file mới với tên homepage.spec.ts
:
import { test, expect } from '@playwright/test';
test('has title', async ({ page }) => {
await page.goto('https://www.google.com/');
// Kiểm tra title của trang
await expect(page).toHaveTitle(/Google/);
});
test('can search', async ({ page }) => {
await page.goto('https://www.google.com/');
// Nhập từ khóa vào ô tìm kiếm
await page.locator('textarea[name="q"]').fill('Playwright');
// Nhấn Enter để tìm kiếm
await page.keyboard.press('Enter');
// Đợi URL thay đổi và kiểm tra kết quả
await expect(page).toHaveURL(/search\?q=Playwright/);
await expect(page.locator('#search')).toContainText('Playwright');
});
Chạy test
Để chạy test, sử dụng lệnh:
npx playwright test
Để chạy test với UI mode:
npx playwright test --ui
Để chạy test trên một trình duyệt cụ thể:
npx playwright test --project=chromium
Để chạy test với một file cụ thể:
npx playwright test example
<!-- Auto generate tests with Codegen --> Để tự động tạo test với Playwright Codegen, sử dụng lệnh sau:
npx playwright codegen https://www.google.com
Đây là 1 tính năng khá hay của Playwright, giúp bạn tự động tạo mã test bằng cách ghi lại các thao tác của bạn trên trình duyệt. Bạn có thể chọn ngôn ngữ đầu ra là JavaScript hoặc TypeScript.
Cấu trúc dự án Playwright nâng cao
Để dự án dễ bảo trì và mở rộng, chúng ta nên tổ chức mã nguồn theo mô hình Page Object Model (POM).
Cấu trúc thư mục đề xuất
playwright-typescript-project/
├── node_modules/
├── package.json
├── playwright.config.ts
├── tsconfig.json
├── tests/
│ ├── example.spec.ts
│ ├── homepage.spec.ts
│ └── login.spec.ts
├── pages/
│ ├── BasePage.ts
│ ├── HomePage.ts
│ └── LoginPage.ts
├── fixtures/
│ ├── test-data.ts
│ └── auth.setup.ts
├── utils/
│ ├── helpers.ts
│ └── constants.ts
└── reports/
Tạo Page Object Model
Tạo thư mục pages
và tạo file BasePage.ts
:
import { Page, Locator } from '@playwright/test';
export class BasePage {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
async navigateTo(url: string) {
await this.page.goto(url);
}
async getTitle(): Promise<string> {
return await this.page.title();
}
async waitForPageLoad() {
await this.page.waitForLoadState('networkidle');
}
}
Tạo file HomePage.ts
:
import { Page, Locator } from '@playwright/test';
import { BasePage } from './BasePage';
export class HomePage extends BasePage {
readonly searchInput: Locator;
readonly searchButton: Locator;
constructor(page: Page) {
super(page);
this.searchInput = page.locator('textarea[name="q"]');
this.searchButton = page.locator('input[name="btnK"]');
}
async navigateToHomepage() {
await this.navigateTo('https://www.google.com');
}
async search(keyword: string) {
await this.searchInput.fill(keyword);
await this.page.keyboard.press('Enter');
await this.waitForPageLoad();
}
}
Sử dụng Page Object trong test
Cập nhật file homepage.spec.ts
để sử dụng Page Object:
import { test, expect } from '@playwright/test';
import { HomePage } from '../pages/HomePage';
test('Google search test using Page Object Model', async ({ page }) => {
const homePage = new HomePage(page);
// Điều hướng đến trang chủ
await homePage.navigateToHomepage();
// Kiểm tra title
expect(await homePage.getTitle()).toContain('Google');
// Thực hiện tìm kiếm
await homePage.search('Playwright testing');
// Kiểm tra URL sau khi tìm kiếm
await expect(page).toHaveURL(/search\?q=Playwright\+testing/);
});
Cấu hình nâng cao cho Playwright
Thêm các tùy chọn trình duyệt
Cập nhật file playwright.config.ts
để thêm các tùy chọn như headless mode, viewport size và làm chậm việc thực thi các thao tác:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30000,
expect: {
timeout: 5000
},
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [['html'], ['list']],
use: {
baseURL: 'https://www.google.com',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
viewport: { width: 1280, height: 720 },
launchOptions: {
slowMo: process.env.CI ? 0 : 100,
headless: !!process.env.CI,
}
},
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
{
name: 'Mobile Safari',
use: { ...devices['iPhone 12'] },
},
],
});
Thiết lập môi trường test khác nhau
Tạo file .env
và .env.test
để quản lý các biến môi trường:
# .env
BASE_URL=https://www.google.com
# .env.test
BASE_URL=https://staging.google.com
Cài đặt package dotenv:
npm install dotenv --save-dev
Cập nhật file playwright.config.ts
để sử dụng biến môi trường:
import { defineConfig, devices } from '@playwright/test';
import dotenv from 'dotenv';
// Tải biến môi trường từ file .env
dotenv.config({
path: process.env.NODE_ENV === 'test' ? '.env.test' : '.env',
});
export default defineConfig({
// ... các cấu hình khác
use: {
baseURL: process.env.BASE_URL,
// ... các cấu hình khác
},
});
Thực hành nâng cao với Playwright
Test API với Playwright
Playwright không chỉ dùng để test UI mà còn có thể test API:
import { test, expect } from '@playwright/test';
test('API test example', async ({ request }) => {
const response = await request.get('https://api.example.com/users');
expect(response.ok()).toBeTruthy();
const body = await response.json();
expect(body).toHaveProperty('data');
expect(Array.isArray(body.data)).toBeTruthy();
});
Screenshot và Video Recording
Thêm screenshot và video recording vào test:
import { test, expect } from '@playwright/test';
test('Screenshot example', async ({ page }) => {
await page.goto('https://www.google.com');
// Chụp screenshot toàn trang
await page.screenshot({ path: 'screenshots/google-homepage.png', fullPage: true });
// Chụp screenshot một element cụ thể
const searchBox = await page.locator('textarea[name="q"]');
await searchBox.screenshot({ path: 'screenshots/search-box.png' });
await expect(page).toHaveTitle(/Google/);
});
Sử dụng fixtures
Fixtures là một tính năng mạnh mẽ của Playwright, cho phép chia sẻ trạng thái giữa các test:
Tạo file fixtures/auth.fixture.ts
:
import { test as base } from '@playwright/test';
import { HomePage } from '../pages/HomePage';
import { LoginPage } from '../pages/LoginPage';
// Định nghĩa interface cho fixtures
interface MyFixtures {
homePage: HomePage;
loginPage: LoginPage;
loggedInPage: LoginPage;
}
// Mở rộng test với fixtures tùy chỉnh
export const test = base.extend<MyFixtures>({
homePage: async ({ page }, use) => {
const homePage = new HomePage(page);
await homePage.navigateToHomepage();
await use(homePage);
},
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await loginPage.navigateToLoginPage();
await use(loginPage);
},
loggedInPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await loginPage.navigateToLoginPage();
await loginPage.login('test@example.com', 'password123');
await use(loginPage);
},
});
export { expect } from '@playwright/test';
Sử dụng fixtures trong test:
import { test, expect } from '../fixtures/auth.fixture';
test('Login test with fixture', async ({ loggedInPage }) => {
// Test đã được đăng nhập từ fixture
await expect(loggedInPage.welcomeMessage).toBeVisible();
await expect(loggedInPage.welcomeMessage).toContainText('Welcome');
});
So sánh Playwright với các framework testing khác
Dưới đây là bảng so sánh Playwright với các framework testing phổ biến khác:
Tính năng | Playwright | Cypress | Selenium | Puppeteer |
---|---|---|---|---|
Hỗ trợ trình duyệt | Chrome, Firefox, Safari, Edge | Chrome, Firefox, Edge | Tất cả trình duyệt phổ biến | Chỉ Chrome/Chromium |
Ngôn ngữ lập trình | JavaScript, TypeScript, Python, .NET, Java | JavaScript, TypeScript | Java, C#, Python, Ruby, JS | JavaScript, TypeScript |
Auto-waiting | Có | Có | Không | Không |
Parallel testing | Có | Có (với trả phí) | Có | Cần cấu hình thêm |
Tracing & Debugging | Rất mạnh | Rất mạnh | Cơ bản | Cơ bản |
Mobile testing | Emulation | Không có sẵn | Có với Appium | Không |
Network interception | Có | Có | Cần plugin | Có |
Community & Support | Đang phát triển | Lớn | Rất lớn | Trung bình |
Độ ổn định | Cao | Cao | Trung bình | Cao |
Tích hợp Playwright vào CI/CD
GitHub Actions
Tạo file .github/workflows/playwright.yml
:
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request: