Playwright 如何检查元素是否存在
断言行首选 expect(locator).toBeVisible() / toBeAttached()(自动等待);逻辑分支用 locator.count() 或 isVisible()。本文讲清"存在、可见、可交互"三种语义的区别与选择。
一句话回答:测试断言用 await expect(locator).toBeVisible()(带自动等待与重试);需要在代码里做分支判断时用 await locator.isVisible() 或 await locator.count() > 0。注意三种语义的区别:存在于 DOM(toBeAttached)≠ 可见(toBeVisible)≠ 数量为 1。
断言写法(推荐)
// 元素可见(在 DOM 中且非隐藏、有尺寸)
await expect(page.getByRole('button', { name: '提交' })).toBeVisible();
// 元素存在但可能不可见(如 display:none)
await expect(page.locator('#modal')).toBeAttached();
// 元素不存在/不可见
await expect(page.locator('.error')).toBeHidden();
await expect(page.locator('.error')).not.toBeAttached();
// 数量断言
await expect(page.locator('ul > li')).toHaveCount(5);
expect 断言自带自动重试(默认 5 秒内反复检查直到满足),这是它比裸 if 判断可靠的核心原因。
逻辑分支写法
// 场景:有"不再提示"弹窗就关掉,没有就跳过
const dialog = page.locator('.dialog').first();
if (await dialog.count() > 0 && await dialog.isVisible()) {
await dialog.getByRole('button', { name: '关闭' }).click();
}
⚠️ 注意:isVisible() 是即时查询,不等待——元素尚未渲染时返回 false。可选弹窗若异步出现,该分支可能漏掉;先等待应用已知稳定信号,必要时用有界等待。必需元素直接用 expect 断言。
三种语义速查
| 方法 | 含义 | 场景 |
|---|---|---|
toBeAttached() |
在 DOM 树里 | 不关心可见性,只关心存不存在 |
toBeVisible() |
非空边界框且非 visibility:hidden | 不等于在视口内或可交互;opacity:0 也可能算可见 |
toHaveCount(n) |
匹配数量 | 列表、校验重复元素 |
常见问题(FAQ)
Q:isVisible() 和 toBeVisible() 到底用哪个?
A:断言用 toBeVisible()(自动等待重试);业务流程分支(有弹窗就关)用 isVisible() 即时判断。拿不准时优先断言式写法,测试更稳定。
Q:元素要等一会才出现,if 判断总是漏?
A:if (await locator.count()) 在元素渲染前执行就漏了。改为 await locator.waitFor() 显式等待,或直接用 expect 断言让 Playwright 帮你等。
Q:如何判断"元素消失了"?
A:await expect(locator).toBeHidden() 或 not.toBeAttached(),同样自动等待——适合"loading 消失后再继续"的场景。
参考资料
本文依据官方资料核对,未进行现场运行测试;代码与配置示例需结合实际版本、权限和环境验证。