@chen-rmag/ai-runner 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -0
- package/SUMMARY_USAGE.md +359 -0
- package/TOOLS_INTEGRATION_SUMMARY.md +206 -0
- package/dist/agents/error-analyzer.d.ts +62 -0
- package/dist/agents/error-analyzer.d.ts.map +1 -0
- package/dist/agents/error-analyzer.js +168 -0
- package/dist/agents/error-analyzer.js.map +1 -0
- package/dist/agents/heal-agent.d.ts +30 -0
- package/dist/agents/heal-agent.d.ts.map +1 -0
- package/dist/agents/heal-agent.js +76 -0
- package/dist/agents/heal-agent.js.map +1 -0
- package/dist/agents/healer.d.ts +73 -0
- package/dist/agents/healer.d.ts.map +1 -0
- package/dist/agents/healer.js +538 -0
- package/dist/agents/healer.js.map +1 -0
- package/dist/agents/langgraph-agent.d.ts +44 -0
- package/dist/agents/langgraph-agent.d.ts.map +1 -0
- package/dist/agents/langgraph-agent.js +328 -0
- package/dist/agents/langgraph-agent.js.map +1 -0
- package/dist/agents/react-agent.d.ts +52 -0
- package/dist/agents/react-agent.d.ts.map +1 -0
- package/dist/agents/react-agent.js +262 -0
- package/dist/agents/react-agent.js.map +1 -0
- package/dist/agents/tools/form.d.ts +22 -0
- package/dist/agents/tools/form.d.ts.map +1 -0
- package/dist/agents/tools/form.js +134 -0
- package/dist/agents/tools/form.js.map +1 -0
- package/dist/agents/tools/index.d.ts +13 -0
- package/dist/agents/tools/index.d.ts.map +1 -0
- package/dist/agents/tools/index.js +33 -0
- package/dist/agents/tools/index.js.map +1 -0
- package/dist/agents/tools/navigate.d.ts +22 -0
- package/dist/agents/tools/navigate.d.ts.map +1 -0
- package/dist/agents/tools/navigate.js +74 -0
- package/dist/agents/tools/navigate.js.map +1 -0
- package/dist/agents/tools/snapshot.d.ts +22 -0
- package/dist/agents/tools/snapshot.d.ts.map +1 -0
- package/dist/agents/tools/snapshot.js +110 -0
- package/dist/agents/tools/snapshot.js.map +1 -0
- package/dist/agents/tools/verify.d.ts +34 -0
- package/dist/agents/tools/verify.d.ts.map +1 -0
- package/dist/agents/tools/verify.js +169 -0
- package/dist/agents/tools/verify.js.map +1 -0
- package/dist/agents/tools/wait.d.ts +22 -0
- package/dist/agents/tools/wait.d.ts.map +1 -0
- package/dist/agents/tools/wait.js +104 -0
- package/dist/agents/tools/wait.js.map +1 -0
- package/dist/agents/types.d.ts +51 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +6 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/core/ai-heal.d.ts +89 -0
- package/dist/core/ai-heal.d.ts.map +1 -0
- package/dist/core/ai-heal.js +468 -0
- package/dist/core/ai-heal.js.map +1 -0
- package/dist/core/execution-engine.d.ts +16 -0
- package/dist/core/execution-engine.d.ts.map +1 -0
- package/dist/core/execution-engine.js +44 -0
- package/dist/core/execution-engine.js.map +1 -0
- package/dist/core/runner.d.ts +195 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +658 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/types/external.d.ts +6 -0
- package/dist/types/external.d.ts.map +1 -0
- package/dist/types/external.js +7 -0
- package/dist/types/external.js.map +1 -0
- package/dist/types/index.d.ts +153 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +26 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/object-registry.d.ts +48 -0
- package/dist/utils/object-registry.d.ts.map +1 -0
- package/dist/utils/object-registry.js +133 -0
- package/dist/utils/object-registry.js.map +1 -0
- package/package.json +37 -0
- package/playwright.config.ts +38 -0
- package/src/agents/heal-agent.ts +85 -0
- package/src/agents/healer.ts +619 -0
- package/src/agents/tools/EXAMPLES.md +347 -0
- package/src/agents/tools/README.md +207 -0
- package/src/agents/tools/form.ts +138 -0
- package/src/agents/tools/index.ts +29 -0
- package/src/agents/tools/navigate.ts +69 -0
- package/src/agents/tools/snapshot.ts +109 -0
- package/src/agents/tools/verify.ts +168 -0
- package/src/agents/tools/wait.ts +103 -0
- package/src/agents/types.ts +79 -0
- package/src/core/runner.ts +756 -0
- package/src/index.ts +29 -0
- package/src/types/external.ts +7 -0
- package/src/types/index.ts +200 -0
- package/tests/agent/test-heal-agent.spec.ts +81 -0
- package/tests/tools/README.md +227 -0
- package/tests/tools/TEST_SUMMARY.md +214 -0
- package/tests/tools/quick-test.ts +88 -0
- package/tests/tools/tools.test.ts +491 -0
- package/tsconfig.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# @ai-test/ai-heal
|
|
2
|
+
|
|
3
|
+
AI-powered self-healing SDK for Playwright test scripts.
|
|
4
|
+
|
|
5
|
+
> **版本**: v0.2.0
|
|
6
|
+
> **状态**: 核心设计完成,准备开发
|
|
7
|
+
> **重大更新**: 基于 MCP 工具限制重新设计架构,可行性提升至 ⭐⭐⭐⭐⭐
|
|
8
|
+
|
|
9
|
+
## 概述
|
|
10
|
+
|
|
11
|
+
`ai-heal` 是一个为 Playwright 测试脚本设计的自愈 SDK,通过 AI Agent 在测试执行失败时自动修复脚本错误,提高测试稳定性和维护效率。
|
|
12
|
+
|
|
13
|
+
## 核心特性
|
|
14
|
+
|
|
15
|
+
- 🔄 **自动自愈**: 测试步骤失败时自动触发 AI 修复流程
|
|
16
|
+
- 🤖 **智能 Agent**: 基于 LangGraph 的 ReAct 循环实现智能决策
|
|
17
|
+
- 🔧 **变量绑定**: Ref<T> 包装器支持复杂 Playwright 对象的引用传递
|
|
18
|
+
- 📝 **代码生成**: Agent 分析错误并生成修复代码,在用户 Browser 上下文执行
|
|
19
|
+
- 🎯 **类型安全**: 完整的 TypeScript 类型支持
|
|
20
|
+
- ⚡ **零状态隔离**: 在用户真实 Browser 中执行,状态完全一致
|
|
21
|
+
|
|
22
|
+
## 架构亮点
|
|
23
|
+
|
|
24
|
+
### ✅ 解决核心问题
|
|
25
|
+
|
|
26
|
+
**问题**: Playwright MCP 工具无法返回 Page、Tab、DOM 节点等复杂对象。
|
|
27
|
+
|
|
28
|
+
**方案**:
|
|
29
|
+
```
|
|
30
|
+
Agent 使用 MCP 观察(只读)→ 生成修复代码 → SDK 在用户 Browser 执行
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**优势**:
|
|
34
|
+
- ✅ 完全绕过 MCP 返回值限制
|
|
35
|
+
- ✅ 支持所有 Playwright 复杂对象
|
|
36
|
+
- ✅ Cookie、Session、Storage 完全共享
|
|
37
|
+
- ✅ 原生 Playwright API 完全可用
|
|
38
|
+
|
|
39
|
+
## 快速开始
|
|
40
|
+
|
|
41
|
+
### 安装
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @ai-test/ai-heal
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 基本使用
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { AIHeal, Ref } from '@ai-test/ai-heal';
|
|
51
|
+
import { test, expect } from '@playwright/test';
|
|
52
|
+
|
|
53
|
+
test('示例测试', async ({ page }) => {
|
|
54
|
+
// 初始化自愈实例
|
|
55
|
+
const heal = new AIHeal({
|
|
56
|
+
testCaseId: 'test-123',
|
|
57
|
+
projectId: 'project-456'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// 声明需要自愈的变量
|
|
61
|
+
const userPage = new Ref<typeof>(null);
|
|
62
|
+
const userData = new Ref<any>(null);
|
|
63
|
+
|
|
64
|
+
// 使用 runStep 包装测试步骤
|
|
65
|
+
await heal.runStep({
|
|
66
|
+
description: '打开登录页面并输入用户信息',
|
|
67
|
+
variables: {
|
|
68
|
+
page: userPage,
|
|
69
|
+
data: userData
|
|
70
|
+
},
|
|
71
|
+
context: page
|
|
72
|
+
}, async () => {
|
|
73
|
+
await page.goto('https://example.com/login');
|
|
74
|
+
await page.fill('#username', 'testuser');
|
|
75
|
+
await page.fill('#password', 'password123');
|
|
76
|
+
await page.click('#login-button');
|
|
77
|
+
|
|
78
|
+
// 保存变量供后续使用
|
|
79
|
+
userData.current = { username: 'testuser' };
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// 继续使用自愈后的变量
|
|
83
|
+
await heal.runStep({
|
|
84
|
+
description: '验证用户登录成功',
|
|
85
|
+
variables: { page: userPage }
|
|
86
|
+
}, async () => {
|
|
87
|
+
await expect(userPage.current).toHaveURL(/.*dashboard/);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// 生成自愈报告和修复后的脚本
|
|
91
|
+
const summary = await heal.summary();
|
|
92
|
+
console.log(`总步骤数: ${summary.totalSteps}`);
|
|
93
|
+
console.log(`自愈成功数: ${summary.healedSteps}`);
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API 文档
|
|
98
|
+
|
|
99
|
+
### AIHeal
|
|
100
|
+
|
|
101
|
+
#### 构造函数
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
new AIHeal(config: AIHealConfig)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**参数:**
|
|
108
|
+
- `testCaseId?: string` - 测试用例 ID,用于查询原始脚本
|
|
109
|
+
- `projectId?: string` - 项目 ID
|
|
110
|
+
- `scriptContent?: string` - 手动注入的脚本内容
|
|
111
|
+
- `modelConfig?: ModelConfig` - AI 模型配置
|
|
112
|
+
- `enableAutoSave?: boolean` - 是否自动保存修复后的脚本(默认 false)
|
|
113
|
+
- `maxRetries?: number` - 最大自愈重试次数(默认 3)
|
|
114
|
+
|
|
115
|
+
#### runStep
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
async runStep<T>(
|
|
119
|
+
options: RunStepOptions,
|
|
120
|
+
fn: () => Promise
|
|
121
|
+
): Promise<T>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**参数:**
|
|
125
|
+
- `description: string` - 步骤描述,用于 AI 理解
|
|
126
|
+
- `variables?: Record<string, Ref<any>>` - 需要传递的变量绑定
|
|
127
|
+
- `context?: any` - Playwright 上下文对象(Page, BrowserContext 等)
|
|
128
|
+
|
|
129
|
+
**返回:**
|
|
130
|
+
- 泛型 `T` - 步骤执行结果
|
|
131
|
+
|
|
132
|
+
#### summary
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
async summary(): Promise<HealSummary>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**返回:**
|
|
139
|
+
- `totalSteps: number` - 总步骤数
|
|
140
|
+
- `healedSteps: number` - 自愈成功的步骤数
|
|
141
|
+
- `modifiedScript?: string` - 修复后的脚本
|
|
142
|
+
- `healingDetails: HealingDetail[]` - 每次自愈的详细信息
|
|
143
|
+
|
|
144
|
+
### Ref<T>
|
|
145
|
+
|
|
146
|
+
用于包装需要跨步骤传递的变量,支持 AI Agent 修改外部变量。
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const page = new Ref<Page>(null);
|
|
150
|
+
|
|
151
|
+
// 获取值
|
|
152
|
+
const currentPage = page.current;
|
|
153
|
+
|
|
154
|
+
// 赋值
|
|
155
|
+
page.current = await context.newPage();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 架构设计
|
|
159
|
+
|
|
160
|
+
### 核心组件
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
ai-heal/
|
|
164
|
+
├── src/
|
|
165
|
+
│ ├── core/ # 核心逻辑
|
|
166
|
+
│ │ ├── ai-heal.ts # AIHeal 主类
|
|
167
|
+
│ │ ├── healer.ts # 自愈执行器
|
|
168
|
+
│ │ └── variable-binding.ts # 变量绑定机制
|
|
169
|
+
│ ├── agents/ # AI Agent
|
|
170
|
+
│ │ ├── heal-agent.ts # 自愈 Agent
|
|
171
|
+
│ │ └── graph.ts # LangGraph 定义
|
|
172
|
+
│ ├── types/ # 类型定义
|
|
173
|
+
│ ├── utils/ # 工具函数
|
|
174
|
+
│ └── index.ts # 导出入口
|
|
175
|
+
├── docs/ # 文档
|
|
176
|
+
├── examples/ # 使用示例
|
|
177
|
+
└── tests/ # 测试
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 自愈流程
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
1. 执行原始代码
|
|
184
|
+
↓
|
|
185
|
+
2. 捕获错误
|
|
186
|
+
↓
|
|
187
|
+
3. 判断是否可自愈
|
|
188
|
+
↓
|
|
189
|
+
4. 构建 ReAct Agent
|
|
190
|
+
↓
|
|
191
|
+
5. Agent 使用 Playwright 工具重新执行
|
|
192
|
+
↓
|
|
193
|
+
6. 解析并应用变量赋值
|
|
194
|
+
↓
|
|
195
|
+
7. 记录自愈上下文
|
|
196
|
+
↓
|
|
197
|
+
8. 返回结果
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## 开发计划
|
|
201
|
+
|
|
202
|
+
- [x] 核心架构设计
|
|
203
|
+
- [x] 技术方案文档
|
|
204
|
+
- [x] POC 验证 (3个)
|
|
205
|
+
- [ ] 基础类型定义
|
|
206
|
+
- [ ] 变量绑定机制实现
|
|
207
|
+
- [ ] AIHeal 主类实现
|
|
208
|
+
- [ ] LangGraph Agent 集成
|
|
209
|
+
- [ ] Playwright MCP 集成
|
|
210
|
+
- [ ] 脚本修复逻辑
|
|
211
|
+
- [ ] 单元测试
|
|
212
|
+
- [ ] 集成测试
|
|
213
|
+
- [ ] 文档完善
|
|
214
|
+
|
|
215
|
+
## POC 验证
|
|
216
|
+
|
|
217
|
+
**当前状态**: ✅ 准备就绪
|
|
218
|
+
|
|
219
|
+
我们已经创建了 3 个 POC 验证脚本,用于验证核心技术方案的可行性:
|
|
220
|
+
|
|
221
|
+
### POC 清单
|
|
222
|
+
|
|
223
|
+
| POC | 验证内容 | 文件 | 预期时间 |
|
|
224
|
+
|-----|---------|------|---------|
|
|
225
|
+
| **POC 1** | Ref<T> 类型推断 | `src/poc/poc1-ref-type-inference.ts` | ~2s |
|
|
226
|
+
| **POC 2** | 上下文代码执行 | `src/poc/poc2-context-execution.ts` | ~15s |
|
|
227
|
+
| **POC 3** | 复杂对象序列化 | `src/poc/poc3-object-serialization.ts` | ~10s |
|
|
228
|
+
|
|
229
|
+
### 快速运行
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# 进入项目目录
|
|
233
|
+
cd ai-heal
|
|
234
|
+
|
|
235
|
+
# 安装依赖
|
|
236
|
+
npm install
|
|
237
|
+
npx playwright install
|
|
238
|
+
|
|
239
|
+
# 运行所有 POC 测试
|
|
240
|
+
npm test
|
|
241
|
+
|
|
242
|
+
# 或使用 Playwright 直接运行
|
|
243
|
+
npx playwright test src/poc/
|
|
244
|
+
|
|
245
|
+
# 查看详细报告
|
|
246
|
+
npx playwright show-report
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 详细说明
|
|
250
|
+
|
|
251
|
+
请查看 [POC README](src/poc/README.md) 了解完整的验证说明和验收标准。
|
|
252
|
+
|
|
253
|
+
## 技术方案
|
|
254
|
+
|
|
255
|
+
详见 [docs/technical-design.md](docs/technical-design.md)
|
|
256
|
+
|
|
257
|
+
## 可行性分析
|
|
258
|
+
|
|
259
|
+
详见 [docs/feasibility-analysis.md](docs/feasibility-analysis.md)
|
|
260
|
+
|
|
261
|
+
## 许可证
|
|
262
|
+
|
|
263
|
+
MIT
|
package/SUMMARY_USAGE.md
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# AIHeal Summary 功能使用指南
|
|
2
|
+
|
|
3
|
+
## 功能概述
|
|
4
|
+
|
|
5
|
+
AIHeal 的 `summary()` 方法会在测试执行完毕后:
|
|
6
|
+
1. 收集所有自愈上下文
|
|
7
|
+
2. 如果配置了 `enableAutoSave: true`,使用 LLM 生成修复后的完整脚本
|
|
8
|
+
3. 根据是否提供 `projectId` 和 `testCaseId`,决定是保存到数据库还是打印到控制台
|
|
9
|
+
|
|
10
|
+
## 基本用法
|
|
11
|
+
|
|
12
|
+
### 1. 仅收集统计信息(默认行为)
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { AIHeal } from '@ai-test/ai-heal';
|
|
16
|
+
|
|
17
|
+
const heal = new AIHeal({
|
|
18
|
+
modelConfigId: 'your-model-id'
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// ... 执行测试步骤
|
|
22
|
+
|
|
23
|
+
const summary = await heal.summary();
|
|
24
|
+
|
|
25
|
+
console.log(`总步骤数: ${summary.totalSteps}`);
|
|
26
|
+
console.log(`自愈步骤数: ${summary.healedSteps}`);
|
|
27
|
+
console.log(`自愈详情:`, summary.healingDetails);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**输出**:
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"totalSteps": 5,
|
|
34
|
+
"healedSteps": 2,
|
|
35
|
+
"healingDetails": [
|
|
36
|
+
{
|
|
37
|
+
"step": "点击提交按钮",
|
|
38
|
+
"error": "Timeout 5000ms exceeded",
|
|
39
|
+
"recoveryTime": 3500,
|
|
40
|
+
"llmInteractions": 0
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. 启用自动脚本生成和保存
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const heal = new AIHeal({
|
|
50
|
+
modelConfigId: 'your-model-id',
|
|
51
|
+
enableAutoSave: true, // 启用自动脚本生成
|
|
52
|
+
projectId: 'project-123',
|
|
53
|
+
testCaseId: 'test-456'
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// ... 执行测试步骤
|
|
57
|
+
|
|
58
|
+
const summary = await heal.summary();
|
|
59
|
+
|
|
60
|
+
// 如果有自愈发生,summary.modifiedScript 会包含修复后的脚本
|
|
61
|
+
if (summary.modifiedScript) {
|
|
62
|
+
console.log('脚本已修复并保存!');
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**行为**:
|
|
67
|
+
- ✅ 如果提供了 `projectId` 和 `testCaseId`,脚本会保存到 `TestCaseRepository`
|
|
68
|
+
- ❌ 如果保存失败,会回退到打印到控制台
|
|
69
|
+
- 如果没有提供项目信息,直接打印到控制台
|
|
70
|
+
|
|
71
|
+
### 3. 无项目信息时打印脚本
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const heal = new AIHeal({
|
|
75
|
+
modelConfigId: 'your-model-id',
|
|
76
|
+
enableAutoSave: true
|
|
77
|
+
// 不提供 projectId 和 testCaseId
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ... 执行测试步骤
|
|
81
|
+
|
|
82
|
+
const summary = await heal.summary();
|
|
83
|
+
|
|
84
|
+
// 脚本会打印到控制台
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**控制台输出**:
|
|
88
|
+
```
|
|
89
|
+
========================================
|
|
90
|
+
[AIHeal] 生成修复后的脚本...
|
|
91
|
+
========================================
|
|
92
|
+
[AIHeal] 调用 LLM 生成修复脚本...
|
|
93
|
+
[AIHeal] 修复脚本生成完成
|
|
94
|
+
========================================
|
|
95
|
+
[AIHeal] 修复后的测试脚本
|
|
96
|
+
========================================
|
|
97
|
+
|
|
98
|
+
test('example test', async ({ page }) => {
|
|
99
|
+
await page.goto('https://example.com');
|
|
100
|
+
|
|
101
|
+
// 修复:使用更稳定的选择器
|
|
102
|
+
await page.click('button[type="submit"]', { timeout: 10000 });
|
|
103
|
+
|
|
104
|
+
const title = await page.title();
|
|
105
|
+
expect(title).toBeTruthy();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
========================================
|
|
109
|
+
[AIHeal] 脚本处理完成
|
|
110
|
+
========================================
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 完整示例
|
|
114
|
+
|
|
115
|
+
### 示例 1: 有项目信息的集成测试
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { test, expect } from '@playwright/test';
|
|
119
|
+
import { AIHeal, Ref } from '@ai-test/ai-heal';
|
|
120
|
+
|
|
121
|
+
test.describe('电商网站测试', () => {
|
|
122
|
+
test('购物车功能', async ({ page, context }) => {
|
|
123
|
+
const heal = new AIHeal({
|
|
124
|
+
modelConfigId: 'model-config-id',
|
|
125
|
+
enableAutoSave: true, // 启用自动保存
|
|
126
|
+
projectId: 'ecommerce-project',
|
|
127
|
+
testCaseId: 'cart-test-001',
|
|
128
|
+
debugMode: true
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// 步骤 1: 访问网站
|
|
132
|
+
await heal.runStep({
|
|
133
|
+
description: '访问购物车页面',
|
|
134
|
+
context: { page, context }
|
|
135
|
+
}, async () => {
|
|
136
|
+
await page.goto('https://shop.example.com/cart');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// 步骤 2: 添加商品(可能失败并触发自愈)
|
|
140
|
+
const productId = new Ref<string>('');
|
|
141
|
+
|
|
142
|
+
await heal.runStep({
|
|
143
|
+
description: '获取第一个商品ID',
|
|
144
|
+
context: { page, context },
|
|
145
|
+
variables: { productId }
|
|
146
|
+
}, async () => {
|
|
147
|
+
// 这个选择器可能会变化,触发自愈
|
|
148
|
+
const id = await page.locator('.product-item:first-child').getAttribute('data-id');
|
|
149
|
+
productId.value = id || '';
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// 步骤 3: 点击结算
|
|
153
|
+
await heal.runStep({
|
|
154
|
+
description: '点击结算按钮',
|
|
155
|
+
context: { page, context }
|
|
156
|
+
}, async () => {
|
|
157
|
+
await page.click('#checkout-btn');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// 测试结束,生成摘要和修复脚本
|
|
161
|
+
const summary = await heal.summary();
|
|
162
|
+
|
|
163
|
+
console.log(`测试完成,共 ${summary.totalSteps} 步`);
|
|
164
|
+
console.log(`自愈了 ${summary.healedSteps} 个步骤`);
|
|
165
|
+
|
|
166
|
+
if (summary.modifiedScript) {
|
|
167
|
+
console.log('修复后的脚本已保存到项目中');
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 示例 2: 本地调试(无项目信息)
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { test } from '@playwright/test';
|
|
177
|
+
import { AIHeal } from '@ai-test/ai-heal';
|
|
178
|
+
|
|
179
|
+
test('本地测试调试', async ({ page, context }) => {
|
|
180
|
+
const heal = new AIHeal({
|
|
181
|
+
modelConfigId: 'model-config-id',
|
|
182
|
+
enableAutoSave: true,
|
|
183
|
+
debugMode: true
|
|
184
|
+
// 不提供 projectId 和 testCaseId
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// ... 测试步骤
|
|
188
|
+
|
|
189
|
+
const summary = await heal.summary();
|
|
190
|
+
|
|
191
|
+
// 修复后的脚本会打印到控制台
|
|
192
|
+
// 可以手动复制并更新到测试文件中
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 配置选项
|
|
197
|
+
|
|
198
|
+
### AIHealConfig 相关字段
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
interface AIHealConfig {
|
|
202
|
+
/** 是否自动生成并保存修复后的脚本 */
|
|
203
|
+
enableAutoSave?: boolean;
|
|
204
|
+
|
|
205
|
+
/** 项目 ID(用于保存脚本) */
|
|
206
|
+
projectId?: string;
|
|
207
|
+
|
|
208
|
+
/** 测试用例 ID(用于保存脚本) */
|
|
209
|
+
testCaseId?: string;
|
|
210
|
+
|
|
211
|
+
/** 模型配置 ID(用于生成脚本) */
|
|
212
|
+
modelConfigId?: string;
|
|
213
|
+
|
|
214
|
+
/** Agent 最大执行步数 */
|
|
215
|
+
agentMaxSteps?: number;
|
|
216
|
+
|
|
217
|
+
/** 是否开启调试模式 */
|
|
218
|
+
debugMode?: boolean;
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 工作流程
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
测试执行
|
|
226
|
+
↓
|
|
227
|
+
runStep() 执行(可能触发自愈)
|
|
228
|
+
↓
|
|
229
|
+
记录 HealContext(错误、恢复过程等)
|
|
230
|
+
↓
|
|
231
|
+
调用 summary()
|
|
232
|
+
↓
|
|
233
|
+
检查 enableAutoSave && 有自愈发生
|
|
234
|
+
↓
|
|
235
|
+
┌─────────────────────────────────┐
|
|
236
|
+
│ 使用 LLM 生成修复后的脚本 │
|
|
237
|
+
│ - 输入:原始脚本 + 自愈历史 │
|
|
238
|
+
│ - 输出:修复后的完整脚本 │
|
|
239
|
+
└─────────────────────────────────┘
|
|
240
|
+
↓
|
|
241
|
+
┌─────────────────────────────────┐
|
|
242
|
+
│ 判断:有 projectId && testCaseId? │
|
|
243
|
+
└─────────────────────────────────┘
|
|
244
|
+
↓ 是 ↓ 否
|
|
245
|
+
保存到数据库 打印到控制台
|
|
246
|
+
↓
|
|
247
|
+
返回 HealSummary
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## HealSummary 返回值
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
interface HealSummary {
|
|
254
|
+
/** 总步骤数 */
|
|
255
|
+
totalSteps: number;
|
|
256
|
+
|
|
257
|
+
/** 自愈步骤数 */
|
|
258
|
+
healedSteps: number;
|
|
259
|
+
|
|
260
|
+
/** 修复后的脚本(如果启用 enableAutoSave) */
|
|
261
|
+
modifiedScript?: string;
|
|
262
|
+
|
|
263
|
+
/** 自愈详情列表 */
|
|
264
|
+
healingDetails: HealingDetail[];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface HealingDetail {
|
|
268
|
+
/** 步骤描述 */
|
|
269
|
+
step: string;
|
|
270
|
+
|
|
271
|
+
/** 错误信息 */
|
|
272
|
+
error: string;
|
|
273
|
+
|
|
274
|
+
/** 恢复时间(毫秒) */
|
|
275
|
+
recoveryTime: number;
|
|
276
|
+
|
|
277
|
+
/** LLM 交互次数(暂未实现) */
|
|
278
|
+
llmInteractions: number;
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## LLM 生成脚本的质量
|
|
283
|
+
|
|
284
|
+
### 优点
|
|
285
|
+
- ✅ 基于实际自愈经验
|
|
286
|
+
- ✅ 包含详细的修复注释
|
|
287
|
+
- ✅ 使用稳定的选择器
|
|
288
|
+
- ✅ 保留原始代码结构
|
|
289
|
+
|
|
290
|
+
### 注意事项
|
|
291
|
+
- ⚠️ LLM 生成的代码需要人工审查
|
|
292
|
+
- ⚠️ 复杂的业务逻辑可能需要手动调整
|
|
293
|
+
- ⚠️ 建议在测试环境中验证修复后的脚本
|
|
294
|
+
|
|
295
|
+
## 最佳实践
|
|
296
|
+
|
|
297
|
+
1. **开发阶段**:不启用 `enableAutoSave`,只查看统计信息
|
|
298
|
+
```typescript
|
|
299
|
+
const heal = new AIHeal({
|
|
300
|
+
modelConfigId: 'xxx'
|
|
301
|
+
// enableAutoSave: false // 默认
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
2. **CI/CD 集成**:启用自动保存,但需要人工审核
|
|
306
|
+
```typescript
|
|
307
|
+
const heal = new AIHeal({
|
|
308
|
+
modelConfigId: 'xxx',
|
|
309
|
+
enableAutoSave: true,
|
|
310
|
+
projectId: 'xxx',
|
|
311
|
+
testCaseId: 'xxx'
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
3. **调试阶段**:启用 debugMode 查看详细过程
|
|
316
|
+
```typescript
|
|
317
|
+
const heal = new AIHeal({
|
|
318
|
+
modelConfigId: 'xxx',
|
|
319
|
+
enableAutoSave: true,
|
|
320
|
+
debugMode: true
|
|
321
|
+
});
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## 故障排查
|
|
325
|
+
|
|
326
|
+
### 问题 1: 脚本没有生成
|
|
327
|
+
|
|
328
|
+
**原因**:`enableAutoSave` 未设置或没有自愈发生
|
|
329
|
+
|
|
330
|
+
**解决**:
|
|
331
|
+
```typescript
|
|
332
|
+
// 确保启用自动保存
|
|
333
|
+
const heal = new AIHeal({
|
|
334
|
+
enableAutoSave: true, // 必须设置为 true
|
|
335
|
+
modelConfigId: 'xxx'
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// 确保有自愈发生
|
|
339
|
+
const summary = await heal.summary();
|
|
340
|
+
console.log('自愈步骤数:', summary.healedSteps);
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### 问题 2: 脚本保存失败
|
|
344
|
+
|
|
345
|
+
**原因**: projectId 或 testCaseId 错误
|
|
346
|
+
|
|
347
|
+
**解决**:
|
|
348
|
+
- 检查控制台错误日志
|
|
349
|
+
- 脚本会自动回退到打印模式
|
|
350
|
+
- 手动复制打印的脚本
|
|
351
|
+
|
|
352
|
+
### 问题 3: LLM 生成的代码质量差
|
|
353
|
+
|
|
354
|
+
**原因**:模型配置不当或提示词不够清晰
|
|
355
|
+
|
|
356
|
+
**解决**:
|
|
357
|
+
- 使用更强的模型(如 Claude 3.5 Sonnet)
|
|
358
|
+
- 在 `buildSystemPrompt()` 中调整提示词
|
|
359
|
+
- 人工审查和修改生成的代码
|