☰
Playwright CLI自动化测试实战:从安装调试到Selenium迁移
2026/10/21 10:22:48 网站建设 项目流程

过去几年我在自动化测试上有个很深的体会:工具链里真正决定工作效率的,往往不是某个功能最丰富的库,而是那个你天天都会调用的命令行入口。Playwright CLI就是这样一个存在。它不只是“安装完点一下运行”的玩具,从环境初始化、脚本生成、调试追踪到把老一套测试框架整体迁过来,几乎所有关键步骤都能在终端里一气呵成。这篇内容我会按自己实际踩过的路,从零开始讲清楚安装、常用命令、配置协同,再重点拆解迁移这一环,最后把常见报错和排查思路单独拉出来。无论你是刚接触自动化的小白,还是正在评估切换框架的老手,这应该都是一份能直接“照着做”的参考。

1. 为什么是CLI:安装到迁移的核心思路

1.1 CLI在整个自动化工作流里的定位

很多人第一次接触自动化测试时,会习惯性地先开一屏幕的图形界面工具,再来回切换浏览器窗口点来点去。Playwright CLI的思路不太一样:它把整条链路都往前压到了终端里。装依赖、装浏览器、录脚本、跑用例、开报告、看Trace,每个环节都有对应的子命令,命令之间还能组合。

我一开始也有疑问:图形化工具点按钮不是更直观吗?后来真在项目里用起来才发现,CLI的核心优势是“可脚本化”和“可复现”。你在本地执行过的一串命令,可以原样写进CI配置里;新人接手时不用花时间找某个按钮藏在哪,打开终端跑一遍就知道了。这种一致性在大规模迁移时尤其珍贵,因为迁移本身要处理大量琐碎的规则转换,如果连执行入口都不统一,后面排查起来会非常痛苦。

1.2 CLI工具链能解决什么实际问题

拿刚接触Playwright时的场景举例。我记得第一次只是想快速验证“某个页面能不能正常登录”,如果走传统方式,得先建项目、装依赖、写一段测试脚本、再跑起来,中间任何一个环节报错都可能卡半天。用Playwright CLI,一条playwright codegen就能打开浏览器录制操作,登录、点击、填表单全都会被自动转换成测试代码,省掉起步阶段最枯燥的样板代码。

更重要的一点是,CLI自带的能力是成体系的。playwright test负责执行和报告,playwright show-trace负责看失败录屏里的每一步操作,playwright screenshot和playwright pdf则能快速截图、出PDF。这意味着从验证环境到排查线上问题,整个流程不需要跳出终端去另找工具。对做迁移的人来说,这套自洽的工具链意味着旧的Selenium脚本里那些“截图保存”“WebDriverWait轮询”等散落逻辑,几乎都能找到对应的替代方案,迁移路径会很清晰。

2. 环境准备:从零装好Playwright CLI

2.1 安装方式选型与依赖选择

装Playwright CLI目前主流有两条路:Node.js生态用npm或pnpm,Python生态用pip。我没法替你决定团队技术栈,但有一个原则可以参考:如果你的测试代码准备用JavaScript或TypeScript写,就把它装成项目级依赖,不要图省事全局安装。

# 推荐在项目目录里执行 npm init -y npm install -D @playwright/test

为什么不推荐npm install -g playwright?因为全局安装会让版本散落在不同机器上,项目A和项目B用的可能不是同一套CLI,CI环境里还得额外处理全局依赖。项目级安装的好处是package.json锁住了版本,任何人拉到仓库后执行npm install,得到的CLI行为完全一致。我个人更习惯用pnpm,磁盘占用小,安装速度快;如果你的环境已经有pnpm,直接用pnpm add -D @playwright/test效果一样。

Python这条路径适合团队主语言就是Python的情况:

pip install playwright playwright install

两种方式装出来的CLI命令都是playwright,如果你同时有Node和Python环境,注意别搞混,最好在项目文档里写清楚用哪个解释器,不然执行命令时会遇到“缺模块”或“版本不对”这类让人头疼的问题。

2.2 浏览器二进制与系统依赖安装

装完npm包不意味着可以直接跑测试,因为Playwright默认使用自己维护的浏览器二进制版本,而不是系统里已有的Chrome或Firefox。这一步必须单独做:

npx playwright install

默认会安装Chromium、Firefox和WebKit三套浏览器。如果你只想先跑通Chromium,可以指定:

npx playwright install chromium

实际部署到Linux服务器时,光装浏览器还不够,系统里可能缺动态链接库,此时要跑:

npx playwright install-deps

这条命令会根据你当前的操作系统自动补齐依赖包。我在某个干净容器环境里试过,直接跳过这一步跑测试会报一连串“libnss3.so not found”之类的错,看报错以为是代码问题,折腾了半天才发现是系统库缺失。现在我的习惯是:任何全新的CI镜像或Docker环境,装完Playwright后立刻把install-deps也跑一遍,能省掉大量排查时间。

2.3 第一轮验证:初始化最小工程

装完之后先别急着写业务代码,做一次最简验证:

npx playwright --version

能正常输出版本号,说明CLI本体装好了。接着建一个最简单的测试文件,比如tests/demo.spec.js:

const { test, expect } = require('@playwright/test'); test('homepage has title', async ({ page }) => { await page.goto('https://example.com'); await expect(page).toHaveTitle(/Example Domain/); });

然后执行:

npx playwright test

看到测试通过,再顺手打开HTML报告看一遍:

npx playwright show-report

到这里,Playwright CLI的最小闭环已经打通,后续无论是写用例还是迁移老框架,都建立在这么一个能稳定运行的基础上。很多人在这一步直接拿旧Selenium脚本改改就跑,忽略了环境验证,结果后面报了错也不知道是CLI问题还是脚本问题。

3. 核心命令拆解:日常用得最勤的几个CLI入口

3.1 codegen:从人工操作到自动化脚本的加速器

先说playwright codegen,这是我认为性价比最高的一个命令。它做的事情很直接:打开一个浏览器窗口,你在里面手动点点点,它会把对应的Locator和步骤自动翻译成代码。

npx playwright codegen https://example.com

默认会直接打开Chromium,操作过程中右侧实时生成代码。我习惯先把目标页面的核心用户路径录一遍,比如“从首页登录→进入某个表单→填写→提交”,然后把生成的代码粘到测试文件里作为骨架,再手工调整断言的合理性。

这里有个容易被忽略的点:codegen默认生成的是选择器优先的代码,比如page.getByRole('button', { name: '提交' })。很多从Selenium迁过来的人会不习惯,习惯性地想改成XPath。我建议尽量保留这种语义化定位方式,它面对页面改版时的稳定性更好,后面在迁移部分还会重点说。

3.2 test与report:跑用例、看报告

playwright test是真正执行测试的核心命令,但它不是只能傻傻地跑完整套用例。我常用的组合方式包括:

# 只跑某个文件 npx playwright test tests/login.spec.js # 跑某条用例 npx playwright test tests/login.spec.js -g "should login with valid credentials" # 指定浏览器 npx playwright test --project=chromium # 带界面模式调试 npx playwright test --headed --debug

执行完默认会在playwright-report目录下生成HTML报告。我目前比较常用的是npx playwright show-report,它会拉起一个本地服务展示报告。报告里包含每个步骤的截图、网络请求、耗时信息,如果测试挂了还能直接看到失败现场。对于排查那种“本地好好的CI上挂了”的问题,这份报告往往是第一手证据。

3.3 screenshot、pdf与show-trace:调试辅助三件套

测试框架自带的截图功能已经很强了,但CLI单拆出来的playwright screenshot命令在快速验证环境时非常有用:

npx playwright screenshot --viewport-size="1440,900" --wait-for-timeout=3000 https://example.com shot.png

它不需要写任何测试代码就能拿到指定视口下的页面截图,适合用来确认样式问题,或者临时给某页面存个基线图。

playwright pdf和screenshot类似,只是输出是PDF,需要Chromium环境支持。如果是生成页面文档、导出报表这类场景,直接命令行处理很方便。

playwright show-trace看的是Trace文件,这个文件需要先有Trace数据,比如在配置里打开了trace: 'on-first-retry',失败重试时就会生成一个.zip文件。用show-trace打开后,能看到每一步操作的DOM快照、网络请求时间和控制台日志,排查那种“点击没反应”“元素闪现一下后消失”这类问题特别有效。

4. 配置协同:让CLI听你的话而不是反过来

4.1 配置文件里的关键字段该怎么定

Playwright CLI的行为受playwright.config.js或playwright.config.ts控制。CLI帮你执行,但“执行成什么样”大部分写在配置文件里。我用的比较顺手的配置结构大致是:

const { defineConfig } = require('@playwright/test'); module.exports = defineConfig({ testDir: './tests', timeout: 30_000, expect: { timeout: 5_000 }, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 4 : undefined, reporter: [['html'], ['list']], use: { baseURL: 'https://example.com', trace: 'on-first-retry', screenshot: 'only-on-failure', }, projects: [ { name: 'chromium', use: { browserName: 'chromium' } }, { name: 'firefox', use: { browserName: 'firefox' } }, { name: 'webkit', use: { browserName: 'webkit' } }, ], });

几个字段的取舍逻辑是这样的:retries在本地不想等太久,可以设置0;但CI上网络和资源波动大,2次重试能把偶发性失败过滤掉。workers控制并行度,本地默认自动,CI里固定成4比较稳定。trace开on-first-retry是折中方案,不会每个用例都产生大量Trace文件,但出问题时又有足够的现场数据可用。

4.2 CLI与npm scripts的组合用法

CLI的命令拼起来可能会很长,每次都敲全量参数既容易出错,也不好记。我的做法是把常用命令收进package.json的scripts字段:

{ "scripts": { "test": "playwright test", "test:headed": "playwright test --headed", "test:chrome": "playwright test --project=chromium", "report": "playwright show-report" } }

这样团队成员执行npm run test:chrome就行,不用关心底层是哪个浏览器、参数长什么样。对迁移项目来说,这一步最好在一开始就做掉,因为旧团队可能已经习惯了“跑一条命令看测试结果”的心智模型,你在新框架里提供同样易用的命令入口,迁移阻力会小很多。

4.3 针对性运行与调试断点

CLI跑测试时,最常用的调试组合是--headed --debug。--headed让浏览器窗口显示出来,--debug会在每个操作前暂停,方便观察当前页面状态。这个组合特别适合排查“元素能找到但点击后没反应”的情况。

如果你只想调试某条用例,可以用--grep加模糊关键词,或用-g接具体用例名。还有一个我后期才发现的技巧:在用例代码里某个步骤前加await page.pause(),CLI运行到这一行时会自动暂停并打开Playwright Inspector,配合--debug使用体验很流畅。对于旧测试脚本迁移过来的复杂周六操作,这个暂停功能比log大法容易定位问题。

5. 迁移实操:把旧测试套件搬到Playwright上

5.1 迁移前先想明白:换框架本质换什么

老测试框架迁到Playwright,表面上是换API,本质上是换一套执行逻辑。以Selenium为例,它的经典心智模型是“我写代码去操作远程浏览器”,所以会有WebDriver、DesiredCapabilities、显式等待这一系列概念。Playwright的心智模型更接近“浏览器就是我代码的执行环境”,通过登录状态复用、多页面Context、自动等待来减少人为干预。

对这个差异想得越透,迁移过程中越少走弯路。拿到旧脚本,不要急着逐行翻译,先按业务用途分类:哪些是登录流程,哪些是数据校验,哪些是跨窗口操作。分类之后你会发现,旧的“等待”“重试”“处理弹窗”这三类代码在Playwright里大多不需要显式存在,删掉比翻译更正确。我迁移过一个模拟项目X,旧脚本里大量WebDriverWait循环,迁到新框架后直接删了几十行,测试时间反而缩短,因为Playwright的自动等待只在元素真正可操作时才放行。

5.2 从零复制关键路径:录制与回放

我做过几次迁移之后,总结出一条最稳的实操路线:别只盯着旧代码翻译,先跑一遍业务路径,用codegen生成新的基础脚本。因为旧代码里那些定位符可能早就失效了,而业务人员实际操作的路径反而最可靠。

具体操作是:在旧系统和新系统同时准备一个测试账号,用npx playwright codegen走一遍核心路径。生成新脚本后,把旧的断言逻辑填进去,比如“提交后应出现成功提示”“列表里应多出一条记录”。这样一来,迁移后的测试至少跑的是当前真实业务流,而不是过去某个时候正确的历史逻辑。

5.3 等待策略、定位器与新窗口处理

迁移时最容易踩的三块,我单独拎出来讲。

第一是等待策略。Selenium时代常见的time.sleep(2)或WebDriverWait在Playwright里大部分不需要。Playwright的操作会在元素出现在DOM且可见、可点击、不遮挡时自动继续。需要保留显式等待的场景一般是“发起请求后等待接口返回”或“等待某个元素数量发生变化”。这时用page.waitForResponse或expect(locator).toHaveCount(n)更合适,而不是简单睡眠。这一点很多从旧框架迁过来的人一开始会非常焦虑,总觉得不加等待会不稳,实际上需要克服的是习惯,不是框架能力。

第二是定位器。旧的driver.find_element(By.ID, 'username')应该改成page.getByLabel('用户名')或page.getByPlaceholder('请输入用户名')。XPath能不用就尽量不用,Playwright的Locator是支持跨框架查询的,语义化定位在页面结构调整时容错更高。我见过最典型的坑是旧的XPath里写死了某个div[3]的层级,页面改动之后定位全挂,这在语义化定位里基本不会发生。

第三是多窗口与iframe。Selenium里switch_to.window、switch_to.frame是高频操作,Playwright换成了多Page结构:新窗口打开时监听context.waitForEvent('page'),切换到新窗口后直接用这个Page对象操作。iframe用page.frameLocator(selector)避免切换上下文。这个差异如果没意识到,迁移时会在“莫名找不到元素”上卡很久。

6. 常见问题与排查技巧实录

6.1 安装环节最常踩的坑

我把实际遇到过的高频报错列成一张速查表,按出现频率排序。

现象常见原因处理方式
command not found: playwright并未安装全局CLI,或npx没有找到本地依赖优先用npx playwright,确认node_modules/.bin存在
Executable doesn't exist...没有执行playwright install,或装着多个版本浏览器路径对不上执行npx playwright install,必要时npx playwright install --with-deps
打开浏览器即闪退容器或服务器缺系统依赖库执行npx playwright install-deps,再看具体报错库名
测试时浏览器乱码中文字体缺失容器里安装字体包,比如fonts-noto-cjk
代理环境下安装失败下载二进制没有走代理配置配置环境变量HTTPS_PROXY,或手动下载浏览器包放到缓存目录

其中“容器闪退”这条最迷惑人。报错可能只是error while loading shared libraries: libnss3.so,但表象是“浏览器打开了又立刻关了”。遇到这种情况,第一反应不是改代码,而是检查系统依赖。

6.2 运行期报错与调试思路

运行期最常见的报错之一是无匹配元素:waiting for locator...。如果是旧脚本迁移过来的,大概率是定位器语义不匹配。我排查时会打开Trace文件看失败时截图,确认页面上元素是否存在、文本是否多了一个空格、是否被弹窗遮住。对于“存在但不可见”的元素,Playwright默认不会点击,需要检查CSS属性是否设置了display:none或visibility:hidden。

另一个高频问题是超时:Timeout 30000ms exceeded。我会先看playwright-report里失败步骤对应的网络请求,是接口响应太慢,还是元素需要等待,再决定是否加expect.poll或page.waitForNavigation。不要只是为了“变得更稳”把所有超时都调大,那只会掩盖真实的性能退化或脚本缺陷。

6.3 迁移期隐蔽适配点

迁移时有一些问题不会立刻暴露,但会在特定条件下突然冒出来,我把它们记在这里。

  • 本地存储与登录态:旧脚本往往每次重新登录,Playwright里如果测试跑得快,频繁登录会很浪费。用storageState保存登录态,直接通过CLI或配置文件指定,能显著提速。
  • 文件下载与上传:Selenium处理下载目录很麻烦,Playwright里监听page.waitForEvent('download')就能拿到下载对象。上传则用setInputFiles直接指定文件路径,不用去点系统级弹窗。
  • 多浏览器兼容:旧框架只跑Chrome的项目,迁到Playwright后我建议至少先加一个Firefox project跑一遍。真正的兼容性问题不会“等”你上线后才暴露,越早用CLI的多project机制跑,越能在迁移期间就发现问题。
  • 并行带来的数据竞争:Playwright默认可以并行跑用例,如果旧系统在同一账号下会有“互踢”问题,迁移时建议配置fullyParallel: false,或者在共享环境里为每个worker准备独立测试账号。

6.4 独家避坑技巧

调试时不要只盯着失败截图,多利用--trace on手动跑一轮完整流程。我习惯在迁移期间把trace临时设为'on',所有用例都生成Trace,跑完后用show-trace逐帧看操作。这样能看到在哪个步骤页面状态发生了变化,比我反复打断点快得多。

还有一点是签字模式不适用的情况也要提前知道:如果被测系统有严格的验证码或硬件指纹校验,任何自动化框架都绕不开。迁移前先和业务确认这部分是否有白名单方案,否则会在这一步卡住整个迁移进度。

最后:几条值得长期保留的使用习惯

写到最后,分享几个我在实际项目中固化下来的习惯。第一,把常用CLI命令收进npm scripts,让团队所有成员用同一套短命令。第二,每次迁移一个模块后立刻用playwright test配合show-report验证,不要攒到最后一次性处理,否则排查成本会指数上升。第三,遇到“本地过了CI挂了”这类问题,别急着重跑,先把Trace和报告存下来,对比本地和CI环境在浏览器版本、系统依赖上的差异。这些习惯不会直接体现在某个命令里,但能让CLI的使用效率高出不少。

如果你刚开始接触Playwright CLI,我建议先从codegen命令玩起,录一段真实业务操作,再慢慢尝试test、show-report和show-trace。当这些命令顺手之后,再回看那些想迁移的旧脚本,你会发现自己已经有了清晰的转换思路和足够的排查底气。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询