在自动化浏览器测试中处理 Shadow DOM
封装问题
Shadow DOM 防止外部 CSS 和 JavaScript 影响组件内部结构——这对于设计系统来说是一个有价值的特性。但这种相同的封装使标准的测试选择器失效。document.querySelector('.my-button') 无法找到 Shadow root 中的 .my-button。
Playwright 的 Shadow DOM 支持
Playwright 对 Shadow DOM 有内置支持,但它需要了解正在使用哪种 Shadow DOM 实现。
对于开放的 Shadow DOM(mode: "open"),Playwright 的选择器引擎可以自动穿透 Shadow 边界:
await page.locator('my-component >> .inner-button').click()>> 语法表示"穿透 Shadow DOM 边界"。这适用于整个选择器链。
封闭 Shadow DOM 的挑战
封闭的 Shadow DOM(mode: "closed")是真正的障碍。Shadow root 无法从外部访问,即使是 Playwright 的选择器引擎也无法穿透它。
在实践中,封闭的 Shadow DOM 在最终用户库中很少见,在你自己构建的组件中几乎不应该使用——测试能力是使用封闭模式的充分理由。但如果你必须与封闭的 Shadow DOM 交互,注入脚本是唯一可靠的方法。
实际策略
最可靠的方法是使用数据属性而不是 CSS 类进行测试选择器:
await page.locator('[data-testid="submit-button"]').click()数据属性在 Shadow DOM 边界上的工作方式与在常规 DOM 中相同,并且它们清楚地表明其存在是为了测试目的,而不是样式。
组件库注意事项
如果你使用带有 Shadow DOM 的第三方组件库,检查它们是否公开推荐的测试钩子。许多现代组件库包含专门设计用于自动化测试的 data-testid 属性或aria-label 约定。