Danh sách bài viết

Bài 13: Option Fixture video, screenshot, trace

Ba option fixtures video, screenshot, và trace kiểm soát việc Playwright tạo debug artifact sau mỗi test. Chúng không phải bật/tắt đơn thuần — mỗi cái có tập mode riêng (off / on / retain-on-failure / on-first-retry / ...) và object form cho phép control chi tiết hơn. Bài này deep dive từng option: mode có sẵn, object form, performance trade-off, cách combine cả ba cho từng môi trường (local dev, CI staging, production smoke), per-file override, output location, phân biệt với programmatic API, và 4 pitfall hay gặp khi cấu hình sai.

27/05/2026
14 phút đọc
0 lượt xem
1

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, trace và 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.

2

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 qua use: ở 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.

3

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.

4

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 định false (chỉ viewport). Đặt true để chụp cả nội dung scroll.
  • omitBackground: boolean — mặc định false. Khi true, 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.

5

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.

6

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',
  },
});
7

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.

8

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
},
9

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.

10

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.

11

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).

12

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
13

Tổng Kết

  • video, screenshot, trace là Option Fixtures — override được qua use: ở project / file / describe scope.
  • video có 4 mode: 'off', 'on', 'retain-on-failure', 'on-first-retry'. Object form thêm size để giảm resolution.
  • screenshot có 3 mode chính: 'off', 'on', 'only-on-failure'. v1.49 thêm 'on-first-failure'. Object form thêm fullPageomitBackground. Chỉ chụp 1 ảnh cuối test — không phải mỗi action.
  • trace có 5 mode: 'off', 'on', 'retain-on-failure', 'on-first-retry', 'on-all-retries'. v1.43 thêm 'retain-on-first-failure'. Object form control screenshots, 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. screenshot gầ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.ts hoạ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.
14

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:

  1. 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.
  2. 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.
  3. 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'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:

  1. 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.
  2. 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.

15

Bài Tiếp Theo

Bài 14 tiếp tục nhóm Fixtures - Options với actionTimeoutnavigationTimeout — hai option kiểm soát timeout ở tầng fixture thay vì hard-code trong từng assertion.

Bài 14: Option Fixture actionTimeout, navigationTimeout