Mục lục
- Mục Tiêu Bài Học
- Tổng Quan — Ba Artifact Fixtures
- Option Fixture
video— Mode Và Object Form - Option Fixture
screenshot— Mode Và Object Form - Option Fixture
trace— Mode Và Object Form - Output Location — Artifact Được Lưu Ở Đâu
- Performance Trade-off Của Từng Option
- Combine Cả Ba Theo Môi Trường
- Env-driven Config Pattern
- Per-file Override Với test.use()
- Option Fixture Vs Programmatic API
- 4 Pitfalls Thực Tế
- Tổng Kết
- Quiz Củng Cố
- Bài Tiếp Theo
Mục Tiêu Bài Học
Sau khi hoàn thành bài này, bạn sẽ:
- Biết đầy đủ các mode của
video,screenshot,tracevà object form mở rộng của từng option. - Hiểu performance trade-off của mỗi artifact và chọn mode phù hợp cho từng môi trường.
- Viết được env-driven config kết hợp cả ba option cho local dev, CI staging, và production smoke.
- Override per-file bằng
test.use()đúng cách để bật trace cho test flaky cụ thể. - Phân biệt option fixture (declarative) với
context.tracing.start()(programmatic). - Biết output location của artifact và tránh 4 pitfall hay gặp khi config sai.
Bài này không lặp lại nội dung về video modes (bài 366 Series 1) hay trace config on-first-retry (bài 381 Series 1). Focus vào tầng fixture, object form nâng cao, và cách ba option phối hợp với nhau.
Tổng Quan — Ba Artifact Fixtures
video, screenshot, trace là ba Option Fixtures thuộc nhóm artifact — chúng kiểm soát việc Playwright ghi lại "bằng chứng" trong và sau khi test chạy. Ba cái này có điểm chung:
- Đều là Option Fixtures với annotation
{ option: true }— override được quause:ở project / file / describe level. - Đều có dạng chuỗi mode đơn giản (
'off','on', ...) hoặc object form mở rộng. - Đều lưu artifact vào folder
test-results/theo cấu trúc nhất định.
Config baseline khuyến nghị cho phần lớn dự án:
// playwright.config.ts
export default defineConfig({
use: {
video: 'retain-on-failure',
screenshot: 'only-on-failure',
trace: 'on-first-retry',
},
});
Ba mode trên cân bằng giữa khả năng debug (có artifact khi fail) và overhead storage (không giữ artifact khi pass). Phần sau deep dive từng option.
Option Fixture video — Mode Và Object Form
video option yêu cầu Playwright record màn hình browser trong quá trình test. Video được lưu dưới dạng .webm.
Bốn mode chuỗi
| Mode | Hành vi |
|---|---|
'off' |
Không record. Default — không có overhead. |
'on' |
Record mọi test, giữ tất cả video sau khi chạy xong (kể cả test pass). |
'retain-on-failure' |
Record mọi test nhưng chỉ giữ video khi test fail. Video của test pass bị xóa. |
'on-first-retry' |
Chỉ bật record khi test được retry lần đầu. Lần chạy gốc không record. |
Lưu ý quan trọng về 'retain-on-failure': Playwright vẫn record trong suốt test — chỉ quyết định xóa hay giữ sau khi test kết thúc. Không phải "chỉ bật khi phát hiện fail". Điều này có nghĩa overhead recording luôn có, dù video của test pass không được giữ lại.
Object form — custom resolution
// playwright.config.ts
export default defineConfig({
use: {
video: {
mode: 'retain-on-failure',
size: { width: 640, height: 480 }, // giảm resolution để giảm file size
},
},
});
Object form thêm hai property:
mode: một trong bốn mode string trên.size:{ width, height }— resolution của video frame. Default bằng viewport size. Giảm về 640×480 giúp giảm file size đáng kể mà không mất quá nhiều chi tiết.
Khi viewport lớn (ví dụ 1920×1080), mỗi video test có thể lên tới 20-50MB. Đặt size: { width: 800, height: 600 } cắt giảm còn khoảng 5-10MB mà vẫn đủ thấy luồng test.
Option Fixture screenshot — Mode Và Object Form
screenshot option yêu cầu Playwright chụp ảnh màn hình ở cuối test (không phải mỗi action). File lưu dạng .png.
Ba mode chuỗi
| Mode | Hành vi |
|---|---|
'off' |
Không chụp. Default. |
'on' |
Chụp ảnh ở cuối mọi test — kể cả test pass. |
'only-on-failure' |
Chỉ chụp khi test fail. |
Playwright v1.49 bổ sung thêm mode 'on-first-failure' — chỉ chụp khi test fail lần đầu tiên trong run, không chụp thêm nếu retry cũng fail. Hữu ích khi muốn tránh lưu nhiều screenshot của cùng một lỗi.
Object form — fullPage và omitBackground
export default defineConfig({
use: {
screenshot: {
mode: 'only-on-failure',
fullPage: true, // chụp toàn bộ trang, không chỉ viewport
omitBackground: true, // background transparent thay vì trắng — tốt cho visual diff
},
},
});
Object form hỗ trợ:
mode: một trong các mode string trên.fullPage:boolean— mặc địnhfalse(chỉ viewport). Đặttrueđể chụp cả nội dung scroll.omitBackground:boolean— mặc địnhfalse. Khitrue, background transparent (chỉ có ý nghĩa với PNG).
Lưu ý về screenshot: 'on': Option này chụp 1 ảnh ở cuối test, không phải mỗi click hay navigation. Nếu cần screenshot tại nhiều điểm trong test, dùng page.screenshot() trong test body — đây không liên quan đến option fixture này.
Option Fixture trace — Mode Và Object Form
Trace là artifact phong phú nhất — một file .zip chứa toàn bộ timeline: screenshots theo từng action, network requests, DOM snapshots, console logs, và call stack. Mở bằng Playwright Trace Viewer (npx playwright show-trace trace.zip).
Năm mode chuỗi
| Mode | Hành vi |
|---|---|
'off' |
Không collect trace. Default. |
'on' |
Collect trace mọi test, giữ tất cả. |
'retain-on-failure' |
Collect mọi test, giữ chỉ khi fail. |
'on-first-retry' |
Chỉ bật khi test bị retry lần đầu. |
'on-all-retries' |
Bật cho tất cả các lần retry (không bật lần chạy gốc). |
Playwright v1.43 thêm mode 'retain-on-first-failure': collect trace, giữ lại chỉ khi test fail lần đầu — các lần retry tiếp theo dù fail cũng không giữ trace. Mục đích tránh tích lũy nhiều trace file của cùng một flaky test.
Object form — granular control
export default defineConfig({
use: {
trace: {
mode: 'on-first-retry',
screenshots: true, // default true — ảnh thumbnail mỗi action
snapshots: true, // default true — DOM snapshot mỗi action
sources: true, // default true — source code context tại vị trí gọi
},
},
});
Tắt bớt component để giảm file size trace khi cần:
// Trace nhẹ hơn — chỉ timeline không có DOM snapshot
trace: {
mode: 'on-first-retry',
screenshots: true,
snapshots: false, // bỏ DOM snapshot — file nhỏ hơn đáng kể
sources: true,
},
Tắt snapshots giúp giảm file trace từ 20-50MB xuống còn 5-10MB trên test phức tạp, nhưng mất khả năng xem DOM tại từng bước trong Trace Viewer. Hữu ích khi chỉ cần xem network timeline và action sequence.
Output Location — Artifact Được Lưu Ở Đâu
Mọi artifact đều nằm trong test-results/ (hoặc folder chỉ định bởi outputDir trong config). Cấu trúc thư mục:
test-results/
<file>-<test-title>-<project>/
trace.zip
video.webm
screenshot.png
test-failed-1.png (screenshot của retry 1 nếu có)
Ví dụ cụ thể — test file tests/checkout.spec.ts, test title checkout flow completes, project chromium:
test-results/
checkout-checkout-flow-completes-chromium/
trace.zip
video.webm
screenshot.png
Tên thư mục được sanitize: ký tự đặc biệt, dấu cách, dấu gạch chéo bị thay bằng dấu gạch ngang. Nếu tên quá dài, Playwright hash bớt để tránh path quá dài trên Windows.
Playwright HTML report (playwright-report/) tự link đến artifact trong test-results/ — click vào test fail trong report sẽ mở Trace Viewer inline hoặc hiển thị video và screenshot trực tiếp.
Output dir tùy chỉnh:
// playwright.config.ts
export default defineConfig({
outputDir: 'ci-artifacts', // thay vì test-results/
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
});
Performance Trade-off Của Từng Option
Ba option đều có overhead. Số liệu ước tính dựa trên test suite thông thường (10-30 giây/test, viewport 1280×720):
| Option | Mode | Duration overhead | Storage per test |
|---|---|---|---|
video |
'off' |
0% | 0 |
video |
'on' / 'retain-on-failure' |
+30–50% | 2–50MB (.webm) |
video |
'on-first-retry' |
+30–50% (chỉ lần retry) | 2–50MB khi retry |
screenshot |
'on' / 'only-on-failure' |
+1–3% (chỉ chụp cuối test) | 50–500KB (.png) |
trace |
'on' / 'retain-on-failure' |
+10–20% | 5–100MB (.zip) |
trace |
'on-first-retry' |
+10–20% (chỉ lần retry) | 5–100MB khi retry |
Video có overhead cao nhất vì cần encode frame liên tục song song với test. Trace nhẹ hơn do chỉ snapshot DOM tại mỗi action (không liên tục). Screenshot gần như không ảnh hưởng do chỉ chụp một lần cuối test.
Khuyến nghị: Chỉ bật video: 'on' hoặc trace: 'on' khi đang debug một test cụ thể, không dùng 'on' cho toàn bộ CI suite. Với test suite 100 test, chuyển từ trace: 'on-first-retry' sang trace: 'on' có thể tăng CI duration từ 10 phút lên 12–14 phút và phát sinh hàng GB artifact.
Combine Cả Ba Theo Môi Trường
Mỗi môi trường có yêu cầu khác nhau về balance giữa tốc độ, storage, và debug capability:
Local dev — debug nhanh
use: {
trace: 'on', // collect trace mọi test — debug ngay sau khi chạy
screenshot: 'only-on-failure',
video: 'off', // video tốn kém — tắt khi dev
},
Khi dev chạy local, trace 'on' cho phép mở Trace Viewer ngay cả với test pass để xem timeline, không cần reproduce lỗi. Video 'off' để test chạy nhanh.
CI staging — tiết kiệm storage, vẫn có artifact khi fail
use: {
trace: 'on-first-retry', // trace chi tiết khi retry
screenshot: 'only-on-failure', // ảnh cuối khi fail
video: 'retain-on-failure', // video khi fail — diagnose flaky test
},
Pattern khuyến nghị cho CI thông thường. Test pass không tạo artifact. Test fail (hoặc retry) đều có đủ 3 loại artifact để diagnose.
Production smoke — minimal overhead
use: {
trace: 'retain-on-failure', // trace nhưng chỉ giữ khi fail
screenshot: 'only-on-failure',
video: 'off', // production smoke không cần video
},
Production smoke test cần chạy nhanh và nhẹ. Tắt video, giữ trace và screenshot chỉ khi fail để không tốn storage khi suite pass.
Pattern combine đầy đủ cho CI
// Combo khuyến nghị — cân bằng debug vs overhead
use: {
trace: 'on-first-retry', // detailed khi retry
screenshot: 'only-on-failure', // visual khi fail
video: 'retain-on-failure', // recording khi fail
},
Env-driven Config Pattern
Dùng biến môi trường để một file config duy nhất hoạt động đúng ở cả local lẫn CI:
// playwright.config.ts
const isCI = !!process.env.CI;
export default defineConfig({
use: {
trace: isCI ? 'on-first-retry' : 'on',
screenshot: 'only-on-failure',
video: isCI ? 'retain-on-failure' : 'off',
},
});
Giải thích từng dòng:
trace: CI dùng'on-first-retry'để tiết kiệm — local dùng'on'để dev xem trace ngay sau khi chạy.screenshot:'only-on-failure'hợp lý cho cả hai môi trường.video: CI giữ video khi fail để diagnose — local tắt để test chạy nhanh.
Nếu cần phân biệt thêm nhiều môi trường (staging vs production CI):
// playwright.config.ts
const env = process.env.TEST_ENV ?? 'local'; // 'local' | 'ci-staging' | 'ci-prod'
const artifactConfig = {
local: {
trace: 'on' as const,
screenshot: 'only-on-failure' as const,
video: 'off' as const,
},
'ci-staging': {
trace: 'on-first-retry' as const,
screenshot: 'only-on-failure' as const,
video: 'retain-on-failure' as const,
},
'ci-prod': {
trace: 'retain-on-failure' as const,
screenshot: 'only-on-failure' as const,
video: 'off' as const,
},
};
export default defineConfig({
use: artifactConfig[env] ?? artifactConfig.local,
});
Chạy với: TEST_ENV=ci-staging npx playwright test. Fallback về local nếu không set.
Per-file Override Với test.use()
Khi một file test chứa test flaky cần debug chuyên sâu, override trace ở file-scope mà không cần đổi config global:
// checkout-flaky.spec.ts
import { test, expect } from '@playwright/test';
// Override trace cho toàn bộ file này
test.use({ trace: 'on' });
test('checkout flow', async ({ page }) => {
// mọi action đều được record trong trace
await page.goto('/checkout');
await page.getByRole('button', { name: 'Add to cart' }).click();
await expect(page.getByText('Cart updated')).toBeVisible();
});
Có thể override chỉ cho một describe block:
// mixed.spec.ts
test('normal test', async ({ page }) => {
// dùng trace từ global config (ví dụ: 'on-first-retry')
});
test.describe('flaky payment tests', () => {
test.use({ trace: 'on', video: 'on' }); // bật cả trace lẫn video cho block này
test('payment flow', async ({ page }) => {
// trace và video đều được record
});
test('refund flow', async ({ page }) => {
// trace và video đều được record
});
});
Quan trọng: test.use() phải đặt ở file-scope hoặc trong test.describe(), không đặt bên trong test body — Option Fixture được resolve trước khi test body chạy nên đặt trong body không có tác dụng.
Option Fixture Vs Programmatic API
Playwright cung cấp hai cách control tracing: option fixture (declarative) và programmatic API. Biết sự khác biệt để chọn đúng tool:
Option Fixture (use: { trace }) |
Programmatic API (context.tracing) |
|
|---|---|---|
| Cú pháp | Declarative trong config hoặc test.use() |
context.tracing.start() / .stop() |
| Phạm vi | Toàn test, toàn file, toàn project | Đoạn code tùy ý trong test body |
| Granularity | Bắt đầu từ đầu test, kết thúc cuối test | Bắt đầu / kết thúc tại bất kỳ điểm nào |
| Use case | Audit toàn bộ test — CI/debug | Trace đoạn code phức tạp, chunk riêng biệt |
| Kết hợp | Có thể dùng song song | Không bật programmatic khi option trace đang 'on' — conflict |
// Option fixture — toàn test
test.use({ trace: 'on' });
test('full trace', async ({ page }) => { /* ... */ });
// Programmatic — chỉ đoạn quan trọng
test('selective trace', async ({ page, context }) => {
await page.goto('/');
// Chỉ trace đoạn checkout
await context.tracing.start({ screenshots: true, snapshots: true });
await page.getByRole('button', { name: 'Checkout' }).click();
await page.getByRole('button', { name: 'Confirm' }).click();
await context.tracing.stop({ path: 'checkout-trace.zip' });
});
Programmatic API (context.tracing.start(), .startChunk(), .stop()) là nâng cao — sẽ được cover ở chương J (Tracing API chuyên sâu).
4 Pitfalls Thực Tế
1. Bật trace: 'on' hoặc video: 'on' trong CI mà không giới hạn
Đây là pitfall phổ biến nhất. Developer bật trace: 'on' khi debug local, commit config, và CI bắt đầu chậm gấp đôi:
// SAI — CI sẽ chậm và artifact storage tăng vọt
export default defineConfig({
use: {
trace: 'on', // mọi test đều collect trace → +10-20% duration, hàng GB artifact
video: 'on', // mọi test đều record → +30-50% duration, vài chục GB artifact
},
});
// ĐÚNG — chỉ bật khi cần
export default defineConfig({
use: {
trace: process.env.CI ? 'on-first-retry' : 'on',
video: process.env.CI ? 'retain-on-failure' : 'off',
},
});
2. Quên bật video và không có recording khi test fail trên CI
CI chạy headless, không có màn hình thật. Nếu config mặc định (video: 'off') và test fail, không có cách nào xem luồng thực tế:
// Thiếu — không có video artifact khi fail trên CI
export default defineConfig({
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
// video bỏ quên → 'off' theo default
},
});
// Đủ
export default defineConfig({
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure', // thêm vào
},
});
3. Mix mode không nhất quán giữa các project
// Dễ gây nhầm lẫn — project A trace 'on', project B trace 'on-first-retry'
projects: [
{
name: 'chromium',
use: { trace: 'on' }, // mọi test có trace
},
{
name: 'firefox',
use: { trace: 'on-first-retry' }, // chỉ retry có trace
},
],
// Kết quả: cùng test fail, chromium có trace đầy đủ, firefox không có
// → confusing khi debug cross-browser issue
Giải pháp: đặt mode artifact ở global use, không override per-project trừ khi có lý do rõ ràng.
4. screenshot: 'on' tưởng chụp nhiều ảnh nhưng chỉ chụp 1
Một số dev nhầm tưởng screenshot: 'on' sẽ chụp ảnh sau mỗi action (như trace). Thực tế nó chỉ chụp 1 ảnh ở cuối test:
// Hiểu sai — nghĩ sẽ có nhiều screenshot như trace
use: { screenshot: 'on' }
// Thực tế chỉ có: test-results/.../screenshot.png (1 file duy nhất)
// Nếu cần screenshot tại nhiều điểm, dùng trong test body:
test('multi-step verification', async ({ page }) => {
await page.goto('/');
await page.screenshot({ path: 'step1.png' }); // explicit
await page.getByRole('button', { name: 'Next' }).click();
await page.screenshot({ path: 'step2.png' }); // explicit
});
// Hoặc dùng trace với screenshots:true — có thumbnail tại mỗi action
Tổng Kết
video,screenshot,tracelà Option Fixtures — override được quause:ở project / file / describe scope.videocó 4 mode:'off','on','retain-on-failure','on-first-retry'. Object form thêmsizeđể giảm resolution.screenshotcó 3 mode chính:'off','on','only-on-failure'. v1.49 thêm'on-first-failure'. Object form thêmfullPagevàomitBackground. Chỉ chụp 1 ảnh cuối test — không phải mỗi action.tracecó 5 mode:'off','on','retain-on-failure','on-first-retry','on-all-retries'. v1.43 thêm'retain-on-first-failure'. Object form controlscreenshots,snapshots,sourcesđể giảm file size.- Artifact lưu trong
test-results/<file>-<title>-<project>/. video: 'on'tăng duration +30–50%.trace: 'on'tăng +10–20%, file 5–100MB.screenshotgần như không ảnh hưởng duration.- Combo khuyến nghị cho CI:
trace: 'on-first-retry',screenshot: 'only-on-failure',video: 'retain-on-failure'. - Dùng env-driven config để một file
playwright.config.tshoạt động đúng ở local lẫn CI. - Option fixture (declarative) khác
context.tracing.start()(programmatic) — fixture toàn test, programmatic kiểm soát từng đoạn.
Quiz Củng Cố
Câu 1
Config sau có vấn đề gì khi chạy trên CI với 200 test, mỗi test trung bình 20 giây?
export default defineConfig({
use: {
trace: 'on',
video: 'on',
screenshot: 'on',
},
});
Đáp án
Ba vấn đề chính:
- Duration tăng vọt:
video: 'on'thêm 30–50% duration → 200 test × 20s × 1.4 ≈ 93 phút thay vì 67 phút.trace: 'on'thêm 10–20% nữa. - Storage artifact khổng lồ: 200 video (2–50MB mỗi cái) + 200 trace (5–100MB) = có thể vài chục GB. CI artifact quota thường 1–10GB.
- artifact của test pass không cần thiết: Tất cả video và trace của test pass được giữ lại — không có giá trị debug, chỉ tốn storage.
Fix: trace: 'on-first-retry', video: 'retain-on-failure', screenshot: 'only-on-failure'.
Câu 2
Sự khác biệt giữa video: 'retain-on-failure' và video: 'on-first-retry' là gì? Khi nào nên dùng mode nào?
Đáp án
'retain-on-failure': Record mọi test ngay từ lần chạy đầu. Sau khi test kết thúc, nếu fail → giữ video, nếu pass → xóa. Overhead recording có ở mọi test.
'on-first-retry': Không record lần chạy đầu. Chỉ bật record khi test bị retry lần đầu. Overhead recording chỉ có khi có retry.
Dùng 'retain-on-failure' khi: test hay fail ngay lần đầu (không retry), cần xem toàn bộ luồng từ đầu khi fail.
Dùng 'on-first-retry' khi: test chủ yếu fail do flaky (cần retry để reproduce), muốn giảm tối đa overhead cho test ổn định.
Câu 3
Đoạn code sau có đúng không? Giải thích:
test('debug payment', async ({ page }) => {
test.use({ trace: 'on', video: 'on' });
await page.goto('/payment');
// ...
});
Đáp án
Sai. test.use() bên trong test body không có tác dụng. Option Fixtures được resolve trước khi test body chạy — context và page đã được tạo từ config hiện tại. Playwright sẽ không thay đổi trace/video setting sau khi test đã bắt đầu.
Fix: đặt test.use() ở file-scope hoặc trong test.describe():
// File-scope
test.use({ trace: 'on', video: 'on' });
test('debug payment', async ({ page }) => {
await page.goto('/payment');
});
Câu 4
Mode trace: 'retain-on-first-failure' (v1.43) khác trace: 'retain-on-failure' như thế nào?
Đáp án
'retain-on-failure': Collect trace cho mọi test. Giữ trace khi fail — bao gồm tất cả các lần retry cũng fail. Một test fail 3 lần có thể tạo ra 3 trace file.
'retain-on-first-failure': Collect trace nhưng chỉ giữ trace của lần fail đầu tiên. Nếu test retry lần 2 hoặc 3 cũng fail, trace đó bị bỏ qua (không giữ). Tránh tích lũy nhiều trace file từ cùng một flaky test liên tục fail.
Dùng 'retain-on-first-failure' khi suite có nhiều flaky test hay retry nhiều lần — giúp kiểm soát lượng artifact tốt hơn.
Câu 5
Một developer muốn giảm kích thước file trace vì CI artifact quota gần hết. Có hai giải pháp nào trong object form của trace? Trade-off là gì?
Đáp án
Hai giải pháp trong trace object form:
- Tắt
snapshots: false: Bỏ DOM snapshot tại mỗi action. File trace giảm mạnh (có thể từ 50MB xuống 10MB). Trade-off: mất khả năng xem DOM state tại từng bước trong Trace Viewer — chỉ còn timeline action và network. - Tắt
screenshots: false: Bỏ thumbnail screenshot tại mỗi action. File trace giảm vừa phải. Trade-off: mất visual preview từng bước — Trace Viewer không có ảnh minh họa tại mỗi action, khó hình dung luồng.
trace: {
mode: 'on-first-retry',
snapshots: false, // giảm kích thước nhất
screenshots: true,
sources: true,
},
Ngoài ra cũng có thể xem lại mode — chuyển từ 'on' sang 'on-first-retry' giảm số lượng trace file tạo ra là cách hiệu quả nhất để giảm tổng storage.
Bài Tiếp Theo
Bài 14 tiếp tục nhóm Fixtures - Options với actionTimeout và navigationTimeout — hai option kiểm soát timeout ở tầng fixture thay vì hard-code trong từng assertion.
