TestInfo (Metadata của test đang chạy & đính kèm bằng chứng vào report)
automationplaywright
TestInfo là object Playwright truyền vào mỗi test chứa metadata về lần chạy hiện tại: title, file, project, retry số mấy, worker, thư mục output... Quan trọng nhất là testInfo.attach() — đính kèm file/log bất kỳ (payload API, ảnh tự chụp, log hệ thống) vào HTML report để debug mà không cần mở server.
Khái niệm & Bản chất
- Mỗi test khi chạy nhận một object testInfo (tham số thứ 2 sau fixtures) — test 'tự biết' nó đang ở đâu, project nào, retry lần mấy.
testInfo.outputPath('ten-file')trả đường dẫn trongtest-results/<test>/— chỗ an toàn để ghi file mà không đè lẫn nhau khi chạy parallel.testInfo.attach()gắn attachment (text, JSON, ảnh, file) hiện thẳng trong HTML report — bằng chứng đi cùng kết quả test.testInfo.annotationsgắn chú thích hiện trên report (vd link Jira) — biến report thành tài liệu truy vết, không chỉ bảng pass/fail.
Cách hoạt động & API chính
- Metadata hay dùng:
testInfo.title,titlePath,file,project.name,retry,workerIndex,status,expectedStatus,duration,errors. - Ghi file đúng chỗ:
testInfo.outputPath('payload.json')→ file nằm trong thư mục riêng của test, tự đính kèm report. - Attach trực tiếp:
await testInfo.attach('api-response', { body: '...', contentType: 'application/json' })hoặc{ path: filePath }với file đã có. - Annotation:
testInfo.annotations.push({ type: 'issue', description: 'HT-101' })— hiện trên report, tiện trace test ↔ ticket. - Điều khiển runtime:
testInfo.skip(dieuKien, 'lý do')skip ngay trong thân test,testInfo.slow()/testInfo.setTimeout()nới timeout — mạnh hơntest.skip()khai báo tĩnh.
Ví dụ & Cú pháp thực tế
- Đính kèm response API + annotation vào report:
``
ts import { test, expect } from '@playwright/test'; test('đặt hàng COD', async ({ page, request }, testInfo) => { // Link ticket hiện trên report testInfo.annotations.push({ type: 'issue', description: 'HT-101' }); const res = await request.post('/api/cart', { data: { sku: 'PW-01', qty: 1 }, }); const body = await res.json(); // Attach payload — dev mở report là xem được request/response await testInfo.attach('cart-api-response', { body: JSON.stringify(body, null, 2), contentType: 'application/json', }); await page.goto('/cart'); await expect(page.getByText('PW-01')).toBeVisible(); });`` - Hành xử khác khi đang retry — attach thêm bằng chứng soi flaky:
``
ts test('upload file', async ({ page }, testInfo) => { await page.goto('/upload'); // ... thao tác upload if (testInfo.retry > 0) { // Chỉ lần retry mới chụp thêm bằng chứng await testInfo.attach('retry-screenshot', { body: await page.screenshot({ fullPage: true }), contentType: 'image/png', }); } });`` - Skip runtime theo điều kiện và dọn dẹp trong hook:
``
ts test('tính năng chỉ có ở prod', async ({ page }, testInfo) => { testInfo.skip(!process.env.RUN_PROD_ONLY, 'Chỉ chạy khi có RUN_PROD_ONLY'); // ... }); test.afterEach(async ({ page }, testInfo) => { // Lúc này status đã chốt — attach log nếu fail if (testInfo.status !== testInfo.expectedStatus) { await testInfo.attach('failure-shot', { body: await page.screenshot(), contentType: 'image/png', }); } });``
Best practices & Khi nào dùng
- Test nặng API: luôn
attachrequest/response payload vào report — khi fail trên CI, dev đọc report là đủ, không cần reproduce môi trường. - Luôn ghi file qua
testInfo.outputPath()thay vì hardcode./screenshots/x.png— file đi kèm đúng test, parallel không đè nhau. - Dùng
testInfo.retryđể hành xử khác ở lần retry: attach thêm screenshot/log, hoặc bỏ qua cleanup để giữ hiện trường. - Chuẩn hoá annotation trong team (
issue,docs,owner...) để filter và trace report dễ dàng. - Trong fixture tự viết cũng nhận được testInfo — attach log setup/teardown rất tiện debug lỗi xảy ra ngoài thân test.
Gotchas, So sánh & Lưu ý
testInfochỉ tồn tại trong context test/hook/fixture — helper function bên ngoài muốn dùng phải truyền tay vào.testInfo.statuschỉ chốt sau khi test xong — muốn biết pass/fail thật thì đọc trongafterEach, đừng check trong thân test.- Attach body quá lớn (vài MB text) làm HTML report phình nặng — file lớn nên ghi ra
outputPathrồi attach bằng{ path }. testInfo.skip()kháctest.skip(): skip() chạy được runtime theo điều kiện (vd thiếu env, feature flag off) — linh hoạt hơn skip khai báo tĩnh.- Annotation type là chuỗi tuỳ ý — không chuẩn hoá sẽ loạn ('bug', 'issue', 'JIRA' lẫn lộn); thống nhất một vài type cố định ngay từ đầu.
