Annotations — skip, fixme, fail, slow (đánh dấu trạng thái test)
automationplaywright
Annotations là các cờ đánh dấu trạng thái của test: test.skip bỏ qua, test.fixme đánh dấu 'biết hỏng chưa fix', test.fail kỳ vọng fail (known bug), test.slow nới timeout gấp 3 — tất cả đều hỗ trợ điều kiện runtime. Chúng giải quyết việc quản lý test flaky, test chờ bug fix, và test browser-specific mà không phải comment code hay xoá test.
Khái niệm & Bản chất
test.skip— không chạy test, report hiển thị skipped. Dùng cho test chưa sẵn sàng, hoặc không áp dụng cho env hiện tại.test.fixme— về mặt chạy giống skip, nhưng ngữ nghĩa là 'biết là hỏng, chưa fix'; report tách riêng nhóm fixme để nhìn nợ kỹ thuật.test.fail— test được kỳ vọng fail: chạy bình thường, fail thật → báo 'expected to fail' (đếm pass), pass thật → báo 'unexpectedly passed' (coi như cần gỡ cờ).test.slow— đánh dấu test chạy chậm hợp lệ, timeout tự nhân 3 so với timeout mặc định.- Tất cả đều có dạng conditional:
test.skip(condition, 'lý do')— chỉ áp dụng khi condition true; lý do hiển thị trên report.
Cách hoạt động & API chính
- Gọi trong body test → annotation áp dụng tại thời điểm runtime gọi (có thể đặt sau vài dòng logic check).
- Gọi trong describe (ngoài test) → áp dụng cho toàn bộ test trong nhóm:
test.describe('x', () => { test.fixme(); ... }). - Gọi trong beforeEach → skip có điều kiện theo env/browser/feature flag trước khi test chạy.
- Dạng khai báo tĩnh qua details object:
test('name', { annotation: { type: 'issue', description: 'JIRA-123' } }, fn)— metadata custom, render trên HTML report. - Kết hợp được:
test.describe.skip,test.describe.fixme, hoặc tag kèm annotation cùng lúc.
Ví dụ & Cú pháp thực tế
- Các annotation cơ bản trong body test:
``
ts import { test, expect } from '@playwright/test'; test('upload file lớn', async ({ page }) => { test.slow(); // upload chậm hợp lệ — timeout x3 // ... }); test('tính năng export PDF', async ({ page }) => { test.fixme(); // TODO: chờ BE release API v2 // ... }); test('chỉ chạy trên Chromium', async ({ page, browserName }) => { test.skip(browserName !== 'chromium', 'Chỉ hỗ trợ Chromium'); // ... });`` - test.fail cho known-bug — tự 'bật đèn' khi dev fix xong:
``
ts test('hiển thị đúng ngày 29/02', async ({ page }) => { test.fail(true, 'BUG-88: lỗi timezone năm nhuận'); await page.goto('/calendar/2024-02'); // khi BUG-88 được fix, test này pass → report báo // 'unexpectedly passed' → nhắc mình gỡ test.fail });`` - Skip cả nhóm trong describe + skip có điều kiện theo env:
``
ts test.describe('Payment - thẻ quốc tế', () => { test.fixme(); // toàn nhóm đang chờ fix PAY-102 test('thanh toán Visa', async ({ page }) => { /* ... */ }); }); test.describe('Mobile-only', () => { test.skip(({ isMobile }) => !isMobile, 'Chỉ chạy trên project mobile'); // ... });`` - Annotation tĩnh kèm link ticket trên report:
``
ts test( 'đồng bộ giỏ hàng sau khi login', { annotation: { type: 'issue', description: 'https://jira.local/BUG-88' } }, async ({ page }) => { /* ... */ } );``
Best practices & Khi nào dùng
- Luôn kèm lý do/ticket:
test.fixme('PAY-102: chờ API v2')hoặc annotation description — ai đọc report cũng biết test này liên quan bug nào, khi nào gỡ. - Ưu tiên test.fail cho known-bug thay vì skip: test vẫn chạy mỗi build, bug fix xong nó 'unexpectedly passed' → nhắc gỡ cờ. Skip thì im lặng mãi mãi.
- Conditional skip cho test browser/env-specific thay vì comment out — nhưng nếu cả nhóm chỉ chạy 1 browser, cân nhắc dùng
greptrong project cho gọn. test.slowcho test chậm hợp lý (upload, report nặng, ví điện tử) — nhưng nó chỉ né timeout, không phải phép màu; test chậm vô lý vẫn phải tối ưu.- Review định kỳ danh sách fixme trên report — nhiều fixme dồn = nợ test suite, không phải 'coverage'.
Gotchas, So sánh & Lưu ý
- Skip trong
beforeEachvẫn tốn thời gian chạy hook trước đó (và mọi test vẫn được 'khởi động') — với điều kiện tĩnh (browser, OS), lọc bằng--grep/projectgrepInverthiệu quả hơn. test.failđảo ngữ nghĩa pass/fail — dễ confuse khi debug: test 'xanh' nhưng thực chất nó đang fail đúng như kỳ vọng. Đọc kỹ cột annotation trên report.test.slow()nhân 3 test timeout — nếu test timeout đã 60s thì slow = 180s; không tính vào expect timeout riêng.- Annotation gọi sau action vẫn hợp lệ (runtime), nhưng code sau
test.skip()trong cùng test không chạy — nó throw ngầm để abort test. - So sánh Jest: tương đương
xit/test.todo, nhưng Playwright thêmfail(expected-fail) vàslow— hai thứ Jest không có sẵn. - Đừng lạm dụng
fixmeđể 'giữ chỗ' test chưa viết — dùngtest.fixme('tên', async () => {})body rỗng hoặc chỉ khai báotest.fixme('tên', ...)cũng hiển thị fixme trên report.
