news 2026/10/19 5:34:29

Playwright录制+AI补全:UI自动化脚本成本降五分之一

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Playwright录制+AI补全:UI自动化脚本成本降五分之一

最近在给一个内部后台页面做回归测试,翻出年初写的那批 UI 自动化脚本,发现大半已经不能用了——元素定位变了、登录逻辑换了、断言也不够稳。正当我准备重新手写一遍的时候,顺手算了一笔账:如果走“AI 全量生成”的老路,一个两百行的 E2E 脚本光是首轮的 token 消耗就能轻松破万,改两轮下来比写脚本本身还贵。后来我把整个流程换成了“Playwright codegen 人工录制 + AI Skills 补全”的组合拳,成本直接缩到原来的五分之一,脚本稳定性还比以前高出不少。

这篇文章就把这套玩法的完整落地过程讲清楚,包括 token 账怎么算、环境怎么准备、录制时哪些操作必须人来干、Skills 怎么定义才能让 AI 只补关键逻辑而不是从零生成。适合正在做 UI 自动化、又对脚本脆弱性和 AI 烧钱问题头疼的人参考。

1. 这笔 token 账是怎么算明白的:codegen 免费,AI 收费,差别在哪

1.1 AI 全量生成脚本的真实消耗

先说一个反直觉的事实:让 AI 从零生成一个 UI 自动化脚本,最大的成本不是“生成”的时候,而是“修复”的时候。

假设要写一个“登录→新建订单→校验列表→退出”的端到端场景。如果直接把需求丢给 AI 让它全量生成,第一步要先给它喂上下文——被测系统的页面结构、历史脚本风格、业务规则说明,这些预热信息通常就要消耗 2000 到 3000 token。第二步是输出,一份 250 行左右的脚本,输出端消耗 6000 到 8000 token 是很常见的。第三步才是最坑的:脚本跑一遍不可能一次就对,定位符猜错、等待方式不对、某个页面元素没渲染出来,你只能把报错信息连同整个脚本重新发给 AI 让它修改,这又是一次全量上下文重传。我自己实测,一个 250 行的 E2E 场景,从生成到稳定运行,往往要跑三轮修改,累计消耗一万五千 token 起步。

更麻烦的是钱还是小事,质量才是大问题。AI 没有真实看到页面,生成的定位符基本都是靠猜,class 名稍微变一点就碎。换一次前端构建,十个用例挂掉一半是常有的事。这让人很崩溃——你说它不懂吧,它写的代码逻辑看着挺完整;你说它懂吧,实际跑起来就是各种元素找不到。

1.2 录制生成的代码为什么不消耗 token

Playwright 的 codegen 模式解决的就是“AI 看不见真实页面”这个核心痛点。它会启动一个带录制器控制面板的 Chromium 窗口,你在页面上点哪里、输入什么、跳转到哪个页面,它都在后台实时生成对应的脚本代码,并同步显示在编辑器里。

关键在于:这个过程完全不调用模型接口。录制生成脚本的所有逻辑都在本地完成,不产生任何 API 请求,token 消耗严格来说是 0。所谓“人工录制省 Token”,省的就是这一大块反复生成和修复的代价。

当然,录制生成的代码并不是完美的,它会有不少冗余,比如录制器会把你的鼠标滑过元素的 hover 动作也记录下来,有时一个点击会连带生成两三个中间步骤。但这部分冗余是一次性的,录制结束之后花几分钟裁剪一下就好。相比之下,AI 全量生成的问题是长期存在的——你改一次它重写一次,每次重写都是一次新的 token 消耗。

1.3 Skills 在整套流程里的真实定位

这里说的 Skills,指的是 AI 编码助手里可以预置的技能包,也可以理解成一套“带约束的指令模板”。你可以把项目里反复出现的补全需求——比如“给这段操作加 Playwright 标准断言”“给关键节点补显式等待”“把从页面提取的文本做 strip 和类型转换”——封装成固定的 Skills,之后让 AI 按 Skill 的规则去处理,而不是每次重新描述一遍需求。

这个设计对 token 的影响很直接。有了 Skills,补全时的 prompt 可以写得很短,只需要告诉 AI“用断言 Skill 处理这个函数”,而不需要把断言怎么写、等待怎么写、用什么语法全都写一遍。项目特定的规则在 Skills 里定义好之后,后续每次触发都只需要一个简短的引用,上下文 token 能省下不少。

所以这套组合拳的本质是:codegen 负责“抓真”——拿到真实页面对应的稳定代码骨架,AI 负责“补虚”——在骨架基础上补充断言、异常处理等逻辑,人工负责“兜底”——做最后的裁剪和验证。三者分工清楚,缺一不可。

2. 录制前的准备工作:把 Playwright 环境调成真正能录的状态

2.1 基础环境安装与配置

先装环境,这一步别跳,很多莫名其妙的问题都出在环境不完整上。我用 Python 版演示,Node 版的思路完全一样。

mkdir ui-automation && cd ui-automation python -m venv venv source venv/bin/activate pip install playwright playwright install chromium

装完之后建议先跑一次playwright install看有没有系统依赖缺失,报什么补什么。

如果你用的是 Node 版,对应命令是:

npm init -y npm install -D @playwright/test npx playwright install chromium

这里有个小细节:如果项目里有现成的 pytest 体系,建议同时装一个pytest-playwright,后面跑用例和失败重试都会方便很多。我一开始只用纯 Python 的 playwright 库,跑用例还得自己写函数,后来切到 pytest 体系才发现,有些现成的 fixture 是真的省事。

2.2 进入录制模式前必须搞定的两件事

第一件事,确定目标地址是干净的。我建议用一套独立于开发环境的测试环境,数据可控、页面不会突然弹出别人的调试信息。录制的时候如果页面里混入弹窗、消息提醒、其他协作者的鼠标操作,生成的脚本会包含一堆莫名其妙的选择器,后面裁剪都费劲。

第二件事,提前把登录态处理掉。最典型的失误是一上来就录登录流程,结果每次录制前都要重新走一遍登录,而且登录页的验证码、二次校验很容易让录制中断。处理方法是先用--save-storage保存登录态:

playwright codegen --save-storage=auth.json http://app.example.com/login

在弹出的浏览器里手动完成登录,然后关掉录制窗口。这时候auth.json会把登录后的 cookie 和 localStorage 一起存下来。之后每次录制,直接用这个文件加载登录态:

playwright codegen --load-storage=auth.json http://app.example.com/orders

这样录制窗口一打开就是已登录状态,直接开始录业务主流程,干净利落。我第一次用这个功能的时候还担心 cookie 会过期,实际用下来发现,只要设置合理的过期时间,录一整个上午都没问题。

2.3 录制窗口的角色分配

一个很反直觉但必须遵守的原则:不要一边开着录制器,一边让另一个人手动操作同一个浏览器页面来“帮忙测试”。codegen 的录制窗口和常规浏览器不同,它会把页面上所有 click、input、scroll 都记录下来,人手在页面上的任何多余动作都会变成脚本里的噪音。

正确做法是:录制窗口打开之后,只通过录制器自己的控制面板去操作页面,或者说,把录制窗口当成一个“专用的提词器”。实际录制的过程中,每个点击之间稍微停顿一两秒,让前端把异步数据加载完再点下一个,这样生成的代码里会自然带上等待逻辑,比录制完再统一补等待靠谱得多。

另外,我强烈建议录制的时候把浏览器窗口固定在一个分辨率,比如 1440x900。不同分辨率下某些元素的位置和显示状态不一样,录制时如果来回拖拽窗口大小,生成的定位符可能出现状态不一致的问题,后面运行时会平白多出很多麻烦。

3. 人工录制时的操作纪律:先保稳定定位,再谈省 Token

3.1 录制时就要有“少而稳”的意识

很多人在录制阶段以为“反正后面还能改”,于是把凡是能看到的位置都点了一遍。这个想法问题很大。录制的每一步都会变成代码,而每多一步代码,后续 AI 补全时的上下文就多一份负担,运行时的失败点也跟着多一个。

我录制时给自己定了几条操作纪律:

  • 不点与当前业务场景无关的菜单、折叠面板、消息中心。
  • 不做无意义的鼠标滑过,hover 动作除非业务必需,否则一律不录。
  • 页面加载完成后停顿一下再继续,避免录制器把跳转和点击揉在一起。
  • 录入文本时尽量用稳定的测试数据,比如订单号用“TEST-2025-001”这种固定前缀,不要在录制时随机输入一段带特殊字符的内容。

这些纪律看起来很基础,但真正做到之后,录制生成的代码骨架会短很多,而且几乎不需要再大改。我印象特别深的是有一次录一个数据筛选流程,我手滑在页面上多划了几下鼠标,生成的文件里凭空多出七八个locator("div").nth(3)这类无意义定位,后来删得我头大。

3.2 录制后的裁剪顺序与关键动作

录制完成之后,生成的代码通常长这样:

from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False) context = browser.new_context(storage_state="auth.json") page = context.new_page() page.goto("http://app.example.com/orders") page.get_by_role("button", name="新建订单").click() page.get_by_label("订单编号").fill("TEST-2025-001") page.get_by_label("客户名称").fill("某测试客户") page.get_by_role("button", name="提交").click() # 到这里录制结束,需要人工补充后续逻辑 context.close() browser.close()

这已经是一个比较干净的骨架了,但我还会做三件事再交给 AI:

第一,把重复的page.goto清理掉。录制时如果中间点了浏览器的返回按钮,会出现一次多余的页面跳转,这种要直接删。第二,给关键节点补上简单的注释,比如# 提交表单后等待列表刷新。AI 补全时看到注释,理解上下文比看一堆裸代码快得多。第三,把硬编码的测试数据提取成函数参数或常量,比如订单号统一放到一个变量里,方便后续参数化。

做完这三步,这个骨架文件基本就是“可补全状态”了。我粗略统计过,一个完整订单流程的录制产物通常在 80 到 120 行,裁剪后能压到 30 到 40 行。剩下的内容全是真实业务操作,没有冗余,也没有 AI 猜测出来的假象。

3.3 定位符的稳定性要在这个阶段解决

录制生成的选择器乍看能用,但有一个隐性问题:很多前端组件是动态渲染的,列表内容、按钮状态都会变。录制时页面上第二行订单点了一下,生成的定位符可能是page.locator("tbody tr").nth(1),运行的时候如果第一行订单被删了,这个nth(1)指向的就是另一个完全不同的订单,后续断言必挂。

我的经验是:录制结束后,花几分钟检查关键操作的定位符,优先换成更稳定的方式。比如:

  • 有>以下是录制好的订单创建脚本骨架。请只补全 verify_order_list 函数的内部逻辑,要求: 1. 使用“标准断言”Skill 定义的 expect 方式校验列表中出现订单号 TEST-2025-001 2. 提交按钮点击后需要等待列表刷新,使用显式等待,不要用 time.sleep 3. 不要修改其他函数 4. 输出格式:只返回补全后的 verify_order_list 函数体,不要解释 【骨架代码】 <粘贴裁剪后的 30 行代码>

    这样一个 prompt 的输入 token 量大概就是“几十行代码 + 几行约束”,输出也只有函数体,比全量生成少了太多。关键在于“只返回函数体”这个约束,很多 AI 助手默认会给你输出一堆解释和说明文字,这既浪费 token,又干扰代码合并。

    4.3 补全后的验证流程

    AI 补全完之后,不要直接合并进测试套件,先单独跑一遍目标函数。我用的是 headed 模式,这样能看到真实浏览器里每一步执行到哪了:

    pytest tests/test_order_flow.py --headed --maxfail=1 -s

    如果是 Node 版,对应命令是:

    npx playwright test tests/order.spec.js --headed --reporter=line

    跑挂了之后,先冷静地把报错信息、截图、trace 收集起来,判断是定位问题还是断言条件问题,再决定要不要拿给 AI 改。这个判断非常关键——如果直接把报错一股脑丢给 AI 让它重写,很容易出现“改一个 bug 引出两个新 bug”的循环,token 消耗直接失控。

    前面骨架中录制下来的步骤如果定位稳定,跑挂的原因大概率出在 AI 补全的部分,也就是断言等待时间不够、元素文本带空格没 strip、或者某个中间状态没处理。有针对性地局部修改,一两个来回就能稳定下来。

    5. 一个订单流程的完整实战:从录制骨架到带断言的可用脚本

    5.1 需求与录制过程回顾

    用前面那套流程,给“订单创建”这个场景做一个完整的演示。需求很简单:打开订单列表页,点击新建订单,填写订单编号和客户名称,提交,最后在列表里校验新订单出现。

    录制的时候,我先用--load-storage=auth.json加载了登录态,然后直接在订单列表页开始操作。整个录制过程大约两分钟,生成的骨架代码我先做了裁剪,主要是删掉了录制时手滑产生的两处多余 hover,以及把重复的 goto 清理掉。最终的骨架如下:

    from playwright.sync_api import Page, expect ORDER_ID = "TEST-2025-001" def create_order(page: Page) -> None: page.get_by_role("button", name="新建订单").click() page.get_by_label("订单编号").fill(ORDER_ID) page.get_by_label("客户名称").fill("某测试客户") page.get_by_role("button", name="提交").click() def verify_order_list(page: Page) -> None: # TODO: 待 AI 补全 pass def test_order_flow(page: Page) -> None: page.goto("http://app.example.com/orders") create_order(page) verify_order_list(page)

    这就是典型的“人工录制+裁剪”产物,中间的逻辑被压缩到了最精简的状态。剩下的verify_order_list是空的,等待 AI 补全。

    5.2 AI 补全的实际输出与人工校核

    我把骨架和 prompt 发给了 AI 助手,它补全后的函数是这样的:

    def verify_order_list(page: Page) -> None: # 提交按钮点击后,页面会刷新列表数据,等待目标订单出现 expect(page.get_by_text(ORDER_ID)).to_be_visible(timeout=10000) # 同时校验订单状态列显示为“处理中” row = page.get_by_role("row", name=ORDER_ID) expect(row).to_contain_text("处理中", timeout=5000)

    乍看没有大问题,但人工校核还是发现了一个隐患:page.get_by_text(ORDER_ID)在页面上只有一行的时候是精确匹配,但如果页面有搜索框或者某些隐藏的全局变量中也包含订单号字符串,就有概率定位到多个元素。我手动把这一行改成了page.get_by_role("row", name=ORDER_ID),先定位到包含这个订单号的表格行,再对这个行做断言。这类细节是 AI 不容易判断的,因为 AI 看不到这个页面上到底有哪些其他元素也包含同样的文本。

    5.3 最终跑通的效果与运行数据

    改良后的脚本跑起来很顺利。我用 headed 模式跟踪了一遍执行过程,提交按钮点击后,列表区域确实异步刷新了大约两秒,expect的显式等待完美覆盖了这个时间窗口。最终脚本总行数不到 50 行,从录制到稳定运行花了大约二十分钟。

    作为对比,我用同样需求让 AI 全量生成了一版脚本做试验。最终脚本 260 行,看起来功能齐全,但实际运行时定位符错了三处,用了整整两天才稳定下来,期间消耗的 token 和反复修正的时间都远远超过了录制方案。这个对比让我彻底放弃了“全量生成脚本”的路线。

    6. 跑了三周后踩到的坑:定位漂移、token 虚高、Skills 边界

    6.1 动态列表引起的定位漂移

    这是我在三周里遇到的最大坑。第一次录制时列表页只有三行订单,nth(1)这样的相对定位在录制时是准确的。但随着测试数据越加越多,列表行数变化,这个相对定位指向的元素也跟着变化,导致一次回归测试中连续三个用例失败。

    后来我把列表行都加上了>

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 5:33:46

从零实现命令行图像处理工具:灰度化、缩放与边缘检测

第三次作业&#xff0c;听起来平平无奇&#xff0c;但经历过的人都知道&#xff0c;这往往是学习曲线上第一道真正的坎。前两次作业基本是照着课件把代码敲一遍&#xff0c;输入输出都是预设好的&#xff0c;顶多改改参数。第三次突然换了风格——某高校的图像处理课程直接甩了…

作者头像 李华
网站建设 2026/10/19 5:33:38

GNN配套代码实战解析:从GCN原理到PyTorch实现与避坑指南

简介&#xff1a;《深入浅出图神经网络&#xff1a;GNN原理解析》一书的官方配套代码包&#xff0c;面向正阅读该书并希望动手实践图神经网络算法的读者。代码按章节组织&#xff0c;覆盖图卷积网络、图采样、自注意力池化、自编码器等核心主题&#xff0c;并附有交互式笔记本示…

作者头像 李华
网站建设 2026/10/19 5:32:42

Mac虚拟机入门:Apple Silicon上跑Windows和Linux的实操指南

简介&#xff1a;本资源为Mac平台下Windows应用兼容方案的核心工具包&#xff0c;面向需跨系统运行特定Windows软件的macOS用户&#xff0c;尤其适合开发者、测试人员及办公场景中依赖IE兼容网站、Office套件或轻量级Windows工具的群体。资源主体为CrossOver安装程序&#xff0…

作者头像 李华
网站建设 2026/10/19 5:32:06

手写词法分析器:从原理到实现,避开预读与位置信息陷阱

1. 词法分析器到底在编译器里扮演什么角色很多人学编译原理&#xff0c;一上来就被“有限自动机”“正则表达式”“NFA转DFA”这些术语砸晕&#xff0c;结果代码没写几行&#xff0c;先被理论劝退。我当初也是这么过来的&#xff0c;后来在某个模拟项目里被要求手写一个能跑通四…

作者头像 李华
网站建设 2026/10/19 5:32:06

Python求解VaR与CVaR:从风险度量到组合优化实战

做组合风控或者写量化策略的人&#xff0c;大概率绕不开VaR&#xff08;Value at Risk&#xff09;和CVaR&#xff08;Conditional Value at Risk&#xff09;这两个指标。我最早把这两套东西用Python跑起来&#xff0c;是在帮团队搭风控体系的时候。当时Excel手算VaR已经撑不住…

作者头像 李华
网站建设 2026/10/19 5:31:43

鸢尾花数据集实战:KNN分类与机器学习建模全流程解析

1. 从入门到实操&#xff1a;鸢尾花项目到底在练什么很多人第一次接触人工智能和数据分析&#xff0c;都是从鸢尾花&#xff08;Iris&#xff09;开始的。这个数据集在圈内几乎是“Hello World”级别的存在——它不复杂&#xff0c;却能把机器学习的完整流程走一遍。当初我在某…

作者头像 李华