chore: import zh skill playwright-skill
This commit is contained in:
@@ -0,0 +1,425 @@
|
||||
# 追踪与调试
|
||||
|
||||
> **使用场景**:调试失败的操作、分析性能瓶颈、捕获执行证据、理解交互未生效的原因,或在自动化过程中检查网络及控制台活动。
|
||||
> **前置条件**:[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 # 保存追踪用于详细分析
|
||||
```
|
||||
Reference in New Issue
Block a user