Playwright UI Mode 怎么用:把改一行跑一次的循环缩短
改一个 locator,切到终端敲一次 npx playwright test tests/checkout.spec.ts,等浏览器起来,看一行红字,回编辑器再改一个字符——写端到端用例的人对这个来回都不陌生。真正难受的地方不在这一来一回本身,是你看不到失败那一刻页面长什么样,只能靠报错文本猜。Playwright 仓库里为这件事准备的东西叫 UI Mode,文档在 docs/src/test-ui-mode-js.md。
这篇只讲仓库里白纸黑字写了的部分:怎么启动、watch 到底盯什么、按标签和 project 过滤怎么写、pick locator 怎么用,以及源码里几处「文档没说但代码写了」的边界。
一、UI Mode 想解决的是哪一段
按 docs/src/test-ui-mode-js.md 开头那段的说法,UI Mode 把测试文件全部列在侧边栏,可以展开到单个 describe 块甚至单条用例去运行、观察、watch、调试;跑完之后能看到完整的 trace,在时间轴上前后拖动,看每一步动作发生时页面是什么样子;DOM snapshot 还能弹到独立窗口里,用浏览器 DevTools 去查 HTML 和 CSS。
换句话说,它把「跑一次—看结果—定位元素」这三件原本分散在终端、报告文件和浏览器里的事,收进了同一个界面。docs/src/running-tests-js.md 里那句推荐语提到的三样东西——locator picker、watch mode 和逐步回看——就是它和普通 npx playwright test 的差别所在。
二、前置条件(这一段别跳)
它属于 Test Runner,不是浏览器 API 那一层。 --ui 这三个选项定义在 packages/playwright/src/program.ts 里,也就是 npx playwright test 这个命令自带的,用 Playwright 的 Library 形态直接驱动浏览器时没有这个入口。
语言绑定要看清。 仓库 docs/src/ 下 UI Mode 的文档页只有 JavaScript 版本,文件名带 -js 后缀;我们没有在该目录下找到 Python / Java / C# 对应的 UI Mode 指南页。按仓库里的目录约定,带语言后缀的页面就是该语言专属页,所以要照着这篇做,你的项目得是 @playwright/test 那一套。
环境要求以仓库为准。 docs/src/intro-js.md 有一节 System requirements,列了受支持的 Node.js 与操作系统版本。那一节的具体数值随版本变,这里不抄,用之前自己去仓库看一眼。
三、启动与几个参数
最基本的一条,直接抄自文档:
npx playwright test --ui
docs/src/intro-js.md 里同一段还给了另外两个包管理器的写法:yarn playwright test --ui 和 pnpm exec playwright test --ui。
docs/src/test-cli-js.md 的选项表里,跟 UI 有关的一共三个:--ui(Run tests in interactive UI mode)、--ui-host <host>、--ui-port <port>。后两个的描述里有同一句话——指定它就会在浏览器标签页里打开 UI。这句话在源码里能对上:packages/playwright/src/runner/testServer.ts 的 runUIMode() 判断 options.host !== undefined || options.port !== undefined,成立时走 openTraceInBrowser(),否则走 openTraceViewerApp() 开一个 Chromium 窗口,并且这个窗口关闭时会取消整个会话。
Docker 与 GitHub Codespaces 这类容器环境,文档给的是:
npx playwright test --ui-host=0.0.0.0
理由文档自己写了:端点要能被容器外访问,就得绑到 0.0.0.0 接口。想固定端口再加一个:
npx playwright test --ui-port=8080 --ui-host=0.0.0.0
这里的 8080 是文档示例里的值,不是什么约定端口。文档在这段下面挂了一个 note,措辞很直白:指定 --ui-host=0.0.0.0 之后,UI Mode 连同你的 trace、密码和密钥都能被同一网络里的其它机器访问到。要绑之前先想清楚这台机器在什么网段上。
Windows 侧还有一个细节:runUIMode() 走本地窗口那条路时,会先调 installedChromiumChannelForUI(),这个函数按 chromium、chrome、msedge 的顺序,从你 config 的各个 project 里挑一个已配置的 channel。也就是说 UI Mode 这个壳本身是 Chromium 系的窗口,和你测试跑在哪个浏览器上是两回事。
四、watch 模式盯的是哪些文件
文档里的操作很简单:侧边栏每条测试名字旁边有个眼睛图标,点一下就开启 watch,改动这条测试时会自动重跑;可以同时给多条开,也可以点顶部那个眼睛给全部开。
源码把「改动」的范围说得更清楚。packages/playwright/src/runner/testRunner.ts 里的 watch(fileNames) 是这样的:对传进来的每个文件,先把文件本身加进 _watchedTestDependencies,再调 dependenciesForTestFile(fileName) 把它的依赖一起加进去。所以被盯住的不只是那个 .spec.ts,还包括它 import 的页面对象、工具函数这些文件。你改一个共用的 helper,watch 里的用例同样会被触发——这一点文档没展开,但代码是这么写的。
五、过滤:按名字、按 @tag、按 project
界面里的过滤,文档列了四类:按 name、按 projects(就是 playwright.config 里配的那些)、按 @tag,以及按 passed / failed / skipped 的执行状态。
标签本身是测试代码里声明的。docs/src/test-annotations-js.md 写明两种写法:在声明测试时给一个附加对象,或者在标题里加 @ token,且标签必须以 @ 开头:
import { test, expect } from '@playwright/test';
test('test login page', {
tag: '@fast',
}, async ({ page }) => {
// ...
});
test('test full report @slow', async ({ page }) => {
// ...
});
test.describe 上也能挂 tag,值可以是数组,一次给多个。
命令行侧对应的是 --grep。同一份文档给出了几种组合,注意 Windows 这一栏和 bash 不一样:
npx playwright test --grep @fast
PowerShell 里文档给的是 npx playwright test --grep "@fast";要「任一标签」的或逻辑,bash 写 npx playwright test --grep "@fast|@slow",PowerShell 那一栏则是 npx playwright test --grep --% "@fast^|@slow"——竖线要转义,还要 --% 停止解析。取反用 --grep-invert,两个标签都要则用正则前瞻 npx playwright test --grep "(?=.*@fast)(?=.*@slow)"。
project 那边是 --project <project-name...>,选项表里写明支持 * 通配。这些命令行过滤在 UI Mode 下不会被丢掉:packages/playwright/src/cli/testActions.ts 里调 runUIMode() 时,把 args、grep、grepInvert、project、reporter 一起传了进去。
以上命令均逐条抄自仓库文档,组合使用时以仓库最新内容与 --help 的实际输出为准,我们未做实测。
六、pick locator 与 DOM 弹窗
文档的 Pick locator 一节写的流程是:点 pick locator 按钮,鼠标划过 DOM snapshot,元素上会高亮出对应的 locator;点中某个元素,它会被送进 locator playground;你可以在 playground 里改这个 locator,看改完之后还能不能在当前 snapshot 里匹配到元素;满意了用复制按钮拿走,粘回测试代码。
配套的还有 Pop out and inspect the DOM:snapshot 上方有个弹出图标,点了会把这一刻的 DOM 单独开一个窗口,在那里可以开 DevTools 查 HTML、CSS、Console。文档还提了一个用法——把两个不同动作的 snapshot 分别弹出来并排比,比在一个界面里来回切好判断。
另外几个标签页各管一块:Actions 显示每个动作用了哪个 locator;Call 显示是否处于 strict 模式、按了什么键;Log 显示 Playwright 在背后做的事,比如滚动到可见、等待元素可见与稳定;Network 能按状态码、方法、内容类型等排序。
七、边界:源码里几处会咬人的地方
--only-changed 在 UI Mode 里直接报错。 packages/playwright/src/cli/testActions.ts 里进 UI Mode 的分支第一句就是判断 opts.onlyChanged,命中就抛异常,错误信息里说明这是 UI Mode 不支持,并附了一个 GitHub issue 链接。
--debug 和 --trace 在 UI Mode 下会被清掉。 同一文件的 overridesFromOptions() 里,if (options.ui) 成立时把 options.debug 和 options.trace 置为 undefined。这里有个值得放在一起看的细节:进入 UI Mode 的条件是 opts.ui || opts.uiHost || opts.uiPort 三者任一,而清空 debug/trace 只看 options.ui。两处判断条件不一致,我们只指出这个差异,不推断它会导致什么。
UI Mode 里跑用例不走你配置的 retries。 packages/playwright/src/runner/testRunner.ts 的 _innerRunTests() 在构造 overrides 时写死了 repeatEach: 1 和 retries: 0。这是仓库当前代码里的写法,随版本可能变动。想验重试逻辑,别在这里验。
project 依赖不会替你跑。 UI Mode 文档明说:用了 project dependencies 的话,要先手动跑 setup 测试再跑依赖它们的测试,UI Mode 不会把 setup 考虑进去。对照着看会更清楚——docs/src/test-projects-js.md 写的是,命令行侧的 --grep / --shard / 按位置过滤这些选中主测试后,依赖项目的测试也会一起跑,除非加 --no-deps。两边的行为在仓库里就是分开写的,别把命令行的经验直接搬过来。
它会启动真实浏览器。 UI Mode 跑的是真用例,会打开浏览器、执行页面脚本、读写你配置的存储状态。别因为它长得像个界面工具就当成沙箱。
八、怎么确认自己配对了
三步就够:
- 先跑
npx playwright test --help,在输出里找--ui、--ui-host、--ui-port这三项。找不到,说明你敲的playwright不是@playwright/test那个,或者版本对不上。 - 起
npx playwright test --ui,看侧边栏是不是把测试文件都列出来了,能不能展开到describe块。列不出来通常是 config 路径的问题,不是 UI Mode 的问题。 - 给一条用例点上眼睛图标,然后去改它 import 的那个 helper 文件——按
watch()的实现,依赖文件也在监听范围内,这条用例应该被重新触发。
至于过滤,给一条测试挂上 tag: '@fast',在界面的过滤框里按 @tag 过滤,看它是不是只剩这一条。命令行侧同理用 --grep @fast 对一遍,两边结果能对上,说明标签写法没问题。
该项目持续更新,文中涉及的命令、选项、配置项与代码路径随版本变动,请以仓库最新内容为准。
本文依据 github.com/microsoft/playwright 仓库于 2026-08-18 的公开内容整理,
事实来自仓库内的文档与源码。我们没有对文中涉及的功能做过实测,
因此不涉及运行速度、稳定性与实际表现的任何描述。
该项目迭代频繁,文中涉及的 API 签名、配置项与默认值随版本变动,请以仓库最新内容为准。
本文不涉及浏览器版本矩阵与版本清单,相关信息请以官方发布说明为准。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。