Files
2026-07-13 21:36:47 +08:00

12 KiB
Raw Permalink Blame History

追踪与调试

使用场景:调试失败的操作、分析性能瓶颈、捕获执行证据、理解交互未生效的原因,或在自动化过程中检查网络及控制台活动。 前置条件core-commands.md —— 掌握基本 CLI 用法

快速参考

# 追踪会话
playwright-cli tracing-start
playwright-cli open https://example.com
playwright-cli click e4
playwright-cli fill e7 "test"
playwright-cli tracing-stop

# 查看控制台消息
playwright-cli console                # 所有级别
playwright-cli console error          # 仅错误
playwright-cli console warning        # 仅警告

# 查看网络活动
playwright-cli network

追踪

追踪会捕获一切 —— 包括 DOM 快照、截图、网络活动、控制台日志以及时间信息,覆盖会话中的每一个操作。

基本用法

# 在要调试的流程之前开始录制
playwright-cli tracing-start

# 执行操作
playwright-cli open https://example.com
playwright-cli snapshot
playwright-cli click e4
playwright-cli fill e7 "test data"
playwright-cli click e9

# 停止并保存追踪
playwright-cli tracing-stop

追踪捕获的内容

类别 详情
操作 每次点击、填写、悬停、键盘输入、导航 —— 附带时间信息
DOM 快照 每个操作前后的完整 DOM 状态
截图 每一步的视觉状态
网络 所有 HTTP 请求、响应、请求头、响应体、时间信息
控制台 所有 console.logconsole.warnconsole.error 消息
时间信息 每个操作的具体耗时
来源 每个操作由哪个命令触发

追踪输出文件

当追踪激活时,Playwright 会创建一个 traces/ 目录:

trace-{时间戳}.trace —— 主追踪文件,包含:

  • 附带 DOM 快照的操作日志
  • 每一步的截图
  • 时间信息
  • 控制台消息

trace-{时间戳}.network —— 网络活动:

  • 所有 HTTP 请求与响应
  • 请求/响应请求头与响应体
  • DNS、连接、TLS、TTFB、下载时间
  • 资源大小及失败的请求

resources/ —— 用于追踪回放的缓存资源:

  • 图片、字体、样式表、脚本
  • 用于离线回放的响应体

查看追踪

在 Playwright 的 Trace Viewer 中打开追踪 —— 这是一个用于逐步调试的丰富 GUI:

# 在 Trace Viewer Web 应用中打开追踪
npx playwright show-trace traces/trace-123456.trace

# 或使用在线 Trace Viewer
# 将追踪文件上传至:https://trace.playwright.dev

Trace Viewer 会显示:

  • 时间轴:带截图的逐步操作
  • DOM 快照:检查每一步中的元素(类似 DevTools)
  • 网络:所有请求的水fall图
  • 控制台:带时间戳的日志消息
  • 来源:触发每个操作的代码

控制台监控

查看页面的 JavaScript 控制台输出 —— 对捕获错误至关重要:

# 显示所有控制台消息
playwright-cli console

# 按严重级别筛选
playwright-cli console error         # 仅错误
playwright-cli console warning       # 仅警告
playwright-cli console info          # 仅信息消息
playwright-cli console log           # 仅日志消息

常见调试模式

playwright-cli open https://app.example.com
playwright-cli snapshot
playwright-cli click e5              # 发生了意外情况

# 检查是否有 JavaScript 错误
playwright-cli console error
# 输出可能显示:
# [error] TypeError: Cannot read properties of undefined (reading 'map')
# [error] Uncaught ReferenceError: processData is not defined

交互期间查看控制台

使用 run-code 设置持续的控制台监控:

playwright-cli run-code "async page => {
  page.on('console', msg => {
    if (msg.type() === 'error' || msg.type() === 'warning') {
      console.log(\`[\${msg.type()}] \${msg.text()}\`);
    }
  });
}"
# 现在开始交互 —— 错误和警告会实时打印
playwright-cli click e5
playwright-cli fill e3 "test"

捕获未捕获的异常

playwright-cli run-code "async page => {
  page.on('pageerror', error => {
    console.log('Uncaught exception:', error.message);
  });
}"

网络监控

查看页面发出的所有网络请求:

playwright-cli network

实时查看网络

playwright-cli run-code "async page => {
  page.on('request', request => {
    console.log(\`>> \${request.method()} \${request.url()}\`);
  });
  page.on('response', response => {
    console.log(\`<< \${response.status()} \${response.url()}\`);
  });
}"

# 现在开始交互 —— 请求会实时打印
playwright-cli click e5

监控失败的请求

playwright-cli run-code "async page => {
  page.on('requestfailed', request => {
    console.log(\`FAILED: \${request.method()} \${request.url()} - \${request.failure()?.errorText}\`);
  });
}"

检查特定响应

playwright-cli run-code "async page => {
  const response = await page.waitForResponse('**/api/users');
  return {
    status: response.status(),
    statusText: response.statusText(),
    headers: response.headers(),
    body: await response.json()
  };
}"

调试策略

策略 1:快照前后对比

最简单的调试方法 —— 查看发生了什么变化:

playwright-cli snapshot --filename=before.yaml
playwright-cli click e5
playwright-cli snapshot --filename=after.yaml
# 比较两个快照,了解变化内容

策略 2:追踪失败流程

在失败步骤之前开始追踪:

playwright-cli tracing-start

# 重现问题
playwright-cli goto https://app.example.com/checkout
playwright-cli fill e1 "Jane Doe"
playwright-cli click e5    # 此步骤失败

playwright-cli tracing-stop
# 打开追踪,查看尝试点击时的 DOM 状态

策略 3:检查元素状态

当交互失败时,检查元素的实际状态:

# 元素是否可见?
playwright-cli eval "el => window.getComputedStyle(el).display" e5
playwright-cli eval "el => window.getComputedStyle(el).visibility" e5
playwright-cli eval "el => el.getBoundingClientRect()" e5

# 是否被其他元素遮挡?
playwright-cli eval "el => {
  const rect = el.getBoundingClientRect();
  const topEl = document.elementFromPoint(rect.x + rect.width/2, rect.y + rect.height/2);
  return topEl === el ? 'Element is on top' : 'Covered by: ' + topEl?.tagName + '.' + topEl?.className;
}" e5

# 是否被禁用?
playwright-cli eval "el => el.disabled" e5
playwright-cli eval "el => el.getAttribute('aria-disabled')" e5

策略 4:控制台 + 网络组合

# 同时监控控制台和网络
playwright-cli run-code "async page => {
  page.on('console', msg => {
    if (msg.type() === 'error') console.log('[CONSOLE]', msg.text());
  });
  page.on('requestfailed', req => {
    console.log('[NETWORK]', req.method(), req.url(), req.failure()?.errorText);
  });
  page.on('response', resp => {
    if (resp.status() >= 400) {
      console.log('[HTTP ERROR]', resp.status(), resp.url());
    }
  });
}"

# 现在开始交互并查看错误
playwright-cli click e5
playwright-cli fill e3 "test"

策略 5:等待与重试

如果操作因时序问题失败,可添加显式等待:

# 等待元素变为可操作状态
playwright-cli run-code "async page => {
  await page.locator('#dynamic-button').waitFor({ state: 'visible', timeout: 10000 });
}"
playwright-cli snapshot
playwright-cli click e5

# 等待页面稳定
playwright-cli run-code "async page => {
  await page.waitForLoadState('networkidle');
}"
playwright-cli snapshot

性能分析

测量页面加载时间

playwright-cli run-code "async page => {
  const timing = await page.evaluate(() => {
    const t = performance.timing;
    return {
      dns: t.domainLookupEnd - t.domainLookupStart,
      tcp: t.connectEnd - t.connectStart,
      ttfb: t.responseStart - t.requestStart,
      download: t.responseEnd - t.responseStart,
      domParsing: t.domInteractive - t.domLoading,
      domComplete: t.domComplete - t.domLoading,
      total: t.loadEventEnd - t.navigationStart
    };
  });
  return timing;
}"

使用 Navigation Timing API 分析

playwright-cli run-code "async page => {
  const entries = await page.evaluate(() => {
    return performance.getEntriesByType('navigation').map(e => ({
      type: e.type,
      redirectTime: e.redirectEnd - e.redirectStart,
      dnsTime: e.domainLookupEnd - e.domainLookupStart,
      connectTime: e.connectEnd - e.connectStart,
      tlsTime: e.secureConnectionStart > 0 ? e.connectEnd - e.secureConnectionStart : 0,
      requestTime: e.responseStart - e.requestStart,
      responseTime: e.responseEnd - e.responseStart,
      domProcessing: e.domComplete - e.domInteractive,
      loadTime: e.loadEventEnd - e.loadEventStart,
      totalTime: e.loadEventEnd - e.startTime
    }));
  });
  return entries;
}"

列出慢资源

playwright-cli run-code "async page => {
  const resources = await page.evaluate(() => {
    return performance.getEntriesByType('resource')
      .map(r => ({ name: r.name.split('/').pop(), duration: Math.round(r.duration), size: r.transferSize }))
      .sort((a, b) => b.duration - a.duration)
      .slice(0, 10);
  });
  return resources;
}"

追踪 vs 视频 vs 截图

选择合适的捕获方式:

功能 追踪 视频 截图
格式 .trace 文件 .webm 视频 .png 图片
DOM 检查
网络详情
逐步回放 连续播放 单帧
控制台日志
文件大小 中等
最佳用途 调试 演示、文档 快速捕获

选择指南

  • 操作失败且不明原因 → 追踪
  • 需要向他人展示流程 → 视频
  • 需要验证视觉状态 → 截图
  • 需要分析性能 → 追踪(包含网络水fall图)
  • CI 中失败测试的产物 → 追踪 + 截图

最佳实践

1. 在问题发生前开始追踪

追踪导致失败的整个流程,而不仅仅是失败的步骤:

playwright-cli tracing-start
# 从头重现完整流程
playwright-cli open https://app.example.com
playwright-cli fill e1 "user@example.com"
playwright-cli click e3
# ... 直至失败的所有步骤 ...
playwright-cli tracing-stop

2. 主动使用控制台监控

在任何调试会话开始时即启动控制台监控:

playwright-cli run-code "async page => {
  page.on('console', msg => console.log(\`[\${msg.type()}] \${msg.text()}\`));
  page.on('pageerror', err => console.log('[EXCEPTION]', err.message));
}"

3. 清理旧追踪

追踪文件会占用大量磁盘空间:

# 删除 7 天前的追踪文件
find .playwright-cli/traces -mtime +7 -delete

4. 组合多种技术

最有效的调试往往结合多种方法:

playwright-cli tracing-start           # 捕获一切
playwright-cli console error           # 监控 JS 错误
playwright-cli network                 # 监控失败的请求
playwright-cli snapshot                # 查看当前状态
# ... 交互并调试 ...
playwright-cli tracing-stop            # 保存追踪用于详细分析