测试 ID 策略 getByTestId
本教程共 59 篇 · 第 13 篇 · 更新于 2026-08-04 · 约 8 分钟阅读
本节目标:理解测试 ID 定位为什么最抗变动、又为什么不能滥用,学会用 getByTestId,并知道怎么把属性名从 data-testid 改成你们团队约定的名字。
它为什么最稳
page.getByTestId() 按元素的 data-testid 属性找目标。它只认这个标记,不认文字、不认角色、也不认结构。
好处很直接。按钮文案从「登录」改成「Sign in」,DOM 嵌套推倒重来,只要 data-testid 没动,用例照样过。
<button data-testid="directions">Itinéraire</button>
await page.getByTestId('directions').click();
这就是测试圈说的显式测试契约(Explicit Testing Contract)。开发和测试提前约好一个标记,各改各的,互不踩脚。
Note官方把测试 ID 列为最抗变动的定位方式。文字和角色都是产品说改就改的东西,测试 ID 是你们自己攥在手里的。
它的问题:不是用户视角
凡事有代价。测试 ID 不反映真实用户怎么看页面。用户认的是文字和角色,没人会去看 data-testid。
所以在定位优先级里,它排在 role、text、label 后面:
- 有明确角色 → 用
getByRole - 只有一段文字 → 用
getByText - 表单控件 → 用
getByLabel - 实在没抓手 → 用
getByTestId
只有两种情况该让它上位:用 role 和 text 真的定位不到;或者你们团队本来就走「测试 ID 方法论」这条路线。
怎么和开发约定
测试 ID 不是测试同学单方面能定的事,得开发配合。常见做法有三条:
- 在组件里加
data-testid,名字要有语义,比如submit-btn、cart-count。 - 把测试 ID 当成组件对外接口的一部分写进契约,别随手删。
- 列表项加上唯一 ID,方便精确定位到某一行。
<ul>
<li data-testid="apple">apple</li>
<li data-testid="banana">banana</li>
<li data-testid="orange">orange</li>
</ul>
await page.getByTestId('orange').click();
自定义属性名
Playwright 默认认 data-testid。团队约定了别的名字,比如 data-pw,在配置文件里加一行就行:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
testIdAttribute: 'data-pw',
},
});
HTML 里改用 data-pw:
<button data-pw="directions">Itinéraire</button>
测试代码一个字不用改,还是 getByTestId('directions')。Playwright 会自动去认 data-pw。
库模式下也可以用 selectors.setTestIdAttribute('data-pw') 在代码里动态改。不过配置文件里设一次更省心,全项目统一。
三个常踩的坑
一是拿测试 ID 当 CSS 选择器写。 有人写成 page.locator('[data-testid="cart"]'),能跑,但绕开了 testIdAttribute 配置。哪天属性名一改,这类写法全废。统一走 getByTestId。
二是给列表用同一个 ID。 十行数据挂同一个 data-testid="row",一操作就撞严格模式。要么给每行拼上唯一后缀,要么配合上一节的过滤方法收窄。
三是把测试 ID 当样式钩子。 data-testid 一旦被 CSS 或业务代码引用,就再也不敢删改了。它只该服务测试,别让它长出第二个身份。
// ✖ 绕开了 testIdAttribute 配置
await page.locator('[data-testid="cart"]').click();
// ✔ 配置改了也不用动测试代码
await page.getByTestId('cart').click();
小结
getByTestId 按 data-testid 定位,抗文案和结构变动最强,代价是脱离了用户视角,所以排在 role / text / label 后面。它需要开发和测试提前约定标记,属性名可以在配置里改。
下一章预告:链式定位与过滤——用
.locator()、.filter()、.nth()、.first()、.last()从一堆相似元素里精准取一个。