☰
用 Playwright + Claude Code 做自动化测试:一套从0到1跑通的实战流程(TaoToken 统一 Key 接入版)
2026/10/18 18:52:11 网站建设 项目流程

1. 从零跑通 Playwright + Claude Code 自动化测试的真实场景

如果你正在搜「Playwright Claude Code 自动化测试怎么从零跑通」,大概率遇到过这种局面:脚本能生成,但一跑就红;选择器今天能用,明天页面改个 class 就全挂;CI 上偶发失败,本地却怎么都复现不出来。问题往往不在 Playwright 本身,而在于 AI 生成代码时缺少项目上下文,以及模型调用链路不稳定。

我这套流程的目标很明确:让 Claude Code 真正读懂你的 Playwright 项目结构,生成可维护的端到端测试,并且把模型请求统一走 TaoToken 的 Key,避免多工具切换时 endpoint 和鉴权各写一套。适合谁?适合已经会写基础 JS/TS、想用 AI 加速 E2E 测试、但被「生成即废」折磨过的开发者。

整条链路分四段:项目约束文件 → Claude Code 接入配置 → 测试脚本生成与执行 → 失败用例回喂修复。每一步都有可复制的配置和命令,你照着做就能跑通。下面先讲清楚为什么这套组合值得用,再进入具体配置。

Playwright 的 API 语义化程度高,getByRole、getByTestId、expect(locator).toBeVisible()这些写法本身就接近自然语言描述,模型生成时不容易跑偏。Claude Code 的优势是能读取项目文件,包括你的CLAUDE.md、playwright.config.ts、已有的 Page Object,这让生成结果从「看起来像测试」变成「能直接进项目」。

但有个前提:你得先把项目约束写清楚,否则模型只能靠猜。很多人跳过这一步,直接让 AI 写登录测试,结果选择器用了一堆div:nth-child(3),断言只判断元素存在,等待用waitForTimeout(3000)。这不是模型不行,是输入信息不够。

所以第一步不是写 prompt,而是给项目建一个「说明书」。这个文件放在根目录,Claude Code 每次会话都会读取,相当于给模型一份项目地图。内容不需要长,但要把技术栈、测试目录、命名规范、选择器优先级写明白。

# CLAUDE.md ## 项目信息 - 前端:React + TypeScript + Vite - 测试框架:Playwright - 测试目录:tests/e2e/ - Base URL:http://localhost:3000 - 包管理器:pnpm ## 测试规范 - 使用 Page Object 模式,页面对象放 tests/e2e/pages/ - 优先使用>{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "sk-你的TaoToken密钥", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" } }

文件路径:macOS/Linux 是~/.claude/settings.json,Windows 是C:\Users\你的用户名\.claude\settings.json。如果目录不存在就手动创建。

如果你更习惯用环境变量,也可以这样写:

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="sk-你的TaoToken密钥" export ANTHROPIC_MODEL="claude-sonnet-4-20250514"

但环境变量在每次新开终端都要重新 source,容易忘。settings.json 更省心。

还有一种情况:你用的是 Codex 或 Cline 这类工具,它们读auth.json。Codex 的 auth.json 路径通常在~/.codex/auth.json,内容格式如下:

{ "OPENAI_API_KEY": "sk-你的TaoToken密钥", "OPENAI_BASE_URL": "https://taotoken.net/api" }

注意 Codex 用的是 OpenAI 兼容格式,字段名是OPENAI_API_KEY和OPENAI_BASE_URL,但值填 TaoToken 的 Key 和地址。Model ID 在 Codex 的配置文件里单独指定,通常是config.toml:

model = "claude-sonnet-4-20250514" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "OPENAI_API_KEY"

这样 Codex 就会走 TaoToken 的通道。三件套对齐后,Claude Code 和 Codex 可以共用同一个 Key,切换工具时不用重新申请。

配置完成后,先别急着写测试。用一条最小请求验证链路是否通。下一节给验证命令。

3. 可复制配置:playwright.config.ts 与 Claude Code 协同设置

这一节给完整可复制的配置文件,包括playwright.config.ts、Page Object 模板、以及 Claude Code 读取项目时的关键设置。目标是让你复制粘贴后就能跑。

先看playwright.config.ts。这个文件决定了测试怎么跑、报告怎么出、失败怎么重试。配置里要显式声明testDir,和CLAUDE.md里写的一致,否则 Claude Code 生成的文件可能放错目录。

import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests/e2e', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: [ ['html', { outputFolder: 'playwright-report' }], ['list'] ], use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, ], webServer: { command: 'pnpm dev', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, timeout: 120 * 1000, }, });

几个关键点:trace: 'on-first-retry'让你在失败时能回放操作步骤;webServer自动拉起开发服务,不用手动开终端;retries在 CI 下设 2,本地设 0,避免本地掩盖 flaky。

然后是 Page Object 模板。Claude Code 生成代码时会参考已有 Page Object 的写法,所以先建一个标准模板,后续生成会保持一致风格。

// tests/e2e/pages/LoginPage.ts import { Page, Locator, expect } from '@playwright/test'; export class LoginPage { readonly page: Page; readonly usernameInput: Locator; readonly passwordInput: Locator; readonly submitButton: Locator; readonly errorMessage: Locator; constructor(page: Page) { this.page = page; this.usernameInput = page.getByTestId('login-username'); this.passwordInput = page.getByTestId('login-password'); this.submitButton = page.getByTestId('login-submit'); this.errorMessage = page.getByTestId('login-error'); } async goto() { await this.page.goto('/login'); } async login(username: string, password: string) { await this.usernameInput.fill(username); await this.passwordInput.fill(password); await this.submitButton.click(); } async expectError(text: string) { await expect(this.errorMessage).toHaveText(text); } }

这个模板里所有定位都用getByTestId,和CLAUDE.md的规范一致。Claude Code 读到这个文件后,生成新页面对象时会沿用同样的结构。

接下来是 Claude Code 的项目级配置。除了~/.claude/settings.json的全局配置,你还可以在项目根目录放.claude/settings.json,让项目内的会话走特定模型。比如测试项目想用更稳定的模型:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_AUTH_TOKEN": "sk-你的TaoToken密钥", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" }, "permissions": { "allow": [ "Read", "Write", "Bash(pnpm playwright test:*)", "Bash(pnpm dev)" ] } }

permissions.allow里把常用命令加白名单,Claude Code 执行时不用每次确认。注意Bash(pnpm playwright test:*)这种写法是前缀匹配,:*表示允许带参数。

配置齐了之后,目录结构应该是这样:

project/ ├── CLAUDE.md ├── playwright.config.ts ├── package.json ├── .claude/ │ └── settings.json └── tests/ └── e2e/ ├── pages/ │ └── LoginPage.ts └── login.spec.ts

login.spec.ts先留空或者写个占位,下一步让 Claude Code 生成。

4. 验证请求:生成测试脚本并确认执行结果一致

这一节验证两件事:Claude Code 能否通过 TaoToken 正常响应,以及生成的测试脚本能否真实跑通。先做最小请求验证,再生成完整用例。

最小验证用 curl 发一条消息,确认 endpoint 和 Key 有效:

curl -X POST https://taotoken.net/api/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: sk-你的TaoToken密钥" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 100, "messages": [ {"role": "user", "content": "回复 OK 两个字母即可"} ] }'

如果返回里有content字段且文本是 OK,说明链路通。如果返回 401,检查 Key 是否复制完整;如果返回 model not found,检查 Model ID 拼写。

链路通了之后,在项目根目录启动 Claude Code:

claude

然后输入生成指令。注意指令要包含测试场景的完整描述,而不是一句「写个登录测试」。参考这个结构:

参考 tests/e2e/pages/LoginPage.ts 的写法,在 tests/e2e/login.spec.ts 生成登录功能的 E2E 测试。 场景: 1. 正确用户名密码登录成功,跳转到 /dashboard 2. 密码错误,显示错误提示「用户名或密码错误」 3. 用户名为空提交,显示校验提示 4. 密码为空提交,显示校验提示 要求: - 使用 LoginPage 页面对象 - 每个用例独立,用 beforeEach 处理前置 - 断言包含 URL 跳转和错误文本 - 不使用 waitForTimeout

Claude Code 会读取CLAUDE.md、LoginPage.ts、playwright.config.ts,然后生成login.spec.ts。生成结果大概长这样:

import { test, expect } from '@playwright/test'; import { LoginPage } from './pages/LoginPage'; test.describe('登录功能', () => { let loginPage: LoginPage; test.beforeEach(async ({ page }) => { loginPage = new LoginPage(page); await loginPage.goto(); }); test('正确凭证登录成功', async ({ page }) => { await loginPage.login('testuser', 'correct-password'); await expect(page).toHaveURL(/\/dashboard/); }); test('密码错误显示提示', async () => { await loginPage.login('testuser', 'wrong-password'); await loginPage.expectError('用户名或密码错误'); }); test('用户名为空提交', async () => { await loginPage.login('', 'some-password'); await loginPage.expectError('请输入用户名'); }); test('密码为空提交', async () => { await loginPage.login('testuser', ''); await loginPage.expectError('请输入密码'); }); });

生成后先 review 一遍,重点看选择器是否用了data-testid、断言是否完整、有没有隐式依赖。确认没问题后执行:

pnpm playwright test tests/e2e/login.spec.ts --headed

--headed让你看到浏览器操作过程,方便调试。第一次跑大概率会有失败,这很正常。把失败信息复制给 Claude Code,让它参与修复:

运行 pnpm playwright test tests/e2e/login.spec.ts 报错如下: [粘贴报错] 请分析原因并修改 login.spec.ts 或 LoginPage.ts。

通常两三轮就能稳定。稳定后去掉--headed,跑全量:

pnpm playwright test

报告在playwright-report/index.html,用pnpm playwright show-report打开。确认所有用例绿色通过,这一步的验证就完成了。

5. 本篇常见错误排查:401、local proxy failed、reading choices

这一节对照真实报错,给排查路径。这些错误我在配置过程中都遇到过,按顺序检查基本能定位。

401 Unauthorized

最常见。原因通常是 Key 没配、Key 复制不完整、或者环境变量没生效。检查顺序:

先确认~/.claude/settings.json里的ANTHROPIC_AUTH_TOKEN值是否以sk-开头且完整。然后确认没有其他地方覆盖了这个变量,比如 shell 的.zshrc里设了旧的ANTHROPIC_API_KEY。Claude Code 优先读ANTHROPIC_AUTH_TOKEN,但如果同时存在ANTHROPIC_API_KEY且指向官方地址,可能冲突。清理掉旧变量:

unset ANTHROPIC_API_KEY

再重启 Claude Code。

local proxy failed / connection refused

这个报错说明请求没到达 TaoToken,卡在本地。检查ANTHROPIC_BASE_URL是否写成了https://taotoken.net/api,注意结尾没有斜杠,也没有多余路径。如果写成https://taotoken.net/api/v1就会 404。另外检查本机网络是否能访问外网,公司内网可能有防火墙限制。

还有一种情况:你之前配过其他工具的代理,环境变量HTTP_PROXY或HTTPS_PROXY指向了一个已关闭的本地端口。检查并清理:

echo $HTTP_PROXY echo $HTTPS_PROXY unset HTTP_PROXY HTTPS_PROXY

reading choices / unexpected response format

这个报错通常出现在 Codex 或 OpenAI 兼容客户端上,说明返回的 JSON 结构不符合预期。原因可能是 Model ID 填了 OpenAI 的模型名,但走的是 Anthropic 格式的接口。检查config.toml里的model字段,确认是 Anthropic 系列模型 ID。如果你确实想用 OpenAI 系列模型,确认 TaoToken 文档里该模型的调用格式,可能需要换 endpoint 路径。

OAuth 相关报错

如果你之前用 Claude Code 官方登录过,本地可能残留 OAuth token,和 API Key 模式冲突。清理凭据文件:

rm -rf ~/.claude/credentials.json

然后重新用 settings.json 的 Key 模式启动。注意不要同时用 OAuth 和 API Key,二选一。

测试脚本报错:locator not found

这不是接入问题,是选择器问题。检查页面是否真的渲染了data-testid,用--headed模式看浏览器实际 DOM。如果元素在 iframe 里,需要先frameLocator。如果元素是动态加载的,用await expect(locator).toBeVisible()自动等待,不要加固定 sleep。

CI 上 flaky,本地稳定

检查playwright.config.ts里 CI 的retries和workers。CI 环境资源有限,workers: 1减少并发冲突。另外确认webServer的timeout够长,CI 冷启动可能超过 60 秒。trace 文件在test-results/下,下载后本地pnpm playwright show-trace回放。

排查完这些,链路基本就稳了。如果还有问题,接入文档里有更详细的错误码说明: https://taotoken.net/doc 。

6. 长期跑 E2E 与 Agent 编码的 Key 管理建议

测试跑通只是开始。真正在项目里长期用,Key 管理和模型选择会变成日常问题。这一节给几个实用建议。

第一,把 Key 放在环境变量或密钥管理工具里,不要硬编码进settings.json提交到 Git。可以在.gitignore里排除.claude/settings.local.json,本地配置写这个文件,团队共享的settings.json只放非敏感配置。Claude Code 会合并读取这两个文件。

第二,如果你同时用 Claude Code 写测试、用 Codex 改业务代码、用 Cline 做重构,统一走 TaoToken 的 Key 能省很多事。一个 Key 管所有工具,额度在控制台统一看。切换工具时只改 Base URL 和 Model ID,不用重新申请。

第三,长期跑 E2E 建议开 Coding Plan。测试脚本会不断迭代,模型调用频率不低,按量计费在频繁调试时成本不好控。Coding Plan 的额度更适合这种持续编码场景,地址在 https://taotoken.net/coding-plan 。

第四,模型选择上,生成测试脚本用 Sonnet 系列性价比高,复杂重构或调试可以用更强的模型。在settings.json里改ANTHROPIC_MODEL就行,不用改其他配置。

第五,定期清理test-results/和playwright-report/,这两个目录会随测试次数增长。加到.gitignore里,CI 上作为 artifact 上传后自动清理。

最后说一个实际经验:Claude Code 生成的测试脚本,第一次能直接跑通的比例大概一半,剩下的一半需要一到两轮修复。修复的关键是把完整报错和页面 DOM 结构一起给它,信息越全,修得越快。不要只丢一句「跑失败了」,那样它只能猜。

整套流程跑下来,从项目初始化到 CI 绿色,一个中等复杂度的登录模块大概两三个小时。比手写快,但快在重复编码,测试场景设计和断言逻辑还是得你自己把关。把CLAUDE.md写扎实,后面每个新模块的生成质量都会受益。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询