Hướng dẫn dùng Claude Code và Playwright để kiểm tra giao diện web
Mình là Tony, làm và vận hành các sản phẩm web, với Claude Code là công cụ phát triển chính hằng ngày. Khi dùng AI coding, mình thấy có một khoảng cách cần kiểm soát: agent có thể sửa code, chạy test thành công rồi báo hoàn thành, trong khi người dùng vẫn gặp lỗi trên giao diện. Build thành công không chứng minh một nhân viên có thể đăng nhập, xem đúng dữ liệu, thực hiện thao tác được cấp quyền và nhận kết quả mong đợi. Đây là vấn đề cần giải quyết khi giao cho agent triển khai những tính năng có nhiều điều kiện nghiệp vụ.
Bài này thuộc series "Claude Code cho dự án thực tế", tập trung vào những vấn đề dev gặp khi đưa Claude Code vào một codebase đang phát triển. Nếu bạn làm frontend, full-stack hoặc đang dùng AI coding cho ứng dụng web, mình sẽ hướng dẫn cách kết hợp Claude Code với Playwright để kiểm tra một luồng có authentication, phân quyền và dữ liệu nhiều tổ chức. Bài viết sử dụng một dự án giả định xuyên suốt, từ thiết kế kịch bản đến thu thập bằng chứng và sửa lỗi. Bạn có thể lấy về mẫu test plan, checklist môi trường, skeleton Playwright Test và mẫu báo cáo test evidence để điều chỉnh cho dự án của mình.
1. Vì sao test pass chưa đủ để xác minh một tính năng web?
Giả sử team đang xây ứng dụng quản trị cho phép nhân viên xem báo cáo và xuất dữ liệu. Claude Code vừa hoàn thành chức năng Export, chạy bộ test hiện có và nhận kết quả thành công. Trên giao diện, nút "Xuất báo cáo" xuất hiện đúng vị trí, người quản trị click được và ứng dụng không báo lỗi. Nếu chỉ kiểm tra đến đây, agent có thể cho rằng tính năng đã hoàn thành.
Nhưng yêu cầu nghiệp vụ còn những điều kiện khác. Người chỉ có quyền xem báo cáo không được xuất dữ liệu, dù thao tác trên giao diện hay gửi request trực tiếp. Người thuộc tổ chức A không được nhận dữ liệu của tổ chức B, kể cả khi biết mã báo cáo. File Export cũng phải chứa đúng dữ liệu được phép truy cập, thay vì chỉ tải xuống thành công.
Các lớp kiểm thử trả lời những câu hỏi khác nhau:
| Lớp kiểm thử | Câu hỏi chính | Ví dụ với Export |
|---|---|---|
| Unit test | Một đơn vị logic có xử lý đúng không? | Hàm kiểm tra quyền Export trả về kết quả phù hợp với role |
| Integration test | Các thành phần phối hợp đúng không? | API áp dụng quyền truy cập và lọc dữ liệu theo tenant |
| E2E test | Luồng ứng dụng có chạy đúng từ đầu đến cuối không? | Đăng nhập, mở báo cáo, xuất dữ liệu và kiểm tra kết quả |
| Kiểm tra hành vi người dùng | Người dùng thực sự có thể hoàn thành công việc theo yêu cầu không? | Đúng role thực hiện đúng thao tác, nhận đúng dữ liệu và không vượt quyền |
Unit test có thể chứng minh hàm phân quyền hoạt động đúng, nhưng chưa chắc mọi API đều gọi hàm đó. Integration test xác minh được endpoint, nhưng chưa cho biết giao diện có hiển thị thông báo sai hoặc xử lý loading không đúng. E2E test tiến gần hơn đến hành vi thực tế, nhưng vẫn bỏ sót lỗi nếu kịch bản chỉ kiểm tra happy path. Một test đăng nhập bằng Admin, mở báo cáo và click Export có thể pass mà không cung cấp bằng chứng nào về Viewer hoặc tenant khác.
Mình tách hai câu hỏi khi đánh giá kết quả của agent: code có hoạt động theo logic đã viết không, và logic đó có đáp ứng yêu cầu nghiệp vụ không. Câu thứ nhất cần test và assertion phù hợp. Câu thứ hai cần acceptance criteria rõ ràng cùng bằng chứng để developer đối chiếu. Nếu agent tự viết cả tính năng lẫn tiêu chí kiểm tra mà không có ràng buộc độc lập, nó có thể xác minh đúng phần đã triển khai nhưng bỏ sót yêu cầu ban đầu.
2. Claude Code có thể phối hợp với browser automation như thế nào?
Claude Code có thể đọc code, chỉnh sửa file và làm việc với công cụ được kết nối. Playwright hỗ trợ tự động hóa trình duyệt để kiểm tra ứng dụng qua những thao tác tương tự người dùng. Khi kết hợp hai công cụ, agent có thể quan sát giao diện sau khi triển khai thay vì chỉ đọc kết quả từ terminal. Có hai cách sử dụng Playwright, phù hợp với những giai đoạn kiểm thử khác nhau.
Cách thứ nhất là Playwright MCP. Claude Code kết nối với Playwright MCP để mở trang, điều hướng, click, điền form, đọc trạng thái giao diện và chụp ảnh khi cần. Mình dùng cách này khi muốn khám phá một luồng chưa rõ hoặc tái hiện lỗi chưa xác định nguyên nhân. Agent có thể quan sát kết quả từng bước rồi kiểm tra tiếp dựa trên trạng thái thực tế.
Bạn thêm Playwright MCP bằng lệnh:
claude mcp add playwright -- npx @playwright/mcp@latest
Trong cú pháp này, claude mcp add đăng ký MCP server, playwright là tên server và dấu -- phân tách option của Claude với lệnh chạy server. Mặc định, Claude Code sử dụng scope local, áp dụng cho dự án hiện tại và lưu cấu hình trong ~/.claude.json. Nếu team muốn chia sẻ cấu hình qua Git, có thể chọn scope project, lưu trong .mcp.json ở gốc repository.
claude mcp add --scope project playwright -- npx @playwright/mcp@latest
Claude Code còn hỗ trợ scope user cho mọi dự án. Các lệnh claude mcp list, claude mcp get playwright và claude mcp remove playwright lần lượt giúp xem danh sách, kiểm tra chi tiết và gỡ server. Trong phiên Claude Code, /mcp hiển thị trạng thái kết nối. Claude Code mặc định chỉ nạp tên tool và chỉ dẫn của MCP server cho tới khi sử dụng, nên cài thêm server không đồng nghĩa toàn bộ định nghĩa tool đều chiếm context ngay từ đầu.
Cách thứ hai là Playwright Test. Mình yêu cầu Claude viết test vào repository để team có thể chạy lặp lại và đưa vào CI. Playwright Test sử dụng assertion để kiểm tra kết quả mong đợi, thay vì phụ thuộc vào nhận xét của agent sau mỗi lượt thao tác. Các test chạy bằng npx playwright test, còn báo cáo được mở bằng npx playwright show-report.
| Nhu cầu | Công cụ phù hợp |
|---|---|
| Khám phá luồng giao diện mới | Playwright MCP |
| Tái hiện một lỗi chưa xác định nguyên nhân | Playwright MCP |
| Quan sát trạng thái bất thường | Playwright MCP |
| Xác minh hành vi ổn định qua nhiều lần chạy | Playwright Test |
| Kiểm tra regression sau khi sửa code | Playwright Test |
| Đưa acceptance criteria vào CI | Playwright Test |

Mình dùng MCP để tìm hiểu ứng dụng và thu thập bằng chứng ban đầu, sau đó chuyển những hành vi cần bảo vệ lâu dài thành Playwright Test. Claude Code điều phối thao tác, Playwright làm việc với trình duyệt, còn ứng dụng chạy trong môi trường thử nghiệm riêng. Developer xác định điều kiện thành công và đánh giá kết quả. Cách phân chia này tránh phụ thuộc hoàn toàn vào một phiên agent khi cần kiểm tra lại tính năng.
3. Chuẩn bị môi trường kiểm thử có kiểm soát
Agent điều khiển trình duyệt có thể thực hiện những thao tác mà tài khoản đăng nhập được phép thực hiện. Với ứng dụng quản trị, các thao tác đó có thể bao gồm chỉnh sửa dữ liệu, xuất báo cáo hoặc truy cập thông tin nhạy cảm. Trước khi cho agent mở trình duyệt, mình xác định môi trường, tài khoản và phạm vi thao tác. Các giới hạn cần được thực thi bằng cấu hình và quyền truy cập thực tế, không chỉ mô tả trong prompt.
Ví dụ xuyên suốt bài là một monorepo TypeScript giả định:
project/
apps/
admin/
api/
packages/
ui/
shared/
tests/
e2e/
e2e-test-plan.md
apps/admin chứa giao diện quản trị, apps/api cung cấp API phục vụ nhiều tổ chức khách hàng, packages/ui chứa các thành phần giao diện dùng chung và packages/shared chứa định nghĩa được nhiều ứng dụng sử dụng. Team quản lý monorepo bằng pnpm, chẳng hạn chạy test API bằng pnpm -F api test. API phải thực thi tenant isolation để một tổ chức không thể truy cập dữ liệu tổ chức khác chỉ bằng cách thay mã tài nguyên. Đây là yêu cầu nghiệp vụ bắt buộc của hệ thống giả định.
Môi trường test có hai tổ chức là tenant-alpha và tenant-beta, mỗi tổ chức có dữ liệu báo cáo riêng. Team tạo ba tài khoản và seed dữ liệu đủ khác nhau để nhận diện lỗi truy cập chéo. Sau mỗi đợt kiểm thử, dữ liệu cần trở về trạng thái xác định để các lần chạy có cùng điều kiện. Toàn bộ tài khoản và báo cáo đều là dữ liệu giả, tách khỏi production.
| Tài khoản | Tenant | Role | Quyền với báo cáo |
|---|---|---|---|
| admin.alpha | Alpha | Admin | Xem và Export báo cáo Alpha |
| viewer.alpha | Alpha | Viewer | Chỉ xem báo cáo Alpha |
| admin.beta | Beta | Admin | Xem và Export báo cáo Beta |
Checklist trước khi mở trình duyệt
- [ ] Ứng dụng trỏ tới môi trường test, không phải production.
- [ ] API và database dùng dữ liệu seed riêng.
- [ ] Có tài khoản kiểm thử cho từng role cần xác minh.
- [ ] Mỗi tenant có báo cáo nhận diện được bằng mã và nội dung.
- [ ] Trạng thái khởi tạo của dữ liệu đã được xác định.
- [ ] Các tài khoản test chỉ có quyền cần thiết.
- [ ] Mật khẩu được cung cấp qua biến môi trường, không ghi trong prompt hoặc file commit.
- [ ] Team biết thao tác nào agent được thực hiện và thao tác nào cần phê duyệt.
- [ ] Có cách kiểm tra dữ liệu sau những thao tác làm thay đổi trạng thái.
Claude Code định danh MCP tool theo mẫu mcp__<server>__<tool>, nên mcp__playwright__* đại diện cho các tool thuộc server Playwright. Bạn có thể cấu hình quyền trong permissions.allow, permissions.ask và permissions.deny. Mình tách quyền sử dụng công cụ khỏi quyền truy cập ứng dụng vì hai lớp này kiểm soát những rủi ro khác nhau. Một tool được phép chạy không có nghĩa agent được quyền sử dụng mọi tài khoản hoặc truy cập mọi môi trường.
Một phiên kiểm tra có thể bắt đầu bằng prompt:
Bạn đang kiểm tra apps/admin trong monorepo này.
Chỉ sử dụng ứng dụng và dữ liệu thuộc môi trường test.
Không truy cập production hoặc dùng tài khoản thật.
Hãy đọc e2e-test-plan.md trước khi thao tác.
Sử dụng các tài khoản test được cấu hình trong môi trường.
Không in mật khẩu hoặc giá trị secret vào báo cáo.
Trước tiên, chỉ khám phá luồng xem và Export báo cáo.
Không sửa code cho tới khi hoàn thành bước tái hiện lỗi.
Với mỗi kết luận, ghi lại thao tác, kết quả quan sát
và bằng chứng. Nếu chưa xác minh được, hãy ghi rõ.
Prompt giúp agent hiểu phạm vi công việc nhưng không thay thế các giới hạn kỹ thuật. Nếu tài khoản test có quyền truy cập dữ liệu production, lời nhắc không đủ để bảo vệ dữ liệu đó. Vì thế, mình sử dụng tài khoản với permission tối thiểu, biến môi trường cho thông tin đăng nhập và dữ liệu seed riêng. Môi trường kiểm thử phải giới hạn được hậu quả ngay cả khi agent thao tác sai.
4. Chuyển acceptance criteria thành kịch bản thao tác
Yêu cầu "Viewer không được Export" có thể khiến agent chỉ viết test kiểm tra nút Export bị ẩn. Test đó đúng với một phần giao diện, nhưng không chứng minh API từ chối request. Nếu endpoint vẫn cho phép Viewer xuất báo cáo, yêu cầu nghiệp vụ chưa được đáp ứng. Mình chuyển acceptance criteria thành các kịch bản có đủ trạng thái ban đầu, hành động, kết quả mong đợi và bằng chứng.

Mỗi test case cần chỉ rõ tài khoản, role, tenant và dữ liệu sử dụng. Kết quả mong đợi phải đủ cụ thể để một developer khác xác minh độc lập. Với Export, mình tách quyền xem báo cáo, quyền xuất dữ liệu và quyền truy cập giữa các tenant thành những tiêu chí riêng. Cách này giúp agent không gộp nhiều điều kiện nghiệp vụ vào một assertion quá rộng.
Đây là mẫu e2e-test-plan.md đặt tại gốc repository:
# E2E Test Plan: Report Export
## Environment
- Application: apps/admin
- Backend: apps/api
- Target: dedicated test environment
- Dataset: seeded Alpha and Beta reports
## Acceptance criteria
AC01:
Admin Alpha can view Alpha reports.
AC02:
Admin Alpha can export Alpha reports.
AC03:
Viewer Alpha can view Alpha reports
but cannot export them.
AC04:
Accounts in Alpha cannot access Beta reports.
AC05:
Exported content must belong to the
authenticated user's permitted tenant.
## Test scenarios
### TC01: Admin export
Account: admin.alpha
Given: Alpha report exists
When: Open report and select Export
Then: Download completes
And: Exported data matches Alpha report
### TC02: Viewer restriction
Account: viewer.alpha
Given: Alpha report exists
When: Open report
Then: Export action is unavailable
And: Direct export request is rejected
### TC03: Tenant isolation
Account: admin.alpha
Given: Beta report exists
When: Attempt to access Beta report
Then: Report content is not disclosed
And: Export of Beta report is rejected
### TC04: Loading and failure
Account: admin.alpha
Given: Export operation is delayed or fails
When: Start export
Then: UI shows the expected state
And: The user can identify the outcome
## Evidence required
- Executed steps
- Expected and actual results
- Relevant assertions
- Console and network observations
- Screenshots when needed
- Download content verification
- Pass, Fail or Not verified
Team sẽ bổ sung đường dẫn, selector và tên dữ liệu seed sau khi đối chiếu ứng dụng thực tế. Mình không gắn test plan với mã báo cáo ngẫu nhiên vì các lần chạy cần dùng dữ liệu có thể tạo lại. Với từng test case, agent phải ghi Pass, Fail hoặc Not verified dựa trên bằng chứng thu được. Nếu Viewer không thấy nút Export nhưng chưa kiểm tra API, tiêu chí phân quyền đầy đủ vẫn là Not verified.
Kịch bản cũng cần mô tả trạng thái lỗi thay vì chỉ kiểm tra thao tác thành công. Ví dụ, giao diện phải phản hồi thế nào khi Export mất nhiều thời gian, request thất bại hoặc session hết hiệu lực? Team cần xác định hành vi mong đợi trước khi kiểm thử. Nếu sản phẩm chưa quy định cách xử lý, agent ghi nhận trạng thái chưa xác định thay vì tự đặt tiêu chí.
5. Cho agent thực hiện và thu thập bằng chứng
Sau khi có test plan, mình cho agent thực hiện từng kịch bản bằng Playwright MCP, chưa sửa code ngay khi gặp lỗi. Agent thao tác trên giao diện, quan sát trạng thái, kiểm tra console và network khi cần, rồi đối chiếu với acceptance criteria. Ảnh chụp chỉ cần thiết khi trạng thái giao diện giúp chứng minh phát hiện. Mình muốn mỗi kết luận gắn với một test case và các bước tái hiện rõ ràng.
Prompt thực hiện có thể viết như sau:
Đọc e2e-test-plan.md và thực hiện TC01 đến TC04
bằng Playwright MCP trên môi trường test.
Với mỗi test case:
1. Xác nhận tài khoản, role và tenant.
2. Ghi lại các thao tác trên trình duyệt.
3. Đối chiếu kết quả với acceptance criteria.
4. Kiểm tra console và network khi có lỗi.
5. Chụp ảnh ở trạng thái cần làm bằng chứng.
6. Ghi Pass, Fail hoặc Not verified.
Không suy luận API an toàn chỉ vì một nút bị ẩn.
Không tự sửa code trong giai đoạn kiểm tra.
Cuối cùng, tổng hợp những phát hiện có thể
tái hiện và những tiêu chí chưa xác minh.
Khi agent đã xác định được các thao tác ổn định, mình chuyển chúng thành Playwright Test. Trong repository giả định, test kiểm tra quyền Export nằm tại tests/e2e/report-access.spec.ts. Skeleton dưới đây đăng nhập bằng tài khoản test thông qua biến môi trường và dùng locator theo vai trò để kiểm tra giao diện. Team cần điều chỉnh đường dẫn, nhãn và dữ liệu seed cho đúng ứng dụng đang phát triển.
import { test, expect, Page } from '@playwright/test';
const baseUrl = process.env.E2E_BASE_URL;
const adminEmail = process.env.E2E_ADMIN_EMAIL;
const adminPassword = process.env.E2E_ADMIN_PASSWORD;
const viewerEmail = process.env.E2E_VIEWER_EMAIL;
const viewerPassword = process.env.E2E_VIEWER_PASSWORD;
if (
!baseUrl ||
!adminEmail ||
!adminPassword ||
!viewerEmail ||
!viewerPassword
) {
throw new Error('Missing E2E test configuration');
}
async function login(
page: Page,
email: string,
password: string
) {
await page.goto(`${baseUrl}/login`);
await page.getByRole('textbox', {
name: 'Email',
}).fill(email);
await page.getByRole('textbox', {
name: 'Mật khẩu',
}).fill(password);
await page.getByRole('button', {
name: 'Đăng nhập',
}).click();
await expect(
page.getByRole('heading', {
name: 'Tổng quan',
})
).toBeVisible();
}
test('Admin can access report export', async ({
page,
}) => {
await login(
page,
adminEmail,
adminPassword
);
await page.goto(`${baseUrl}/reports`);
await expect(
page.getByText('Báo cáo Alpha')
).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Xuất báo cáo',
})
).toBeVisible();
});
test('Viewer cannot access export action', async ({
page,
}) => {
await login(
page,
viewerEmail,
viewerPassword
);
await page.goto(`${baseUrl}/reports`);
await expect(
page.getByText('Báo cáo Alpha')
).toBeVisible();
await expect(
page.getByRole('button', {
name: 'Xuất báo cáo',
})
).toHaveCount(0);
});
test('Viewer cannot see Beta report', async ({
page,
}) => {
await login(
page,
viewerEmail,
viewerPassword
);
await page.goto(`${baseUrl}/reports`);
await expect(
page.getByText('Báo cáo Beta')
).toHaveCount(0);
});
Skeleton này mới kiểm tra quyền hiển thị trên giao diện. Test đầu tiên xác minh Admin nhìn thấy nút Export, nhưng chưa kiểm tra file tải xuống. Test thứ hai xác minh Viewer không thấy nút, nhưng chưa chứng minh API chặn request. Test thứ ba xác minh báo cáo Beta không xuất hiện trong danh sách, nhưng chưa kiểm tra đường truy cập trực tiếp đến dữ liệu tenant khác.
Team cần bổ sung test cho quá trình tải file, nội dung file và phản hồi của API để hoàn thành các acceptance criteria còn lại. Mình giữ tên test sát với assertion thực tế để tránh tạo cảm giác một yêu cầu rộng đã được xác minh. Những hành vi liên quan đến quyền truy cập ở server cần có test tương ứng tại API hoặc integration layer. Playwright Test ở giao diện là một phần của bộ kiểm thử, không phải nơi giải quyết mọi yêu cầu bảo mật.
Chạy các test đã viết bằng:
npx playwright test
Sau khi chạy, mở báo cáo:
npx playwright show-report
Khi xem kết quả, mình đối chiếu những assertion đã chạy với danh sách acceptance criteria. Nếu tất cả test pass nhưng chưa có kiểm tra nội dung file Export, tiêu chí đó vẫn chưa được xác minh. Nếu agent phát hiện lỗi ngoài phạm vi test hiện có, team cần giữ lại các bước tái hiện. Một báo cáo hữu ích phải thể hiện cả kết quả đã xác nhận lẫn những phần còn thiếu bằng chứng.
6. Kiểm tra những lỗi mà giao diện dễ che giấu
Trong tình huống Export báo cáo, mình tập trung vào bốn nhóm lỗi: phân quyền, tenant isolation, validation và trạng thái bất thường. Những lỗi này có thể tồn tại dù giao diện hiển thị bình thường và console không báo exception. Agent cần đối chiếu hành vi trên trình duyệt với phản hồi API hoặc dữ liệu đầu ra khi acceptance criteria yêu cầu. Chỉ quan sát DOM sẽ không đủ để kết luận về những giới hạn được server thực thi.
Phân quyền không đồng nghĩa với ẩn nút
Ứng dụng có thể ẩn nút Export đối với Viewer nhưng endpoint vẫn xử lý request do tài khoản đó gửi trực tiếp. Test UI cần xác minh người dùng không được cung cấp thao tác Export, còn test API phải xác minh server từ chối request thiếu quyền. Ngược lại, nếu API chặn đúng nhưng Viewer vẫn thấy nút Export, backend có thể đã bảo vệ dữ liệu trong khi giao diện chưa đáp ứng yêu cầu sản phẩm. Hai lỗi cần được ghi nhận và sửa ở đúng lớp.
Tenant isolation phải được kiểm tra bằng dữ liệu
Giả sử Admin Alpha mở danh sách báo cáo và chỉ nhìn thấy dữ liệu Alpha. Kết quả này chưa chứng minh API luôn giới hạn tài nguyên theo tenant của tài khoản đăng nhập. Nếu endpoint lấy báo cáo bằng ID nhưng bỏ qua tenant, người dùng Alpha có thể truy cập báo cáo Beta khi biết mã tài nguyên. Vì vậy, test cần kiểm tra cả đường truy cập trực tiếp và thao tác Export với báo cáo thuộc tenant khác.
Dữ liệu seed nên có dấu hiệu nhận diện riêng, chẳng hạn báo cáo Alpha chứa ALPHA-REPORT và báo cáo Beta chứa BETA-REPORT. Khi kiểm tra file tải xuống, team đối chiếu nội dung với dữ liệu seed để phát hiện bản ghi sai tenant. Tên file hợp lệ hoặc request thành công không chứng minh dữ liệu bên trong chính xác. Với hệ thống phục vụ nhiều tổ chức, đây là tiêu chí nghiệp vụ cần được kiểm tra độc lập.
Validation và trạng thái bất thường
Giao diện Export có thể hỗ trợ lọc báo cáo theo ngày hoặc điều kiện tìm kiếm. Nếu form cho phép gửi giá trị không hợp lệ, agent cần xác minh cách giao diện phản hồi và API xử lý dữ liệu đầu vào. Khi người dùng đổi bộ lọc trong lúc request đang chạy, kết quả hiển thị phải phù hợp với hành vi sản phẩm đã quy định. Những trường hợp này thường không xuất hiện trong happy path.
Trạng thái loading cũng cần được kiểm tra khi request bị trì hoãn hoặc thất bại. Một nút có thể cho click lặp lại trong lúc xử lý, hoặc giao diện có thể giữ loading mãi sau khi server trả lỗi. Team phải xác định người dùng được thử lại, nhận thông báo hay bị chặn thao tác lặp trong từng tình huống. Nếu chưa có acceptance criteria, agent ghi nhận hành vi thực tế và để trạng thái chưa xác minh.
Console sạch không chứng minh nghiệp vụ đúng
Agent có thể không phát hiện lỗi JavaScript nào, còn network request trả về phản hồi thành công. Tuy nhiên, file Export vẫn có thể chứa dữ liệu sai tenant hoặc thiếu bản ghi. Mình muốn đối chiếu bằng chứng từ trình duyệt, API và nội dung dữ liệu, thay vì chỉ dựa vào trạng thái request. Mỗi nguồn bằng chứng trả lời một phần khác nhau của yêu cầu.
Đây là mẫu báo cáo test evidence:
# Test Evidence: TC03
## Scenario
Tenant isolation for report access
## Environment
Test environment with seeded data
## Identity
Role: Admin
Tenant: Alpha
## Reproduction
1. Sign in as Admin Alpha
2. Open Alpha report list
3. Attempt access to Beta report
4. Attempt export of Beta report
## Expected
Beta report content is not disclosed.
Beta export request is rejected.
## Observed
Record actual UI and API results here.
## Evidence
- Browser state
- Relevant console output
- Relevant network request and response
- Screenshot reference if applicable
- API or integration test result
## Assessment
Pass / Fail / Not verified
## Remaining checks
Identify any unverified acceptance criteria.
Mẫu này lưu kết quả theo từng test case, gồm điều kiện kiểm thử, bước tái hiện và phạm vi kết luận. Nếu agent chưa quan sát được request hoặc chưa chạy test API, phần tương ứng vẫn phải được ghi là chưa xác minh. Ảnh chụp nên gắn với trạng thái cụ thể, chẳng hạn thông báo lỗi hoặc nút đang loading. Với lỗi dữ liệu, bằng chứng cần cho phép developer đối chiếu kết quả với bộ seed ban đầu.
7. Biến phát hiện thành sửa lỗi có thể xác minh lại
Giả sử agent phát hiện Viewer không thấy nút Export nhưng API vẫn cho phép xuất báo cáo khi gửi request trực tiếp. Một thông báo "permission bug" chưa đủ để developer tái hiện và sửa lỗi. Mình muốn agent ghi lại tài khoản test, dữ liệu ban đầu, bước thao tác, kết quả mong đợi và kết quả thực tế. Khi đã có bằng chứng, agent mới chuyển sang phân tích code.

Trong tình huống này, agent cần kiểm tra đường xử lý Export và đối chiếu permission model. Nếu server không xác minh quyền, thay đổi phải nằm ở phần kiểm soát quyền phía server, thay vì chỉ tiếp tục ẩn nút giao diện. Nếu API đã chặn đúng nhưng UI hiển thị sai, developer sửa logic hiển thị tương ứng. Mỗi thay đổi phải có test xác minh hành vi mà nó chịu trách nhiệm.
Prompt sửa lỗi có thể viết:
Dựa trên test evidence của TC02:
1. Xác định bước tái hiện lỗi và kết quả thực tế.
2. Đối chiếu với acceptance criteria.
3. Kiểm tra đường xử lý liên quan trong apps/admin
và apps/api.
4. Đề xuất thay đổi nhỏ nhất để đáp ứng yêu cầu.
5. Bổ sung test cho hành vi đang bị lỗi.
6. Chạy lại test liên quan sau khi sửa.
7. Báo cáo kết quả trước và sau thay đổi.
Không xem việc ẩn nút Export là bằng chứng
API đã kiểm tra quyền.
Nếu chưa xác minh được một tiêu chí,
hãy giữ trạng thái Not verified.
Sau khi sửa, mình cho agent chạy lại đúng kịch bản đã phát hiện lỗi. Với lỗi phân quyền Viewer, retest phải bao gồm cả giao diện và phản hồi API. Với lỗi tenant isolation, retest phải sử dụng tài khoản và dữ liệu thuộc những tenant khác nhau. Nếu chỉ chạy lại happy path bằng tài khoản Admin hợp lệ, lỗi ban đầu vẫn chưa được xác minh là đã khắc phục.
Những lỗi đã xác nhận nên được giữ lại dưới dạng regression test. Playwright MCP hỗ trợ khám phá và tái hiện, còn Playwright Test giúp team kiểm tra lại hành vi ổn định qua nhiều lần chạy. Nếu nguyên nhân nằm ở backend, cần bổ sung unit hoặc integration test phù hợp thay vì cố giải quyết toàn bộ bằng test giao diện. Mình muốn mỗi bug có đường đi rõ ràng từ phát hiện đến sửa và xác minh lại.
Đặt verification vào quy trình phát triển
Trong bài hướng dẫn viết CLAUDE.md để Claude Code hiểu đúng dự án, mình đã trình bày cách cung cấp bối cảnh repository và các quy tắc agent cần tuân thủ. Những thông tin đó giúp Claude hiểu cấu trúc code, lệnh kiểm tra và ràng buộc như tenant isolation. Nhưng hiểu repository chưa chứng minh tính năng đáp ứng yêu cầu. Developer vẫn cần kiểm tra kết quả sau khi agent triển khai.
Trong bài về quy trình làm một tính năng từ đầu đến cuối của series, verification nằm sau bước triển khai và trước khi developer chấp nhận kết quả. Agent đối chiếu code và hành vi thực tế với acceptance criteria, thay vì chỉ dựa trên build hoặc test pass. Với ứng dụng web, mình sử dụng môi trường thử nghiệm, dữ liệu seed và browser automation cho bước này. Nếu phát hiện lỗi, agent sửa phần liên quan rồi chạy lại kịch bản đã thất bại.
Quyền công cụ cũng cần được kiểm soát trong suốt quy trình. Bài về cấu hình quyền trong series sẽ đi sâu vào cách quản lý các tool Claude Code được phép sử dụng. Riêng với browser automation, mình phân biệt quyền MCP tool, quyền của tài khoản test và giới hạn môi trường. Cả ba đều ảnh hưởng trực tiếp đến phạm vi thao tác mà agent có thể thực hiện.
Khi nào có thể coi một luồng web đã được xác minh?
Với chức năng Export báo cáo, mình chỉ chấp nhận kết quả sau khi có bằng chứng cho cả hành vi được phép và hành vi bị từ chối. Admin Alpha phải xem và xuất được dữ liệu Alpha, Viewer Alpha phải bị chặn Export, còn tài khoản Alpha không được truy cập báo cáo Beta. Nội dung file tải xuống phải khớp dữ liệu mong đợi, và giao diện phải xử lý lỗi theo acceptance criteria. Những tiêu chí chưa có bằng chứng cần được giữ ở trạng thái Not verified.
Nếu test chỉ xác minh nút Export xuất hiện và click được, kết luận phải giới hạn ở hành vi đó. Nếu Playwright Test pass nhưng chưa kiểm tra nội dung file, team vẫn còn phần xác minh dữ liệu. Nếu test thất bại, agent cần giữ lại bước tái hiện và bằng chứng thay vì chỉ chạy lại cho đến khi thấy kết quả thành công. Developer quyết định chấp nhận tính năng dựa trên mức độ đáp ứng yêu cầu, không dựa riêng vào thông báo hoàn thành của công cụ.
Claude Code và Playwright giúp mình đưa kiểm tra giao diện vào cùng quy trình phát triển. MCP phù hợp để khám phá và tái hiện lỗi, Playwright Test giữ các kiểm tra lặp lại được, còn acceptance criteria xác định kết quả nào thực sự có ý nghĩa. Khi agent ghi rõ điều đã xác minh và điều còn thiếu, developer có cơ sở để quyết định sửa tiếp hay chấp nhận tính năng. Đó là kết quả mình muốn đạt được từ browser automation, thay vì chỉ có thêm một công cụ chạy test.
Các bài trong series
Series Claude Code cho dự án thực tế, mỗi bài trả lời một câu hỏi dev hay gặp khi đưa Claude Code vào dự án thật:
- Hướng dẫn viết CLAUDE.md để Claude Code hiểu đúng dự án của bạn
- Hướng dẫn dùng Claude Code để phát triển một tính năng từ đầu đến cuối
- Hướng dẫn tạo Skill cho Claude Code từ một quy trình làm việc thực tế
- Cách quản lý context và memory trong Claude Code khi làm việc với dự án lớn
- Hướng dẫn cấu hình quyền cho Claude Code bằng settings.json
All Rights Reserved