直接用 .card__header--large 断言会导致测试与样式实现细节强耦合,一旦类名拼写错误、动态拼接漏空格、设计系统重命名或语义结构变更(如换标签、删ARIA),测试假失败或漏检,且无法保障结构语义正确性。

测试里直接用 .card__header--large 会出什么问题
不是类名不能用,而是把它当“唯一标识”来断言时,容易让测试和样式实现细节强耦合。比如 JS 动态拼接类名:className={`card__header ${size === 'large' ? 'card__header--large' : ''}`,一旦拼写漏掉空格、大小写错、或逻辑分支没覆盖全,测试就挂,但 UI 可能完全正常。
更隐蔽的问题是:BEM 类名本身可能随设计系统迭代被重命名(如 card__header → card__title),而测试没同步改,就会假失败;或者团队为 SEO 或可访问性把 <h2 class="card__header"></h2> 换成 <div role="heading" class="card__header">,测试仍过,但语义已退化。
<ul>
<li>类名变动不触发编译报错,只在运行时暴露</li>
<li>测试通过 ≠ 结构语义正确,尤其当元素类型/role/aria属性变更时</li>
<li>多人协作中,有人删了类名但忘了删对应测试,导致“死代码”残留</li>
</ul>
<h3>什么时候该坚持用 <code>getByClassName,什么时候该换 getByRole
核心看目标节点是否承担明确的语义角色。按钮、标题、表单控件这些天然有 role 或语义标签的,优先走语义查询;纯装饰性容器(如卡片外层 div)或状态指示器(如加载中的 span)才考虑类名。
- 查按钮:
getByRole('button', { name: /submit/i })✅,比getByClassName('form__submit--primary')更健壮 - 查标题:
getByRole('heading', { level: 2 })✅,比getByClassName('card__header')不依赖具体 class 名 - 查加载态:
getByLabelText('Loading...')或getByTestId('loading-spinner')✅,getByClassName('spinner--active')❌(modifier 易变且无语义) - 查仅用于布局隔离的 wrapper:
getByTestId('card-content-wrapper')✅,它不对外暴露语义,testid 是合理选择
data-testid 和 BEM 类名混用的雷区
最常见错误是同一元素同时挂 class="card__body" 和 data-testid="card-body",后续维护时只改一边——比如重构 CSS 把 card__body 拆成 card__content 和 card__footer,但测试仍查 card__body,结果断言失效却没人发现。
立即学习“前端免费学习笔记(深入)”;
- 如果组件严格遵循 BEM 且类名无运行时拼接,
getByClassName('block__element')轻量可行,但 modifier 必须成对验证(如断言button--loading时,同步检查button是否在 classList) - 若存在动态类名拼接,或团队约定“禁止依赖 class”,那就统一用
data-testid,且值必须按 BEM 逻辑命名:card__header、user-list__item,保持语义一致性 - 绝对禁止在同一个组件里混合策略:要么全用语义查询,要么全用 testid,要么全用稳定类名——路径分裂是维护噩梦
BEM 类名在测试中真正不可替代的场景
不是所有地方都能用 role 替代。当组件行为完全由 CSS 驱动、无 ARIA 或语义标签支撑时,类名就是唯一可靠信号。典型如视觉状态切换:tooltip--visible 控制显隐,但 tooltip 元素本身可能是 div 且无 role;或动画 class:slide-in 触发 CSS transition,但无对应语义事件。
- 这类场景下,
waitForElementToBeRemoved(screen.queryByClassName('tooltip--hidden'))是合理做法 - 关键是要限制范围:只用于纯视觉状态、无交互语义的 class,且 modifier 必须和 block/element 同时存在(避免单独断言
--disabled) - 每次写
getByClassName前,先问一句:这个类名是否承载了用户可感知的状态?如果不是,就该补 ARIA 或换 query 方式


















