426 lines
12 KiB
Markdown
426 lines
12 KiB
Markdown
# 追踪与调试
|
||
|
||
> **使用场景**:调试失败的操作、分析性能瓶颈、捕获执行证据、理解交互未生效的原因,或在自动化过程中检查网络及控制台活动。
|
||
> **前置条件**:[core-commands.md](core-commands.md) —— 掌握基本 CLI 用法
|
||
|
||
## 快速参考
|
||
|
||
```bash
|
||
# 追踪会话
|
||
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 快照、截图、网络活动、控制台日志以及时间信息,覆盖会话中的每一个操作。
|
||
|
||
### 基本用法
|
||
|
||
```bash
|
||
# 在要调试的流程之前开始录制
|
||
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.log`、`console.warn`、`console.error` 消息 |
|
||
| **时间信息** | 每个操作的具体耗时 |
|
||
| **来源** | 每个操作由哪个命令触发 |
|
||
|
||
### 追踪输出文件
|
||
|
||
当追踪激活时,Playwright 会创建一个 `traces/` 目录:
|
||
|
||
**`trace-{时间戳}.trace`** —— 主追踪文件,包含:
|
||
|
||
- 附带 DOM 快照的操作日志
|
||
- 每一步的截图
|
||
- 时间信息
|
||
- 控制台消息
|
||
|
||
**`trace-{时间戳}.network`** —— 网络活动:
|
||
|
||
- 所有 HTTP 请求与响应
|
||
- 请求/响应请求头与响应体
|
||
- DNS、连接、TLS、TTFB、下载时间
|
||
- 资源大小及失败的请求
|
||
|
||
**`resources/`** —— 用于追踪回放的缓存资源:
|
||
|
||
- 图片、字体、样式表、脚本
|
||
- 用于离线回放的响应体
|
||
|
||
### 查看追踪
|
||
|
||
在 Playwright 的 Trace Viewer 中打开追踪 —— 这是一个用于逐步调试的丰富 GUI:
|
||
|
||
```bash
|
||
# 在 Trace Viewer Web 应用中打开追踪
|
||
npx playwright show-trace traces/trace-123456.trace
|
||
|
||
# 或使用在线 Trace Viewer
|
||
# 将追踪文件上传至:https://trace.playwright.dev
|
||
```
|
||
|
||
Trace Viewer 会显示:
|
||
|
||
- **时间轴**:带截图的逐步操作
|
||
- **DOM 快照**:检查每一步中的元素(类似 DevTools)
|
||
- **网络**:所有请求的水fall图
|
||
- **控制台**:带时间戳的日志消息
|
||
- **来源**:触发每个操作的代码
|
||
|
||
## 控制台监控
|
||
|
||
查看页面的 JavaScript 控制台输出 —— 对捕获错误至关重要:
|
||
|
||
```bash
|
||
# 显示所有控制台消息
|
||
playwright-cli console
|
||
|
||
# 按严重级别筛选
|
||
playwright-cli console error # 仅错误
|
||
playwright-cli console warning # 仅警告
|
||
playwright-cli console info # 仅信息消息
|
||
playwright-cli console log # 仅日志消息
|
||
```
|
||
|
||
### 常见调试模式
|
||
|
||
```bash
|
||
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` 设置持续的控制台监控:
|
||
|
||
```bash
|
||
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"
|
||
```
|
||
|
||
### 捕获未捕获的异常
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
page.on('pageerror', error => {
|
||
console.log('Uncaught exception:', error.message);
|
||
});
|
||
}"
|
||
```
|
||
|
||
## 网络监控
|
||
|
||
查看页面发出的所有网络请求:
|
||
|
||
```bash
|
||
playwright-cli network
|
||
```
|
||
|
||
### 实时查看网络
|
||
|
||
```bash
|
||
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
|
||
```
|
||
|
||
### 监控失败的请求
|
||
|
||
```bash
|
||
playwright-cli run-code "async page => {
|
||
page.on('requestfailed', request => {
|
||
console.log(\`FAILED: \${request.method()} \${request.url()} - \${request.failure()?.errorText}\`);
|
||
});
|
||
}"
|
||
```
|
||
|
||
### 检查特定响应
|
||
|
||
```bash
|
||
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:快照前后对比
|
||
|
||
最简单的调试方法 —— 查看发生了什么变化:
|
||
|
||
```bash
|
||
playwright-cli snapshot --filename=before.yaml
|
||
playwright-cli click e5
|
||
playwright-cli snapshot --filename=after.yaml
|
||
# 比较两个快照,了解变化内容
|
||
```
|
||
|
||
### 策略 2:追踪失败流程
|
||
|
||
在失败步骤之前开始追踪:
|
||
|
||
```bash
|
||
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:检查元素状态
|
||
|
||
当交互失败时,检查元素的实际状态:
|
||
|
||
```bash
|
||
# 元素是否可见?
|
||
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:控制台 + 网络组合
|
||
|
||
```bash
|
||
# 同时监控控制台和网络
|
||
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:等待与重试
|
||
|
||
如果操作因时序问题失败,可添加显式等待:
|
||
|
||
```bash
|
||
# 等待元素变为可操作状态
|
||
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
|
||
```
|
||
|
||
## 性能分析
|
||
|
||
### 测量页面加载时间
|
||
|
||
```bash
|
||
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 分析
|
||
|
||
```bash
|
||
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;
|
||
}"
|
||
```
|
||
|
||
### 列出慢资源
|
||
|
||
```bash
|
||
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. 在问题发生前开始追踪
|
||
|
||
追踪导致失败的整个流程,而不仅仅是失败的步骤:
|
||
|
||
```bash
|
||
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. 主动使用控制台监控
|
||
|
||
在任何调试会话开始时即启动控制台监控:
|
||
|
||
```bash
|
||
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. 清理旧追踪
|
||
|
||
追踪文件会占用大量磁盘空间:
|
||
|
||
```bash
|
||
# 删除 7 天前的追踪文件
|
||
find .playwright-cli/traces -mtime +7 -delete
|
||
```
|
||
|
||
### 4. 组合多种技术
|
||
|
||
最有效的调试往往结合多种方法:
|
||
|
||
```bash
|
||
playwright-cli tracing-start # 捕获一切
|
||
playwright-cli console error # 监控 JS 错误
|
||
playwright-cli network # 监控失败的请求
|
||
playwright-cli snapshot # 查看当前状态
|
||
# ... 交互并调试 ...
|
||
playwright-cli tracing-stop # 保存追踪用于详细分析
|
||
```
|