Wiki

← Tất cả bài wiki

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 recordHar trong browser.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/matcher giớ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 update khi 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.