1. 从 Selenium 到 Playwright:测试自动化迁移的真实痛点
如果你手里有一批跑了三五年的 Selenium 脚本,最近又在考虑换到 Playwright,那你大概率会遇到几个绕不开的问题:老脚本里到处是WebDriverWait和expected_conditions,选择器写的是 XPath 绝对路径,一改 UI 就全红;新项目想用 Playwright 的自动等待和locator语义,但迁移工作量看起来像重写一遍。我最近就在做这件事,把一套电商结算流程的 Selenium + pytest 用例迁到 Playwright,同时用 Cursor 做 AI 辅助重构,中间踩了不少坑,也总结出一套能直接抄的配置。
先说清楚这篇适合谁:如果你是会写 Python 或 JavaScript 测试、用过 Selenium、现在想用 Cursor 加速迁移到 Playwright 的测试工程师,这篇就是给你写的。核心检索词就三个——Cursor 辅助测试自动化、Selenium 迁移 Playwright、TaoToken 统一管理 Key。我会把 Cursor 规则文件、Playwright 配置片段、迁移前后对比验证步骤全部给出来,最后说明怎么把 Base URL 改到 TaoToken,让 Key 集中管理,不用在每个项目里散落一堆环境变量。
迁移的痛点其实不在语法,而在“语义对齐”。Selenium 的显式等待是命令式的,你得告诉它等什么条件;Playwright 的locator是声明式的,它自己会等元素可操作。这意味着你不能简单地把find_element换成locator,而是要把整个“等待 + 查找 + 操作”的三段式,压缩成一句await page.locator(...).click()。Cursor 在这里的价值,是它能读懂你旧脚本的意图,然后按 Playwright 的惯用法重写,而不是做机械替换。
我试过直接让 Cursor 把整个 Selenium 文件转成 Playwright,结果它把WebDriverWait原样保留,只是换了个 API 名字,跑起来还是各种超时。后来我改成“先写规则文件,再分文件迁移”,效果才稳定下来。下面先讲 TaoToken 的前置配置,因为不管你是用 Cursor 还是直接调模型,Key 管理都是第一步。
2. TaoToken 前置:把 Base URL 和 Key 统一管起来
在开始迁移之前,先把模型调用的入口统一到 TaoToken。原因很简单:Cursor 里可以配自定义模型,Playwright 测试里也可能需要调 AI 做断言或生成数据,如果每个地方都填不同的 Key,后面排查 401 会非常痛苦。TaoToken 的 API 地址是https://taotoken.net/api,官网是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,你可以在控制台里创建 Key,然后所有工具都指向同一个 Base URL。
具体操作分三步。第一步,打开官网注册并登录,进入控制台。第二步,在 API Keys 页面创建一个新 Key,复制出来,注意它只显示一次。第三步,把 Key 写进环境变量,不要硬编码在代码里。Linux 或 macOS 下可以这样:
export TAOTOKEN_API_KEY="sk-你的实际Key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"Windows PowerShell 用:
$env:TAOTOKEN_API_KEY="sk-你的实际Key" $env:TAOTOKEN_BASE_URL="https://taotoken.net/api"如果你用 Cursor,可以在设置里找到 Models 或 OpenAI API Key 的配置项,把 Base URL 改成https://taotoken.net/api,Key 填上面创建的。这样 Cursor 里的对话和代码生成就走 TaoToken 了。注意 Cursor 的配置界面版本之间略有差异,如果找不到自定义 Base URL 的入口,可以查接入文档,里面有截图说明。
这里有个容易忽略的点:TaoToken 的 Base URL 末尾不要加/v1,它自己会处理路径。我一开始填了https://taotoken.net/api/v1,结果请求 404,改成https://taotoken.net/api就正常了。另外,如果你在 CI 里跑 Playwright 测试,记得把环境变量注入到 pipeline 的 secrets 里,不要提交到仓库。
统一 Key 之后,你可以在 TaoToken 控制台看到所有调用的用量和日志,哪个项目在什么时候调了什么模型一目了然。这对测试团队尤其有用,因为测试环境经常多人共用,Key 散落各处根本没法审计。把 Base URL 改到 TaoToken 之后,Cursor 的补全、Playwright 里的 AI 断言、甚至你本地跑的脚本,都走同一个入口,排查问题只需要看一个地方。
3. 可复制配置:Cursor 规则文件与 Playwright 配置片段
这一节是全文的核心,直接给可复制的配置。先说 Cursor 的规则文件。Cursor 支持在项目根目录放.cursorrules文件,它会作为系统提示的一部分,影响 AI 生成代码的风格。我针对 Playwright 迁移写了一份,你可以直接复制到项目根目录:
# .cursorrules You are a test automation engineer migrating Selenium tests to Playwright. Rules: - Always use Playwright's built-in auto-waiting. Never use explicit sleep or WebDriverWait. - Use `page.locator()` with role, text, or>import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', timeout: 30_000, expect: { timeout: 5_000 }, fullyParallel: true, retries: process.env.CI ? 2 : 0, reporter: [['html'], ['list']], use: { baseURL: process.env.BASE_URL || 'https://your-shop.example.com', trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, ], });如果你用 Python 版 Playwright,对应的pytest.ini或pyproject.toml里加:
[tool.pytest.ini_options] addopts = "--headed --tracing=retain-on-failure"然后conftest.py里配 fixture:
import pytest from playwright.sync_api import sync_playwright @pytest.fixture(scope="session") def browser(): with sync_playwright() as p: browser = p.chromium.launch(headless=True) yield browser browser.close() @pytest.fixture def page(browser): context = browser.new_context(base_url="https://your-shop.example.com") page = context.new_page() yield page context.close()注意 Python 版和 Node 版的 API 名字略有不同,但语义一致。Cursor 在生成时会根据文件扩展名自动选对版本,前提是你的.cursorrules里写清楚了。
还有一个关键配置是模型 ID。如果你在 Cursor 里用 TaoToken 调模型,需要在设置里填 Model ID,比如claude-sonnet-4-20250514或gpt-4o。这个 ID 要和 TaoToken 支持的模型列表一致,填错了会报model not found。三件套就是 Base URL、Key、Model ID,缺一不可。Base URL 填https://taotoken.net/api,Key 填你创建的,Model ID 按需选。
4. 验证请求:迁移前后对比与成功结果
配置好之后,先别急着迁全部用例,拿一个最简单的登录测试做验证。我拿一个电商结算流程里的“优惠券应用”用例做对比。迁移前的 Selenium 代码大概是这样:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By def test_coupon_application(driver): driver.get("https://your-shop.example.com/checkout") wait = WebDriverWait(driver, 10) coupon_input = wait.until(EC.presence_of_element_located((By.ID, "coupon-code"))) coupon_input.send_keys("DISCOUNT20") apply_btn = wait.until(EC.element_to_be_clickable((By.ID, "apply-coupon"))) apply_btn.click() discount = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".discount-applied"))) assert "20%" in discount.text迁移后,用 Cursor 按规则重写成 Playwright:
import { test, expect } from '@playwright/test'; test('coupon application', async ({ page }) => { await test.step('打开结算页', async () => { await page.goto('/checkout'); }); await test.step('输入优惠券并应用', async () => { await page.getByLabel('优惠券码').fill('DISCOUNT20'); await page.getByRole('button', { name: '应用' }).click(); }); await test.step('验证折扣显示', async () => { await expect(page.locator('.discount-applied')).toContainText('20%'); }); });对比一下:Selenium 版有 3 处显式等待,Playwright 版一处都没有,全靠自动等待。选择器从By.ID和By.CSS_SELECTOR换成了getByLabel和getByRole,语义更强,UI 小改也不容易断。test.step让报告更清晰,失败时能直接看到是哪一步。
跑起来验证:
npx playwright test tests/coupon.spec.ts --project=chromium成功的话你会看到类似输出:
Running 1 test using 1 worker ✓ 1 tests/coupon.spec.ts:3:1 › coupon application (2.3s) 1 passed (3.1s)如果失败,Playwright 会自动截图和保留 trace,用npx playwright show-trace trace.zip可以回放。这一步很关键,因为迁移过程中最常见的失败不是逻辑错,而是选择器没对上。用 trace 能看到每一步的 DOM 快照,比 Selenium 的截图强太多。
我实测下来,一个中等复杂度的结算流程,Selenium 版有 120 行左右,Cursor 重写成 Playwright 后大概 70 行,维护时间减少一半以上。而且因为自动等待,之前那些偶发的ElementNotInteractableException基本消失了。迁移不是一次全量替换,而是按用例逐个验证,跑通一个再迁下一个。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
迁移和配置过程中,报错主要集中在两类:TaoToken 接入报错和 Playwright 运行报错。我按真实遇到的顺序列出来。
第一类,401 Unauthorized。这个几乎都是 Key 没配对。检查三件事:环境变量TAOTOKEN_API_KEY是否真的导出到了当前 shell;Cursor 设置里的 Key 有没有多余空格;Base URL 是不是写成了https://taotoken.net/api/v1。我遇到过一次是复制 Key 时带了个换行,导致请求头里多了个\n,报 401。解决办法是重新复制,或者用echo -n $TAOTOKEN_API_KEY | wc -c确认长度。
第二类,local proxy failed或连接超时。这个通常是你本地网络环境的问题,不是 TaoToken 本身。检查你的 HTTP_PROXY / HTTPS_PROXY 环境变量有没有指向一个不可用的地址。如果你在 CI 里跑,确认 runner 能正常访问外网。另外,有些公司内网会拦截非标准端口,TaoToken 走的是标准 HTTPS,一般没问题,但如果你的代理配置有问题,会报这个错。清掉代理环境变量再试:
unset HTTP_PROXY HTTPS_PROXY第三类,reading choices相关报错。这个出现在模型返回格式不符合预期时,比如你让 Cursor 生成代码,但它返回了一个空响应或截断的 JSON。常见原因是 Model ID 填错了,或者请求参数里的max_tokens设得太小。检查 Cursor 设置里的 Model ID 是否在 TaoToken 支持列表里,然后把max_tokens调到 4096 以上。如果还是不行,换一个模型试试,比如从gpt-4o换到claude-sonnet-4-20250514。
第四类,OAuth 相关报错。如果你在 Cursor 里用 OAuth 登录而不是 API Key,可能会遇到 token 过期。解决办法是退出重新登录,或者干脆切到 API Key 模式,用 TaoToken 的 Key 更稳定。Cursor 的 OAuth 和 API Key 是两条路径,配了 Key 之后就不需要 OAuth 了。
还有一个 Playwright 特有的坑:page.frameLocator找不到 iframe。Selenium 里用switch_to.frame,Playwright 用frameLocator,但如果你 iframe 的 src 是动态加载的,需要先等 iframe 出现:
await page.locator('iframe.card-frame').waitFor(); await page.frameLocator('.card-frame').getByLabel('卡号').fill('4111111111111111');这个在迁移支付表单时特别常见,Cursor 有时候会漏掉waitFor,你手动补上就行。
排查顺序建议:先确认 Key 和 Base URL,再确认 Model ID,最后看 Playwright 选择器。大部分问题在前两步就能解决。
6. 语义一致 CTA:把 Key 管好,迁移才跑得顺
迁移到 Playwright 这件事,工具选对了能省一半力气,但前提是模型调用这条链路是通的。把 Base URL 统一到 TaoToken 之后,Cursor 的代码生成、Playwright 里的 AI 辅助断言、CI 里的自动化调用,都走同一个 Key,排查问题只需要看一个控制台。如果你还没配,可以先从 API Keys 页面创建一个,然后按接入文档把 Cursor 和 Playwright 都指过去。
具体入口我放这里:创建和管理 Key 在 API Keys 页面,配置说明看接入文档,想先试试模型效果可以去模型对话。如果你打算长期用 Cursor 做测试自动化,甚至把 AI 断言集成到 CI 里,Coding Plan 会更划算,用量和模型选择都更灵活。
迁移不是一蹴而就的,我的建议是先拿一个用例跑通全流程——从 Selenium 旧脚本,到 Cursor 按规则重写,到 Playwright 跑绿,再到 TaoToken 控制台看到调用记录。这一个闭环走通之后,剩下的就是重复劳动,而重复劳动正是 AI 最擅长的部分。