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