1. UI 自动化脚本的困境与破局思路做过 UI 自动化的朋友应该都有体会,写脚本这件事本身并不难,难的是“写得快、写得稳、写得省”。一个中等规模的 Web 项目,页面元素动辄几百个,每个元素都要定位、等待、断言,纯手写脚本的话,一个熟练工一天能覆盖的用例数量也就十来个。更麻烦的是,前端改个 class 名或者调个 DOM 结构,脚本就得跟着改,维护成本高得离谱。传统的录制回放工具,比如早期的一些 IDE 插件,确实能帮你把操作录下来生成代码,但生成出来的脚本往往“能用但不好用”——定位器脆弱、没有合理的等待策略、断言缺失、结构混乱。而纯靠 AI 生成脚本呢,又面临另一个问题:AI 对页面实际结构不了解,生成的定位器经常是猜的,跑起来一堆报错,你还得反复把错误信息喂回去让它修,Token 消耗大不说,来回调试的时间也不比手写少多少。我最近在几个项目里试了一套组合拳:用 Playwright 的 codegen 做人工录制,拿到可靠的定位器和操作序列,再让 AI 基于录制结果补全断言、异常处理和参数化逻辑。这套流程的核心逻辑是——让机器做它擅长的事(精确录制元素定位),让人和 AI 做各自擅长的事(人判断业务流程,AI 补全代码结构)。实测下来,单个用例的脚本产出时间从原来的 40 分钟压缩到 12 分钟左右,而且脚本的稳定性明显优于纯 AI 生成或纯手写的版本。这套方法适合谁呢?如果你正在做 Web 项目的 UI 自动化,团队里有人懂基本的测试流程但写代码速度跟不上,或者你已经在用 Playwright 但觉得写脚本效率太低,那这套“录制 + AI 补全”的思路可以直接抄作业。下面我把整个流程拆开,从工具选型、录制技巧、AI 补全的提示词设计到最终的脚本调优,一步步说清楚。2. 工具选型与核心原理拆解2.1 为什么是 Playwright codegen 而不是其他录制工具市面上的录制工具不少,浏览器自带的 DevTools 能录,Selenium IDE 也能录,还有一些商业化的低代码平台。我选 Playwright codegen 主要看中三点:第一,定位器质量高。Playwright 的 codegen 默认会优先生成基于角色(role)、文本(text)、标签(label)的定位器,而不是脆弱的 CSS 类名或 XPath。比如一个登录按钮,它生成的是page.getByRole('button', { name: '登录' })而不是page.locator('#app > div > form > button.btn-primary')。前者在前端重构时几乎不会失效,后者改个样式就废了。第二,自动等待机制完善。Playwright 内置了 actionability 检查,点击前会自动等待元素可见、可交互、稳定。codegen 录出来的脚本天然带这个能力,不需要你手动加一堆sleep或waitForSelector。第三,代码结构干净。codegen 生成的代码是标准的 Playwright 测试结构,可以直接放进测试框架里跑,不需要额外转换。相比之下,Selenium IDE 生成的脚本定位器质量参差不齐,而且等待策略需要手动补;商业低代码平台虽然界面友好,但生成的脚本往往绑定平台,迁移成本高。所以如果你打算长期维护一套 UI 自动化,Playwright codegen 是目前性价比最高的起点。2.2 “人工录制省 Token”背后的成本账这里说的“省 Token”不是指省那点 API 费用,而是指省掉 AI 反复试错的过程。我做过对比实验:同一个登录流程,纯让 AI 根据页面描述生成脚本,平均要来回 6 到 8 轮才能跑通,每轮都要把页面 HTML 片段和报错信息发给模型,Token 消耗在 8000 到 12000 左右。而先用 codegen 录一遍,把生成的代码发给 AI 让它补全断言和异常处理,通常 1 到 2 轮就能定稿,Token 消耗降到 2000 以内。更重要的是时间成本。纯 AI 生成时,你需要不断复制页面结构、解释业务逻辑、修正定位器,这个过程非常碎片化。而录制之后,AI 拿到的是已经验证过能跑通的代码,它只需要在现有基础上做增强,不需要从零推理页面结构,准确率和速度都高一个档次。2.3 “AI 补全脚本”具体补什么录制出来的脚本是“裸”的——它只有操作步骤,没有断言、没有异常处理、没有参数化、没有测试数据管理。AI 补全的核心就是把这四块加上去:断言补全:录制时你点了登录按钮,但脚本不知道登录成功的标志是什么。AI 可以根据页面上下文推断出应该断言 URL 变化、某个欢迎文本出现、或者某个元素消失。异常处理:网络波动、元素加载慢、弹窗干扰,这些在录制时不会出现,但实际跑的时候经常遇到。AI 可以帮你加上重试逻辑、超时处理和弹窗关闭的兜底代码。参数化:把硬编码的用户名、密码、搜索关键词提取成变量或测试数据,方便多组数据驱动。结构优化:把重复的操作提取成辅助函数,加上合理的注释和日志,让脚本可读可维护。这四块如果手写,一个用例至少多花 20 分钟。交给 AI 做,你只需要写一段清晰的提示词,几分钟就能拿到可用的增强版脚本。3. 录制环节的实操细节与避坑指南3.1 环境准备与 codegen 启动参数Playwright 的安装很简单,一条命令搞定:npm init playwright@latest安装过程中会让你选语言(TypeScript 或 JavaScript)、测试目录、是否加 GitHub Actions。如果你只是先试试,选 JavaScript 就行,后面想换 TypeScript 也不难。启动 codegen 的命令是:npx playwright codegen https://你的目标站点.com但这里有几个参数我强烈建议加上:npx playwright codegen \ --target=javascript \ --output=recorded-login.spec.js \ --viewport-size=1440,900 \ --lang=zh-CN \ https://你的目标站点.com逐个解释一下:--target=javascript:指定生成 JavaScript 代码,如果你用 TypeScript 就改成--target=typescript。--output:直接把录制的代码写到文件里,不用手动复制粘贴。--viewport-size:固定视口大小,避免因为窗口尺寸不同导致元素位置变化,影响定位器生成。--lang=zh-CN:设置浏览器语言,有些站点的文本会随语言变化,固定住能保证定位器里的文本一致。注意:如果你录制的站点需要登录才能访问,建议先用--save-storage参数保存登录状态,下次录制时用--load-storage加载,省去每次录登录流程的麻烦。3.2 录制时的操作节奏与定位器选择codegen 窗口打开后,左边是浏览器,右边是代码生成区。你在浏览器里的每一步操作都会实时生成代码。这里有几个实操心得:第一,操作前先想清楚步骤。不要一边录一边想“下一步点哪”,那样录出来的脚本会有很多多余的点击和等待。我习惯先在纸上或脑子里过一遍完整流程,然后一气呵成录完。第二,优先用键盘操作代替鼠标。比如输入框,用page.getByLabel('用户名').fill('testuser')比点击输入框再输入更稳定。codegen 会自动识别 fill 操作,生成的代码更干净。第三,遇到动态元素时暂停一下。如果某个元素是异步加载的,codegen 可能会在你点击时还没生成定位器,导致录出来的代码定位不准。这时候可以在浏览器里等元素出现后再操作,或者手动在代码区修正定位器。第四,善用断言录制。codegen 右上角有个“Assert”按钮,点一下可以录制断言。比如你想断言登录后出现了“欢迎”文本,就点 Assert,然后点那个文本元素,codegen 会生成expect(page.getByText('欢迎')).toBeVisible()。这个功能很多人不知道,但非常实用。3.3 录制产物的初步检查清单录完之后别急着丢给 AI,先自己过一遍,检查这几个点:检查项合格标准常见问题定位器类型优先 role/text/label出现大量 CSS 类名或 XPath等待策略无硬编码 sleep出现waitForTimeout(5000)操作完整性覆盖所有关键步骤漏掉弹窗关闭、页面跳转等待断言存在至少有一个关键断言完全没有断言,只有操作代码结构线性流程,无重复块同一操作重复出现多次如果定位器里出现了类似#app > div:nth-child(3) > button这种,说明 codegen 没找到更好的定位方式,你需要手动改成基于文本或角色的定位。比如改成page.getByRole('button', { name: '提交' })。这一步花两分钟,能省掉后面无数次的调试。4. AI 补全脚本的提示词设计与实操4.1 提示词的核心结构让 AI 补全脚本,提示词的质量直接决定输出质量。我试过很多版本,最后固定下来一个结构:角色设定 + 输入代码 + 补全要求 + 输出格式。具体来说,我会这样写:你是一名资深 Playwright 测试工程师。下面是一段通过 codegen 录制的 UI 自动化脚本,请帮我补全以下内容: 1. 为每个关键操作添加合理的断言(优先使用 expect 的 toBeVisible、toHaveURL、toHaveText) 2. 添加异常处理:对可能失败的操作加上重试逻辑,对可能出现的弹窗加上关闭兜底 3. 将硬编码的测试数据提取为变量,放在脚本顶部 4. 添加必要的注释和日志,方便后续维护 5. 保持原有的定位器不变,不要修改已经能跑通的定位方式 输出要求:直接输出完整的 JavaScript 代码,不要解释,不要用 markdown 代码块包裹。 录制的脚本如下: [粘贴 codegen 生成的代码]这个提示词的关键点在于:明确告诉 AI 不要改定位器。因为 codegen 录出来的定位器是经过验证的,AI 如果自作主张改成它“觉得更好”的定位器,反而可能跑不通。另外,要求“直接输出代码”能避免 AI 加一堆解释性文字,省得你还要手动删。4.2 补全后的脚本长什么样举个例子,录制一个登录流程,codegen 原始输出大概是这样的:await page.goto('https://example.com/login'); await page.getByLabel('用户名').fill('testuser'); await page.getByLabel('密码').fill('password123'); await page.getByRole('button', { name: '登录' }).click();AI 补全后变成:const BASE_URL = 'https://example.com/login'; const USERNAME = 'testuser'; const PASSWORD = 'password123'; async function login(page) { await page.goto(BASE_URL); await page.getByLabel('用户名').fill(USERNAME); await page.getByLabel('密码').fill(PASSWORD); await page.getByRole('button', { name: '登录' }).click(); // 断言登录成功:URL 跳转到首页,且出现欢迎文本 await expect(page).toHaveURL(/.*dashboard/); await expect(page.getByText('欢迎回来')).toBeVisible(); // 兜底:如果出现引导弹窗,自动关闭 const guidePopup = page.getByRole('button', { name: '跳过引导' }); if (await guidePopup.isVisible().catch(() => false)) { await guidePopup.click(); } }对比一下就能看出差别:原始脚本只有操作,补全后有了断言、有了兜底、有了参数化。而且 AI 加的断言是基于页面上下文的合理推断,比如它知道登录后通常会跳转 URL 并显示欢迎信息。4.3 多轮补全的策略有时候一轮补全不够,比如 AI 加的断言跑起来发现页面实际没有那个文本。这时候不要重新生成,而是把报错信息发给 AI,让它针对性修正:上面脚本跑的时候,第 15 行断言失败,报错是:expect.toBeVisible: Error: strict mode violation: getByText('欢迎回来') resolved to 2 elements。请修正这个断言,只匹配可见的那个元素。这种针对性修正通常一轮就能解决,比重新生成整个脚本效率高得多。我一般最多做两轮修正,如果两轮还搞不定,说明录制环节可能有问题,需要回去重新录。5. 常见问题排查与避坑经验5.1 定位器失效的三种典型场景场景一:文本随语言或环境变化。比如按钮文本是“提交”,但英文环境下变成“Submit”。解决办法是用正则匹配:page.getByRole('button', { name: /提交|Submit/ })。场景二:元素在 iframe 里。codegen 录制时如果操作了 iframe 内的元素,生成的代码可能缺少 frame 切换。你需要手动加上page.frameLocator('#iframe-id').getByLabel('用户名')。场景三:动态生成的 ID。有些前端框架会生成类似id="input-1234"的动态 ID,每次刷新都变。这种定位器录下来也是废的,必须改成基于 label 或 role 的定位。5.2 AI 补全时的常见翻车点翻车点一:AI 擅自修改定位器。前面提示词里强调了不要改,但有时候 AI 还是会“好心”帮你优化。解决办法是在提示词里加一句“如果必须修改定位器,请在注释里说明原因”。翻车点二:AI 加的断言过于具体。比如它断言expect(page.getByText('欢迎回来,testuser')).toBeVisible(),但实际页面显示的是“欢迎回来,张三”。这种断言太脆弱,应该改成expect(page.getByText(/欢迎回来/)).toBeVisible()。翻车点三:异常处理过度。AI 有时候会加一堆 try-catch,把真正的错误也吞掉了。我的原则是:只对“预期内可能失败”的操作加兜底,比如弹窗关闭、可选引导页跳过。核心业务操作不要加 try-catch,让它失败,这样你才能发现问题。5.3 脚本稳定性调优的实操技巧录完、补全完,脚本能跑通只是第一步。要让它稳定跑在 CI 环境里,还需要做几件事:第一,设置合理的超时。Playwright 默认超时是 30 秒,对于加载慢的页面可能不够。可以在playwright.config.js里全局设置timeout: 60000,也可以对单个操作设置{ timeout: 10000 }。第二,启用重试机制。在配置文件里加上retries: 2,这样偶发的网络波动不会导致整个测试失败。第三,固定测试数据。不要用随机生成的数据,除非你确定每次跑完都能清理。我习惯在测试前用 API 创建固定数据,测试后删除,保证每次跑的环境一致。第四,截图和录屏。在配置文件里开启screenshot: 'only-on-failure'和video: 'retain-on-failure',失败时能直接看到现场,排查效率翻倍。5.4 常见问题速查表问题现象可能原因解决方法元素找不到定位器失效或元素未加载检查定位器,加 waitFor 或改用 role 定位点击没反应元素被遮挡或不可交互加{ force: true }或先关闭遮挡弹窗断言失败但页面正常断言条件太严格改用正则或部分匹配脚本跑一半卡住页面跳转未等待加waitForURL或waitForLoadStateCI 上失败本地成功环境差异或超时太短增加超时,检查 CI 网络和分辨率6. 从单脚本到测试套件的扩展思路单个脚本跑通之后,下一步就是把它扩展成一套可维护的测试套件。这里分享几个我在实际项目中验证过的做法。第一,提取公共操作成辅助函数。登录、登出、导航到某个模块,这些操作在多个用例里都会用到,提取成helpers.js里的函数,用例里直接调用。这样前端改登录流程时,你只需要改一个地方。第二,用 fixtures 管理测试上下文。Playwright 的 fixtures 机制非常适合管理登录状态、测试数据、页面对象。你可以定义一个authenticatedPagefixture,它自动完成登录并返回已登录的 page 对象,用例里直接用就行。第三,按业务模块组织测试文件。不要把所有用例塞在一个文件里,按模块分目录,比如tests/login/、tests/order/、tests/profile/。每个目录下放对应的 spec 文件和辅助函数。第四,定期回归录制。前端大改版后,原来的定位器可能失效。这时候不要一个个手动修,重新用 codegen 录一遍关键流程,把新录的代码和旧脚本对比,快速定位变化点。这套“录制 + AI 补全”的流程,我用了大概三个月,覆盖了五个项目的 UI 自动化建设。最大的感受是:不要把 AI 当成万能生成器,而是当成一个高效的代码助手。录制负责提供准确的“事实”,AI 负责在这些事实上做增强和补全,人负责判断业务逻辑和把控质量。三者各司其职,效率和质量才能同时上去。最后分享一个小技巧:如果你录制的流程比较长,可以分段录制,每段录完先让 AI 补全并跑通,再录下一段。这样问题能及早发现,不会等到最后才发现某个环节的定位器有问题,导致整个脚本要重录。
1. UI 自动化脚本的困境与破局思路做过 UI 自动化的朋友应该都有体会,写脚本这件事本身并不难,难的是“写得快、写得稳、写得省”。一个中等规模的 Web 项目,页面元素动辄几百个,每个元素都要定位、等待、断言,纯手写脚本的话,一个熟练工一天能覆盖的用例数量也就十来个。更麻烦的是,前端改个 class 名或者调个 DOM 结构,脚本就得跟着改,维护成本高得离谱。传统的录制回放工具,比如早期的一些 IDE 插件,确实能帮你把操作录下来生成代码,但生成出来的脚本往往“能用但不好用”——定位器脆弱、没有合理的等待策略、断言缺失、结构混乱。而纯靠 AI 生成脚本呢,又面临另一个问题:AI 对页面实际结构不了解,生成的定位器经常是猜的,跑起来一堆报错,你还得反复把错误信息喂回去让它修,Token 消耗大不说,来回调试的时间也不比手写少多少。我最近在几个项目里试了一套组合拳:用 Playwright 的 codegen 做人工录制,拿到可靠的定位器和操作序列,再让 AI 基于录制结果补全断言、异常处理和参数化逻辑。这套流程的核心逻辑是——让机器做它擅长的事(精确录制元素定位),让人和 AI 做各自擅长的事(人判断业务流程,AI 补全代码结构)。实测下来,单个用例的脚本产出时间从原来的 40 分钟压缩到 12 分钟左右,而且脚本的稳定性明显优于纯 AI 生成或纯手写的版本。这套方法适合谁呢?如果你正在做 Web 项目的 UI 自动化,团队里有人懂基本的测试流程但写代码速度跟不上,或者你已经在用 Playwright 但觉得写脚本效率太低,那这套“录制 + AI 补全”的思路可以直接抄作业。下面我把整个流程拆开,从工具选型、录制技巧、AI 补全的提示词设计到最终的脚本调优,一步步说清楚。2. 工具选型与核心原理拆解2.1 为什么是 Playwright codegen 而不是其他录制工具市面上的录制工具不少,浏览器自带的 DevTools 能录,Selenium IDE 也能录,还有一些商业化的低代码平台。我选 Playwright codegen 主要看中三点:第一,定位器质量高。Playwright 的 codegen 默认会优先生成基于角色(role)、文本(text)、标签(label)的定位器,而不是脆弱的 CSS 类名或 XPath。比如一个登录按钮,它生成的是page.getByRole('button', { name: '登录' })而不是page.locator('#app > div > form > button.btn-primary')。前者在前端重构时几乎不会失效,后者改个样式就废了。第二,自动等待机制完善。Playwright 内置了 actionability 检查,点击前会自动等待元素可见、可交互、稳定。codegen 录出来的脚本天然带这个能力,不需要你手动加一堆sleep或waitForSelector。第三,代码结构干净。codegen 生成的代码是标准的 Playwright 测试结构,可以直接放进测试框架里跑,不需要额外转换。相比之下,Selenium IDE 生成的脚本定位器质量参差不齐,而且等待策略需要手动补;商业低代码平台虽然界面友好,但生成的脚本往往绑定平台,迁移成本高。所以如果你打算长期维护一套 UI 自动化,Playwright codegen 是目前性价比最高的起点。2.2 “人工录制省 Token”背后的成本账这里说的“省 Token”不是指省那点 API 费用,而是指省掉 AI 反复试错的过程。我做过对比实验:同一个登录流程,纯让 AI 根据页面描述生成脚本,平均要来回 6 到 8 轮才能跑通,每轮都要把页面 HTML 片段和报错信息发给模型,Token 消耗在 8000 到 12000 左右。而先用 codegen 录一遍,把生成的代码发给 AI 让它补全断言和异常处理,通常 1 到 2 轮就能定稿,Token 消耗降到 2000 以内。更重要的是时间成本。纯 AI 生成时,你需要不断复制页面结构、解释业务逻辑、修正定位器,这个过程非常碎片化。而录制之后,AI 拿到的是已经验证过能跑通的代码,它只需要在现有基础上做增强,不需要从零推理页面结构,准确率和速度都高一个档次。2.3 “AI 补全脚本”具体补什么录制出来的脚本是“裸”的——它只有操作步骤,没有断言、没有异常处理、没有参数化、没有测试数据管理。AI 补全的核心就是把这四块加上去:断言补全:录制时你点了登录按钮,但脚本不知道登录成功的标志是什么。AI 可以根据页面上下文推断出应该断言 URL 变化、某个欢迎文本出现、或者某个元素消失。异常处理:网络波动、元素加载慢、弹窗干扰,这些在录制时不会出现,但实际跑的时候经常遇到。AI 可以帮你加上重试逻辑、超时处理和弹窗关闭的兜底代码。参数化:把硬编码的用户名、密码、搜索关键词提取成变量或测试数据,方便多组数据驱动。结构优化:把重复的操作提取成辅助函数,加上合理的注释和日志,让脚本可读可维护。这四块如果手写,一个用例至少多花 20 分钟。交给 AI 做,你只需要写一段清晰的提示词,几分钟就能拿到可用的增强版脚本。3. 录制环节的实操细节与避坑指南3.1 环境准备与 codegen 启动参数Playwright 的安装很简单,一条命令搞定:npm init playwright@latest安装过程中会让你选语言(TypeScript 或 JavaScript)、测试目录、是否加 GitHub Actions。如果你只是先试试,选 JavaScript 就行,后面想换 TypeScript 也不难。启动 codegen 的命令是:npx playwright codegen https://你的目标站点.com但这里有几个参数我强烈建议加上:npx playwright codegen \ --target=javascript \ --output=recorded-login.spec.js \ --viewport-size=1440,900 \ --lang=zh-CN \ https://你的目标站点.com逐个解释一下:--target=javascript:指定生成 JavaScript 代码,如果你用 TypeScript 就改成--target=typescript。--output:直接把录制的代码写到文件里,不用手动复制粘贴。--viewport-size:固定视口大小,避免因为窗口尺寸不同导致元素位置变化,影响定位器生成。--lang=zh-CN:设置浏览器语言,有些站点的文本会随语言变化,固定住能保证定位器里的文本一致。注意:如果你录制的站点需要登录才能访问,建议先用--save-storage参数保存登录状态,下次录制时用--load-storage加载,省去每次录登录流程的麻烦。3.2 录制时的操作节奏与定位器选择codegen 窗口打开后,左边是浏览器,右边是代码生成区。你在浏览器里的每一步操作都会实时生成代码。这里有几个实操心得:第一,操作前先想清楚步骤。不要一边录一边想“下一步点哪”,那样录出来的脚本会有很多多余的点击和等待。我习惯先在纸上或脑子里过一遍完整流程,然后一气呵成录完。第二,优先用键盘操作代替鼠标。比如输入框,用page.getByLabel('用户名').fill('testuser')比点击输入框再输入更稳定。codegen 会自动识别 fill 操作,生成的代码更干净。第三,遇到动态元素时暂停一下。如果某个元素是异步加载的,codegen 可能会在你点击时还没生成定位器,导致录出来的代码定位不准。这时候可以在浏览器里等元素出现后再操作,或者手动在代码区修正定位器。第四,善用断言录制。codegen 右上角有个“Assert”按钮,点一下可以录制断言。比如你想断言登录后出现了“欢迎”文本,就点 Assert,然后点那个文本元素,codegen 会生成expect(page.getByText('欢迎')).toBeVisible()。这个功能很多人不知道,但非常实用。3.3 录制产物的初步检查清单录完之后别急着丢给 AI,先自己过一遍,检查这几个点:检查项合格标准常见问题定位器类型优先 role/text/label出现大量 CSS 类名或 XPath等待策略无硬编码 sleep出现waitForTimeout(5000)操作完整性覆盖所有关键步骤漏掉弹窗关闭、页面跳转等待断言存在至少有一个关键断言完全没有断言,只有操作代码结构线性流程,无重复块同一操作重复出现多次如果定位器里出现了类似#app > div:nth-child(3) > button这种,说明 codegen 没找到更好的定位方式,你需要手动改成基于文本或角色的定位。比如改成page.getByRole('button', { name: '提交' })。这一步花两分钟,能省掉后面无数次的调试。4. AI 补全脚本的提示词设计与实操4.1 提示词的核心结构让 AI 补全脚本,提示词的质量直接决定输出质量。我试过很多版本,最后固定下来一个结构:角色设定 + 输入代码 + 补全要求 + 输出格式。具体来说,我会这样写:你是一名资深 Playwright 测试工程师。下面是一段通过 codegen 录制的 UI 自动化脚本,请帮我补全以下内容: 1. 为每个关键操作添加合理的断言(优先使用 expect 的 toBeVisible、toHaveURL、toHaveText) 2. 添加异常处理:对可能失败的操作加上重试逻辑,对可能出现的弹窗加上关闭兜底 3. 将硬编码的测试数据提取为变量,放在脚本顶部 4. 添加必要的注释和日志,方便后续维护 5. 保持原有的定位器不变,不要修改已经能跑通的定位方式 输出要求:直接输出完整的 JavaScript 代码,不要解释,不要用 markdown 代码块包裹。 录制的脚本如下: [粘贴 codegen 生成的代码]这个提示词的关键点在于:明确告诉 AI 不要改定位器。因为 codegen 录出来的定位器是经过验证的,AI 如果自作主张改成它“觉得更好”的定位器,反而可能跑不通。另外,要求“直接输出代码”能避免 AI 加一堆解释性文字,省得你还要手动删。4.2 补全后的脚本长什么样举个例子,录制一个登录流程,codegen 原始输出大概是这样的:await page.goto('https://example.com/login'); await page.getByLabel('用户名').fill('testuser'); await page.getByLabel('密码').fill('password123'); await page.getByRole('button', { name: '登录' }).click();AI 补全后变成:const BASE_URL = 'https://example.com/login'; const USERNAME = 'testuser'; const PASSWORD = 'password123'; async function login(page) { await page.goto(BASE_URL); await page.getByLabel('用户名').fill(USERNAME); await page.getByLabel('密码').fill(PASSWORD); await page.getByRole('button', { name: '登录' }).click(); // 断言登录成功:URL 跳转到首页,且出现欢迎文本 await expect(page).toHaveURL(/.*dashboard/); await expect(page.getByText('欢迎回来')).toBeVisible(); // 兜底:如果出现引导弹窗,自动关闭 const guidePopup = page.getByRole('button', { name: '跳过引导' }); if (await guidePopup.isVisible().catch(() => false)) { await guidePopup.click(); } }对比一下就能看出差别:原始脚本只有操作,补全后有了断言、有了兜底、有了参数化。而且 AI 加的断言是基于页面上下文的合理推断,比如它知道登录后通常会跳转 URL 并显示欢迎信息。4.3 多轮补全的策略有时候一轮补全不够,比如 AI 加的断言跑起来发现页面实际没有那个文本。这时候不要重新生成,而是把报错信息发给 AI,让它针对性修正:上面脚本跑的时候,第 15 行断言失败,报错是:expect.toBeVisible: Error: strict mode violation: getByText('欢迎回来') resolved to 2 elements。请修正这个断言,只匹配可见的那个元素。这种针对性修正通常一轮就能解决,比重新生成整个脚本效率高得多。我一般最多做两轮修正,如果两轮还搞不定,说明录制环节可能有问题,需要回去重新录。5. 常见问题排查与避坑经验5.1 定位器失效的三种典型场景场景一:文本随语言或环境变化。比如按钮文本是“提交”,但英文环境下变成“Submit”。解决办法是用正则匹配:page.getByRole('button', { name: /提交|Submit/ })。场景二:元素在 iframe 里。codegen 录制时如果操作了 iframe 内的元素,生成的代码可能缺少 frame 切换。你需要手动加上page.frameLocator('#iframe-id').getByLabel('用户名')。场景三:动态生成的 ID。有些前端框架会生成类似id="input-1234"的动态 ID,每次刷新都变。这种定位器录下来也是废的,必须改成基于 label 或 role 的定位。5.2 AI 补全时的常见翻车点翻车点一:AI 擅自修改定位器。前面提示词里强调了不要改,但有时候 AI 还是会“好心”帮你优化。解决办法是在提示词里加一句“如果必须修改定位器,请在注释里说明原因”。翻车点二:AI 加的断言过于具体。比如它断言expect(page.getByText('欢迎回来,testuser')).toBeVisible(),但实际页面显示的是“欢迎回来,张三”。这种断言太脆弱,应该改成expect(page.getByText(/欢迎回来/)).toBeVisible()。翻车点三:异常处理过度。AI 有时候会加一堆 try-catch,把真正的错误也吞掉了。我的原则是:只对“预期内可能失败”的操作加兜底,比如弹窗关闭、可选引导页跳过。核心业务操作不要加 try-catch,让它失败,这样你才能发现问题。5.3 脚本稳定性调优的实操技巧录完、补全完,脚本能跑通只是第一步。要让它稳定跑在 CI 环境里,还需要做几件事:第一,设置合理的超时。Playwright 默认超时是 30 秒,对于加载慢的页面可能不够。可以在playwright.config.js里全局设置timeout: 60000,也可以对单个操作设置{ timeout: 10000 }。第二,启用重试机制。在配置文件里加上retries: 2,这样偶发的网络波动不会导致整个测试失败。第三,固定测试数据。不要用随机生成的数据,除非你确定每次跑完都能清理。我习惯在测试前用 API 创建固定数据,测试后删除,保证每次跑的环境一致。第四,截图和录屏。在配置文件里开启screenshot: 'only-on-failure'和video: 'retain-on-failure',失败时能直接看到现场,排查效率翻倍。5.4 常见问题速查表问题现象可能原因解决方法元素找不到定位器失效或元素未加载检查定位器,加 waitFor 或改用 role 定位点击没反应元素被遮挡或不可交互加{ force: true }或先关闭遮挡弹窗断言失败但页面正常断言条件太严格改用正则或部分匹配脚本跑一半卡住页面跳转未等待加waitForURL或waitForLoadStateCI 上失败本地成功环境差异或超时太短增加超时,检查 CI 网络和分辨率6. 从单脚本到测试套件的扩展思路单个脚本跑通之后,下一步就是把它扩展成一套可维护的测试套件。这里分享几个我在实际项目中验证过的做法。第一,提取公共操作成辅助函数。登录、登出、导航到某个模块,这些操作在多个用例里都会用到,提取成helpers.js里的函数,用例里直接调用。这样前端改登录流程时,你只需要改一个地方。第二,用 fixtures 管理测试上下文。Playwright 的 fixtures 机制非常适合管理登录状态、测试数据、页面对象。你可以定义一个authenticatedPagefixture,它自动完成登录并返回已登录的 page 对象,用例里直接用就行。第三,按业务模块组织测试文件。不要把所有用例塞在一个文件里,按模块分目录,比如tests/login/、tests/order/、tests/profile/。每个目录下放对应的 spec 文件和辅助函数。第四,定期回归录制。前端大改版后,原来的定位器可能失效。这时候不要一个个手动修,重新用 codegen 录一遍关键流程,把新录的代码和旧脚本对比,快速定位变化点。这套“录制 + AI 补全”的流程,我用了大概三个月,覆盖了五个项目的 UI 自动化建设。最大的感受是:不要把 AI 当成万能生成器,而是当成一个高效的代码助手。录制负责提供准确的“事实”,AI 负责在这些事实上做增强和补全,人负责判断业务逻辑和把控质量。三者各司其职,效率和质量才能同时上去。最后分享一个小技巧:如果你录制的流程比较长,可以分段录制,每段录完先让 AI 补全并跑通,再录下一段。这样问题能及早发现,不会等到最后才发现某个环节的定位器有问题,导致整个脚本要重录。