# Playwright 错误索引 针对特定 Playwright 错误消息的快速参考手册。找到你的错误,了解原因,应用修复。 > **如何使用**:在此文件中搜索你在终端或测试报告中看到的确切错误文本。每条记录都给出了原因和可行的修复方案。 --- ## 定位器与元素错误 --- ### "locator.click: Target closed" **原因**:Playwright 完成对元素的操作之前,页面或框架发生了导航跳转(或已被关闭)。 **常见触发场景**: - 点击触发导航的链接时,另一个操作仍在等待中 - 表单提交导致页面重新加载,而后续的 `click()` 或 `fill()` 尚未完成 - 在 `finally` 块中调用了 `page.close()` 或 `context.close()`,与正在执行的操作产生竞态 - 应用程序中未处理的异常触发了错误页面的重定向 **修复**:在执行下一个操作之前等待导航完成,或者使用 `Promise.all` 协调点击和导航。 ```typescript // TypeScript — 等待由点击链接引起的导航完成 await Promise.all([ page.waitForURL("**/dashboard"), page.getByRole("link", { name: "Dashboard" }).click(), ]) ``` ```javascript // JavaScript — 相同的模式 await Promise.all([ page.waitForURL("**/dashboard"), page.getByRole("link", { name: "Dashboard" }).click(), ]) ``` 如果页面是有意关闭的(例如弹窗),请在操作之前捕获引用: ```typescript // TypeScript — 处理自动关闭的弹窗 const popupPromise = page.waitForEvent("popup") await page.getByRole("button", { name: "Open popup" }).click() const popup = await popupPromise await popup.waitForLoadState() // 在弹窗关闭前与其交互 await popup.getByRole("button", { name: "Confirm" }).click() ``` ```javascript // JavaScript — 处理自动关闭的弹窗 const popupPromise = page.waitForEvent("popup") await page.getByRole("button", { name: "Open popup" }).click() const popup = await popupPromise await popup.waitForLoadState() await popup.getByRole("button", { name: "Confirm" }).click() ``` **相关**:[core/assertions-and-waiting.md](assertions-and-waiting.md)、[core/multi-context-and-popups.md](multi-context-and-popups.md) --- ### "waiting for locator('...') to be visible" **原因**:Playwright 的自动等待超时,因为元素从未出现在 DOM 中或一直处于隐藏状态(例如 `display: none`、`visibility: hidden`、零尺寸或位于 `aria-hidden` 之后)。 **常见触发场景**: - 元素是条件渲染的,但条件未满足(缺少数据、未认证状态) - 内容是异步加载的,定位器在 API 响应返回之前就被执行了 - 选择器错误——角色、名称或测试 ID 中有拼写错误 - 元素存在但在屏幕之外或位于折叠的容器内 - CSS 动画或过渡使元素保持 `opacity: 0`,而 Playwright 尚未判定为可见 **修复**:首先使用 Playwright Inspector 确认定位器与你期望的元素匹配。然后确保元素出现的先决条件已满足。 ```typescript // TypeScript — 调试:检查定位器解析出什么 console.log(await page.getByRole("button", { name: "Submit" }).count()) // 如果为 0,则元素不在 DOM 中——检查选择器或页面状态 // 正确做法:先等待数据加载完成 await page.waitForResponse((resp) => resp.url().includes("/api/data") && resp.status() === 200) await expect(page.getByRole("button", { name: "Submit" })).toBeVisible() ``` ```javascript // JavaScript — 相同的做法 console.log(await page.getByRole("button", { name: "Submit" }).count()) await page.waitForResponse((resp) => resp.url().includes("/api/data") && resp.status() === 200) await expect(page.getByRole("button", { name: "Submit" })).toBeVisible() ``` **相关**:[core/locators.md](locators.md)、[core/assertions-and-waiting.md](assertions-and-waiting.md) --- ### "locator.click: Error: strict mode violation" **原因**:定位器匹配了多个元素,Playwright 的严格模式(默认启用)拒绝在模棱两可的匹配上执行操作。 **常见触发场景**: - 页面上存在多个按钮时使用 `getByRole('button')` - "Save" 和 "Save as draft" 同时存在时使用 `getByText('Save')` - 需要 `exact: true` 时使用了部分文本匹配 - 同一个组件被渲染了多次(例如在列表中) **修复**:使定位器更加具体,确保解析到唯一一个元素。 ```typescript // TypeScript // 不好——匹配了多个按钮 await page.getByRole("button", { name: "Save" }).click() // 好——使用精确匹配 await page.getByRole("button", { name: "Save", exact: true }).click() // 好——限定到特定容器 await page.getByRole("dialog").getByRole("button", { name: "Save" }).click() // 好——在顺序有意义时使用 .first()、.last()、.nth() await page.getByRole("listitem").first().click() // 好——针对列表项链式使用 filter await page .getByRole("listitem") .filter({ hasText: "Project Alpha" }) .getByRole("button", { name: "Delete" }) .click() ``` ```javascript // JavaScript // 不好——匹配了多个按钮 await page.getByRole("button", { name: "Save" }).click() // 好——使用精确匹配 await page.getByRole("button", { name: "Save", exact: true }).click() // 好——限定到特定容器 await page.getByRole("dialog").getByRole("button", { name: "Save" }).click() // 好——在顺序有意义时使用 .first()、.last()、.nth() await page.getByRole("listitem").first().click() // 好——针对列表项链式使用 filter await page .getByRole("listitem") .filter({ hasText: "Project Alpha" }) .getByRole("button", { name: "Delete" }) .click() ``` **相关**:[core/locators.md](locators.md)、[core/locator-strategy.md](locator-strategy.md) --- ### "Error: expect(locator).toBeVisible() — locator resolved to X elements" **原因**:与上述严格模式违规的根因相同——断言的定位器匹配了多个元素,因此 Playwright 无法确定要对哪个元素进行断言。 **常见触发场景**: - 与上述严格模式违规的触发场景相同 - 当存在多个 `.item` 元素时写 `expect(page.locator('.item')).toBeVisible()` **修复**:将定位器缩小到单个元素(参见上方严格模式违规的修复方法)。或者,如果你有意要检查所有匹配: ```typescript // TypeScript — 断言数量而非可见性 await expect(page.getByRole("listitem")).toHaveCount(5) // 或者对特定元素进行断言 await expect(page.getByRole("listitem").first()).toBeVisible() // 或者使用循环断言所有元素都可见 for (const item of await page.getByRole("listitem").all()) { await expect(item).toBeVisible() } ``` ```javascript // JavaScript — 断言数量而非可见性 await expect(page.getByRole("listitem")).toHaveCount(5) // 或者对特定元素进行断言 await expect(page.getByRole("listitem").first()).toBeVisible() // 或者使用循环断言所有元素都可见 for (const item of await page.getByRole("listitem").all()) { await expect(item).toBeVisible() } ``` **相关**:[core/locators.md](locators.md)、[core/assertions-and-waiting.md](assertions-and-waiting.md) --- ### "locator.fill: Error: Element is not an ,