HAR Record & Replay (Ghi và phát lại traffic mạng)
automationplaywright
Playwright cho phép ghi toàn bộ request/response của trang ra file HAR (HTTP Archive) lúc chạy test lần đầu, rồi lần sau dùng page.routeFromHAR để phát lại y hệt — không cần backend, không cần viết từng mock. Cách nhanh nhất để có bộ mock data thật phục vụ test offline hoặc regression ổn định.
Khái niệm & Bản chất
- HAR (HTTP Archive) là format JSON chuẩn ghi lại toàn bộ traffic mạng: mỗi entry chứa request (URL, method, headers, postData) và response (status, headers, body base64/text). DevTools network tab xuất HAR được.
- Record: set
recordHartrongbrowser.newContext({ recordHar: { path, urlFilter } })→ context tự ghi mọi request/response trong suốt phiên làm việc ra file khi đóng context. - Replay:
page.routeFromHAR('file.har')→ Playwright đọc HAR, với mỗi request mà app bắn ra, tìm entry khớp và trả lại đúng response đã ghi — backend không cần tồn tại. - Bản chất: đây là 'snapshot' của phía mạng — thay vì viết mock bằng tay (route.fulfill), bạn ghi lại data thật một lần rồi replay. Playwright match request theo URL + method (+ postData nếu bật).
Cách hoạt động & API chính
- recordHar options:
path(bắt buộc),urlFilter(glob/regex — chỉ ghi API, bỏ ảnh/static),mode('full'mặc định hoặc'minimal'— minimal chỉ ghi phần cần để replay),content('embed'/'attach'/'omit'). - routeFromHAR options:
update: true— vừa replay vừa ghi thêm request chưa có trong HAR vào cuối file;updateContent: 'embed'để lưu body vào file;updateMode: 'minimal';url/matchergiới hạn request nào được replay. - notFound:
'abort'(mặc định — request không có trong HAR bị huỷ) hoặc'fallback'(request không khớp thì đi tiếp tới server thật — dùng khi chỉ muốn replay 1 phần). - serviceWorkers:
'block'để chặn SW chiếm request (SW không qua route, sẽ ăn mất traffic trước khi HAR kịp match).
Ví dụ & Cú pháp thực tế
- ```ts import { test, expect } from '@playwright/test'; // BƯỚC 1 — chạy 1 lần để GHI HAR (backend đang sống) test('record HAR', async ({ browser }) => { const context = await browser.newContext({ recordHar: { path: 'har/app.har', urlFilter: '/api/', // chỉ ghi API, bỏ static assets }, }); const page = await context.newPage(); await page.goto('https://app.hoctest.com'); await page.getByRole('button', { name: 'Tải dữ liệu' }).click(); // ... đi qua flow cần ghi ... await context.close(); // QUAN TRỌNG: HAR chỉ ghi ra file khi context đóng });
- ```ts // BƯỚC 2 — mọi lần chạy sau: REPLAY, không cần backend test('test offline từ HAR', async ({ page }) => { await page.routeFromHAR('har/app.har', { notFound: 'abort', // request lạ → huỷ, để phát hiện test lệch data }); await page.goto('https://app.hoctest.com'); await page.getByRole('button', { name: 'Tải dữ liệu' }).click(); await expect(page.getByText('Kết quả')).toBeVisible(); });
- ```ts // Chế độ UPDATE: replay cái đã có, ghi bổ sung cái chưa có test('update HAR khi flow thay đổi', async ({ page }) => { await page.routeFromHAR('har/app.har', { update: true, updateContent: 'embed', }); // Chạy flow mới — request khớp thì replay, request mới thì gọi thật // rồi được thêm vào app.har await page.goto('https://app.hoctest.com'); });
- ```ts // Hybrid: replay API nhưng vẫn cho ảnh/static qua server thật await page.routeFromHAR('har/api-only.har', { url: '/api/', notFound: 'fallback', // request không khớp đi tiếp tới server });
Best practices & Khi nào dùng
- Khi nào dùng: cần mock nhanh một màn hình có nhiều API, muốn test regression ổn định theo data tại 1 thời điểm, CI chạy không với được backend staging, demo/reproduce bug cho dev.
- Chỉ ghi API, bỏ static:
urlFilter: '**/api/**'+mode: 'minimal'— file HAR chứa ảnh/font sẽ phình to và replay chậm. - Commit HAR vào repo như fixture — nhưng kiểm tra kích thước; HAR chứa binary (ảnh base64) nên lọc content-type.
- Quy trình thực tế: (1) chạy record 1 lần trên env ổn định, (2) commit file, (3) replay trong mọi test, (4) định kỳ chạy lại mode
updatekhi API đổi. - Soi request lạ bằng notFound:'abort' — nếu test fail vì request bị abort nghĩa là app đổi API, HAR cần ghi lại. Đây vừa là bug detector.
Gotchas, So sánh & Lưu ý
- Quên context.close() → file HAR rỗng/chưa hoàn chỉnh — lỗi gặp nhiều nhất. HAR chỉ flush ra đĩa khi context đóng.
- Request có dynamic data không match được: POST với body chứa timestamp/token/random ID sẽ không khớp entry trong HAR → bị abort. Xử lý: lọc chỉ replay GET, hoặc dùng matcher tuỳ chỉnh, hoặc tách những request này dùng route.fulfill tay.
- Service Worker nuốt request: nếu app dùng SW (PWA), request đi qua SW không qua route → replay trật. Set
serviceWorkers: 'block'trong context options khi test. - So với route.fulfill tay: HAR nhanh để có mock cho nhiều API nhưng khó đọc/khó sửa data; fulfill rõ ràng, kiểm soát từng field nhưng mất công với màn nhiều API. Thường phối hợp: HAR cho nền, route riêng cho case cần sửa.
- HAR chứa secrets: response ghi lại có thể chứa token, cookie, thông tin user — KHÔNG commit HAR ghi từ production có data thật nhạy cảm; sanitize hoặc chỉ ghi từ env test.
- Không replay được WebSocket/SSE: HAR chỉ là HTTP request/response — streaming và WS không nằm trong file.
