Playwright 故障排查 #
常见错误类型 #
元素定位失败 #
问题:元素未找到 #
text
Error: locator.click: Timeout 30000ms exceeded.
waiting for locator('button.submit')
原因分析:
- 选择器错误
- 元素尚未加载
- 元素在 iframe 中
- 元素被动态移除
解决方案:
typescript
// 1. 检查元素是否存在
const count = await page.locator('button.submit').count();
console.log(`找到 ${count} 个元素`);
// 2. 使用更可靠的选择器
await page.getByRole('button', { name: 'Submit' }).click();
// 3. 等待元素出现
await page.locator('button.submit').waitFor({ state: 'visible' });
// 4. 检查是否在 iframe 中
const frame = page.frameLocator('iframe');
await frame.locator('button.submit').click();
// 5. 增加超时时间
await page.locator('button.submit').click({ timeout: 60000 });
问题:元素不可见 #
text
Error: element is not visible
解决方案:
typescript
// 1. 等待元素可见
await page.locator('.element').waitFor({ state: 'visible' });
// 2. 滚动到元素
await page.locator('.element').scrollIntoViewIfNeeded();
// 3. 强制操作(不推荐)
await page.locator('.element').click({ force: true });
// 4. 检查可见性
const isVisible = await page.locator('.element').isVisible();
console.log(`元素可见: ${isVisible}`);
问题:元素不可交互 #
text
Error: element is not enabled
解决方案:
typescript
// 1. 等待元素启用
await expect(page.locator('button')).toBeEnabled();
// 2. 检查元素状态
const isEnabled = await page.locator('button').isEnabled();
console.log(`元素启用: ${isEnabled}`);
// 3. 检查是否有覆盖层
const overlay = await page.locator('.overlay').isVisible();
if (overlay) {
await page.locator('.overlay').click();
}
超时问题 #
问题:测试超时 #
text
Error: Test timeout of 30000ms exceeded.
解决方案:
typescript
// 1. 增加测试超时
test('慢速测试', async ({ page }) => {
test.setTimeout(60000);
// 测试代码
});
// 2. 标记为慢测试
test('慢速测试', async ({ page }) => {
test.slow(); // 超时时间翻三倍
// 测试代码
});
// 3. 全局配置
// playwright.config.ts
export default defineConfig({
timeout: 60000,
});
问题:断言超时 #
text
Error: expect(received).toBeVisible()
Timeout: 5000ms
解决方案:
typescript
// 1. 增加断言超时
await expect(page.locator('.element')).toBeVisible({
timeout: 10000,
});
// 2. 全局配置
// playwright.config.ts
export default defineConfig({
expect: {
timeout: 10000,
},
});
问题:导航超时 #
text
Error: page.goto: Timeout 30000ms exceeded.
解决方案:
typescript
// 1. 增加导航超时
await page.goto('/', { timeout: 60000 });
// 2. 等待特定状态
await page.goto('/', { waitUntil: 'domcontentloaded' });
// 3. 全局配置
// playwright.config.ts
export default defineConfig({
use: {
navigationTimeout: 60000,
},
});
浏览器问题 #
问题:浏览器启动失败 #
text
Error: browserType.launch: Executable doesn't exist
解决方案:
bash
# 安装浏览器
npx playwright install
# 安装系统依赖
npx playwright install-deps
# 检查安装
npx playwright --version
问题:Linux 上缺少依赖 #
text
Error: Host system is missing dependencies
解决方案:
bash
# Ubuntu/Debian
sudo npx playwright install-deps
# 或手动安装
sudo apt-get install -y \
libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libdrm2 libxkbcommon0 libxcomposite1 \
libxdamage1 libxfixes3 libxrandr2 libgbm1 \
libasound2 libpango-1.0-0 libcairo2
问题:内存不足 #
text
Error: Out of memory
解决方案:
typescript
// 1. 减少 workers
// playwright.config.ts
export default defineConfig({
workers: 1,
});
// 2. 关闭浏览器上下文
test.afterEach(async ({ context }) => {
await context.close();
});
// 3. 禁用视频录制
export default defineConfig({
use: {
video: 'off',
},
});
网络问题 #
问题:请求失败 #
text
Error: page.goto: net::ERR_CONNECTION_REFUSED
解决方案:
typescript
// 1. 检查服务器是否运行
const response = await page.goto('/', { waitUntil: 'networkidle' });
console.log(`状态码: ${response?.status()}`);
// 2. 使用正确的 URL
await page.goto('http://localhost:3000');
// 3. 忽略 HTTPS 错误
// playwright.config.ts
export default defineConfig({
use: {
ignoreHTTPSErrors: true,
},
});
问题:API Mock 不生效 #
解决方案:
typescript
// 1. 确保在导航前设置路由
await page.route('**/api/users', route => {
route.fulfill({ status: 200, body: '[]' });
});
await page.goto('/');
// 2. 检查 URL 匹配
await page.route('**/api/**', route => {
console.log(`拦截请求: ${route.request().url()}`);
route.continue();
});
// 3. 清理路由
await page.unrouteAll();
并发问题 #
问题:测试相互影响 #
解决方案:
typescript
// 1. 确保测试隔离
test.describe.configure({ mode: 'parallel' });
// 2. 使用独立数据
test('测试', async ({ page, request }) => {
// 创建独立测试数据
const uniqueId = Date.now();
await request.post('/api/users', {
data: { email: `test-${uniqueId}@example.com` },
});
});
// 3. 清理测试数据
test.afterEach(async ({ request }) => {
await request.delete('/api/test-data');
});
问题:竞态条件 #
解决方案:
typescript
// 1. 使用正确的等待
await page.click('button');
await expect(page.locator('.result')).toBeVisible();
// 2. 等待网络请求
const responsePromise = page.waitForResponse('**/api/data');
await page.click('button');
await responsePromise;
// 3. 使用 Promise.all
await Promise.all([
page.waitForResponse('**/api/data'),
page.click('button'),
]);
调试技巧 #
1. 使用 Trace Viewer #
bash
# 启用追踪
npx playwright test --trace on
# 查看追踪
npx playwright show-trace trace.zip
2. 使用 page.pause() #
typescript
test('调试', async ({ page }) => {
await page.goto('/');
await page.pause(); // 打开 Inspector
});
3. 输出调试信息 #
typescript
test('调试', async ({ page }) => {
// 监听控制台
page.on('console', msg => console.log(`浏览器: ${msg.text()}`));
// 监听请求
page.on('request', req => console.log(`请求: ${req.url()}`));
// 监听响应
page.on('response', res => console.log(`响应: ${res.status()}`));
await page.goto('/');
});
4. 截图调试 #
typescript
test('截图调试', async ({ page }) => {
await page.goto('/');
await page.screenshot({ path: 'debug.png', fullPage: true });
});
5. HTML 调试 #
typescript
test.afterEach(async ({ page }, testInfo) => {
if (testInfo.status === 'failed') {
const html = await page.content();
require('fs').writeFileSync('debug.html', html);
}
});
常见错误速查表 #
| 错误信息 | 可能原因 | 解决方案 |
|---|---|---|
Timeout exceeded |
元素未找到或加载慢 | 增加超时或等待元素 |
Element not visible |
元素隐藏或被遮挡 | 等待可见或滚动到元素 |
Element not enabled |
元素被禁用 | 等待启用状态 |
Element detached |
元素被移除 | 重新定位元素 |
Navigation failed |
页面加载失败 | 检查 URL 和网络 |
Connection refused |
服务器未运行 | 启动服务器 |
Out of memory |
内存不足 | 减少 workers |
Browser closed |
浏览器崩溃 | 检查系统资源 |
预防措施 #
1. 使用可靠的选择器 #
typescript
// ✅ 推荐
await page.getByRole('button', { name: 'Submit' }).click();
// ❌ 不推荐
await page.locator('#btn-123').click();
2. 添加适当的等待 #
typescript
// ✅ 推荐
await expect(page.locator('.result')).toBeVisible();
// ❌ 不推荐
await page.waitForTimeout(2000);
3. 使用测试夹具 #
typescript
// ✅ 推荐
export const test = base.extend({
authenticatedPage: async ({ page }, use) => {
// 设置
await use(page);
// 清理
},
});
4. 合理设置超时 #
typescript
// playwright.config.ts
export default defineConfig({
timeout: 30000,
expect: { timeout: 5000 },
use: {
actionTimeout: 10000,
navigationTimeout: 30000,
},
});
下一步 #
现在你已经掌握了故障排查技巧,接下来学习 扩展工具 了解更多 Playwright 生态工具!
最后更新:2026-03-28