Playwright 调试技巧 #

调试工具概述 #

Playwright 提供多种调试工具,帮助开发者快速定位和解决测试问题。

调试工具列表 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Playwright 调试工具                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  🔧 Trace Viewer   - 测试执行追踪查看器                       │
│  🎯 Codegen        - 代码生成工具                            │
│  🖥️ UI Mode        - 交互式测试运行器                         │
│  💻 VS Code        - VS Code 插件                           │
│  🐛 Debug Mode     - 调试模式                                │
│  📸 Screenshots    - 截图和视频                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Trace Viewer #

启用追踪 #

typescript
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    // 总是启用追踪
    trace: 'on',
    
    // 失败时启用追踪
    trace: 'on-first-retry',
    
    // 失败时保留追踪
    trace: 'retain-on-failure',
  },
});

命令行启用 #

bash
# 启用追踪运行测试
npx playwright test --trace on

# 失败时追踪
npx playwright test --trace on-first-retry

查看追踪 #

bash
# 查看追踪文件
npx playwright show-trace trace.zip

# 查看特定追踪
npx playwright show-trace test-results/test-name/trace.zip

Trace Viewer 功能 #

text
Trace Viewer 界面:

┌─────────────────────────────────────────────────────────────┐
│  时间线                                                     │
│  ├── 显示所有操作的时间顺序                                  │
│  └── 可点击跳转到特定操作                                    │
├─────────────────────────────────────────────────────────────┤
│  操作列表                                                   │
│  ├── 显示所有页面操作                                        │
│  ├── 显示网络请求                                            │
│  └── 显示控制台日志                                          │
├─────────────────────────────────────────────────────────────┤
│  快照                                                       │
│  ├── 操作前后的页面快照                                      │
│  └── 可以查看 DOM 结构                                       │
├─────────────────────────────────────────────────────────────┤
│  网络请求                                                   │
│  ├── 请求/响应详情                                           │
│  └── 请求时间线                                              │
├─────────────────────────────────────────────────────────────┤
│  控制台                                                     │
│  ├── 日志输出                                                │
│  └── 错误信息                                                │
└─────────────────────────────────────────────────────────────┘

在测试中手动追踪 #

typescript
import { test, expect } from '@playwright/test';

test('手动追踪', async ({ page, context }) => {
  // 开始追踪
  await context.tracing.start({ screenshots: true, snapshots: true });
  
  await page.goto('/');
  await page.click('button');
  
  // 停止追踪并保存
  await context.tracing.stop({ path: 'trace.zip' });
});

Codegen - 代码生成 #

启动 Codegen #

bash
# 基本用法
npx playwright codegen

# 指定 URL
npx playwright codegen https://example.com

# 指定浏览器
npx playwright codegen --browser=firefox https://example.com

# 指定设备
npx playwright codegen --device="iPhone 12" https://example.com

# 指定语言
npx playwright codegen --lang=python https://example.com

# 保存到文件
npx playwright codegen --output=test.spec.ts https://example.com

Codegen 窗口 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Playwright Inspector                      │
├─────────────────────────────────────────────────────────────┤
│  Record  Stop  Copy  Clear                                  │
├─────────────────────────────────────────────────────────────┤
│  // 生成的代码                                               │
│  const { chromium } = require('playwright');                │
│                                                             │
│  (async () => {                                             │
│    const browser = await chromium.launch();                 │
│    const page = await browser.newPage();                    │
│    await page.goto('https://example.com');                  │
│    await page.click('text=More information');               │
│  })();                                                      │
└─────────────────────────────────────────────────────────────┘

Codegen 选项 #

bash
# 仿真设备
npx playwright codegen \
  --device="iPhone 12" \
  --viewport-size="390,844" \
  --color-scheme="dark" \
  --lang="zh-CN" \
  --timezone="Asia/Shanghai" \
  --geolocation="39.9042,116.4074" \
  https://example.com

UI 模式 #

启动 UI 模式 #

bash
# 启动 UI 模式
npx playwright test --ui

# 指定测试文件
npx playwright test --ui login.spec.ts

# 指定项目
npx playwright test --ui --project=chromium

UI 模式功能 #

text
┌─────────────────────────────────────────────────────────────┐
│                      Playwright UI                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  测试列表                                                   │
│  ├── 显示所有测试文件                                        │
│  ├── 按状态过滤                                              │
│  └── 搜索测试                                                │
│                                                             │
│  测试执行                                                   │
│  ├── 运行单个测试                                            │
│  ├── 运行所有测试                                            │
│  └── 调试模式                                                │
│                                                             │
│  时间旅行                                                   │
│  ├── 查看每个操作的快照                                      │
│  ├── 查看操作前后的页面                                      │
│  └── 查看网络请求                                            │
│                                                             │
│  源码查看                                                   │
│  ├── 显示测试代码                                            │
│  └── 高亮当前执行行                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

UI 模式快捷键 #

快捷键 功能
r 运行当前测试
f 运行失败的测试
t 运行所有测试
p 暂停/继续
s 步进到下一个操作
Esc 取消当前操作

VS Code 插件 #

安装插件 #

  1. 在 VS Code 中搜索 “Playwright Test for VS Code”
  2. 点击安装

插件功能 #

text
VS Code 插件功能:

├── 测试资源管理器
│   ├── 显示所有测试
│   ├── 运行/调试测试
│   └── 查看测试结果
│
├── 代码补全
│   ├── Locator 建议
│   ├── 方法补全
│   └── 参数提示
│
├── 调试支持
│   ├── 断点调试
│   ├── 变量查看
│   └── 调用堆栈
│
└── 内联错误
    ├── 显示错误位置
    └── 显示期望值/实际值

VS Code 配置 #

json
// .vscode/settings.json
{
  "playwright.env": {
    "BASE_URL": "http://localhost:3000"
  },
  "playwright.project": "chromium",
  "playwright.showTrace": true,
  "playwright.reuseBrowser": true
}

调试配置 #

json
// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "pwa-node",
      "request": "launch",
      "name": "Playwright Debug",
      "runtimeExecutable": "npx",
      "runtimeArgs": [
        "playwright",
        "test",
        "--project=chromium"
      ],
      "console": "integratedTerminal"
    }
  ]
}

调试模式 #

–debug 标志 #

bash
# 调试模式运行
npx playwright test --debug

# 调试特定测试
npx playwright test login.spec.ts --debug

page.pause() #

typescript
import { test, expect } from '@playwright/test';

test('使用 pause 调试', async ({ page }) => {
  await page.goto('/');
  
  // 暂停执行,打开 Inspector
  await page.pause();
  
  await page.click('button');
  await expect(page.locator('.result')).toBeVisible();
});

调试特定步骤 #

typescript
test('调试特定步骤', async ({ page }) => {
  await page.goto('/');
  
  console.log('步骤 1: 页面加载完成');
  
  await page.click('button');
  console.log('步骤 2: 按钮点击完成');
  
  // 在关键点暂停
  if (process.env.DEBUG) {
    await page.pause();
  }
  
  await expect(page.locator('.result')).toBeVisible();
  console.log('步骤 3: 断言完成');
});

控制台调试 #

输出调试信息 #

typescript
test('控制台调试', async ({ page }) => {
  // 监听控制台消息
  page.on('console', msg => {
    console.log(`浏览器控制台: ${msg.type()}: ${msg.text()}`);
  });
  
  // 监听页面错误
  page.on('pageerror', error => {
    console.error(`页面错误: ${error.message}`);
  });
  
  // 监听请求
  page.on('request', request => {
    console.log(`请求: ${request.method()} ${request.url()}`);
  });
  
  // 监听响应
  page.on('response', response => {
    console.log(`响应: ${response.status()} ${response.url()}`);
  });
  
  await page.goto('/');
});

使用 evaluate 调试 #

typescript
test('evaluate 调试', async ({ page }) => {
  await page.goto('/');
  
  // 在浏览器上下文中执行代码
  const result = await page.evaluate(() => {
    console.log('在浏览器中执行');
    return {
      title: document.title,
      url: window.location.href,
      elementCount: document.querySelectorAll('*').length,
    };
  });
  
  console.log('页面信息:', result);
});

截图和视频 #

失败时截图 #

typescript
// playwright.config.ts
export default defineConfig({
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
});

手动截图 #

typescript
test('手动截图', async ({ page }) => {
  await page.goto('/');
  
  // 整页截图
  await page.screenshot({ path: 'screenshot.png' });
  
  // 元素截图
  await page.locator('.card').screenshot({ path: 'card.png' });
  
  // 全页截图
  await page.screenshot({ 
    path: 'fullpage.png', 
    fullPage: true 
  });
});

条件截图 #

typescript
test.afterEach(async ({ page }, testInfo) => {
  // 失败时截图
  if (testInfo.status !== testInfo.expectedStatus) {
    await page.screenshot({ 
      path: `screenshots/${testInfo.title}-failure.png` 
    });
  }
});

常见调试场景 #

元素定位问题 #

typescript
test('调试元素定位', async ({ page }) => {
  await page.goto('/');
  
  // 检查元素是否存在
  const element = page.locator('.my-element');
  const count = await element.count();
  console.log(`找到 ${count} 个元素`);
  
  // 检查元素是否可见
  const isVisible = await element.isVisible();
  console.log(`元素可见: ${isVisible}`);
  
  // 获取元素信息
  const text = await element.textContent();
  const html = await element.innerHTML();
  console.log(`元素文本: ${text}`);
  console.log(`元素 HTML: ${html}`);
  
  // 高亮元素(调试用)
  await element.evaluate(el => {
    el.style.border = '2px solid red';
  });
  
  await page.pause();
});

网络请求问题 #

typescript
test('调试网络请求', async ({ page }) => {
  // 记录所有请求
  const requests: any[] = [];
  page.on('request', request => {
    requests.push({
      url: request.url(),
      method: request.method(),
      headers: request.headers(),
    });
  });
  
  // 记录失败请求
  page.on('requestfailed', request => {
    console.log(`请求失败: ${request.url()}`);
    console.log(`失败原因: ${request.failure()?.errorText}`);
  });
  
  await page.goto('/');
  
  console.log('所有请求:', requests);
});

等待问题 #

typescript
test('调试等待问题', async ({ page }) => {
  await page.goto('/');
  
  // 检查元素状态
  const element = page.locator('.dynamic-element');
  
  console.log('等待元素...');
  try {
    await element.waitFor({ state: 'visible', timeout: 5000 });
    console.log('元素已可见');
  } catch (error) {
    console.log('元素未在超时时间内出现');
    
    // 检查元素是否存在
    const count = await element.count();
    console.log(`元素数量: ${count}`);
    
    // 检查 DOM 中是否有类似元素
    const similar = await page.locator('[class*="dynamic"]').count();
    console.log(`类似元素数量: ${similar}`);
  }
});

调试最佳实践 #

1. 使用有意义的测试名称 #

typescript
// ✅ 推荐
test('用户使用有效凭据登录后应该跳转到仪表板', async ({ page }) => {
  // ...
});

// ❌ 不推荐
test('test1', async ({ page }) => {
  // ...
});

2. 添加调试日志 #

typescript
test('带日志的测试', async ({ page }) => {
  console.log('=== 测试开始 ===');
  
  await page.goto('/');
  console.log('页面加载完成');
  
  await page.click('button');
  console.log('按钮点击完成');
  
  console.log('=== 测试结束 ===');
});

3. 使用软断言收集信息 #

typescript
test('软断言调试', async ({ page }) => {
  await page.goto('/');
  
  // 收集所有失败
  await expect.soft(page.locator('.title')).toHaveText('Welcome');
  await expect.soft(page.locator('.subtitle')).toBeVisible();
  await expect.soft(page.locator('.content')).toHaveCount(5);
});

4. 保存调试信息 #

typescript
test.afterEach(async ({ page }, testInfo) => {
  if (testInfo.status === 'failed') {
    // 保存截图
    await page.screenshot({ 
      path: `debug/${testInfo.title}.png` 
    });
    
    // 保存 HTML
    const html = await page.content();
    require('fs').writeFileSync(
      `debug/${testInfo.title}.html`, 
      html
    );
    
    // 保存控制台日志
    // ...
  }
});

下一步 #

现在你已经掌握了调试技巧,接下来学习 视觉测试 了解如何进行视觉回归测试!

最后更新:2026-03-28