Projects (multi-browser / multi-env trong playwright.config.ts)
automationplaywright
Project là một cấu hình chạy định nghĩa trong playwright.config.ts — mỗi project có browser, viewport, baseURL, grep và dependencies riêng, và cùng một test suite nhân ra chạy trên từng project. Nó giải quyết cross-browser testing, mobile emulation, multi-env và setup auth một lần — chọn lọc bằng --project.
Khái niệm & Bản chất
- Project = một entry trong mảng
projectscủaplaywright.config.ts: gồmname,use(options riêng),testDir/testMatch/grep(chọn test),dependencies(project chạy trước). - Số lần chạy = số test × số project — 100 test trên 5 project = 500 lượt; mỗi cặp (test, project) là một kết quả riêng trên report.
- Use case chính: cross-browser (Chromium/Firefox/WebKit), device emulation (mobile viewport), multi-env (dev/staging qua
baseURL), phân nhóm (project smoke theo grep). - Dependencies: project 'setup' chạy trước (vd đăng nhập lưu
storageState), các project khác khai báodependencies: ['setup']và reuse. usecủa project merge lênusetoàn cục — project chỉ cần khai báo phần khác biệt.
Cách hoạt động & API chính
- Khai báo:
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }]—deviceslà preset sẵn củaplaywright.devices(viewport, userAgent, deviceScaleFactor...). - Chạy lọc CLI:
npx playwright test --project=chromium, nhiều project:--project=chromium --project=firefox. testMatch/testIgnore/grep/grepInverttrong project giới hạn test project đó pick — vd{ name: 'smoke', grep: /@smoke/ }.dependencies: ['setup']— setup chạy trước, thường kèmtestMatch: /.*\.setup\.ts/; setup fail → các project phụ thuộc bị skip.use.storageStateper project — mỗi project login dưới role khác nhau (admin vs user) với file state khác nhau.- Trong test đọc project hiện tại qua
test.info().project.namehoặc fixturebrowserName,isMobile.
Ví dụ & Cú pháp thực tế
- Config điển hình: setup auth 1 lần + multi-browser + mobile + project theo tag:
``
ts // playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ use: { baseURL: process.env.BASE_URL ?? 'https://dev.hoctest.com', trace: 'on-first-retry', }, projects: [ // setup chạy trước — login 1 lần, lưu storageState { name: 'setup', testMatch: /auth\.setup\.ts/ }, { name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: 'auth/user.json' }, dependencies: ['setup'], }, { name: 'firefox', use: { ...devices['Desktop Firefox'], storageState: 'auth/user.json' }, dependencies: ['setup'], }, { name: 'mobile-safari', use: { ...devices['iPhone 13'], storageState: 'auth/user.json' }, dependencies: ['setup'], }, // chỉ smoke test trên staging { name: 'staging-smoke', use: { baseURL: 'https://staging.hoctest.com' }, grep: /@smoke/, }, ], });`` - File setup login dùng chung cho mọi project phụ thuộc:
``
ts // auth.setup.ts — khớp testMatch của project 'setup' import { test as setup, expect } from '@playwright/test'; setup('đăng nhập và lưu state', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('qa@hoctest.com'); await page.getByLabel('Mật khẩu').fill('secret123'); await page.getByRole('button', { name: 'Đăng nhập' }).click(); await expect(page).toHaveURL(/dashboard/); await page.context().storageState({ path: 'auth/user.json' }); });`` - Chạy lọc theo project:
``
bash npx playwright test --project=chromium # 1 project npx playwright test --project=chromium --project=firefox npx playwright test --project=staging-smoke # smoke trên staging`` - Hai role trong cùng suite — mỗi role một project + storageState riêng:
``
ts { name: 'admin', use: { ...devices['Desktop Chrome'], storageState: 'auth/admin.json' }, grep: /@admin/, }, { name: 'customer', use: { ...devices['Desktop Chrome'], storageState: 'auth/customer.json' }, grep: /@customer/, },``
Best practices & Khi nào dùng
- Chia project theo một trục rõ ràng (browser, env, viewport, role) — tránh project 'kitchen-sink' gộp mọi thứ khó maintain.
- Setup project + dependencies cho auth là pattern chính thức của Playwright — login 1 lần, mọi test reuse
storageState, nhanh hơn login UI từng test rất nhiều. - CI theo tầng: PR/push chạy
--project=chromium(hoặc project smoke), nightly chạy all project — tiết kiệm phút build mà vẫn cover cross-browser định kỳ. - Dùng
grep/grepInverttrong project thay vì CLI flag dài — vd projectstablevớigrepInvert: /@flaky/. - Env linh hoạt hơn bằng biến môi trường (
baseURL: process.env.BASE_URL) kết hợp project — cùng project chromium chạy dev/staging tuỳ CI job.
Gotchas, So sánh & Lưu ý
- Nhân bản số lần chạy — 5 project × 200 test = 1000 lượt; không phải test nào cũng cần cross-browser, dùng
greptrong project hoặctest.skip(browserName !== ...)để cắt bớt. - Dependency project fail → mọi project phụ thuộc bị skip — setup auth hỏng thì cả suite im lặng; monitor project 'setup' riêng.
storageStatephải tồn tại trước khi test chạy — quên dependencies thì test chạy với session trống (như chưa login) và fail khó hiểu.- Tên device preset gắn sẵn
defaultBrowserTypeđúng (Desktop Safari → webkit, iPhone → webkit) — tự override sai browser sẽ lệch UA/viewport. - So sánh với matrix CI (GitHub Actions matrix browser): projects gọn hơn, chạy đủ browser trong 1 job, report gộp chung — matrix tách job song song hoá máy chủ nhưng setup lặp lại.
isMobile/browserNametronguseảnh hưởng test skip có điều kiện — kiểm tra preset device kỹ, vd iPad làisMobile: truecòn Desktop thì false.
