1. Playwright 端对端测试为什么要接统一 Key 通道
Playwright 是微软开源的端对端测试框架,能驱动 Chromium、Firefox、WebKit 三种浏览器,模拟真实用户点击、输入、跳转,并对页面标题、元素文本、截图做断言。它适合谁?适合所有需要验证「页面多模块联动是否正常」的前端团队,尤其是组件库、后台系统、营销页这类交互链路长的项目。单元测试用 Jest 覆盖函数和组件,端对端测试用 Playwright 覆盖真实浏览器里的完整流程,两者互补。
但真正落地时,麻烦往往不在测试脚本本身,而在「测试里要调模型能力」这件事上。比如你想在端对端流程里加一步:让页面上的 AI 助手回答一个问题,然后断言回答内容渲染成功;或者用模型生成测试数据、校验文案。这时候测试代码里就得有 API Key、Base URL、模型名。如果每个开发者本地各配一套,CI 上再配一套,Key 散落在.env、playwright.config.js、GitHub Secrets 里,排查问题时根本不知道当前跑的是哪条链路。
我试过把模型调用统一收敛到一个 Key/API 通道,Playwright 侧只读环境变量,配置写进settings.json骨架,测试脚本不碰明文密钥。这样本地和 CI 用同一套结构,换 Key 只改一处。下面按「前置准备 → 配置骨架 → 跑一次验证 → 报错排查」的顺序走一遍,你可以直接复制。
2. TaoToken 前置:Key、通道与项目结构
TaoToken 在这里扮演的是统一模型调用入口:你拿到一个 Key,配好 Base URL,Playwright 测试里通过环境变量读取,就能在端对端流程中调用模型对话能力。它不替代 Playwright,也不替代你的编辑器,只是把「测试代码要调模型」这条链路的凭证和地址统一起来。
先做三件事。第一,注册并登录控制台,在 API Keys 页面创建一个 Key,复制保存,它只显示一次。第二,确认你要用的模型名,比如对话类模型,记下来。第三,确认 Node 版本与 Playwright 版本匹配,Node 18 LTS 配 Playwright 1.3x 系列是稳的,版本错配会在启动浏览器时报奇怪的错。
项目结构建议这样组织,让配置和测试分离:
my-e2e-project/ ├── tests/ │ └── ai-assistant.spec.js ├── .env ├── settings.json ├── playwright.config.js └── package.json.env放本地密钥,不进 Git;settings.json放非敏感的配置骨架,比如模型名、超时、重试次数;playwright.config.js读环境变量并注入到测试的use里。这样 CI 上只需要在 Secrets 里配同名环境变量,结构完全一致。
注意:Key 只放环境变量或 CI Secrets,不要写进
settings.json提交到仓库。settings.json里只放可以公开的骨架字段。
3. 可复制配置:settings.json 骨架与环境变量写法
先写settings.json。它的作用是给测试运行器提供一份「默认参数」,包括模型通道地址、模型名、请求超时、重试策略。地址用 TaoToken 的 API 入口,不带多余参数:
{ "model": { "baseUrl": "https://taotoken.net/api", "modelName": "gpt-4o-mini", "timeoutMs": 30000, "maxRetries": 2 }, "e2e": { "baseURL": "http://localhost:3000", "trace": "on-first-retry", "screenshot": "only-on-failure" } }baseUrl指向 API 入口,modelName换成你实际要用的模型,timeoutMs给模型调用留足时间,端对端测试里网络慢是常态。e2e段是 Playwright 自己的配置,baseURL指向你本地或测试环境的页面地址。
接着写.env,本地开发用:
TAOTOKEN_API_KEY=sk-你的Key TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_MODEL=gpt-4o-mini E2E_BASE_URL=http://localhost:3000然后在playwright.config.js里读取,并注入到测试上下文中。这样测试脚本里通过process.env拿到的就是统一后的值:
const { defineConfig, devices } = require('@playwright/test'); const settings = require('./settings.json'); module.exports = defineConfig({ testDir: './tests', fullyParallel: true, retries: process.env.CI ? 2 : 0, reporter: 'html', use: { baseURL: process.env.E2E_BASE_URL || settings.e2e.baseURL, trace: settings.e2e.trace, screenshot: settings.e2e.screenshot, }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, ], });如果你在测试里要直接调模型,建议封装一个小的请求函数,把 Key 和 Base URL 从环境变量读进来,避免散落:
// tests/utils/modelClient.js const settings = require('../../settings.json'); async function askModel(prompt) { const apiKey = process.env.TAOTOKEN_API_KEY; const baseUrl = process.env.TAOTOKEN_BASE_URL || settings.model.baseUrl; const model = process.env.TAOTOKEN_MODEL || settings.model.modelName; if (!apiKey) { throw new Error('TAOTOKEN_API_KEY 未设置,请检查 .env 或 CI Secrets'); } const res = await fetch(`${baseUrl}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, }, body: JSON.stringify({ model, messages: [{ role: 'user', content: prompt }], }), }); if (!res.ok) { const text = await res.text(); throw new Error(`模型调用失败 ${res.status}: ${text}`); } const data = await res.json(); return data.choices[0].message.content; } module.exports = { askModel };这段封装的好处是:Key 只在环境变量里,测试脚本不出现明文;Base URL 和模型名有默认值也有覆盖;出错时能拿到状态码和响应体,方便定位。
4. 验证请求:跑一次端对端测试确认链路
配置写好后,写一个最小的端对端用例,既验证页面能打开,也验证模型通道能通。新建tests/ai-assistant.spec.js:
const { test, expect } = require('@playwright/test'); const { askModel } = require('./utils/modelClient'); test('页面标题正确且模型通道可用', async ({ page }) => { await page.goto('/'); await expect(page).toHaveTitle(/我的应用/); const answer = await askModel('用一句话说明端对端测试的价值'); console.log('模型返回:', answer); expect(answer.length).toBeGreaterThan(0); });先启动你的本地页面服务,比如npm run dev,确认http://localhost:3000能打开。然后跑测试:
npx playwright test tests/ai-assistant.spec.js --project=chromium预期输出类似:
Running 1 test using 1 worker 模型返回: 端对端测试能验证真实浏览器中多模块联动的完整流程。 1 passed (3.2s)看到1 passed且控制台打印出模型返回内容,说明两件事都成了:Playwright 能驱动浏览器打开页面,模型通道也能通过环境变量里的 Key 正常调用。如果只想验证模型通道,可以单独跑一个 Node 脚本:
node -e "require('./tests/utils/modelClient').askModel('你好').then(console.log).catch(console.error)"这一步能快速区分是「模型通道问题」还是「Playwright 配置问题」。如果这个脚本能打印回答,但 Playwright 测试失败,问题就在浏览器或页面侧;如果这个脚本也失败,问题在 Key、Base URL 或网络。
5. 本篇常见报错排查
报错一:TAOTOKEN_API_KEY 未设置。说明环境变量没被读到。检查.env是否在项目根目录,Node 是否加载了它。Playwright 默认不会自动读.env,你需要在playwright.config.js顶部加require('dotenv').config(),并安装dotenv。CI 上则确认 Secrets 名称与代码里读的变量名完全一致,大小写敏感。
报错二:模型调用失败 401。Key 无效或过期。去控制台重新生成一个 Key,确认复制时没有多余空格。注意Authorization头是Bearer加 Key,中间一个空格,别漏。
报错三:模型调用失败 404。多半是 Base URL 或路径拼错。settings.json里baseUrl是https://taotoken.net/api,请求时拼/v1/chat/completions。如果你把baseUrl写成了带/v1的地址,就会变成/v1/v1/...。统一在封装函数里拼路径,别在多个地方各拼一次。
报错四:browserType.launch: Executable doesn't exist。浏览器驱动没装。跑npx playwright install chromium,国内下载慢可以设PLAYWRIGHT_DOWNLOAD_HOST指向镜像源。注意 Node 版本与 Playwright 版本匹配,Node 18 配 Playwright 1.3x 系列,版本错配会报启动失败。
报错五:测试超时但模型脚本正常。页面没起来,或baseURL指向的地址不对。确认npm run dev在跑,端口和settings.json里e2e.baseURL一致。Playwright 的use.baseURL只影响page.goto('/')这类相对路径,绝对路径不受影响。
报错六:CI 上通过、本地失败,或反过来。检查两边环境变量是否一致。本地.env和 CI Secrets 的 Key、Base URL、模型名要完全对齐。CI 上如果用了缓存,确认缓存没把旧的settings.json带进去。
排查顺序建议固定:先跑独立 Node 脚本验证模型通道,再跑 Playwright 验证浏览器,最后看两者结合。这样每次都能把问题范围缩小一半。
6. 接入文档与后续操作入口
配置骨架和排查步骤走完,链路基本就通了。后续如果你要换模型、加测试用例、或者把模型调用接到更长的编码任务里,可以按场景选入口:
- 需要创建或轮换 Key、查看接入文档:进 API Keys 管理,接入细节看 接入文档。
- 想先在网页里验证模型回答效果,再写进测试断言:用 模型对话。
- 长期做编码、Agent 类任务,需要更稳定的额度与通道:看 Coding Plan。
- 用 Claude Code 或 Anthropic 风格接口做端对端辅助:参考 ClaudeCodeAnthropic 接入。
把settings.json骨架提交进仓库,.env加进.gitignore,CI Secrets 配同名变量,这套结构就能在本地和流水线之间无缝切换。下次换 Key,只改 Secrets,测试脚本一行不动。