Cursor là IDE fork từ VS Code với Agent Mode (chế độ agent) tích hợp sẵn, cho phép AI không chỉ gợi ý code mà còn tự thực thi hành động — bao gồm cả việc điều khiển trình duyệt qua MCP. Khi bật Playwright MCP trong Cursor, bạn có một trợ lý có thể vừa đọc code frontend, vừa mở trình duyệt thật để kiểm tra hành vi UI tương ứng, rồi tự sinh và debug test E2E (end-to-end) mà không cần bạn rời khỏi editor. Bài này hướng dẫn cách kết nối Playwright MCP vào Cursor Agent Mode, cách sinh test spec dựa trên cả code và user story, quy trình chạy/debug ngay trong IDE, và các hạn chế thực tế cần lưu ý.
Kết Nối Playwright MCP Với Cursor Agent Mode
Cursor hỗ trợ cấu hình MCP server qua file .cursor/mcp.json trong project (khuyến nghị commit vào repo để chia sẻ với team) hoặc qua Settings > MCP ở phạm vi toàn cục. Cấu hình project-level:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
Sau khi lưu file, mở panel Cursor Settings, vào mục "MCP", bạn sẽ thấy server playwright xuất hiện với trạng thái kết nối. Nếu server hiện lỗi đỏ, nguyên nhân thường gặp là Node.js chưa nằm trong PATH mà Cursor sử dụng (khác với PATH của terminal hệ thống trên một số máy macOS) — cách khắc phục nhanh là chỉ định đường dẫn tuyệt đối tới node:
{
"mcpServers": {
"playwright": {
"command": "/usr/local/bin/npx",
"args": ["@playwright/mcp@latest"]
}
}
}
Để agent thực sự dùng được các tool này trong Agent Mode, mở panel Chat, chuyển sang chế độ "Agent" (thay vì "Ask" chỉ hỏi-đáp không hành động), và các tool browser_navigate, browser_snapshot, browser_click... sẽ xuất hiện trong danh sách tool khả dụng ở góc dưới khung chat. Cursor mặc định yêu cầu bạn approve từng tool call MCP lần đầu — bạn có thể chuyển sang "Auto-run" cho riêng server playwright trong Settings nếu muốn agent tự chạy liên tục không cần dừng lại hỏi mỗi bước, nhưng nên giữ approve thủ công trong giai đoạn đầu làm quen.
Đừng quên chạy trước khi bắt đầu:
npx playwright install chromium
Mẹo: Nếu Cursor báo lỗi kết nối MCP dù cấu hình đúng, thử mở một terminal tích hợp trong chính Cursor và chạy thử lệnh
npx @playwright/mcp@latesttrực tiếp — nếu lệnh chạy được trong terminal của Cursor nhưng MCP panel vẫn báo lỗi, khả năng cao là do Cursor cache phiên bản Node cũ, cần restart hoàn toàn ứng dụng (không chỉ reload window).
Sinh Test Spec Playwright Từ Code Và User Story Trong Cursor
Lợi thế lớn nhất của Cursor so với các agent CLI thuần là agent có thể đọc trực tiếp code frontend đang mở trong workspace — component React/Vue, route definition, thậm chí cả file API — trong cùng một session với việc điều khiển trình duyệt qua Playwright MCP. Điều này giúp test sinh ra bám sát đúng cấu trúc thật của UI, không phải suy đoán từ bên ngoài.
Ví dụ, giả sử bạn đang mở file src/components/SearchBar.tsx trong editor. Prompt gợi ý:
Đọc component SearchBar.tsx đang mở để hiểu các prop và data-testid đã có sẵn.
Sau đó mở http://localhost:3000/products và thử tìm kiếm với từ khoá "mouse".
Xác nhận danh sách sản phẩm được lọc đúng và URL có query param ?q=mouse.
Cursor Agent sẽ đọc file component trước để nắm được các data-testid hoặc aria-label đã được dev đặt sẵn trong code, sau đó dùng đúng những selector đó khi gọi browser_snapshot và browser_type — điều này quan trọng vì test sinh ra sẽ nhất quán với convention đặt tên đã có trong codebase, thay vì agent tự "đoán" một aria-label không tồn tại.
Sau khi xác nhận luồng đúng, yêu cầu sinh file spec:
Viết file tests/e2e/search.spec.ts theo chuẩn @playwright/test, dựa trên
data-testid thực tế có trong SearchBar.tsx. Thêm test case cho: tìm kiếm có
kết quả, tìm kiếm không có kết quả (từ khoá "zzzznotfound"), và xoá từ khoá
tìm kiếm để trở về danh sách đầy đủ.
Kết quả tham khảo (giả định component dùng data-testid="search-input"):
import { test, expect } from '@playwright/test';
test.describe('Product search', () => {
test('filters products by keyword', async ({ page }) => {
await page.goto('/products');
await page.getByTestId('search-input').fill('mouse');
await page.getByTestId('search-input').press('Enter');
await expect(page).toHaveURL(/\?q=mouse/);
await expect(page.getByRole('listitem')).toHaveCount(1);
});
test('shows empty state for no matching results', async ({ page }) => {
await page.goto('/products');
await page.getByTestId('search-input').fill('zzzznotfound');
await page.getByTestId('search-input').press('Enter');
await expect(page.getByText('No products found')).toBeVisible();
});
test('clearing search restores the full product list', async ({ page }) => {
await page.goto('/products?q=mouse');
await page.getByTestId('search-input').clear();
await page.getByTestId('search-input').press('Enter');
await expect(page.getByRole('listitem')).toHaveCount(await page.getByRole('listitem').count());
});
});
Mẹo: Trước khi yêu cầu Cursor sinh test, luôn mở đúng file component liên quan trong tab đang active — Cursor Agent Mode ưu tiên đọc context từ các file đang mở trong editor, nên test sinh ra sẽ chính xác hơn nhiều so với việc chỉ mô tả bằng lời mà không cho agent thấy code thật.
Chạy Và Debug Test Playwright Qua Cursor Agent Mode
Sau khi có file .spec.ts, Cursor cho phép chạy và debug ngay trong terminal tích hợp mà không cần rời IDE. Yêu cầu agent:
Chạy file tests/e2e/search.spec.ts vừa tạo. Nếu có test fail, đọc kỹ error
message và stack trace, đề xuất fix cụ thể, và giải thích ngắn gọn nguyên
nhân trước khi sửa code.
Agent sẽ chạy npx playwright test tests/e2e/search.spec.ts trong terminal tích hợp, đọc kết quả output trực tiếp (bao gồm cả đường dẫn tới HTML report và screenshot khi fail), và nếu phát hiện lỗi, nó sẽ tự phân tích. Một pattern thường gặp: nếu test fail vì "element not found", Cursor Agent có thể tự gọi lại browser_snapshot để kiểm tra lại cấu trúc trang hiện tại — có thể selector đã đúng lúc bạn viết nhưng UI đã thay đổi kể từ đó — rồi đề xuất cập nhật selector cho khớp.
Với các trường hợp fail phức tạp hơn (ví dụ do race condition, phần tử chưa render kịp), yêu cầu agent debug sâu hơn bằng cách chạy ở chế độ có trace:
npx playwright test tests/e2e/search.spec.ts --trace on
Sau đó yêu cầu agent:
Test vẫn fail không ổn định (flaky). Chạy lại với --trace on, mở file trace
vừa sinh ra và cho tôi biết chính xác thời điểm nào phần tử "No products found"
xuất hiện so với thời điểm assertion được gọi.
Cursor Agent có thể đọc file trace (dạng zip chứa timeline hành động) để xác định chính xác vấn đề timing, từ đó đề xuất thêm await expect(...).toBeVisible() với auto-retry đúng cách thay vì waitForTimeout cứng — đây là một trong những giá trị thực tế lớn nhất của việc để AI debug test flaky, vì việc đọc trace file thủ công khá tốn thời gian với engineer chưa quen.
Mẹo: Khi gặp test flaky (không ổn định), đừng yêu cầu agent "sửa cho hết lỗi" một cách mơ hồ — hãy yêu cầu cụ thể "chạy lại 5 lần liên tiếp với
--repeat-each=5và cho biết tỉ lệ fail", điều này giúp bạn xác nhận được liệu fix của agent có thực sự giải quyết root cause hay chỉ là giảm khả năng fail một cách tình cờ.
Hạn Chế Và Cách Khắc Phục Khi Dùng Playwright MCP Trong Cursor
Một số hạn chế thực tế bạn sẽ gặp khi dùng Playwright MCP trong Cursor, cùng cách xử lý:
- Agent Mode có thể timeout với luồng dài nhiều bước: nếu một luồng cần hơn 15-20 tool call liên tiếp (ví dụ luồng đăng ký nhiều bước xác thực), Cursor đôi khi dừng agent giữa chừng do giới hạn số lượt gọi tool trong một turn. Cách khắc phục: chia luồng dài thành nhiều prompt tuần tự, mỗi prompt xử lý một giai đoạn, thay vì yêu cầu agent tự hoàn thành toàn bộ trong một lượt.
- Trình duyệt chạy ẩn (headless) theo mặc định khiến khó quan sát trực tiếp: Playwright MCP mặc định chạy headless, nên bạn không thấy cửa sổ Chromium mở lên trong lúc agent thao tác. Nếu cần quan sát trực quan để debug, thêm flag
--headedvào cấu hình args của server trong.cursor/mcp.json, nhưng nhớ đổi lại thành headless khi chạy CI để tránh lỗi thiếu display trên máy chủ. - Đôi khi agent quên context code đã đọc trước đó sau nhiều lượt tool call browser: vì mỗi
browser_snapshottrả về một lượng lớn accessibility tree, sau nhiều lượt agent có thể "quên" chi tiết cụ thể trong file component đã đọc ở đầu session. Giải pháp thực tế: nhắc lại ngắn gọn thông tin quan trọng (ví dụ têndata-testid) ngay trong prompt sinh test cuối, thay vì trông đợi agent tự nhớ lại chính xác từ đầu session. - Chưa hỗ trợ tốt multi-tab và iframe phức tạp: tương tự các agent khác dùng Playwright MCP, các trang có nhiều iframe lồng nhau (ví dụ widget thanh toán bên thứ ba) thường cần can thiệp thủ công vào code sau khi agent sinh bản đầu, vì accessibility tree qua iframe không luôn được expose đầy đủ.
Mẹo: Với luồng dài, hãy yêu cầu Cursor Agent tóm tắt lại các bước đã thực hiện thành một danh sách ngắn ngay giữa session (ví dụ "tóm tắt lại 5 bước vừa làm") trước khi tiếp tục — điều này vừa giúp bạn xác nhận agent hiểu đúng luồng, vừa giữ context gọn hơn cho các bước tiếp theo.
Mẹo Tổng Hợp Khi Dùng Playwright MCP Với Cursor
Mẹo: Kết hợp Playwright MCP với tính năng "Rules" của Cursor (file
.cursor/rules/*.mdc) để định nghĩa sẵn convention viết test cho project — ví dụ "luôn dùng getByTestId với các data-testid có sẵn, không tự tạo selector mới" — nhờ vậy mọi lần agent sinh test trong tương lai đều tuân theo chuẩn chung của team mà bạn không cần nhắc lại trong từng prompt.