Playwright+AI:零基础构建稳定可持续的Web自动化测试
过去很长一段时间,我对“自动化测试”这四个字是有偏见的。
不是因为它没用,而是因为见过太多团队把自动化测试做成了“测试脚本博物馆”——脚本写了一堆,用例全都跑得通,但一遇到需求变更、元素改版、弹窗干扰,整个测试套件就原地失效。维护成本比手工回归还高,最后大家默契地不再提“自动化”,回到最原始的点鼠标。
直到我认真把 Playwright 捡起来,配合现在这波 AI 工具链重新做了一遍 Web 自动化测试,才意识到一个问题:不是自动化测试不行,而是过去那套“录制回放 + 硬编码等待 + 脆弱的 CSS 选择器”的思路早就该被淘汰了。Playwright 这类新一代框架,加上 AI 辅助生成和维护脚本,真正改变的其实不是“怎么把测试跑起来”,而是“测试脚本到底该由谁来写、怎么维护、能不能长期活下来”。
这篇文章我不会只给你贴一段安装命令、甩几个 API 用法。我更想讲清楚一件事:零基础用 Playwright 做 Web 自动化测试,最值得投入时间的 1 小时到底应该花在哪。也会把 AI 和 skills 这类新玩法,从“听起来很玄”拆到“落地到底该怎么做”。
1. 先别急着写脚本,想清楚 Web 自动化到底卡在哪
很多人一上来就想要脚本、想要代码、想要“保姆级教程”,但我建议先停一下。因为如果你不理解 Web 自动化测试过去为什么屡屡失败,那你用 Playwright 也只会把它用成另一个 Selenium,然后得出一个错误结论:这个东西也不好用。
1.1 老问题的根源是“快”和“稳”永远在打架
手工测试最大的痛点不是执行慢,而是人脑能根据页面状态动态判断“现在该点击了”还是“还在加载中”。但传统自动化脚本最缺的就是这个判断能力。
早期用 Selenium 写脚本时,最常见的一个坑是什么?是元素还没加载出来,脚本就去找元素了。于是大家在脚本里拼命加 time.sleep(3)。页面快了,这 3 秒白白浪费;页面慢了,3 秒根本不够。这种靠猜的等待方式,本质上是让测试脚本去适应“某个固定时刻的页面状态”,而不是去适应“页面最终会到达的状态”。
Playwright 和 Selenium 一个很核心的差异就在这里:Playwright 默认所有操作都在等待元素处于可操作状态,它内部有一套自动等待机制。你不需要去猜要不要等、等多久,它自己会判断。这不是某个参数带来的小优化,而是整套设计逻辑变了——脚本不再关心“页面现在进行到哪一步”,而是关心“我要操作的目标是否已经准备好了”。
1.2 Playwright 真正解决的,是让测试脚本从“脆弱的”变成“可控的”
过去测试脚本之所以脆,通常是因为三个地方:
- 等待机制靠 sleep,不稳定。
- 选择器高度依赖 CSS 类名和 DOM 结构,前端稍微改个类名就挂。
- 浏览器环境隔离困难,并行跑用例就互相干扰。
Playwright 的处理方式挺有意思。等待机制刚才说了,是内置的自动等待,不用你再写 time.sleep。选择器这块,它提供了一套更贴近用户视角的定位方式,比如通过文本、通过角色定位元素,而不是死死绑定某个 class。多页面和多标签页之间,它还能用浏览器上下文(Browser Context)做隔离,不同测试用例各用各的上下文,互不打扰。
所以当你看那些“Playwright 一小时上手”的视频,看到别人刷刷刷写出几十行用例时,不要只盯着代码看。真正值钱的是那套“自动等待、可读定位、上下文隔离”的设计。明白了这套东西,你才可能把 Playwright 用好,而不是只会对着录制脚本改选择器。
1.3 Web 自动化的边界:它替代的是回归,不是探索
这里我想先给一个判断,也算给全文定个调:Playwright 这类工具的长期价值,不是“让测试变快”,而是让测试这件事变得可控、可复用、可回流到开发流程里。
换句话说,它替代的主要是重复性极高的回归测试,不是探索性测试。你不可能靠它发现“这个页面设计得反人类”这种体验问题,也很难靠它覆盖需要大量视觉判断的场景。这不是 Playwright 的缺点,是 Web 自动化的天然边界。你看完下面所有内容后,如果还记得一句话,那么我希望是这句。
2. 零基础 1 小时上手,不是“学完”,而是“跑通第一条链路”
很多人看到“1 小时上手”会觉得是标题党,我也觉得是标题党,但它有个前提:如果环境没问题、网络没问题、你知道怎么打开命令行,那 1 小时足够你把一条自动化测试链路完整跑通。这个“跑通”指的是:你能写一个最简单的自动化脚本,访问一个网页,点击几个按钮,输入一点文本,最后断言页面出现了预期内容。
2.1 前 20 分钟:把环境彻彻底底准备好
Playwright 的核心能力是控制浏览器。所以第一步不是写代码,而是把浏览器控制通道搭好。
这里先说一个常见误区。很多人一打开 Playwright 安装文档,就直接复制 npm install @playwright/test,装完就开始写代码。然后执行的时候报错浏览器没找到,又去查资料,发现还要装浏览器内核。这一步非常劝退。
按我的习惯,会先把整个环境链路理解成下面这几块:
| 组件 | 作用 | 安装/准备方式 |
|---|---|---|
| Node.js | 运行 JavaScript 代码的运行时环境 | 去 Node 官网下载 LTS 版本,安装完用 node -v 验证 |
| Playwright 测试库 | 提供编写和运行测试的 API | 在项目目录运行 npm init playwright@latest |
| 浏览器内核 | 被 Playwright 控制的浏览器实例 | 安装完 Playwright 后运行 npx playwright install chromium |
| 系统依赖 | 浏览器运行所需的底层库 | 如果浏览器启动失败,运行 npx playwright install-deps |
注意 npm init playwright@latest 这个命令。它不是让你从零搭项目,而是会直接创建一个 Playwright 测试项目骨架,包括 tests 目录、配置文件 playwright.config.js、一个示例测试文件。对零基础的人来说,这意味着你不用自己纠结目录结构和配置,先跑起来再说。
安装浏览器内核这一步,我看到很多教程会跳过去。但对你来说,这个步骤不做,后面什么事都干不了。它就是那个“台上一分钟,台下十年功”里的十年功。
2.2 中间 30 分钟:跑通第一次浏览器自动化
环境准备好之后,不要急着去看 API 文档。先跑。
在项目目录里创建一个测试文件,比如 tests/first.spec.js,写入一个非常小的用例:
然后运行:
如果一切正常,你会看到测试通过。如果浏览器启动失败,大概率是内核没装好或者系统依赖缺失,回到上面那张表检查。
这里有一个非常重要的认知:Playwright 里的 page 对象就是整个页面本身。 你不用像 Selenium 那样维护一个 WebDriver 实例,也不用操心浏览器启动关闭的细节。Playwright 会在每个测试用例的开始自动创建浏览器上下文,在用例结束后自动关闭。你只需要把一个用例要做的所有事写在一个测试函数里。
2.3 用 codegen 快速生成脚本:录制不是终点,而是起点
说到 1 小时上手,有一个功能必须提前讲,就是 Playwright 的录制功能。
运行下面这条命令:
它会打开一个浏览器窗口,同时打开一个 Playwright Inspector 面板。你在浏览器窗口里做的任何操作——点击、输入、跳转——都会实时生成对应的脚本代码,显示在 Inspector 面板里。做完操作,直接复制生成的代码到你自己的测试文件里。
但我要说清楚一件事:用录制生成脚本,只适合刚上手时快速理解“操作和代码的对应关系”,不建议直接拿录制脚本当测试用例用。为什么?因为录制生成的代码通常是流水账式的操作序列,它没有断言、没有业务含义、有时候还会生成冗余步骤。
正确的姿势是把录制当成“草稿生成器”:先录制一遍完整操作流程,了解哪些元素需要点击、哪些输入框需要填写,然后在这个基础上做三件事:
- 删掉脚本里明显多余的等待或跳转。
- 给关键的交互步骤加上
await expect(...)断言。 - 把硬编码的测试数据提取成变量,方便后续复用或切换环境。
从录制到手动改写,这一步才是真正从“会用工具”走向“会写测试”的分水岭。
2.4 零基础最容易忽略的一组概念:locator 与自动等待
录制脚本的时候,你会发现生成的代码里到处是 page.getByRole('button', { name: '登录' }) 或者 page.locator('#username') 这样的东西。
在 Playwright 的体系里,locator(定位器)是一个核心概念。它不是“某个元素的快照”,而是一个“怎么找到目标元素”的描述。这个区别很关键:传统方式拿到元素后,如果页面刷新了或者 DOM 变了,这个元素引用就失效了;而 locator 每次操作时都会重新去页面里查找,配合自动等待机制,就能在页面动态变化时保持稳定。
所以你写脚本时的核心任务,不是背 API,而是学会选对 locator。优先顺序通常是:
- 用户可读的属性,比如
getByRole、getByText、getByLabel,这些最接近用户视角,前端改样式不影响。 - 稳定的测试专属标记,比如
data-testid。 - 最后才考虑 CSS 选择器或 XPath。
记住这个优先级,后面你踩的坑会少很多。
3. 当 AI 和 skills 介入之后,脚本生产的逻辑真的变了
说完了 Playwright 本身,我们来聊这波更大趋势里最有意思的部分:AI 到底怎么改变自动化测试的生产方式。
这里说的 AI,不是指哪个测试平台挂了个“智能”名头,而是你实际写代码、调脚本的日常流程里,AI 能不能真的帮你把事情干了。
3.1 AI 真正替代的不是“测试工程师”,而是“重复劳动”
很多人担心 AI 会取代测试工程师。我的判断是:它先取代的是一部分纯手写代码的工作,但在那之后,它会把测试工程师的角色往“需求理解”和“质量判断”这两个方向推。
举个实际场景。你有一个登录功能要测试,如果是在传统流程里,你得先看需求文档,再写一套用户名密码输入、点击登录按钮、断言登录成功的脚本。这个过程可能花 20 分钟。现在你用 AI 工具,比如在编辑器里装上支持 AI 编程的插件,输入一句话“帮我写一个登录页面的 Playwright 测试用例”,它几秒钟就能生成一个初稿。
你拿过来一看,结构大致是对的:有 page.goto,有 getByLabel('用户名') 输入,有点击,有断言。但细节可能会有问题,比如按钮名称写错了、没有处理登录失败的场景、断言方式过于固定。
这说明什么?说明 AI 帮你把“从需求到代码初稿”的转换成本降到了极低。但剩下那部分——判断场景覆盖是否完整、修正选择器、补充边界情况——恰恰是最需要测试经验的地方,也是 AI 短期内做不好的地方。
3.2 skills 是什么:给 AI 一套“预置经验”
最近在 AI 编程工具里经常听到一个词叫 skills。不同产品里它的具体形态不太一样,但你可以把它理解为:给 AI 预设的一组知识和操作指南,让它在生成答案时不至于漫无边际。
对应到自动化测试场景里,比如你想让 AI 持续帮你写 Playwright 用例,但你的项目有自己的约定,比如元素定位优先用 data-testid、测试数据放在 fixture 文件里、所有用例都要考虑登录态。如果每次聊天都要重复交代这些,那效率很可怕。
你可以把这些约定整理成一个 skill:写清楚项目使用的测试框架、目录结构、定位方式偏好、需要遵守的断言风格、以及历史踩坑记录。之后 AI 生成代码时会参考这个 skill,输出风格更贴近你项目实际需要。
skill 的意义从来不是“让 AI 更聪明”,而是让 AI 更懂你的上下文。它把散落在你脑子里的项目规则,变成 AI 可以读取和遵循的外部知识。
3.3 用 AI 生成代码时,必须先过一遍的四个检查点
不管你是用通用 AI 助手,还是用专门的测试生成工具,生成的代码都不能直接上。我给自己定了一个“四步验收”流程,分享给你参考。
- 命令是否可执行:先跑一遍,看语法和依赖有没有问题。
- 选择器是否稳定:看它选元素的方式,如果全是 CSS 层级选择器,要警惕前端改动导致失效。
- 断言是否符合业务预期:AI 往往会生成“页面出现某文本”这种断言,但你要确认这是不是业务真正关心的结果。
- 超时和失败处理是否合理:AI 生成的代码里,超时设置和异常处理常常是缺失的,要补上。
这里不光是代码质量问题,也是安全边界问题。AI 毕竟不了解你的业务,它的知识来源是通用代码库和网上公开资料,和你项目的实际情况之间,永远存在翻译误差。
3.4 别忘了 MCP 这类连接能力:AI 与浏览器的本地协作
在热搜内容里反复出现 Playwright MCP、Codex Playwright 这类词。这里做一个不那么严格但比较通俗的解释:
MCP 可以理解为一套“让 AI 工具和本地软件沟通的协议”。当 AI 编程工具接入了 Playwright 的 MCP 服务后,它不再只是凭空生成代码,而是能直接驱动你本地的浏览器,实际去访问页面、截图、查看控制台报错。
这意味着 AI 生成代码后,可以自己做一轮“自证”:打开页面,执行操作,看结果是否通过。这是一个很大的变化。过去 AI 写代码经常出现“看着没问题,一跑就挂”的尴尬,核心原因就是它看不到运行时反馈。有了 MCP 这类连接能力,AI 从“静态代码生成器”变成了“能自我验证的执行器”。
不过要提醒的是,这类能力还在快速演进中,各产品的配置方式差异很大。如果你只是想了解原理,记住上面这个方向就够了;如果你要实际用,最好以对应工具的官方文档为准,不要盲目相信第三方教程。
4. 从“能跑”到“稳定跑”,这四层问题决定了自动化能否长期存在
很多人试过 Playwright 之后会有一个很直观的感受:第一次写脚本真的不难,难的是这套用例能不能稳定跑一个月、三个月、半年。
所谓“稳定跑”,指的是在业务代码没有发生功能性变化的前提下,每次跑测试套件都能得到相同的结果。只要出现一次“测试环境没问题但用例挂了”,就会消耗团队对自动化的信任。而信任一旦消耗殆尽,自动化测试项目基本就凉了。
4.1 第一层问题:非预期弹窗和动态元素
你在热搜里能看到“自动化测试非预期弹窗导致失败 解决方案”这条词,说明这绝对是最高频的痛点之一。
页面突然弹出一个广告浮层、一个 Cookie 授权框、一个新手引导蒙版,测试脚本本来要去点“提交”按钮,结果被弹窗挡住了,或者点击被别的东西截获了,用例就失败了。
这类问题为什么难搞?因为弹窗出现与否往往取决于环境、时间、用户状态,不是每次运行都稳定出现。处理思路可以分三步:
- 先判断弹窗是否属于测试必需路径。如果是,就直接定位弹窗元素并正常操作。
- 如果弹窗和被测功能无关,考虑在测试前置步骤中统一处理,比如进入页面后先关闭弹窗。
- 如果弹窗机制太随机,可以考虑用 Playwright 的路由拦截能力,屏蔽掉与本次测试无关的请求,从源头上避免弹窗产生的条件。
最怕的是你在用例里到处写“如果弹窗存在就关闭”这种分支,那会让用例变得很难读,也会让测试进入一种“不确定状态”。
4.2 第二层问题:等待的边界在哪里
前面说 Playwright 有自动等待,那是不是就不用关心等待问题了?
不是。自动等待解决的是“元素最终会出现在页面上”的场景。但还有一种场景它处理不了:元素已经出现了,但页面上的数据还在加载,此时你以为拿到了最终状态,实际上拿到的是半成品。
举个例子,一个表格数据接口响应比较慢,页面先渲染了表格框架,但数据还没回来。你断言表格中出现了某一行数据,这时 Playwright 会发现元素不存在,然后继续等;但如果接口返回的是空数据,表格框架已经渲染完成,Playwright 就认为“目标状态达到了”,断言可能失败。
解决这类问题,不能只依赖自动等待,更稳妥的方式是让断言等待业务真实关心的条件,比如“表格里出现了 3 行数据”“某个状态文案变成了‘已完成’”。所以我的建议是:默认依赖自动等待,但要对关键业务节点写显式断言,并且把超时时间设置得足够覆盖网络波动。
4.3 第三层问题:动态 iframe 和多页面框架
如果你接触过复杂的 Web 应用,一定会遇到 iframe 嵌套页面,尤其是比如地图、支付、富文本编辑器这类组件。Playwright 里处理 iframe 的方式是使用 frameLocator,先定位 iframe,再在 iframe 里找元素。
这里容易踩的坑是:iframe 的加载时机和主页面不同步,你切换到 iframe 找元素的时候,iframe 可能还没渲染完成。所以处理 iframe 时,建议先等待 iframe 可见,再进行内部定位操作。
多页面框架(比如新标签页)则是另一个高频场景。点击一个链接后,页面在新标签页打开了。Playwright 里可以监听 context.waitForEvent('page') 来获取新页面,然后对新页面执行操作。
这里的 Promise.all 并行写法是 Playwright 的一个常见模式:先注册等待事件的 Promise,再执行会触发该事件的操作。它能避免“事件先触发、后监听”导致丢失的情况。
4.4 给一份排查链路:用例挂了你该按什么顺序查
不管你是新手还是老手,遇到测试用例挂了,最忌讳的是手忙脚乱去改脚本。我自己的排查顺序大概是这样的:
| 顺序 | 检查项 | 具体动作 |
|---|---|---|
| 1 | 看现象 | 用例报错信息是什么?是超时、断言失败,还是无元素可操作? |
| 2 | 看截图和录制 | Playwright 失败时自动生成的截图、Trace 文件能帮你快速还原现场 |
| 3 | 看选择器 | 元素的定位方式是不是靠绝对路径或易变 class?改用更稳定的角色、文本定位 |
| 4 | 看等待 | 是页面还没加载完,还是断言条件设得太早? |
| 5 | 看环境 | 是不是网络慢、资源没释放、浏览器版本不匹配导致的问题? |
| 6 | 看工具边界 | 这个功能是否本来就很难自动化(比如验证码、拖拽、图形识别)? |
这套链路可以帮你把问题从“玄学失败”变成“可定位、可修复”的工程问题。绝大多数情况下,问题会出在第 3 步和第 4 步。
5. 真正的分水岭:把一次脚本升级成可持续的测试资产
写到这里,我想你已经有能力写出第一个真正能跑、能在简单项目里持续使用的 Playwright 用例了。但如果你只是停在这里,那和“录了一个脚本,跑通了一次”并没有本质区别。
真正让自动化测试产生价值的,是把它当成一个长期资产来经营。这个阶段的核心不是写更多脚本,而是解决结构、反馈和效率问题。
5.1 先建立一个“最小但完整”的项目结构
很多零基础教程不会教你规划项目结构,导致你写着写着,所有测试脚本堆在一个目录里,公共方法复制粘贴,测试数据散落各处。等到项目大了,光维护成本就把收益吃掉了。
我更建议从最小但完整的结构做起:
这里不追求复杂,但要把“测试用例”“公共数据”“配置文件”分开。将来增加用例时,你只需在 tests 里加文件;调整环境地址时,只需要改配置文件;生成测试数据时,调用 utils 里的函数就行。
5.2 用 fixture 管理登录态和公共数据
如果你有多个用例都需要先登录才能继续测试,那你一定会遇到“登录态怎么复用”的问题。
Playwright 里可以通过配置 storageState 来复用登录状态。简单理解就是:先跑一次登录流程,把登录后的 Cookie 和本地存储保存到文件,后续用例启动时直接加载这个文件,就不需要每个用例都重新登录了。
这个方案非常适合大型项目的自动化测试,能省掉大量重复登录时间。但要注意一点:登录状态文件是有时效性的,如果测试环境的会话有效期较短,或者用户密码经常变,就需要定期重新生成。所以实际项目中通常会把“登录态准备”放到 CI 流程的前置步骤里。
5.3 不要忽视报告和日志,它们是长期维护的眼睛
测试跑完了,没人看报告,等于白跑。
Playwright 默认会生成 HTML 报告,里面有每个用例的通过/失败状态、执行时长、失败时的截图和堆栈。这个报告在本地看很方便,但如果你的项目要长期维护,还要把它接入 CI 平台,让每个人在代码提交流程里都能看到测试结果。
报告和日志的意义在于:它把“测试用例是不是通过了”这件事,从“只有测试人员知道”变成“全项目组都能看到”。当自动化测试的结果开始影响代码合并决策时,用例的稳定性和重要性才会真正被重视。
5.4 什么项目适合、什么项目不适合
最后说点反“热情”的话,算是给文章收个尾。
Playwright 在大多数标准 Web 应用上表现都很出色,但并不是所有 Web 项目都适合一上来就上自动化。以我个人的标准来判断:
适合的场景:
- 业务流程相对固定,适合回归测试。
- 有明确的输入输出,可以写断言。
- 前端版本迭代快,但核心流程变化不频繁。
- 团队愿意投入时间维护测试资产。
不适合或需要额外评估的场景:
- 大量依赖验证码、短信、图形拖拽等防自动化机制。
- 频繁变更 UI 的快速原型阶段。
- 业务本身缺乏明确断言标准,无法判断“对不对”。
- 测试数据和测试环境都不稳定,连手工测试都难以复现结果。
评估是否引入 Playwright 自动化测试,可以参考三个判断标准:
- 这个流程我过去三个月里手工回归了多少次?
- 这个流程如果跑挂了,团队能否很快定位到问题?
- 我是否愿意为它投入维护成本,而不只是写脚本时爽一下?
如果三个答案都是“是”,那就值得上。如果有一个是否定,我建议你再想想,不要为了自动化而自动化。
写在后面:先跑通,再判断,别让工具替你思考
回到文章开头的问题。为什么很多人用自动化测试失败,而有些人用同一套工具却能把测试越做越稳?
差别不在工具,甚至不在代码水平。差别在于——你是把自动化测试当成“写脚本的一次性任务”,还是把它当成“一个长期演进的质量基础设施”。Playwright 和 AI 能帮我们把脚本生成的成本降到很低,但它替代不了你对业务的理解、对断言的判断、对维护的承诺。
如果你想开始,我给你的建议不是去看一堆教程,而是今天先在本地装好环境,用 npx playwright codegen 打开一个你天天用的网站,手点一遍流程,看看生成的代码,然后花十分钟改写成一条带断言的用例。先跑通这一条链路,你自然就知道下一步该往哪儿走了。