1. 为什么端到端测试总在“最后一公里”翻车
Playwright MCP 是微软开源的一个协议服务,它把 Playwright 浏览器自动化框架封装成 MCP(Model Context Protocol)工具集,让大语言模型能够以结构化方式直接操作浏览器。简单说,它让 AI 不再靠“看截图猜按钮”,而是通过无障碍树拿到每个元素的语义角色和唯一引用,点击、输入、等待都有明确目标。它适合谁?适合那些已经用 Playwright 写测试、但被选择器频繁失效、动态加载时序、多标签页切换折腾到崩溃的开发者;也适合想把自然语言用例直接转成可执行浏览器操作的测试团队。
我见过太多项目,单元测试覆盖率 90%,CI 全绿,结果一上端到端就各种超时。问题往往不在业务逻辑,而在“页面还没渲染完就去点”“元素被遮挡”“iframe 嵌套三层找不到”这类琐碎但致命的细节。传统做法是加waitForTimeout,但这是赌博——赌页面在 3 秒内一定加载完。Playwright MCP 的思路不一样:它先让模型获取页面的无障碍快照,拿到结构化的元素引用,再基于引用执行操作。引用是稳定的,不依赖 CSS 类名或 XPath 的脆弱路径。
另一个痛点是可复现性。你本地跑通的脚本,换台机器、换个浏览器版本、换个网络环境就挂。Playwright MCP 配合统一的模型接入通道,可以把“模型决策”和“浏览器执行”解耦:模型只负责理解页面结构和决定下一步操作,浏览器执行由 Playwright 保证一致性。这样测试链路里最不稳定的“人写选择器”环节被替换成了“模型读结构”,复现概率大幅提升。
这一篇我会带你从零搭一条可复现的端到端测试链路:先配好 Playwright MCP 服务,再写一个可复制的测试脚本骨架,然后通过 TaoToken 统一 Key 接入模型能力,最后跑一次完整用例作为验收。全程命令和配置都可以直接抄。
2. Playwright MCP 服务配置与 TaoToken 统一接入
2.1 环境准备与安装
Playwright MCP 的运行依赖 Node.js 环境。建议用 Node.js 18 或 20 LTS,太老的版本在npx拉取最新包时可能报engine不匹配。先确认版本:
node -v npm -v然后全局安装 Playwright MCP 和浏览器驱动:
npm install -g @playwright/mcp@latest npx playwright install chromium这里只装 chromium 是为了减少下载体积,端到端测试大多数场景 chromium 够用。如果你需要测 WebKit 或 Firefox,把chromium换成对应名称即可。
安装完成后,可以用npx @playwright/mcp@latest --help确认命令可用。如果提示找不到命令,检查 npm 全局 bin 目录是否在 PATH 里。
2.2 在 VS Code / Cursor 中配置 MCP 服务
MCP 客户端(VS Code、Cursor、Claude Desktop 等)通过一个 JSON 配置文件来启动 MCP 服务。以 VS Code 为例,在项目根目录创建.vscode/mcp.json,写入以下内容:
{ "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest", "--headless"], "env": { "PLAYWRIGHT_BROWSERS_PATH": "0" } } } }--headless表示无头模式运行,CI 环境必须加;本地调试想看到浏览器界面就去掉这个参数。PLAYWRIGHT_BROWSERS_PATH设为0表示使用默认缓存路径,避免多项目之间浏览器版本冲突。
如果你用的是 Cursor,配置文件路径通常是~/.cursor/mcp.json,结构一样。Claude Desktop 则是claude_desktop_config.json,同样把mcpServers对象塞进去。
2.3 通过 TaoToken 统一 Key 接入模型能力
Playwright MCP 本身只负责浏览器操作,它需要一个大语言模型来“决定下一步做什么”。这里我们用 TaoToken 作为统一的模型接入通道,好处是一个 Key 可以切换不同模型,不用在多个平台之间来回改配置。
先到 TaoToken 控制台创建一个 API Key:访问https://taotoken.net/api-keys(带 UTM 的完整链接见文末 CTA),登录后点“创建密钥”,复制生成的 Key。然后设置环境变量:
export TAOTOKEN_API_KEY="sk-你的密钥" export TAOTOKEN_BASE_URL="https://taotoken.net/api"如果你在 MCP 配置里需要显式指定模型通道,可以在env里加上:
"env": { "OPENAI_API_KEY": "sk-你的密钥", "OPENAI_BASE_URL": "https://taotoken.net/api" }注意:Base URL 写https://taotoken.net/api,不要加多余的路径后缀。Model ID 根据你实际使用的模型填写,比如gpt-4o或claude-3-5-sonnet,具体以 TaoToken 文档里的模型列表为准。这三件套——Base URL、Key、Model ID——缺一不可,后面排障会反复用到。
2.4 验证 MCP 服务是否启动成功
配置写完后,重启 VS Code 或 Cursor,在 MCP 面板里应该能看到playwright服务状态为绿色。如果客户端没有图形面板,可以直接用命令行测试:
npx @playwright/mcp@latest --headless --port 8931服务启动后会监听本地端口。另开一个终端,用 curl 发一个初始化请求:
curl -X POST http://localhost:8931/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'如果返回里包含serverInfo和capabilities,说明 MCP 服务本身没问题。接下来就是让模型通过 TaoToken 通道来调用这些工具。
3. 可复制的测试脚本骨架与配置片段
3.1 项目结构与依赖
新建一个目录作为测试项目:
mkdir pw-mcp-e2e && cd pw-mcp-e2e npm init -y npm install -D @playwright/test typescript ts-node npx playwright install chromium目录结构建议这样组织:
pw-mcp-e2e/ ├── tests/ │ └── login.spec.ts ├── mcp/ │ └── config.json ├── playwright.config.ts └── package.jsonmcp/config.json放 MCP 服务配置,tests/放测试用例,playwright.config.ts放 Playwright 运行参数。
3.2 Playwright 配置文件
playwright.config.ts内容如下:
import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', timeout: 30000, retries: 1, use: { baseURL: 'http://localhost:3000', headless: true, screenshot: 'only-on-failure', trace: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, ], });retries: 1是给端到端测试留的缓冲,但不要依赖重试来掩盖真实问题。trace: 'retain-on-failure'在失败时保留追踪文件,方便回放。
3.3 MCP 服务配置片段(JSON)
mcp/config.json里把 Playwright MCP 和 TaoToken 通道都写清楚:
{ "mcpServers": { "playwright": { "command": "npx", "args": ["@playwright/mcp@latest", "--headless", "--isolated"], "env": { "OPENAI_API_KEY": "sk-你的TaoToken密钥", "OPENAI_BASE_URL": "https://taotoken.net/api", "PLAYWRIGHT_BROWSERS_PATH": "0" } } } }--isolated表示每次会话独立,关闭后状态清空。如果你需要保持登录态,去掉这个参数,改用持久化上下文。
3.4 测试脚本骨架
tests/login.spec.ts写一个登录流程的端到端用例:
import { test, expect } from '@playwright/test'; test.describe('登录流程端到端验证', () => { test('用户可以用正确凭据登录并看到仪表盘', async ({ page }) => { await page.goto('/login'); await page.getByRole('textbox', { name: '用户名' }).fill('testuser'); await page.getByRole('textbox', { name: '密码' }).fill('testpass123'); await page.getByRole('button', { name: '登录' }).click(); await expect(page.getByRole('heading', { name: '仪表盘' })).toBeVisible({ timeout: 10000, }); const url = page.url(); expect(url).toContain('/dashboard'); }); test('错误密码显示提示信息', async ({ page }) => { await page.goto('/login'); await page.getByRole('textbox', { name: '用户名' }).fill('testuser'); await page.getByRole('textbox', { name: '密码' }).fill('wrongpass'); await page.getByRole('button', { name: '登录' }).click(); await expect(page.getByText('用户名或密码错误')).toBeVisible(); }); });这个骨架的关键点:用getByRole而不是 CSS 选择器,因为无障碍角色比类名稳定得多。Playwright MCP 的快照也是基于同样的无障碍树,所以模型看到的元素引用和测试脚本里的定位方式是一致的。
3.5 让模型通过 MCP 生成测试步骤
在 MCP 客户端里,你可以用自然语言描述用例,让模型调用 Playwright MCP 的工具来执行。比如输入:
打开 http://localhost:3000/login,在用户名输入框填 testuser,密码填 testpass123,点击登录按钮,然后截图。
模型会依次调用browser_navigate、browser_snapshot、browser_type、browser_click、browser_take_screenshot等工具。每个工具的参数里,元素定位用的是快照返回的引用 ID,而不是选择器字符串。这就是结构化交互的核心优势。
4. 验证请求与成功结果
4.1 启动本地被测应用
端到端测试需要一个真实运行的应用。如果你手头没有,可以用一个简单的静态服务器模拟:
npx serve -p 3000 ./public假设public/login.html里有一个登录表单,提交后跳转到dashboard.html。确保页面里有正确的role和name属性,这样getByRole才能定位到。
4.2 运行 Playwright 测试
在项目根目录执行:
npx playwright test tests/login.spec.ts --project=chromium如果一切正常,你会看到类似输出:
Running 2 tests using 1 worker ✓ 1 tests/login.spec.ts:4:3 › 登录流程端到端验证 › 用户可以用正确凭据登录并看到仪表盘 (2.3s) ✓ 2 tests/login.spec.ts:18:3 › 登录流程端到端验证 › 错误密码显示提示信息 (1.8s) 2 passed (4.1s)两个用例都通过,说明测试链路跑通了。如果失败,Playwright 会在test-results/目录下生成截图和 trace 文件,用npx playwright show-trace打开回放。
4.3 通过 MCP 执行一次完整用例
在 MCP 客户端里,用自然语言让模型执行同样的流程。模型会先调用browser_navigate打开登录页,然后browser_snapshot获取页面结构,接着根据快照里的引用 ID 依次执行输入和点击。最后你可以让模型调用browser_take_screenshot保存结果截图。
成功的结果是:模型返回的截图里能看到仪表盘页面,且 URL 包含/dashboard。这和 Playwright 脚本跑出来的结果一致,说明 MCP 通道和直接脚本执行两条路径都验证通过。
4.4 验收标准
一次完整的验收应该包含:
- Playwright 脚本 2 个用例全部通过
- MCP 通道执行同一流程,截图结果与脚本一致
- 失败用例能正确捕获错误提示
- trace 文件可回放,能看到每一步操作
满足这四条,端到端测试链路就算可复现了。
5. 本篇常见错误排查
5.1 401 Unauthorized
这是最常见的错误,通常出现在模型调用环节。报错信息类似:
Error: 401 Unauthorized - invalid api key原因:TaoToken 的 API Key 没设置对,或者 Base URL 写错了。检查三件套:
- Base URL 必须是
https://taotoken.net/api,不要加/v1或其他后缀 - Key 以
sk-开头,复制时不要带空格 - Model ID 要和 TaoToken 文档里的一致
如果环境变量在 MCP 配置里没生效,直接在env对象里写死 Key 测试一下。确认是环境变量问题后再改回引用方式。
5.2 local proxy failed / connection refused
报错:
Error: local proxy failed: dial tcp 127.0.0.1:8931: connect: connection refused原因:MCP 服务没启动,或者端口被占用。先确认npx @playwright/mcp@latest --headless --port 8931能正常启动。如果端口冲突,换一个端口,同时更新客户端配置里的 URL。
另一个可能是防火墙拦截了本地回环连接。检查系统防火墙设置,确保127.0.0.1的入站连接没有被阻止。
5.3 reading choices 相关报错
报错:
Error: reading choices: unexpected end of JSON input原因:模型返回的响应不是合法 JSON,通常是模型通道返回了非预期格式。检查 TaoToken 的 Base URL 是否指向了正确的 API 端点。如果用的是 OpenAI 兼容接口,确认请求路径是/v1/chat/completions而不是其他。
还有一种情况是模型 ID 写错了,导致服务端返回了错误页面而不是 JSON。用 curl 直接测一下:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的密钥" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}]}'如果返回正常 JSON,说明通道没问题,问题在 MCP 客户端的配置。
5.4 OAuth 相关错误
报错:
Error: OAuth token expired or invalid原因:某些 MCP 客户端在连接远程服务时会走 OAuth 流程。如果你用的是本地npx启动的 Playwright MCP,不应该出现 OAuth 错误。检查客户端配置里是否误加了url字段而不是command。本地服务用command+args,远程服务才用url。
5.5 元素定位失败
报错:
Error: locator.click: Target closed原因:页面在操作过程中被关闭或跳转。检查是否有弹窗、新标签页或重定向。Playwright MCP 的browser_snapshot会返回当前活动页面的结构,如果页面切换了,需要重新获取快照。
另一个常见原因是元素还没渲染出来。用browser_wait_for等待特定文本出现:
{"name":"browser_wait_for","parameters":{"text":"仪表盘","time":5}}5.6 CC Switch / Cline MCP / Codex auth.json 配置要点
如果你用 CC Switch 或 Cline 的 MCP 功能,配置里必须写全三件套:
- Base URL:
https://taotoken.net/api - Key:你的 TaoToken 密钥
- Model ID:具体模型名称
Codex 的auth.json里对应字段是api_key和base_url,不要漏掉任何一个。Cline MCP 的配置在cline_mcp_settings.json,结构类似 VS Code 的mcp.json。
6. 把这条链路用起来
端到端测试最难的不是写第一个用例,而是让第一百个用例还能稳定跑。Playwright MCP 加 TaoToken 的组合,核心价值在于把“模型决策”和“浏览器执行”拆开:模型通过结构化快照理解页面,Playwright 负责精确执行。这样你改页面样式不会影响测试,换模型也不用重写脚本。
实际用的时候,建议先从登录、下单、表单提交这三类高频流程开始。每写一个用例,先用 MCP 通道让模型跑一遍,确认快照里的元素引用和脚本里的getByRole能对上。对不上的地方,往往是页面缺少正确的role或aria-label,顺手把无障碍属性补上,对真实用户也是好事。
TaoToken 的 API Key 和接入文档在这里:API Keys 页面https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys,接入文档https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc。想先验证模型对话是否通,可以用模型对话入口https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=chat。长期跑编码和 Agent 任务的话,Coding Plan 页面https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan有更详细的配额说明。
最后留一个实用技巧:在 CI 里跑 Playwright MCP 时,把--headless和--isolated都加上,并且给 MCP 服务设置一个健康检查步骤。如果服务启动失败,直接 fail 掉整个流水线,不要等到测试超时才报错。这样排查问题能省一半时间。