Viết visual regression Playwright, dùng AI triage snapshot an toàn
Thiết kế snapshot Playwright ổn định, giảm nhiễu do môi trường và phần tử động. Dùng AI để hỗ trợ đọc visual diff, nhưng QA vẫn xác minh theo acceptance criteria trước khi chặn PR hoặc cập nhật baseline.
Visual regression có thể chặn một lỗi UI thật — nhưng cũng dễ làm pipeline đỏ chỉ vì font, hover hoặc môi trường chạy khác baseline.
Với Playwright, mục tiêu không phải là làm snapshot “ít fail bằng mọi giá”. Mục tiêu là khiến mỗi lần fail trở thành tín hiệu đủ rõ để QA quyết định: đây là lỗi UI, thay đổi hợp lệ hay nhiễu render.
AI có thể hỗ trợ đọc và phân loại ảnh khác biệt trong bước triage. Tuy nhiên, quyết định chặn PR hay cập nhật baseline vẫn cần dựa trên acceptance criteria và review của người kiểm thử.
Playwright so sánh snapshot như thế nào?
Playwright Test tạo và so sánh screenshot bằng await expect(page).toHaveScreenshot().
Ở lần chạy đầu tiên, nếu chưa có ảnh chuẩn, Playwright tạo snapshot tham chiếu. Các lần chạy sau, ảnh hiện tại sẽ được so sánh với snapshot đó.
ts
import { test, expect } from '@playwright/test';
test('example test', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveScreenshot();
});
Snapshot mặc định được lưu dưới dạng PNG. Tên file có thể gồm tên test, browser và nền tảng chạy. Điều này cần thiết vì font, browser engine và hệ điều hành có thể tạo ra kết quả render khác nhau.
Điểm cần nhớ: snapshot chỉ cho biết ảnh hiện tại có khác baseline hay không. Nó không tự kết luận chức năng đúng hay sai.
Vì vậy, visual test nên đi cùng assertion chức năng, chẳng hạn kiểm tra text, URL, trạng thái hoặc khả năng hiển thị của phần tử.
Playwright cũng chụp nhiều lần cho đến khi hai ảnh liên tiếp khớp nhau rồi lưu ảnh cuối. Tuy nhiên, tài liệu vẫn cảnh báo ảnh có thể khác theo OS, phiên bản, cấu hình máy, phần cứng, nguồn điện, chế độ headless và các yếu tố khác.
Nguyên tắc: tạo baseline và chạy lại visual suite trong môi trường nhất quán.
Giảm nhiễu trước khi nhờ AI
AI không thể sửa một visual suite vốn thiếu ổn định. Trước hết, hãy làm test có tính xác định: cùng dữ liệu và trạng thái thì cho ra cùng ảnh.
1. Chụp đúng vùng cần bảo vệ
Nếu cần bảo vệ một badge trạng thái hoặc thẻ thanh toán, hãy chụp locator thay vì toàn bộ trang. Cách này giảm ảnh hưởng từ banner, footer hay nội dung không thuộc phạm vi test.
ts
await expect(page.getByTestId('status')).toHaveScreenshot();
Trước khi chụp, chờ UI đạt trạng thái mong đợi bằng assertion tự retry của Playwright:
ts
await expect(page.getByTestId('status')).toHaveText('Submitted');
await expect(page.getByTestId('status')).toHaveScreenshot();
Các web assertion dạng async sẽ kiểm tra lại cho đến khi điều kiện đạt hoặc hết timeout. Timeout assertion mặc định là 5 giây.
Điều này giúp tránh chụp đúng lúc UI còn đang tải, rồi biến trạng thái tạm thời thành visual diff ngẫu nhiên.
2. Xử lý phần tử động có chủ đích
Playwright hỗ trợ stylePath: áp dụng CSS riêng trong lúc chụp screenshot. Đây là cách hữu ích để loại khỏi ảnh những vùng biến động không thuộc phạm vi kiểm thử visual.
Ví dụ, ẩn iframe khi iframe đó không phải đối tượng cần kiểm thử:
css
iframe {
visibility: hidden;
}
ts
import path from 'path';
import { test, expect } from '@playwright/test';
test('page screenshot', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveScreenshot({
stylePath: path.join(dirname, 'screenshot.css'),
});
});
Hover cũng có thể làm snapshot thay đổi. Trước khi chụp, di chuyển chuột tới vị trí không kích hoạt hiệu ứng hover:
ts
await page.mouse.move(0, 0);
await expect(page).toHaveScreenshot();
> Che phần tử động là quyết định về phạm vi test, không phải cách làm pipeline xanh. Nếu iframe chứa luồng quan trọng như thanh toán hoặc thông báo lỗi, hãy tạo test riêng cho vùng đó trong điều kiện ổn định hơn.
3. Chỉnh ngưỡng diff, nhưng không nới cho qua
Playwright dùng thư viện pixelmatch để so sánh ảnh.
threshold: mức chênh lệch màu được xem là khác nhau; mặc định là 0.2.
maxDiffPixels: số pixel khác biệt được chấp nhận; mặc định chưa được đặt.
Ví dụ cấu hình dùng chung cho dự án:
ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
expect: {
toHaveScreenshot: {
maxDiffPixels: 100,
threshold: 0.1,
},
},
});
Đừng dùng một ngưỡng rộng cho mọi màn hình. Một cấu hình quá dễ dãi có thể bỏ lọt lỗi như mất icon, sai màu cảnh báo, vỡ viền hoặc cắt chữ.
Hãy ghi rõ trong test plan lý do màn hình nào được phép có sai khác nhỏ và mức sai khác đó có ý nghĩa gì.
Quy trình AI triage cho visual diff trong PR
Tài liệu Playwright mô tả cơ chế tạo, so sánh và cập nhật snapshot. Việc dùng AI để đọc ảnh khác biệt là một quy trình bổ sung do đội QA thiết kế.
Một workflow an toàn có thể gồm:
Chạy visual suite trong môi trường nhất quán với nơi tạo baseline.
Khi test fail, thu thập snapshot baseline, ảnh thực tế và mô tả thay đổi trong PR.
Chỉ gửi dữ liệu đã được xử lý phù hợp với chính sách bảo mật của tổ chức vào công cụ AI được phê duyệt.
Yêu cầu AI phân loại thay đổi, chỉ ra vùng ảnh hưởng và đề xuất bước xác minh.
Tester đối chiếu với acceptance criteria, kiểm tra lại trên browser và chạy lại test khi cần.
Chỉ cập nhật snapshot khi thay đổi là có chủ đích và đã được review.
Lệnh cập nhật snapshot:
bash
npx playwright test --update-snapshots
Thư mục snapshot nên được commit vào version control. Mọi thay đổi snapshot cần được review như thay đổi mã nguồn.
Prompt mẫu để AI hỗ trợ đọc ảnh
Dùng prompt này với công cụ AI nội bộ hoặc công cụ đã được tổ chức phê duyệt. Đính kèm baseline và ảnh thực tế nếu chính sách cho phép.
text
Bạn là QA reviewer cho visual regression.
Bối cảnh tính năng:
<feature spec hoặc acceptance criteria>
Thay đổi dự kiến trong PR:
<PR summary>
Phạm vi screenshot:
<tên trang hoặc component>
Hãy phân loại thay đổi thành một trong các nhãn:
expected-ui-change
probable-rendering-noise
probable-ui-defect
insufficient-evidence
Trả lời theo cấu trúc:
Vùng khác biệt và mô tả trực quan.
Thay đổi có khớp với nội dung dự kiến trong PR không?
Dấu hiệu có thể là lỗi UI: che khuất, cắt chữ, sai trạng thái,
mất thành phần, lệch bố cục hoặc sai tương phản.
Dấu hiệu có thể là nhiễu: font, anti-aliasing, hover, nội dung động,
iframe hoặc khác biệt môi trường.
Các bước QA cần xác minh trên browser.
Mức độ tự tin: thấp, trung bình hoặc cao.
Không đề xuất cập nhật baseline nếu chưa xác minh acceptance criteria.
AI nên đưa ra giả thuyết và ưu tiên kiểm tra, không thay thế quyết định của reviewer.
Ví dụ: kiểm thử trạng thái gửi biểu mẫu
Giả sử yêu cầu là: sau khi gửi biểu mẫu, trạng thái hiển thị Submitted và vùng trạng thái không bị vỡ giao diện.
Test nên kiểm tra cả nội dung lẫn hình ảnh:
ts
import { test, expect } from '@playwright/test';
test('submitted status is readable', async ({ page }) => {
await page.goto('<test-url>');
await expect(page.getByTestId('status')).toHaveText('Submitted');
await expect(page.getByTestId('status')).toHaveScreenshot();
});
Nếu snapshot fail, AI có thể chỉ ra rằng thay đổi tập trung ở badge trạng thái và nghi ngờ màu chữ đã đổi. Đây chỉ là giả thuyết, chưa phải bug report.
QA cần xác minh:
Text thực tế có còn là Submitted không?
Badge có hiển thị và nằm trong viewport không?
Có phần tử khác che badge không?
Diff có tái hiện khi chạy lại trong cùng môi trường không?
PR có chủ đích thay đổi style badge không?
Locator getByTestId('status') có đang trỏ đúng thành phần không?
Nếu UI thực sự sai, bug report nên kèm ảnh baseline, ảnh thực tế, môi trường chạy, bước tái hiện và kết quả mong đợi theo spec.
Nếu thay đổi hợp lệ, reviewer xác nhận trước khi cập nhật snapshot.
Rủi ro cần chặn trong quy trình
Không đưa vào AI công khai ảnh có dữ liệu khách hàng, token, cookie, credential trong URL hoặc thông tin nội bộ.
Ưu tiên dữ liệu test đã che thông tin nhạy cảm và tuân thủ chính sách công cụ của tổ chức.
AI cũng có thể hiểu sai ảnh, không nắm business rule hoặc bỏ qua thay đổi nhỏ nhưng nghiêm trọng. Vì vậy, không nên thiết lập cơ chế “AI nói là noise thì tự động pass”.
Cổng chặn PR vẫn nên dựa trên:
Assertion của Playwright;
Acceptance criteria;
Review snapshot;
Xác minh của QA hoặc người chịu trách nhiệm chất lượng.
Checklist trước khi chặn PR vì visual diff
[ ] Baseline và CI chạy trong môi trường render nhất quán.
[ ] Test chờ UI đạt trạng thái mong đợi trước khi screenshot.
[ ] Vùng chụp đúng phạm vi cần bảo vệ.
[ ] Hover, iframe và nội dung động đã được xử lý có chủ đích.
[ ] Diff được đối chiếu với spec và thay đổi trong PR.
[ ] AI chỉ hỗ trợ triage, không tự cập nhật baseline hay tự duyệt PR.
[ ] Snapshot thay đổi được review và commit cùng mã nguồn.
Visual regression đáng tin cậy không đến từ việc ép snapshot luôn xanh. Nó đến từ một quy trình có ngữ cảnh: lỗi UI thật thì chặn PR, thay đổi hợp lệ thì cập nhật baseline, còn nhiễu thì xử lý tận gốc trong thiết kế test.