openmatrix 0.2.31 → 0.2.34
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 +154 -154
- package/dist/cli/commands/approve.js +35 -1
- package/dist/cli/commands/auto.js +2 -2
- package/dist/cli/commands/check-gitignore.js +34 -30
- package/dist/cli/commands/check.js +1 -1
- package/dist/cli/commands/complete.js +35 -7
- package/dist/cli/commands/debug.js +2 -1
- package/dist/cli/commands/deploy.js +1 -1
- package/dist/cli/commands/install-skills.js +3 -0
- package/dist/cli/commands/meeting.js +37 -1
- package/dist/cli/commands/report.js +1 -1
- package/dist/cli/commands/resume.js +35 -1
- package/dist/cli/commands/retry.js +130 -56
- package/dist/cli/commands/start.js +1 -1
- package/dist/cli/commands/status.js +32 -29
- package/dist/cli/commands/step.js +4 -1
- package/dist/orchestrator/ai-reviewer.d.ts +5 -0
- package/dist/orchestrator/ai-reviewer.js +9 -2
- package/dist/orchestrator/context-collector.js +17 -5
- package/dist/orchestrator/executor.d.ts +8 -0
- package/dist/orchestrator/executor.js +24 -5
- package/dist/orchestrator/phase-executor.d.ts +4 -0
- package/dist/orchestrator/phase-executor.js +21 -4
- package/dist/storage/file-store.js +8 -0
- package/dist/storage/state-manager.js +52 -19
- package/dist/test/generator.js +113 -113
- package/dist/utils/error-handler.d.ts +18 -0
- package/dist/utils/error-handler.js +32 -0
- package/dist/utils/worktree-sync.js +24 -3
- package/package.json +61 -61
- package/skills/auto.md +410 -413
- package/skills/brainstorm.md +19 -12
- package/skills/debug.md +694 -691
- package/skills/deploy.md +658 -658
- package/skills/feature.md +713 -686
- package/skills/{SKILL.md → openmatrix-overview.md} +52 -53
- package/skills/plan.md +298 -296
- package/skills/report.md +9 -5
- package/skills/resume.md +292 -287
- package/skills/start.md +32 -20
- package/skills/status.md +5 -4
- package/skills/test.md +875 -875
- package/dist/agents/base-agent.d.ts +0 -46
- package/dist/agents/base-agent.js +0 -17
- package/dist/cli/commands/analyze.d.ts +0 -2
- package/dist/cli/commands/analyze.js +0 -50
- package/dist/orchestrator/smart-question-analyzer.d.ts +0 -90
- package/dist/orchestrator/smart-question-analyzer.js +0 -512
package/skills/test.md
CHANGED
|
@@ -1,876 +1,876 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: om:test
|
|
3
|
-
description: "Use when user wants to GENERATE or IMPROVE tests. Triggers on TEST-CREATION intent: user wants new test files, better coverage, or test infrastructure setup. DO NOT trigger on: test execution (running tests), test debugging (why test fails), or test questions (how to write tests). Intent signals: user asks to generate/add/write tests, mentions coverage gaps, wants test setup."
|
|
4
|
-
priority: high
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
<INTENT-JUDGMENT>
|
|
8
|
-
## 意图判断指南
|
|
9
|
-
|
|
10
|
-
**AI 应根据用户语义判断意图:**
|
|
11
|
-
|
|
12
|
-
### 触发信号(测试创建意图)
|
|
13
|
-
|
|
14
|
-
- 用户想生成测试文件
|
|
15
|
-
- 用户想改进测试覆盖
|
|
16
|
-
- 用户想设置测试框架
|
|
17
|
-
- 用户提到"没测试"、"需要测试"
|
|
18
|
-
|
|
19
|
-
### 不触发信号
|
|
20
|
-
|
|
21
|
-
| 用户意图 | 应调用 |
|
|
22
|
-
|---------|--------|
|
|
23
|
-
| 运行测试 | 直接执行 npm test |
|
|
24
|
-
| 测试失败想修复 | /om:debug |
|
|
25
|
-
| 询问测试写法 | 直接回答 |
|
|
26
|
-
|
|
27
|
-
### 示例判断
|
|
28
|
-
|
|
29
|
-
| 用户消息 | 判断 | 结果 |
|
|
30
|
-
|---------|------|------|
|
|
31
|
-
| "给这个文件补测试" | 创建测试意图 | 触发 ✓ |
|
|
32
|
-
| "生成单元测试" | 创建意图明确 | 触发 ✓ |
|
|
33
|
-
| "测试覆盖率太低" | 改进覆盖意图 | 触发 ✓ |
|
|
34
|
-
| "运行测试看看" | 执行意图 | 直接运行 |
|
|
35
|
-
| "测试失败了为什么" | 排查意图 | /om:debug |
|
|
36
|
-
</INTENT-JUDGMENT>
|
|
37
|
-
|
|
38
|
-
<NO-OTHER-SKILLS>
|
|
39
|
-
本 skill 与其他任务编排技能功能重叠,请勿同时使用。
|
|
40
|
-
|
|
41
|
-
**测试生成阶段使用 Agent 工具执行。**
|
|
42
|
-
</NO-OTHER-SKILLS>
|
|
43
|
-
|
|
44
|
-
<MANDATORY-EXECUTION-ORDER>
|
|
45
|
-
## 执行顺序 - 必须严格按此顺序,不得跳过
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
Step 1: 调用 CLI 扫描项目 (openmatrix test --json)
|
|
49
|
-
Step 2: AI 分析项目上下文和业务逻辑
|
|
50
|
-
Step 3: 发现测试缺失,输出分析报告
|
|
51
|
-
Step 4: UI 测试决策(如果 isFrontend=true)
|
|
52
|
-
⛔ 分析阶段结束,必须等待用户确认
|
|
53
|
-
Step 5: AskUserQuestion 确认测试范围
|
|
54
|
-
Step 6: 生成测试代码(Agent)
|
|
55
|
-
Step 7: 自动验证测试(循环最多 3 次)
|
|
56
|
-
├─ 通过 → 进入 Step 8
|
|
57
|
-
└─ 失败 → 自动重新生成(带失败信息)
|
|
58
|
-
Step 8: 输出测试报告
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
**铁律:不做项目分析,不许生成测试**
|
|
62
|
-
**铁律:前端项目必须询问 UI 测试需求,不得跳过**
|
|
63
|
-
**铁律:验证失败自动循环,最多 3 次,超过必须暂停**
|
|
64
|
-
</MANDATORY-EXECUTION-ORDER>
|
|
65
|
-
|
|
66
|
-
<IRON-LAW>
|
|
67
|
-
## 铁律:没有失败的测试,不许写生产代码
|
|
68
|
-
|
|
69
|
-
**NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST**
|
|
70
|
-
|
|
71
|
-
在测试前写了代码?删除。重新开始。
|
|
72
|
-
|
|
73
|
-
没有例外:
|
|
74
|
-
- 不要保留作为"参考"
|
|
75
|
-
- 不要"写测试时适应它"
|
|
76
|
-
- 不要看它
|
|
77
|
-
|
|
78
|
-
删除意味着删除。
|
|
79
|
-
|
|
80
|
-
## Why Order Matters
|
|
81
|
-
|
|
82
|
-
### "我会在实现后写测试来验证工作"
|
|
83
|
-
|
|
84
|
-
实现后写的测试立即通过。立即通过什么也证明不了:
|
|
85
|
-
- 可能测试错误的东西
|
|
86
|
-
- 可能测试实现,不是行为
|
|
87
|
-
- 可能遗漏你忘记的边界情况
|
|
88
|
-
- 你从未看到它捕获 bug
|
|
89
|
-
|
|
90
|
-
测试优先强制你看到测试失败,证明它确实测试某些东西。
|
|
91
|
-
|
|
92
|
-
### "我手动测试了所有边界情况"
|
|
93
|
-
|
|
94
|
-
手动测试是临时的。你以为测试了所有东西但:
|
|
95
|
-
- 没有测试记录
|
|
96
|
-
- 代码变化时无法重跑
|
|
97
|
-
- 压力下容易忘记情况
|
|
98
|
-
- "我试过了" ≠ 全面
|
|
99
|
-
|
|
100
|
-
自动化测试是系统的。每次运行相同方式。
|
|
101
|
-
|
|
102
|
-
### "删除 X 小时工作是浪费"
|
|
103
|
-
|
|
104
|
-
沉没成本谬误。时间已经没了。现在选择:
|
|
105
|
-
- 删除并用 TDD 重写(X+小时,高信心)
|
|
106
|
-
- 保留并在后加测试(30分钟,低信心,可能 bug)
|
|
107
|
-
|
|
108
|
-
"浪费"是保留不能信任的代码。无真实测试的工作代码是技术债务。
|
|
109
|
-
|
|
110
|
-
## Good vs Bad Tests
|
|
111
|
-
|
|
112
|
-
| 质量 | Good | Bad |
|
|
113
|
-
|-----|------|-----|
|
|
114
|
-
| **最小化** | 一件事。名字有"and"?拆分。 | `test('validates email and domain and whitespace')` |
|
|
115
|
-
| **清晰** | 名字描述行为 | `test('test1')` |
|
|
116
|
-
| **展示意图** | 展示期望 API | 模糊代码该做什么 |
|
|
117
|
-
| **真实代码** | 无 mock(除非不可避免) | Mock 一切 |
|
|
118
|
-
|
|
119
|
-
### Good Example
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
test('重试失败操作 3 次', async () => {
|
|
123
|
-
let attempts = 0;
|
|
124
|
-
const operation = () => {
|
|
125
|
-
attempts++;
|
|
126
|
-
if (attempts < 3) throw new Error('fail');
|
|
127
|
-
return 'success';
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const result = await retryOperation(operation);
|
|
131
|
-
|
|
132
|
-
expect(result).toBe('success');
|
|
133
|
-
expect(attempts).toBe(3);
|
|
134
|
-
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
一件事,测试真实行为,清晰名字。
|
|
138
|
-
|
|
139
|
-
### Bad Example
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
test('retry works', async () => {
|
|
143
|
-
const mock = jest.fn()
|
|
144
|
-
.mockRejectedValueOnce(new Error())
|
|
145
|
-
.mockRejectedValueOnce(new Error())
|
|
146
|
-
.mockResolvedValueOnce('success');
|
|
147
|
-
await retryOperation(mock);
|
|
148
|
-
expect(mock).toHaveBeenCalledTimes(3);
|
|
149
|
-
});
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
模糊名字,测试 mock 不是代码。
|
|
153
|
-
</IRON-LAW>
|
|
154
|
-
|
|
155
|
-
<objective>
|
|
156
|
-
智能测试生成 - 从业务角度分析代码逻辑,发现测试缺失,自动生成并验证测试。遵循 OpenMatrix 分层原则:CLI 收集原始数据,AI 分析并生成测试。
|
|
157
|
-
</objective>
|
|
158
|
-
|
|
159
|
-
<process>
|
|
160
|
-
|
|
161
|
-
## Step 1: 调用 CLI 扫描项目
|
|
162
|
-
|
|
163
|
-
**检查 `$ARGUMENTS`:**
|
|
164
|
-
|
|
165
|
-
| 参数 | 处理方式 |
|
|
166
|
-
|------|---------|
|
|
167
|
-
| 空 | 扫描整个项目 |
|
|
168
|
-
| `src/auth/` | 扫描指定目录 |
|
|
169
|
-
| `--target src/utils.ts` | 扫描指定文件 |
|
|
170
|
-
|
|
171
|
-
**调用 CLI 扫描:**
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
openmatrix test --json
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
或指定目标:
|
|
178
|
-
|
|
179
|
-
```bash
|
|
180
|
-
openmatrix test
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
**CLI 返回 TestScanResult JSON:**
|
|
184
|
-
|
|
185
|
-
```json
|
|
186
|
-
{
|
|
187
|
-
"timestamp": "2026-04-23T10:00:00Z",
|
|
188
|
-
"projectRoot": "/path/to/project",
|
|
189
|
-
"target": "src/",
|
|
190
|
-
"frameworks": [
|
|
191
|
-
{
|
|
192
|
-
"framework": "vitest",
|
|
193
|
-
"version": "1.2.3",
|
|
194
|
-
"configFile": "vitest.config.ts",
|
|
195
|
-
"isPrimary": true,
|
|
196
|
-
"supportedTypes": ["unit", "integration"],
|
|
197
|
-
"commands": {
|
|
198
|
-
"test": "npm test",
|
|
199
|
-
"testCoverage": "npm test -- --coverage"
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
],
|
|
203
|
-
"existingTests": [
|
|
204
|
-
{ "path": "tests/example.test.ts", "type": "unit", "testCount": 5 }
|
|
205
|
-
],
|
|
206
|
-
"uncoveredSources": [
|
|
207
|
-
{
|
|
208
|
-
"path": "src/auth/login.ts",
|
|
209
|
-
"fileType": "service",
|
|
210
|
-
"exports": ["login", "validateToken"],
|
|
211
|
-
"hasTest": false,
|
|
212
|
-
"suggestedTestTypes": ["unit", "integration"],
|
|
213
|
-
"complexity": { "lines": 150, "functions": 5 }
|
|
214
|
-
}
|
|
215
|
-
],
|
|
216
|
-
"projectType": "typescript",
|
|
217
|
-
"isFrontend": false,
|
|
218
|
-
"hasUIComponents": false,
|
|
219
|
-
"coverageReport": { "total": 45 },
|
|
220
|
-
"testStyle": {
|
|
221
|
-
"namingConvention": "describe-it",
|
|
222
|
-
"assertionLibrary": "expect",
|
|
223
|
-
"usesTypeScript": true,
|
|
224
|
-
"fileSuffix": ".test.ts",
|
|
225
|
-
"fileLocation": "separate"
|
|
226
|
-
},
|
|
227
|
-
"summary": {
|
|
228
|
-
"frameworkCount": 1,
|
|
229
|
-
"existingTestCount": 5,
|
|
230
|
-
"uncoveredSourceCount": 20,
|
|
231
|
-
"hasTestConfig": true,
|
|
232
|
-
"hasCoverageConfig": true
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**从返回结果读取关键数据:**
|
|
238
|
-
- `frameworks`: 检测到的测试框架
|
|
239
|
-
- `existingTests`: 现有测试文件
|
|
240
|
-
- `uncoveredSources`: 未覆盖的源文件
|
|
241
|
-
- `isFrontend`: 是否为前端项目
|
|
242
|
-
- `hasUIComponents`: 是否有 UI 组件
|
|
243
|
-
- `testStyle`: 现有测试风格(用于保持一致性)
|
|
244
|
-
|
|
245
|
-
## Step 2: AI 分析项目上下文
|
|
246
|
-
|
|
247
|
-
**AI 分析任务(读取原始数据后):**
|
|
248
|
-
|
|
249
|
-
1. **识别测试框架**
|
|
250
|
-
- 读取 `frameworks` 数组
|
|
251
|
-
- 确定主要测试框架 `isPrimary: true`
|
|
252
|
-
- 了解支持的测试类型
|
|
253
|
-
|
|
254
|
-
2. **分析项目结构**
|
|
255
|
-
- 读取 `projectType` 确定语言
|
|
256
|
-
- 读取 `uncoveredSources` 了解需要测试的模块
|
|
257
|
-
- 每个源文件的 `exports` 表示需要测试的目标
|
|
258
|
-
|
|
259
|
-
3. **分析现有测试风格**
|
|
260
|
-
- 读取 `testStyle.namingConvention` 保持命名一致
|
|
261
|
-
- 读取 `testStyle.assertionLibrary` 使用相同断言库
|
|
262
|
-
- 读取 `testStyle.fileSuffix` 保持文件后缀一致
|
|
263
|
-
- 读取 `testStyle.fileLocation` 确定测试文件位置
|
|
264
|
-
|
|
265
|
-
4. **评估覆盖率现状**
|
|
266
|
-
- 如果 `coverageReport` 存在,了解当前覆盖率
|
|
267
|
-
- 识别关键业务模块的覆盖缺口
|
|
268
|
-
|
|
269
|
-
## Step 3: 发现测试缺失
|
|
270
|
-
|
|
271
|
-
**AI 分析每个未覆盖源文件:**
|
|
272
|
-
|
|
273
|
-
```
|
|
274
|
-
对于每个 uncoveredSources[i]:
|
|
275
|
-
1. 分析 exports 中的每个函数/类/组件
|
|
276
|
-
2. 理解业务逻辑(不是语法,而是"做什么")
|
|
277
|
-
3. 识别关键业务场景
|
|
278
|
-
4. 确定测试优先级(基于复杂度、重要性)
|
|
279
|
-
5. 生成测试用例清单
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
**输出分析报告:**
|
|
283
|
-
|
|
284
|
-
```
|
|
285
|
-
📊 测试缺失分析报告
|
|
286
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
287
|
-
|
|
288
|
-
项目类型: TypeScript
|
|
289
|
-
测试框架: Vitest (v1.2.3)
|
|
290
|
-
当前覆盖率: 45%
|
|
291
|
-
|
|
292
|
-
未覆盖源文件 (20 个):
|
|
293
|
-
┌────────────────────────────────────────┐
|
|
294
|
-
│ src/auth/login.ts │
|
|
295
|
-
│ 类型: service | 导出: login, validateToken │
|
|
296
|
-
│ 行数: 150 | 函数: 5 │
|
|
297
|
-
│ 建议测试类型: unit, integration │
|
|
298
|
-
│ 关键业务场景: │
|
|
299
|
-
│ - 用户登录成功 │
|
|
300
|
-
│ - 密码错误拒绝 │
|
|
301
|
-
│ - Token 验证过期 │
|
|
302
|
-
│ - 并发登录处理 │
|
|
303
|
-
├────────────────────────────────────────┤
|
|
304
|
-
│ src/utils/format.ts │
|
|
305
|
-
│ 类型: util | 导出: formatDate, parseJSON │
|
|
306
|
-
│ ... │
|
|
307
|
-
└────────────────────────────────────────┘
|
|
308
|
-
|
|
309
|
-
测试优先级建议:
|
|
310
|
-
P0: src/auth/login.ts (认证核心)
|
|
311
|
-
P0: src/api/handler.ts (API 入口)
|
|
312
|
-
P1: src/utils/format.ts (通用工具)
|
|
313
|
-
P2: src/config/index.ts (配置加载)
|
|
314
|
-
|
|
315
|
-
现有测试风格:
|
|
316
|
-
- 命名约定: describe/it
|
|
317
|
-
- 断言库: expect
|
|
318
|
-
- 文件后缀: .test.ts
|
|
319
|
-
- 文件位置: tests/ 目录
|
|
320
|
-
|
|
321
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
## Step 4: UI 测试决策
|
|
325
|
-
|
|
326
|
-
**如果 `isFrontend=true` 或 `hasUIComponents=true`:**
|
|
327
|
-
|
|
328
|
-
**⛔ 必须在此询问用户 UI 测试需求,不得跳过。**
|
|
329
|
-
|
|
330
|
-
AskUserQuestion: `header: "UI 测试"`, `multiSelect: false`
|
|
331
|
-
**question:** 检测到前端/UI 组件,是否需要生成 UI/E2E 测试?
|
|
332
|
-
|
|
333
|
-
| label | description |
|
|
334
|
-
|-------|-------------|
|
|
335
|
-
| 需要 UI 测试 | 生成 Playwright/Cypress E2E 测试 |
|
|
336
|
-
| 仅单元测试 | 只生成单元测试,不生成 E2E |
|
|
337
|
-
| 自定义配置 | 指定 UI 测试框架和范围 |
|
|
338
|
-
|
|
339
|
-
**如果用户选择"自定义配置":**
|
|
340
|
-
|
|
341
|
-
AskUserQuestion: `header: "UI 测试框架"`, `multiSelect: false`
|
|
342
|
-
**question:** 选择 UI 测试框架?
|
|
343
|
-
|
|
344
|
-
| label | description |
|
|
345
|
-
|-------|-------------|
|
|
346
|
-
| Playwright (推荐) | 跨浏览器支持,现代 API |
|
|
347
|
-
| Cypress | 开发体验好,调试方便 |
|
|
348
|
-
| Puppeteer | 轻量级,Chrome 优先 |
|
|
349
|
-
|
|
350
|
-
**如果用户选择"需要 UI 测试":**
|
|
351
|
-
- AI 根据 `frameworks` 中是否有 E2E 框架推荐合适的选择
|
|
352
|
-
- 如果无 E2E 框架,推荐 Playwright
|
|
353
|
-
|
|
354
|
-
## Step 5: 确认测试范围
|
|
355
|
-
|
|
356
|
-
**展示分析报告后,询问用户确认:**
|
|
357
|
-
|
|
358
|
-
AskUserQuestion: `header: "测试范围"`, `multiSelect: true`
|
|
359
|
-
**question:** 选择需要生成测试的源文件?
|
|
360
|
-
|
|
361
|
-
| label | description |
|
|
362
|
-
|-------|-------------|
|
|
363
|
-
| 全部生成 (推荐) | 为所有未覆盖文件生成测试 |
|
|
364
|
-
| P0 优先级 | 只生成 P0 优先级测试 |
|
|
365
|
-
| 自定义选择 | 指定具体文件列表 |
|
|
366
|
-
|
|
367
|
-
**如果用户选择"自定义选择":**
|
|
368
|
-
|
|
369
|
-
展示文件列表,让用户选择具体文件。
|
|
370
|
-
|
|
371
|
-
**确认测试配置:**
|
|
372
|
-
|
|
373
|
-
AskUserQuestion: `header: "测试配置"`, `multiSelect: false`
|
|
374
|
-
**question:** 确认测试生成配置?
|
|
375
|
-
|
|
376
|
-
| label | description |
|
|
377
|
-
|-------|-------------|
|
|
378
|
-
| 自动生成 (推荐) | AI 自动分析业务逻辑生成测试 |
|
|
379
|
-
| 交互式生成 | 每个文件询问测试场景 |
|
|
380
|
-
| 快速生成 | 只生成基础测试,跳过复杂场景 |
|
|
381
|
-
|
|
382
|
-
## Step 6: 生成测试代码
|
|
383
|
-
|
|
384
|
-
**调用 Agent 生成测试:**
|
|
385
|
-
|
|
386
|
-
```typescript
|
|
387
|
-
Agent({
|
|
388
|
-
subagent_type: "general-purpose",
|
|
389
|
-
description: "生成测试代码",
|
|
390
|
-
prompt: `你是测试工程师。根据分析结果生成测试代码。
|
|
391
|
-
|
|
392
|
-
## 铁律
|
|
393
|
-
1. 从业务角度理解代码,不是语法角度
|
|
394
|
-
2. 测试业务场景,不是函数调用
|
|
395
|
-
3. 保持与现有测试风格一致
|
|
396
|
-
4. 每个测试用例必须有明确的业务意义
|
|
397
|
-
|
|
398
|
-
## 项目信息
|
|
399
|
-
- 语言: ${projectType}
|
|
400
|
-
- 测试框架: ${primaryFramework}
|
|
401
|
-
- 测试目录: ${testDirectory}
|
|
402
|
-
- 文件后缀: ${fileSuffix}
|
|
403
|
-
|
|
404
|
-
## 现有测试风格
|
|
405
|
-
- 命名约定: ${namingConvention}
|
|
406
|
-
- 断言库: ${assertionLibrary}
|
|
407
|
-
- 文件位置: ${fileLocation}
|
|
408
|
-
|
|
409
|
-
## 需要测试的源文件
|
|
410
|
-
${selectedFiles.map(f => `
|
|
411
|
-
文件: ${f.path}
|
|
412
|
-
类型: ${f.fileType}
|
|
413
|
-
导出: ${f.exports.join(', ')}
|
|
414
|
-
复杂度: ${f.complexity?.lines || 'unknown'} 行
|
|
415
|
-
`).join('\n')}
|
|
416
|
-
|
|
417
|
-
## 任务
|
|
418
|
-
1. 分析每个源文件的业务逻辑
|
|
419
|
-
2. 识别关键业务场景(成功路径、边界条件、错误处理)
|
|
420
|
-
3. 为每个场景编写测试用例
|
|
421
|
-
4. 测试文件写入正确位置
|
|
422
|
-
5. 保持命名和风格一致
|
|
423
|
-
|
|
424
|
-
## 测试用例要求
|
|
425
|
-
- describe 描述业务场景(不是函数名)
|
|
426
|
-
- it 描述具体行为("should...")
|
|
427
|
-
- 断言验证业务结果
|
|
428
|
-
- Mock 外部依赖(API、数据库等)
|
|
429
|
-
|
|
430
|
-
## 禁止行为
|
|
431
|
-
❌ 测试语法而不是行为
|
|
432
|
-
❌ 使用与项目不一致的风格
|
|
433
|
-
❌ 跳过边界条件和错误处理
|
|
434
|
-
❌ 生成无意义的测试(如 "should exist")`,
|
|
435
|
-
run_in_background: false
|
|
436
|
-
})
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
**UI 测试生成(如果需要):**
|
|
440
|
-
|
|
441
|
-
```typescript
|
|
442
|
-
Agent({
|
|
443
|
-
subagent_type: "general-purpose",
|
|
444
|
-
description: "生成 E2E/UI 测试",
|
|
445
|
-
prompt: `你是 E2E 测试工程师。为前端组件生成 UI 测试。
|
|
446
|
-
|
|
447
|
-
## UI 测试框架
|
|
448
|
-
- 框架: ${uiFramework}
|
|
449
|
-
- 配置文件: ${uiConfigFile || '需要创建'}
|
|
450
|
-
|
|
451
|
-
## 需要测试的 UI 组件
|
|
452
|
-
${uiComponents.map(c => `
|
|
453
|
-
组件: ${c.path}
|
|
454
|
-
导出: ${c.exports.join(', ')}
|
|
455
|
-
功能: ${c.description || '需要分析'}
|
|
456
|
-
`).join('\n')}
|
|
457
|
-
|
|
458
|
-
## 任务
|
|
459
|
-
1. 创建 E2E 测试配置(如果不存在)
|
|
460
|
-
2. 为每个关键用户流程生成测试
|
|
461
|
-
3. 测试用例覆盖:页面渲染、用户交互、数据展示
|
|
462
|
-
4. 截图放置在 tests/e2e/screenshots/
|
|
463
|
-
|
|
464
|
-
## E2E 测试用例要求
|
|
465
|
-
- 测试完整用户流程
|
|
466
|
-
- 验证页面状态变化
|
|
467
|
-
- 检查关键元素可见性
|
|
468
|
-
- 处理异步加载等待
|
|
469
|
-
|
|
470
|
-
## 禁止行为
|
|
471
|
-
❌ 测试单个元素样式
|
|
472
|
-
❌ 跳过用户等待时间
|
|
473
|
-
❌ 硬编码测试数据`,
|
|
474
|
-
run_in_background: false
|
|
475
|
-
})
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
## Step 7: 自动验证测试(循环机制)
|
|
479
|
-
|
|
480
|
-
<LOOP_ENFORCEMENT>
|
|
481
|
-
**此步骤是验证循环,必须执行直到验证通过或达到最大重试次数。**
|
|
482
|
-
|
|
483
|
-
❌ **禁止在验证失败时停止** — 即使 Agent 返回了大段输出,也必须继续循环
|
|
484
|
-
❌ **禁止询问"是否继续验证"** — 自动执行验证,无需用户确认
|
|
485
|
-
❌ **禁止输出"让我知道是否..."后停止** — 继续执行验证循环
|
|
486
|
-
❌ **禁止因为上下文压缩而忘记重试次数** — 使用 TodoWrite 持久化 retryCount
|
|
487
|
-
|
|
488
|
-
**retryCount 持久化机制(防止上下文压缩丢失状态):**
|
|
489
|
-
|
|
490
|
-
验证循环开始时,使用 TodoWrite 记录状态:
|
|
491
|
-
```
|
|
492
|
-
TodoWrite([
|
|
493
|
-
{ content: "验证测试(第 N 次)", activeForm: "正在验证测试(第 N 次)", status: "in_progress" }
|
|
494
|
-
])
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
每次验证失败后:
|
|
498
|
-
1. 更新 TodoWrite 的 retryCount(N → N+1)
|
|
499
|
-
2. 检查是否达到最大次数(>= 3)
|
|
500
|
-
3. 未达到 → 自动回到 Step 6 重新生成
|
|
501
|
-
4. 已达到 → 暂停并报告问题
|
|
502
|
-
|
|
503
|
-
**循环铁律:**
|
|
504
|
-
- retryCount 从 TodoWrite 读取,不依赖上下文记忆
|
|
505
|
-
- 验证失败必须自动循环,不得跳过
|
|
506
|
-
- 最大重试 3 次,超过必须暂停
|
|
507
|
-
</LOOP_ENFORCEMENT>
|
|
508
|
-
|
|
509
|
-
**⛔ 自动验证流程 - 无需用户手动确认**
|
|
510
|
-
|
|
511
|
-
### 7.1 执行验证命令(自动判断结果)
|
|
512
|
-
|
|
513
|
-
```bash
|
|
514
|
-
# 执行测试验证
|
|
515
|
-
VERIFY_RESULT=0
|
|
516
|
-
npm test -- --run > /tmp/test-verify-output.txt 2>&1 || VERIFY_RESULT=1
|
|
517
|
-
|
|
518
|
-
if [ $VERIFY_RESULT -eq 0 ]; then
|
|
519
|
-
echo "✅ 测试验证通过"
|
|
520
|
-
else
|
|
521
|
-
echo "❌ 测试验证失败"
|
|
522
|
-
cat /tmp/test-verify-output.txt | tail -50 # 展示失败详情
|
|
523
|
-
fi
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
### 7.2 验证失败自动循环(无需用户确认)
|
|
527
|
-
|
|
528
|
-
**验证失败时自动处理:**
|
|
529
|
-
|
|
530
|
-
```
|
|
531
|
-
验证失败 → TodoWrite 更新 retryCount → 检查重试次数 →
|
|
532
|
-
├─ < 3 次 → 自动回到 Step 6 重新生成(带失败信息)
|
|
533
|
-
└─ >= 3 次 → 暂停,报告问题,可能是测试框架配置问题
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
**重试计数器持久化:**
|
|
537
|
-
- 使用 TodoWrite 记录 retryCount
|
|
538
|
-
- 每次验证失败后更新 TodoWrite(retryCount + 1)
|
|
539
|
-
- 验证通过后更新 TodoWrite 为 completed
|
|
540
|
-
|
|
541
|
-
### 7.3 自动循环回生成步骤
|
|
542
|
-
|
|
543
|
-
**< 3 次验证失败 → 自动调用 Agent 重新生成:**
|
|
544
|
-
|
|
545
|
-
```typescript
|
|
546
|
-
Agent({
|
|
547
|
-
subagent_type: "general-purpose",
|
|
548
|
-
description: `修复测试 (第 ${retryCount + 1} 次)`,
|
|
549
|
-
prompt: `根据测试验证失败结果修复测试代码。
|
|
550
|
-
|
|
551
|
-
## 铁律
|
|
552
|
-
1. 只修复失败的测试,不修改通过的测试
|
|
553
|
-
2. 分析失败原因,不要盲目修改
|
|
554
|
-
3. 保持测试风格一致
|
|
555
|
-
|
|
556
|
-
## 验证失败详情
|
|
557
|
-
${verifyFailureOutput}
|
|
558
|
-
|
|
559
|
-
## 失败分析
|
|
560
|
-
- 哪些测试失败了?
|
|
561
|
-
- 失败原因是什么?
|
|
562
|
-
- 是测试代码问题还是源代码问题?
|
|
563
|
-
|
|
564
|
-
## 修复策略
|
|
565
|
-
1. 如果是测试语法错误 → 修正测试代码
|
|
566
|
-
2. 如果是断言失败 → 分析预期值是否正确
|
|
567
|
-
3. 如果是 Mock 问题 → 调整 Mock 实现
|
|
568
|
-
|
|
569
|
-
## 禁止行为
|
|
570
|
-
❌ 修改通过的测试
|
|
571
|
-
❌ 删除失败的测试用例
|
|
572
|
-
❌ 跳过 Mock 外部依赖`,
|
|
573
|
-
run_in_background: false
|
|
574
|
-
})
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
### 7.4 达到最大重试次数(>= 3 次)
|
|
578
|
-
|
|
579
|
-
**输出警告并暂停:**
|
|
580
|
-
|
|
581
|
-
```
|
|
582
|
-
⚠️ 已尝试 3 次以上生成,测试仍未通过
|
|
583
|
-
|
|
584
|
-
可能的问题:
|
|
585
|
-
- 测试框架配置不正确
|
|
586
|
-
- 源代码有 bug 导致测试无法通过
|
|
587
|
-
- Mock 设置不完整
|
|
588
|
-
|
|
589
|
-
建议:检查测试框架配置,或手动修复测试代码。
|
|
590
|
-
```
|
|
591
|
-
|
|
592
|
-
AskUserQuestion: `header: "验证问题"`, `multiSelect: false`
|
|
593
|
-
**question:** 已尝试 3 次生成仍未通过,可能存在配置问题。下一步?
|
|
594
|
-
|
|
595
|
-
| label | description |
|
|
596
|
-
|-------|-------------|
|
|
597
|
-
| 检查配置 | 检查测试框架配置文件 |
|
|
598
|
-
| 手动修复 | 输出测试文件路径,用户手动修改 |
|
|
599
|
-
| 结束流程 | 保存当前测试文件,结束流程 |
|
|
600
|
-
|
|
601
|
-
### 7.5 验证通过
|
|
602
|
-
|
|
603
|
-
**验证通过 → 自动进入 Step 8**
|
|
604
|
-
|
|
605
|
-
```
|
|
606
|
-
✅ 测试验证通过
|
|
607
|
-
|
|
608
|
-
所有生成的测试正常运行,自动进入报告阶段。
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
## Step 8: 输出测试报告
|
|
612
|
-
|
|
613
|
-
**展示测试生成报告:**
|
|
614
|
-
|
|
615
|
-
```markdown
|
|
616
|
-
# 测试生成报告
|
|
617
|
-
|
|
618
|
-
**生成时间**: ${timestamp}
|
|
619
|
-
**项目**: ${projectName}
|
|
620
|
-
**测试框架**: ${primaryFramework}
|
|
621
|
-
|
|
622
|
-
## 生成的测试文件
|
|
623
|
-
|
|
624
|
-
| 文件 | 类型 | 测试用例 | 源文件 |
|
|
625
|
-
|------|------|---------|--------|
|
|
626
|
-
| tests/auth/login.test.ts | unit | 12 | src/auth/login.ts |
|
|
627
|
-
| tests/api/handler.test.ts | integration | 8 | src/api/handler.ts |
|
|
628
|
-
| tests/e2e/user-flow.spec.ts | e2e | 5 | 多个组件 |
|
|
629
|
-
|
|
630
|
-
## 测试覆盖统计
|
|
631
|
-
|
|
632
|
-
- 单元测试: 20 个
|
|
633
|
-
- 集成测试: 8 个
|
|
634
|
-
- E2E 测试: 5 个
|
|
635
|
-
- 总计: 33 个测试用例
|
|
636
|
-
|
|
637
|
-
## 验证结果
|
|
638
|
-
|
|
639
|
-
✅ 所有测试通过 (33 passed, 0 failed)
|
|
640
|
-
|
|
641
|
-
## 覆盖率预估
|
|
642
|
-
|
|
643
|
-
当前覆盖率: 45%
|
|
644
|
-
预估覆盖率: 72% (+27%)
|
|
645
|
-
|
|
646
|
-
## 后续建议
|
|
647
|
-
|
|
648
|
-
1. 运行 `npm test -- --coverage` 查看详细覆盖率
|
|
649
|
-
2. 检查 Mock 文件是否需要补充测试数据
|
|
650
|
-
3. E2E 测试截图已放置在 tests/e2e/screenshots/
|
|
651
|
-
|
|
652
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
**Git 提交提示(可选):**
|
|
656
|
-
|
|
657
|
-
AskUserQuestion: `header: "Git 提交"`, `multiSelect: false`
|
|
658
|
-
**question:** 是否提交生成的测试文件?
|
|
659
|
-
|
|
660
|
-
| label | description |
|
|
661
|
-
|-------|-------------|
|
|
662
|
-
| 提交测试文件 | git add tests/ && git commit |
|
|
663
|
-
| 仅保存文件 | 不提交,用户稍后处理 |
|
|
664
|
-
| 查看生成的文件 | 展示文件内容后再决定 |
|
|
665
|
-
|
|
666
|
-
</process>
|
|
667
|
-
|
|
668
|
-
<arguments>
|
|
669
|
-
$ARGUMENTS
|
|
670
|
-
</arguments>
|
|
671
|
-
|
|
672
|
-
<examples>
|
|
673
|
-
/om:test # 扫描整个项目,发现测试缺失
|
|
674
|
-
/om:test src/auth/ # 只为 src/auth/ 目录生成测试
|
|
675
|
-
/om:test --target src/utils.ts # 为指定文件生成测试
|
|
676
|
-
</examples>
|
|
677
|
-
|
|
678
|
-
<notes>
|
|
679
|
-
## 完整流程图
|
|
680
|
-
|
|
681
|
-
```
|
|
682
|
-
Step 1: CLI 扫描 (openmatrix test --json)
|
|
683
|
-
│ 收集原始数据:框架、源文件、覆盖率
|
|
684
|
-
▼
|
|
685
|
-
Step 2: AI 分析项目上下文
|
|
686
|
-
│ • 识别测试框架
|
|
687
|
-
│ • 分析项目结构
|
|
688
|
-
│ • 理解测试风格
|
|
689
|
-
▼
|
|
690
|
-
Step 3: 发现测试缺失
|
|
691
|
-
│ • 对比源文件与测试文件
|
|
692
|
-
│ • 分析业务逻辑复杂度
|
|
693
|
-
│ • 识别关键业务场景
|
|
694
|
-
│ • 输出分析报告
|
|
695
|
-
▼
|
|
696
|
-
Step 4: UI 测试决策 (如果 isFrontend=true)
|
|
697
|
-
│ ⛔ 必须询问用户
|
|
698
|
-
│ AskUserQuestion: 是否需要 UI 测试?
|
|
699
|
-
▼
|
|
700
|
-
Step 5: 确认测试范围
|
|
701
|
-
│ AskUserQuestion: 选择源文件
|
|
702
|
-
│ AskUserQuestion: 确认配置
|
|
703
|
-
▼
|
|
704
|
-
Step 6: 生成测试代码
|
|
705
|
-
│ Agent(general-purpose) 分析业务逻辑生成测试
|
|
706
|
-
│ 如果需要 UI 测试,Agent 生成 E2E 测试
|
|
707
|
-
▼
|
|
708
|
-
Step 7: ⛔ 自动验证测试(无需用户确认)
|
|
709
|
-
│ ├─ 执行 npm test → 自动判断结果
|
|
710
|
-
│ ├─ 通过 → 自动进入 Step 8 ✅
|
|
711
|
-
│ └─ 失败 → 自动循环处理
|
|
712
|
-
│ ├─ < 3 次 → 自动回到 Step 6 重新生成
|
|
713
|
-
│ └─ >= 3 次 → 暂停,可能是配置问题 ⚠️
|
|
714
|
-
▼
|
|
715
|
-
Step 8: 输出测试报告
|
|
716
|
-
│ 展示生成的文件列表
|
|
717
|
-
│ 展示覆盖率统计
|
|
718
|
-
│ Git 提交询问(可选)
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
## 自动验证循环流程(Step 7 详细)
|
|
722
|
-
|
|
723
|
-
```
|
|
724
|
-
┌─────────────────────────────────────────┐
|
|
725
|
-
│ Step 6: 生成测试代码 │
|
|
726
|
-
└─────────────────────┬───────────────────┘
|
|
727
|
-
↓
|
|
728
|
-
┌─────────────────────────────────────────┐
|
|
729
|
-
│ Step 7: 执行测试验证 │
|
|
730
|
-
│ (npm test / npm test -- --run) │
|
|
731
|
-
└─────────────────────┬───────────────────┘
|
|
732
|
-
↓
|
|
733
|
-
┌───────┴───────┐
|
|
734
|
-
│ 自动判断结果 │
|
|
735
|
-
└───────┬───────┘
|
|
736
|
-
┌─────────────┴─────────────┐
|
|
737
|
-
│ │
|
|
738
|
-
退出码=0 退出码≠0
|
|
739
|
-
(测试通过) (测试失败)
|
|
740
|
-
│ │
|
|
741
|
-
↓ ↓
|
|
742
|
-
┌───────────────┐ ┌───────────────────┐
|
|
743
|
-
│ ✅ 进入 Step 8│ │ retryCount + 1 │
|
|
744
|
-
└───────────────┘ └───────┬───────────┘
|
|
745
|
-
↓
|
|
746
|
-
┌────────┴────────┐
|
|
747
|
-
│ 检查重试次数 │
|
|
748
|
-
└───────┬─────────┘
|
|
749
|
-
┌─────────────┴─────────────┐
|
|
750
|
-
│ │
|
|
751
|
-
< 3 次 >= 3 次
|
|
752
|
-
│ │
|
|
753
|
-
↓ ↓
|
|
754
|
-
┌─────────────────┐ ┌───────────────────┐
|
|
755
|
-
│ ⚡ 自动回到 Step 6 │ │ ⚠️ 暂停,检查配置 │
|
|
756
|
-
│ (带失败信息) │ │ 用户手动处理 │
|
|
757
|
-
└─────────────────┘ └───────────────────┘
|
|
758
|
-
```
|
|
759
|
-
|
|
760
|
-
## 铁律
|
|
761
|
-
|
|
762
|
-
**不做项目分析,不许生成测试**
|
|
763
|
-
|
|
764
|
-
**前端项目必须询问 UI 测试需求**
|
|
765
|
-
|
|
766
|
-
**验证失败自动循环,无需用户手动确认**
|
|
767
|
-
|
|
768
|
-
**最大重试 3 次,超过必须暂停检查配置**
|
|
769
|
-
|
|
770
|
-
**没有失败的测试,不许写生产代码(参见 IRON-LAW 区块)**
|
|
771
|
-
|
|
772
|
-
## 红线
|
|
773
|
-
|
|
774
|
-
- 3 次生成失败 → 暂停,检查测试框架配置
|
|
775
|
-
- 不生成与现有风格不一致的测试
|
|
776
|
-
- 不跳过 UI 测试询问(前端项目)
|
|
777
|
-
- 不删除现有的通过的测试
|
|
778
|
-
- **验证必须自动判断,不得依赖用户手动确认**
|
|
779
|
-
- **验证失败自动循环,不得跳过或手动绕过**
|
|
780
|
-
- **达到 3 次重试必须暂停,不得继续生成**
|
|
781
|
-
|
|
782
|
-
## 红旗警告 - 停止并回归流程
|
|
783
|
-
|
|
784
|
-
**如果发现自己在想:**
|
|
785
|
-
- "直接生成测试,不用分析"
|
|
786
|
-
- "跳过 UI 测试询问"
|
|
787
|
-
- "测试看起来很简单,不用验证"
|
|
788
|
-
- "验证失败了,让用户手动修"
|
|
789
|
-
- "重试超过 3 次继续生成"
|
|
790
|
-
- "跳过自动验证"
|
|
791
|
-
- 只测试函数调用而不是业务场景
|
|
792
|
-
- 生成的测试与项目风格不一致
|
|
793
|
-
- "我先写实现,再补测试"
|
|
794
|
-
- "这个测试一次就能过,不用看失败"
|
|
795
|
-
- "测试代码不重要,能过就行"
|
|
796
|
-
- "边界情况太多了,只测主流程"
|
|
797
|
-
- "删除这个失败的测试用例算了"
|
|
798
|
-
- "Mock 返回什么都行,只要测试通过"
|
|
799
|
-
- 测试名字描述实现细节而非业务行为
|
|
800
|
-
- 一个测试验证多个不相关的事情
|
|
801
|
-
- 测试依赖执行顺序或共享状态
|
|
802
|
-
- 使用 `any` 类型绕过类型检查
|
|
803
|
-
|
|
804
|
-
**这些都意味着:停止。回到 Step 2 或执行自动验证循环。**
|
|
805
|
-
|
|
806
|
-
## 测试生成原则
|
|
807
|
-
|
|
808
|
-
### 业务角度测试
|
|
809
|
-
|
|
810
|
-
```
|
|
811
|
-
// ❌ 错误:测试语法
|
|
812
|
-
describe('login function', () => {
|
|
813
|
-
it('should exist', () => {
|
|
814
|
-
expect(login).toBeDefined();
|
|
815
|
-
});
|
|
816
|
-
});
|
|
817
|
-
|
|
818
|
-
// ✅ 正确:测试业务场景
|
|
819
|
-
describe('用户登录', () => {
|
|
820
|
-
it('正确密码应该成功登录', async () => {
|
|
821
|
-
const result = await login('user', 'correct-password');
|
|
822
|
-
expect(result.success).toBe(true);
|
|
823
|
-
expect(result.token).toBeDefined();
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
it('错误密码应该拒绝登录', async () => {
|
|
827
|
-
const result = await login('user', 'wrong-password');
|
|
828
|
-
expect(result.success).toBe(false);
|
|
829
|
-
expect(result.error).toBe('密码错误');
|
|
830
|
-
});
|
|
831
|
-
});
|
|
832
|
-
```
|
|
833
|
-
|
|
834
|
-
### 保持风格一致
|
|
835
|
-
|
|
836
|
-
- 使用项目的命名约定 (describe-it 或 test)
|
|
837
|
-
- 使用相同的断言库 (expect/assert/should)
|
|
838
|
-
- 保持文件后缀一致 (.test.ts/.spec.ts)
|
|
839
|
-
- 保持文件位置风格 (同目录或独立目录)
|
|
840
|
-
|
|
841
|
-
## 分层原则
|
|
842
|
-
|
|
843
|
-
**CLI 只负责:**
|
|
844
|
-
- 扫描项目结构
|
|
845
|
-
- 检测测试框架
|
|
846
|
-
- 运行测试验证
|
|
847
|
-
- 输出结构化 JSON 数据
|
|
848
|
-
|
|
849
|
-
**Skill AI 负责:**
|
|
850
|
-
- 分析业务逻辑
|
|
851
|
-
- 发现测试缺失
|
|
852
|
-
- 推荐测试类型
|
|
853
|
-
- 生成测试代码
|
|
854
|
-
- 处理验证失败
|
|
855
|
-
|
|
856
|
-
**反模式(禁止):**
|
|
857
|
-
```typescript
|
|
858
|
-
// ❌ 错误:CLI 硬编码推荐逻辑
|
|
859
|
-
function recommendTestFramework(projectType) {
|
|
860
|
-
if (projectType === 'typescript') return 'vitest';
|
|
861
|
-
// ...更多 if/else
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
// ✅ 正确:CLI 只输出原始数据,AI 自己判断
|
|
865
|
-
// AI 看到 frameworks 数组,自己决定使用哪个
|
|
866
|
-
```
|
|
867
|
-
|
|
868
|
-
## 实际影响
|
|
869
|
-
|
|
870
|
-
来自测试生成实践:
|
|
871
|
-
- 业务角度测试:更易维护,更有价值
|
|
872
|
-
- 自动验证循环:减少手动调试时间
|
|
873
|
-
- 风格一致性:团队协作更顺畅
|
|
874
|
-
- 首次生成成功率:85%+
|
|
875
|
-
- 3 次循环成功率:95%+
|
|
1
|
+
---
|
|
2
|
+
name: om:test
|
|
3
|
+
description: "Use when user wants to GENERATE or IMPROVE tests. Triggers on TEST-CREATION intent: user wants new test files, better coverage, or test infrastructure setup. DO NOT trigger on: test execution (running tests), test debugging (why test fails), or test questions (how to write tests). Intent signals: user asks to generate/add/write tests, mentions coverage gaps, wants test setup."
|
|
4
|
+
priority: high
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<INTENT-JUDGMENT>
|
|
8
|
+
## 意图判断指南
|
|
9
|
+
|
|
10
|
+
**AI 应根据用户语义判断意图:**
|
|
11
|
+
|
|
12
|
+
### 触发信号(测试创建意图)
|
|
13
|
+
|
|
14
|
+
- 用户想生成测试文件
|
|
15
|
+
- 用户想改进测试覆盖
|
|
16
|
+
- 用户想设置测试框架
|
|
17
|
+
- 用户提到"没测试"、"需要测试"
|
|
18
|
+
|
|
19
|
+
### 不触发信号
|
|
20
|
+
|
|
21
|
+
| 用户意图 | 应调用 |
|
|
22
|
+
|---------|--------|
|
|
23
|
+
| 运行测试 | 直接执行 npm test |
|
|
24
|
+
| 测试失败想修复 | /om:debug |
|
|
25
|
+
| 询问测试写法 | 直接回答 |
|
|
26
|
+
|
|
27
|
+
### 示例判断
|
|
28
|
+
|
|
29
|
+
| 用户消息 | 判断 | 结果 |
|
|
30
|
+
|---------|------|------|
|
|
31
|
+
| "给这个文件补测试" | 创建测试意图 | 触发 ✓ |
|
|
32
|
+
| "生成单元测试" | 创建意图明确 | 触发 ✓ |
|
|
33
|
+
| "测试覆盖率太低" | 改进覆盖意图 | 触发 ✓ |
|
|
34
|
+
| "运行测试看看" | 执行意图 | 直接运行 |
|
|
35
|
+
| "测试失败了为什么" | 排查意图 | /om:debug |
|
|
36
|
+
</INTENT-JUDGMENT>
|
|
37
|
+
|
|
38
|
+
<NO-OTHER-SKILLS>
|
|
39
|
+
本 skill 与其他任务编排技能功能重叠,请勿同时使用。
|
|
40
|
+
|
|
41
|
+
**测试生成阶段使用 Agent 工具执行。**
|
|
42
|
+
</NO-OTHER-SKILLS>
|
|
43
|
+
|
|
44
|
+
<MANDATORY-EXECUTION-ORDER>
|
|
45
|
+
## 执行顺序 - 必须严格按此顺序,不得跳过
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Step 1: 调用 CLI 扫描项目 (openmatrix test --json)
|
|
49
|
+
Step 2: AI 分析项目上下文和业务逻辑
|
|
50
|
+
Step 3: 发现测试缺失,输出分析报告
|
|
51
|
+
Step 4: UI 测试决策(如果 isFrontend=true)
|
|
52
|
+
⛔ 分析阶段结束,必须等待用户确认
|
|
53
|
+
Step 5: AskUserQuestion 确认测试范围
|
|
54
|
+
Step 6: 生成测试代码(Agent)
|
|
55
|
+
Step 7: 自动验证测试(循环最多 3 次)
|
|
56
|
+
├─ 通过 → 进入 Step 8
|
|
57
|
+
└─ 失败 → 自动重新生成(带失败信息)
|
|
58
|
+
Step 8: 输出测试报告
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**铁律:不做项目分析,不许生成测试**
|
|
62
|
+
**铁律:前端项目必须询问 UI 测试需求,不得跳过**
|
|
63
|
+
**铁律:验证失败自动循环,最多 3 次,超过必须暂停**
|
|
64
|
+
</MANDATORY-EXECUTION-ORDER>
|
|
65
|
+
|
|
66
|
+
<IRON-LAW>
|
|
67
|
+
## 铁律:没有失败的测试,不许写生产代码
|
|
68
|
+
|
|
69
|
+
**NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST**
|
|
70
|
+
|
|
71
|
+
在测试前写了代码?删除。重新开始。
|
|
72
|
+
|
|
73
|
+
没有例外:
|
|
74
|
+
- 不要保留作为"参考"
|
|
75
|
+
- 不要"写测试时适应它"
|
|
76
|
+
- 不要看它
|
|
77
|
+
|
|
78
|
+
删除意味着删除。
|
|
79
|
+
|
|
80
|
+
## Why Order Matters
|
|
81
|
+
|
|
82
|
+
### "我会在实现后写测试来验证工作"
|
|
83
|
+
|
|
84
|
+
实现后写的测试立即通过。立即通过什么也证明不了:
|
|
85
|
+
- 可能测试错误的东西
|
|
86
|
+
- 可能测试实现,不是行为
|
|
87
|
+
- 可能遗漏你忘记的边界情况
|
|
88
|
+
- 你从未看到它捕获 bug
|
|
89
|
+
|
|
90
|
+
测试优先强制你看到测试失败,证明它确实测试某些东西。
|
|
91
|
+
|
|
92
|
+
### "我手动测试了所有边界情况"
|
|
93
|
+
|
|
94
|
+
手动测试是临时的。你以为测试了所有东西但:
|
|
95
|
+
- 没有测试记录
|
|
96
|
+
- 代码变化时无法重跑
|
|
97
|
+
- 压力下容易忘记情况
|
|
98
|
+
- "我试过了" ≠ 全面
|
|
99
|
+
|
|
100
|
+
自动化测试是系统的。每次运行相同方式。
|
|
101
|
+
|
|
102
|
+
### "删除 X 小时工作是浪费"
|
|
103
|
+
|
|
104
|
+
沉没成本谬误。时间已经没了。现在选择:
|
|
105
|
+
- 删除并用 TDD 重写(X+小时,高信心)
|
|
106
|
+
- 保留并在后加测试(30分钟,低信心,可能 bug)
|
|
107
|
+
|
|
108
|
+
"浪费"是保留不能信任的代码。无真实测试的工作代码是技术债务。
|
|
109
|
+
|
|
110
|
+
## Good vs Bad Tests
|
|
111
|
+
|
|
112
|
+
| 质量 | Good | Bad |
|
|
113
|
+
|-----|------|-----|
|
|
114
|
+
| **最小化** | 一件事。名字有"and"?拆分。 | `test('validates email and domain and whitespace')` |
|
|
115
|
+
| **清晰** | 名字描述行为 | `test('test1')` |
|
|
116
|
+
| **展示意图** | 展示期望 API | 模糊代码该做什么 |
|
|
117
|
+
| **真实代码** | 无 mock(除非不可避免) | Mock 一切 |
|
|
118
|
+
|
|
119
|
+
### Good Example
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
test('重试失败操作 3 次', async () => {
|
|
123
|
+
let attempts = 0;
|
|
124
|
+
const operation = () => {
|
|
125
|
+
attempts++;
|
|
126
|
+
if (attempts < 3) throw new Error('fail');
|
|
127
|
+
return 'success';
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const result = await retryOperation(operation);
|
|
131
|
+
|
|
132
|
+
expect(result).toBe('success');
|
|
133
|
+
expect(attempts).toBe(3);
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
一件事,测试真实行为,清晰名字。
|
|
138
|
+
|
|
139
|
+
### Bad Example
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
test('retry works', async () => {
|
|
143
|
+
const mock = jest.fn()
|
|
144
|
+
.mockRejectedValueOnce(new Error())
|
|
145
|
+
.mockRejectedValueOnce(new Error())
|
|
146
|
+
.mockResolvedValueOnce('success');
|
|
147
|
+
await retryOperation(mock);
|
|
148
|
+
expect(mock).toHaveBeenCalledTimes(3);
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
模糊名字,测试 mock 不是代码。
|
|
153
|
+
</IRON-LAW>
|
|
154
|
+
|
|
155
|
+
<objective>
|
|
156
|
+
智能测试生成 - 从业务角度分析代码逻辑,发现测试缺失,自动生成并验证测试。遵循 OpenMatrix 分层原则:CLI 收集原始数据,AI 分析并生成测试。
|
|
157
|
+
</objective>
|
|
158
|
+
|
|
159
|
+
<process>
|
|
160
|
+
|
|
161
|
+
## Step 1: 调用 CLI 扫描项目
|
|
162
|
+
|
|
163
|
+
**检查 `$ARGUMENTS`:**
|
|
164
|
+
|
|
165
|
+
| 参数 | 处理方式 |
|
|
166
|
+
|------|---------|
|
|
167
|
+
| 空 | 扫描整个项目 |
|
|
168
|
+
| `src/auth/` | 扫描指定目录 |
|
|
169
|
+
| `--target src/utils.ts` | 扫描指定文件 |
|
|
170
|
+
|
|
171
|
+
**调用 CLI 扫描:**
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
openmatrix test --json
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
或指定目标:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
openmatrix test src/auth/ --json
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**CLI 返回 TestScanResult JSON:**
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"timestamp": "2026-04-23T10:00:00Z",
|
|
188
|
+
"projectRoot": "/path/to/project",
|
|
189
|
+
"target": "src/",
|
|
190
|
+
"frameworks": [
|
|
191
|
+
{
|
|
192
|
+
"framework": "vitest",
|
|
193
|
+
"version": "1.2.3",
|
|
194
|
+
"configFile": "vitest.config.ts",
|
|
195
|
+
"isPrimary": true,
|
|
196
|
+
"supportedTypes": ["unit", "integration"],
|
|
197
|
+
"commands": {
|
|
198
|
+
"test": "npm test",
|
|
199
|
+
"testCoverage": "npm test -- --coverage"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
"existingTests": [
|
|
204
|
+
{ "path": "tests/example.test.ts", "type": "unit", "testCount": 5 }
|
|
205
|
+
],
|
|
206
|
+
"uncoveredSources": [
|
|
207
|
+
{
|
|
208
|
+
"path": "src/auth/login.ts",
|
|
209
|
+
"fileType": "service",
|
|
210
|
+
"exports": ["login", "validateToken"],
|
|
211
|
+
"hasTest": false,
|
|
212
|
+
"suggestedTestTypes": ["unit", "integration"],
|
|
213
|
+
"complexity": { "lines": 150, "functions": 5 }
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
"projectType": "typescript",
|
|
217
|
+
"isFrontend": false,
|
|
218
|
+
"hasUIComponents": false,
|
|
219
|
+
"coverageReport": { "total": 45 },
|
|
220
|
+
"testStyle": {
|
|
221
|
+
"namingConvention": "describe-it",
|
|
222
|
+
"assertionLibrary": "expect",
|
|
223
|
+
"usesTypeScript": true,
|
|
224
|
+
"fileSuffix": ".test.ts",
|
|
225
|
+
"fileLocation": "separate"
|
|
226
|
+
},
|
|
227
|
+
"summary": {
|
|
228
|
+
"frameworkCount": 1,
|
|
229
|
+
"existingTestCount": 5,
|
|
230
|
+
"uncoveredSourceCount": 20,
|
|
231
|
+
"hasTestConfig": true,
|
|
232
|
+
"hasCoverageConfig": true
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**从返回结果读取关键数据:**
|
|
238
|
+
- `frameworks`: 检测到的测试框架
|
|
239
|
+
- `existingTests`: 现有测试文件
|
|
240
|
+
- `uncoveredSources`: 未覆盖的源文件
|
|
241
|
+
- `isFrontend`: 是否为前端项目
|
|
242
|
+
- `hasUIComponents`: 是否有 UI 组件
|
|
243
|
+
- `testStyle`: 现有测试风格(用于保持一致性)
|
|
244
|
+
|
|
245
|
+
## Step 2: AI 分析项目上下文
|
|
246
|
+
|
|
247
|
+
**AI 分析任务(读取原始数据后):**
|
|
248
|
+
|
|
249
|
+
1. **识别测试框架**
|
|
250
|
+
- 读取 `frameworks` 数组
|
|
251
|
+
- 确定主要测试框架 `isPrimary: true`
|
|
252
|
+
- 了解支持的测试类型
|
|
253
|
+
|
|
254
|
+
2. **分析项目结构**
|
|
255
|
+
- 读取 `projectType` 确定语言
|
|
256
|
+
- 读取 `uncoveredSources` 了解需要测试的模块
|
|
257
|
+
- 每个源文件的 `exports` 表示需要测试的目标
|
|
258
|
+
|
|
259
|
+
3. **分析现有测试风格**
|
|
260
|
+
- 读取 `testStyle.namingConvention` 保持命名一致
|
|
261
|
+
- 读取 `testStyle.assertionLibrary` 使用相同断言库
|
|
262
|
+
- 读取 `testStyle.fileSuffix` 保持文件后缀一致
|
|
263
|
+
- 读取 `testStyle.fileLocation` 确定测试文件位置
|
|
264
|
+
|
|
265
|
+
4. **评估覆盖率现状**
|
|
266
|
+
- 如果 `coverageReport` 存在,了解当前覆盖率
|
|
267
|
+
- 识别关键业务模块的覆盖缺口
|
|
268
|
+
|
|
269
|
+
## Step 3: 发现测试缺失
|
|
270
|
+
|
|
271
|
+
**AI 分析每个未覆盖源文件:**
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
对于每个 uncoveredSources[i]:
|
|
275
|
+
1. 分析 exports 中的每个函数/类/组件
|
|
276
|
+
2. 理解业务逻辑(不是语法,而是"做什么")
|
|
277
|
+
3. 识别关键业务场景
|
|
278
|
+
4. 确定测试优先级(基于复杂度、重要性)
|
|
279
|
+
5. 生成测试用例清单
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**输出分析报告:**
|
|
283
|
+
|
|
284
|
+
```
|
|
285
|
+
📊 测试缺失分析报告
|
|
286
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
287
|
+
|
|
288
|
+
项目类型: TypeScript
|
|
289
|
+
测试框架: Vitest (v1.2.3)
|
|
290
|
+
当前覆盖率: 45%
|
|
291
|
+
|
|
292
|
+
未覆盖源文件 (20 个):
|
|
293
|
+
┌────────────────────────────────────────┐
|
|
294
|
+
│ src/auth/login.ts │
|
|
295
|
+
│ 类型: service | 导出: login, validateToken │
|
|
296
|
+
│ 行数: 150 | 函数: 5 │
|
|
297
|
+
│ 建议测试类型: unit, integration │
|
|
298
|
+
│ 关键业务场景: │
|
|
299
|
+
│ - 用户登录成功 │
|
|
300
|
+
│ - 密码错误拒绝 │
|
|
301
|
+
│ - Token 验证过期 │
|
|
302
|
+
│ - 并发登录处理 │
|
|
303
|
+
├────────────────────────────────────────┤
|
|
304
|
+
│ src/utils/format.ts │
|
|
305
|
+
│ 类型: util | 导出: formatDate, parseJSON │
|
|
306
|
+
│ ... │
|
|
307
|
+
└────────────────────────────────────────┘
|
|
308
|
+
|
|
309
|
+
测试优先级建议:
|
|
310
|
+
P0: src/auth/login.ts (认证核心)
|
|
311
|
+
P0: src/api/handler.ts (API 入口)
|
|
312
|
+
P1: src/utils/format.ts (通用工具)
|
|
313
|
+
P2: src/config/index.ts (配置加载)
|
|
314
|
+
|
|
315
|
+
现有测试风格:
|
|
316
|
+
- 命名约定: describe/it
|
|
317
|
+
- 断言库: expect
|
|
318
|
+
- 文件后缀: .test.ts
|
|
319
|
+
- 文件位置: tests/ 目录
|
|
320
|
+
|
|
321
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Step 4: UI 测试决策
|
|
325
|
+
|
|
326
|
+
**如果 `isFrontend=true` 或 `hasUIComponents=true`:**
|
|
327
|
+
|
|
328
|
+
**⛔ 必须在此询问用户 UI 测试需求,不得跳过。**
|
|
329
|
+
|
|
330
|
+
AskUserQuestion: `header: "UI 测试"`, `multiSelect: false`
|
|
331
|
+
**question:** 检测到前端/UI 组件,是否需要生成 UI/E2E 测试?
|
|
332
|
+
|
|
333
|
+
| label | description |
|
|
334
|
+
|-------|-------------|
|
|
335
|
+
| 需要 UI 测试 | 生成 Playwright/Cypress E2E 测试 |
|
|
336
|
+
| 仅单元测试 | 只生成单元测试,不生成 E2E |
|
|
337
|
+
| 自定义配置 | 指定 UI 测试框架和范围 |
|
|
338
|
+
|
|
339
|
+
**如果用户选择"自定义配置":**
|
|
340
|
+
|
|
341
|
+
AskUserQuestion: `header: "UI 测试框架"`, `multiSelect: false`
|
|
342
|
+
**question:** 选择 UI 测试框架?
|
|
343
|
+
|
|
344
|
+
| label | description |
|
|
345
|
+
|-------|-------------|
|
|
346
|
+
| Playwright (推荐) | 跨浏览器支持,现代 API |
|
|
347
|
+
| Cypress | 开发体验好,调试方便 |
|
|
348
|
+
| Puppeteer | 轻量级,Chrome 优先 |
|
|
349
|
+
|
|
350
|
+
**如果用户选择"需要 UI 测试":**
|
|
351
|
+
- AI 根据 `frameworks` 中是否有 E2E 框架推荐合适的选择
|
|
352
|
+
- 如果无 E2E 框架,推荐 Playwright
|
|
353
|
+
|
|
354
|
+
## Step 5: 确认测试范围
|
|
355
|
+
|
|
356
|
+
**展示分析报告后,询问用户确认:**
|
|
357
|
+
|
|
358
|
+
AskUserQuestion: `header: "测试范围"`, `multiSelect: true`
|
|
359
|
+
**question:** 选择需要生成测试的源文件?
|
|
360
|
+
|
|
361
|
+
| label | description |
|
|
362
|
+
|-------|-------------|
|
|
363
|
+
| 全部生成 (推荐) | 为所有未覆盖文件生成测试 |
|
|
364
|
+
| P0 优先级 | 只生成 P0 优先级测试 |
|
|
365
|
+
| 自定义选择 | 指定具体文件列表 |
|
|
366
|
+
|
|
367
|
+
**如果用户选择"自定义选择":**
|
|
368
|
+
|
|
369
|
+
展示文件列表,让用户选择具体文件。
|
|
370
|
+
|
|
371
|
+
**确认测试配置:**
|
|
372
|
+
|
|
373
|
+
AskUserQuestion: `header: "测试配置"`, `multiSelect: false`
|
|
374
|
+
**question:** 确认测试生成配置?
|
|
375
|
+
|
|
376
|
+
| label | description |
|
|
377
|
+
|-------|-------------|
|
|
378
|
+
| 自动生成 (推荐) | AI 自动分析业务逻辑生成测试 |
|
|
379
|
+
| 交互式生成 | 每个文件询问测试场景 |
|
|
380
|
+
| 快速生成 | 只生成基础测试,跳过复杂场景 |
|
|
381
|
+
|
|
382
|
+
## Step 6: 生成测试代码
|
|
383
|
+
|
|
384
|
+
**调用 Agent 生成测试:**
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
Agent({
|
|
388
|
+
subagent_type: "general-purpose",
|
|
389
|
+
description: "生成测试代码",
|
|
390
|
+
prompt: `你是测试工程师。根据分析结果生成测试代码。
|
|
391
|
+
|
|
392
|
+
## 铁律
|
|
393
|
+
1. 从业务角度理解代码,不是语法角度
|
|
394
|
+
2. 测试业务场景,不是函数调用
|
|
395
|
+
3. 保持与现有测试风格一致
|
|
396
|
+
4. 每个测试用例必须有明确的业务意义
|
|
397
|
+
|
|
398
|
+
## 项目信息
|
|
399
|
+
- 语言: ${projectType}
|
|
400
|
+
- 测试框架: ${primaryFramework}
|
|
401
|
+
- 测试目录: ${testDirectory}
|
|
402
|
+
- 文件后缀: ${fileSuffix}
|
|
403
|
+
|
|
404
|
+
## 现有测试风格
|
|
405
|
+
- 命名约定: ${namingConvention}
|
|
406
|
+
- 断言库: ${assertionLibrary}
|
|
407
|
+
- 文件位置: ${fileLocation}
|
|
408
|
+
|
|
409
|
+
## 需要测试的源文件
|
|
410
|
+
${selectedFiles.map(f => `
|
|
411
|
+
文件: ${f.path}
|
|
412
|
+
类型: ${f.fileType}
|
|
413
|
+
导出: ${f.exports.join(', ')}
|
|
414
|
+
复杂度: ${f.complexity?.lines || 'unknown'} 行
|
|
415
|
+
`).join('\n')}
|
|
416
|
+
|
|
417
|
+
## 任务
|
|
418
|
+
1. 分析每个源文件的业务逻辑
|
|
419
|
+
2. 识别关键业务场景(成功路径、边界条件、错误处理)
|
|
420
|
+
3. 为每个场景编写测试用例
|
|
421
|
+
4. 测试文件写入正确位置
|
|
422
|
+
5. 保持命名和风格一致
|
|
423
|
+
|
|
424
|
+
## 测试用例要求
|
|
425
|
+
- describe 描述业务场景(不是函数名)
|
|
426
|
+
- it 描述具体行为("should...")
|
|
427
|
+
- 断言验证业务结果
|
|
428
|
+
- Mock 外部依赖(API、数据库等)
|
|
429
|
+
|
|
430
|
+
## 禁止行为
|
|
431
|
+
❌ 测试语法而不是行为
|
|
432
|
+
❌ 使用与项目不一致的风格
|
|
433
|
+
❌ 跳过边界条件和错误处理
|
|
434
|
+
❌ 生成无意义的测试(如 "should exist")`,
|
|
435
|
+
run_in_background: false
|
|
436
|
+
})
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**UI 测试生成(如果需要):**
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
Agent({
|
|
443
|
+
subagent_type: "general-purpose",
|
|
444
|
+
description: "生成 E2E/UI 测试",
|
|
445
|
+
prompt: `你是 E2E 测试工程师。为前端组件生成 UI 测试。
|
|
446
|
+
|
|
447
|
+
## UI 测试框架
|
|
448
|
+
- 框架: ${uiFramework}
|
|
449
|
+
- 配置文件: ${uiConfigFile || '需要创建'}
|
|
450
|
+
|
|
451
|
+
## 需要测试的 UI 组件
|
|
452
|
+
${uiComponents.map(c => `
|
|
453
|
+
组件: ${c.path}
|
|
454
|
+
导出: ${c.exports.join(', ')}
|
|
455
|
+
功能: ${c.description || '需要分析'}
|
|
456
|
+
`).join('\n')}
|
|
457
|
+
|
|
458
|
+
## 任务
|
|
459
|
+
1. 创建 E2E 测试配置(如果不存在)
|
|
460
|
+
2. 为每个关键用户流程生成测试
|
|
461
|
+
3. 测试用例覆盖:页面渲染、用户交互、数据展示
|
|
462
|
+
4. 截图放置在 tests/e2e/screenshots/
|
|
463
|
+
|
|
464
|
+
## E2E 测试用例要求
|
|
465
|
+
- 测试完整用户流程
|
|
466
|
+
- 验证页面状态变化
|
|
467
|
+
- 检查关键元素可见性
|
|
468
|
+
- 处理异步加载等待
|
|
469
|
+
|
|
470
|
+
## 禁止行为
|
|
471
|
+
❌ 测试单个元素样式
|
|
472
|
+
❌ 跳过用户等待时间
|
|
473
|
+
❌ 硬编码测试数据`,
|
|
474
|
+
run_in_background: false
|
|
475
|
+
})
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Step 7: 自动验证测试(循环机制)
|
|
479
|
+
|
|
480
|
+
<LOOP_ENFORCEMENT>
|
|
481
|
+
**此步骤是验证循环,必须执行直到验证通过或达到最大重试次数。**
|
|
482
|
+
|
|
483
|
+
❌ **禁止在验证失败时停止** — 即使 Agent 返回了大段输出,也必须继续循环
|
|
484
|
+
❌ **禁止询问"是否继续验证"** — 自动执行验证,无需用户确认
|
|
485
|
+
❌ **禁止输出"让我知道是否..."后停止** — 继续执行验证循环
|
|
486
|
+
❌ **禁止因为上下文压缩而忘记重试次数** — 使用 TodoWrite 持久化 retryCount
|
|
487
|
+
|
|
488
|
+
**retryCount 持久化机制(防止上下文压缩丢失状态):**
|
|
489
|
+
|
|
490
|
+
验证循环开始时,使用 TodoWrite 记录状态:
|
|
491
|
+
```
|
|
492
|
+
TodoWrite([
|
|
493
|
+
{ content: "验证测试(第 N 次)", activeForm: "正在验证测试(第 N 次)", status: "in_progress" }
|
|
494
|
+
])
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
每次验证失败后:
|
|
498
|
+
1. 更新 TodoWrite 的 retryCount(N → N+1)
|
|
499
|
+
2. 检查是否达到最大次数(>= 3)
|
|
500
|
+
3. 未达到 → 自动回到 Step 6 重新生成
|
|
501
|
+
4. 已达到 → 暂停并报告问题
|
|
502
|
+
|
|
503
|
+
**循环铁律:**
|
|
504
|
+
- retryCount 从 TodoWrite 读取,不依赖上下文记忆
|
|
505
|
+
- 验证失败必须自动循环,不得跳过
|
|
506
|
+
- 最大重试 3 次,超过必须暂停
|
|
507
|
+
</LOOP_ENFORCEMENT>
|
|
508
|
+
|
|
509
|
+
**⛔ 自动验证流程 - 无需用户手动确认**
|
|
510
|
+
|
|
511
|
+
### 7.1 执行验证命令(自动判断结果)
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
# 执行测试验证
|
|
515
|
+
VERIFY_RESULT=0
|
|
516
|
+
npm test -- --run > /tmp/test-verify-output.txt 2>&1 || VERIFY_RESULT=1
|
|
517
|
+
|
|
518
|
+
if [ $VERIFY_RESULT -eq 0 ]; then
|
|
519
|
+
echo "✅ 测试验证通过"
|
|
520
|
+
else
|
|
521
|
+
echo "❌ 测试验证失败"
|
|
522
|
+
cat /tmp/test-verify-output.txt | tail -50 # 展示失败详情
|
|
523
|
+
fi
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### 7.2 验证失败自动循环(无需用户确认)
|
|
527
|
+
|
|
528
|
+
**验证失败时自动处理:**
|
|
529
|
+
|
|
530
|
+
```
|
|
531
|
+
验证失败 → TodoWrite 更新 retryCount → 检查重试次数 →
|
|
532
|
+
├─ < 3 次 → 自动回到 Step 6 重新生成(带失败信息)
|
|
533
|
+
└─ >= 3 次 → 暂停,报告问题,可能是测试框架配置问题
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
**重试计数器持久化:**
|
|
537
|
+
- 使用 TodoWrite 记录 retryCount
|
|
538
|
+
- 每次验证失败后更新 TodoWrite(retryCount + 1)
|
|
539
|
+
- 验证通过后更新 TodoWrite 为 completed
|
|
540
|
+
|
|
541
|
+
### 7.3 自动循环回生成步骤
|
|
542
|
+
|
|
543
|
+
**< 3 次验证失败 → 自动调用 Agent 重新生成:**
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
Agent({
|
|
547
|
+
subagent_type: "general-purpose",
|
|
548
|
+
description: `修复测试 (第 ${retryCount + 1} 次)`,
|
|
549
|
+
prompt: `根据测试验证失败结果修复测试代码。
|
|
550
|
+
|
|
551
|
+
## 铁律
|
|
552
|
+
1. 只修复失败的测试,不修改通过的测试
|
|
553
|
+
2. 分析失败原因,不要盲目修改
|
|
554
|
+
3. 保持测试风格一致
|
|
555
|
+
|
|
556
|
+
## 验证失败详情
|
|
557
|
+
${verifyFailureOutput}
|
|
558
|
+
|
|
559
|
+
## 失败分析
|
|
560
|
+
- 哪些测试失败了?
|
|
561
|
+
- 失败原因是什么?
|
|
562
|
+
- 是测试代码问题还是源代码问题?
|
|
563
|
+
|
|
564
|
+
## 修复策略
|
|
565
|
+
1. 如果是测试语法错误 → 修正测试代码
|
|
566
|
+
2. 如果是断言失败 → 分析预期值是否正确
|
|
567
|
+
3. 如果是 Mock 问题 → 调整 Mock 实现
|
|
568
|
+
|
|
569
|
+
## 禁止行为
|
|
570
|
+
❌ 修改通过的测试
|
|
571
|
+
❌ 删除失败的测试用例
|
|
572
|
+
❌ 跳过 Mock 外部依赖`,
|
|
573
|
+
run_in_background: false
|
|
574
|
+
})
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### 7.4 达到最大重试次数(>= 3 次)
|
|
578
|
+
|
|
579
|
+
**输出警告并暂停:**
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
⚠️ 已尝试 3 次以上生成,测试仍未通过
|
|
583
|
+
|
|
584
|
+
可能的问题:
|
|
585
|
+
- 测试框架配置不正确
|
|
586
|
+
- 源代码有 bug 导致测试无法通过
|
|
587
|
+
- Mock 设置不完整
|
|
588
|
+
|
|
589
|
+
建议:检查测试框架配置,或手动修复测试代码。
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
AskUserQuestion: `header: "验证问题"`, `multiSelect: false`
|
|
593
|
+
**question:** 已尝试 3 次生成仍未通过,可能存在配置问题。下一步?
|
|
594
|
+
|
|
595
|
+
| label | description |
|
|
596
|
+
|-------|-------------|
|
|
597
|
+
| 检查配置 | 检查测试框架配置文件 |
|
|
598
|
+
| 手动修复 | 输出测试文件路径,用户手动修改 |
|
|
599
|
+
| 结束流程 | 保存当前测试文件,结束流程 |
|
|
600
|
+
|
|
601
|
+
### 7.5 验证通过
|
|
602
|
+
|
|
603
|
+
**验证通过 → 自动进入 Step 8**
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
✅ 测试验证通过
|
|
607
|
+
|
|
608
|
+
所有生成的测试正常运行,自动进入报告阶段。
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
## Step 8: 输出测试报告
|
|
612
|
+
|
|
613
|
+
**展示测试生成报告:**
|
|
614
|
+
|
|
615
|
+
```markdown
|
|
616
|
+
# 测试生成报告
|
|
617
|
+
|
|
618
|
+
**生成时间**: ${timestamp}
|
|
619
|
+
**项目**: ${projectName}
|
|
620
|
+
**测试框架**: ${primaryFramework}
|
|
621
|
+
|
|
622
|
+
## 生成的测试文件
|
|
623
|
+
|
|
624
|
+
| 文件 | 类型 | 测试用例 | 源文件 |
|
|
625
|
+
|------|------|---------|--------|
|
|
626
|
+
| tests/auth/login.test.ts | unit | 12 | src/auth/login.ts |
|
|
627
|
+
| tests/api/handler.test.ts | integration | 8 | src/api/handler.ts |
|
|
628
|
+
| tests/e2e/user-flow.spec.ts | e2e | 5 | 多个组件 |
|
|
629
|
+
|
|
630
|
+
## 测试覆盖统计
|
|
631
|
+
|
|
632
|
+
- 单元测试: 20 个
|
|
633
|
+
- 集成测试: 8 个
|
|
634
|
+
- E2E 测试: 5 个
|
|
635
|
+
- 总计: 33 个测试用例
|
|
636
|
+
|
|
637
|
+
## 验证结果
|
|
638
|
+
|
|
639
|
+
✅ 所有测试通过 (33 passed, 0 failed)
|
|
640
|
+
|
|
641
|
+
## 覆盖率预估
|
|
642
|
+
|
|
643
|
+
当前覆盖率: 45%
|
|
644
|
+
预估覆盖率: 72% (+27%)
|
|
645
|
+
|
|
646
|
+
## 后续建议
|
|
647
|
+
|
|
648
|
+
1. 运行 `npm test -- --coverage` 查看详细覆盖率
|
|
649
|
+
2. 检查 Mock 文件是否需要补充测试数据
|
|
650
|
+
3. E2E 测试截图已放置在 tests/e2e/screenshots/
|
|
651
|
+
|
|
652
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**Git 提交提示(可选):**
|
|
656
|
+
|
|
657
|
+
AskUserQuestion: `header: "Git 提交"`, `multiSelect: false`
|
|
658
|
+
**question:** 是否提交生成的测试文件?
|
|
659
|
+
|
|
660
|
+
| label | description |
|
|
661
|
+
|-------|-------------|
|
|
662
|
+
| 提交测试文件 | git add tests/ && git commit |
|
|
663
|
+
| 仅保存文件 | 不提交,用户稍后处理 |
|
|
664
|
+
| 查看生成的文件 | 展示文件内容后再决定 |
|
|
665
|
+
|
|
666
|
+
</process>
|
|
667
|
+
|
|
668
|
+
<arguments>
|
|
669
|
+
$ARGUMENTS
|
|
670
|
+
</arguments>
|
|
671
|
+
|
|
672
|
+
<examples>
|
|
673
|
+
/om:test # 扫描整个项目,发现测试缺失
|
|
674
|
+
/om:test src/auth/ # 只为 src/auth/ 目录生成测试
|
|
675
|
+
/om:test --target src/utils.ts # 为指定文件生成测试
|
|
676
|
+
</examples>
|
|
677
|
+
|
|
678
|
+
<notes>
|
|
679
|
+
## 完整流程图
|
|
680
|
+
|
|
681
|
+
```
|
|
682
|
+
Step 1: CLI 扫描 (openmatrix test --json)
|
|
683
|
+
│ 收集原始数据:框架、源文件、覆盖率
|
|
684
|
+
▼
|
|
685
|
+
Step 2: AI 分析项目上下文
|
|
686
|
+
│ • 识别测试框架
|
|
687
|
+
│ • 分析项目结构
|
|
688
|
+
│ • 理解测试风格
|
|
689
|
+
▼
|
|
690
|
+
Step 3: 发现测试缺失
|
|
691
|
+
│ • 对比源文件与测试文件
|
|
692
|
+
│ • 分析业务逻辑复杂度
|
|
693
|
+
│ • 识别关键业务场景
|
|
694
|
+
│ • 输出分析报告
|
|
695
|
+
▼
|
|
696
|
+
Step 4: UI 测试决策 (如果 isFrontend=true)
|
|
697
|
+
│ ⛔ 必须询问用户
|
|
698
|
+
│ AskUserQuestion: 是否需要 UI 测试?
|
|
699
|
+
▼
|
|
700
|
+
Step 5: 确认测试范围
|
|
701
|
+
│ AskUserQuestion: 选择源文件
|
|
702
|
+
│ AskUserQuestion: 确认配置
|
|
703
|
+
▼
|
|
704
|
+
Step 6: 生成测试代码
|
|
705
|
+
│ Agent(general-purpose) 分析业务逻辑生成测试
|
|
706
|
+
│ 如果需要 UI 测试,Agent 生成 E2E 测试
|
|
707
|
+
▼
|
|
708
|
+
Step 7: ⛔ 自动验证测试(无需用户确认)
|
|
709
|
+
│ ├─ 执行 npm test → 自动判断结果
|
|
710
|
+
│ ├─ 通过 → 自动进入 Step 8 ✅
|
|
711
|
+
│ └─ 失败 → 自动循环处理
|
|
712
|
+
│ ├─ < 3 次 → 自动回到 Step 6 重新生成
|
|
713
|
+
│ └─ >= 3 次 → 暂停,可能是配置问题 ⚠️
|
|
714
|
+
▼
|
|
715
|
+
Step 8: 输出测试报告
|
|
716
|
+
│ 展示生成的文件列表
|
|
717
|
+
│ 展示覆盖率统计
|
|
718
|
+
│ Git 提交询问(可选)
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
## 自动验证循环流程(Step 7 详细)
|
|
722
|
+
|
|
723
|
+
```
|
|
724
|
+
┌─────────────────────────────────────────┐
|
|
725
|
+
│ Step 6: 生成测试代码 │
|
|
726
|
+
└─────────────────────┬───────────────────┘
|
|
727
|
+
↓
|
|
728
|
+
┌─────────────────────────────────────────┐
|
|
729
|
+
│ Step 7: 执行测试验证 │
|
|
730
|
+
│ (npm test / npm test -- --run) │
|
|
731
|
+
└─────────────────────┬───────────────────┘
|
|
732
|
+
↓
|
|
733
|
+
┌───────┴───────┐
|
|
734
|
+
│ 自动判断结果 │
|
|
735
|
+
└───────┬───────┘
|
|
736
|
+
┌─────────────┴─────────────┐
|
|
737
|
+
│ │
|
|
738
|
+
退出码=0 退出码≠0
|
|
739
|
+
(测试通过) (测试失败)
|
|
740
|
+
│ │
|
|
741
|
+
↓ ↓
|
|
742
|
+
┌───────────────┐ ┌───────────────────┐
|
|
743
|
+
│ ✅ 进入 Step 8│ │ retryCount + 1 │
|
|
744
|
+
└───────────────┘ └───────┬───────────┘
|
|
745
|
+
↓
|
|
746
|
+
┌────────┴────────┐
|
|
747
|
+
│ 检查重试次数 │
|
|
748
|
+
└───────┬─────────┘
|
|
749
|
+
┌─────────────┴─────────────┐
|
|
750
|
+
│ │
|
|
751
|
+
< 3 次 >= 3 次
|
|
752
|
+
│ │
|
|
753
|
+
↓ ↓
|
|
754
|
+
┌─────────────────┐ ┌───────────────────┐
|
|
755
|
+
│ ⚡ 自动回到 Step 6 │ │ ⚠️ 暂停,检查配置 │
|
|
756
|
+
│ (带失败信息) │ │ 用户手动处理 │
|
|
757
|
+
└─────────────────┘ └───────────────────┘
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
## 铁律
|
|
761
|
+
|
|
762
|
+
**不做项目分析,不许生成测试**
|
|
763
|
+
|
|
764
|
+
**前端项目必须询问 UI 测试需求**
|
|
765
|
+
|
|
766
|
+
**验证失败自动循环,无需用户手动确认**
|
|
767
|
+
|
|
768
|
+
**最大重试 3 次,超过必须暂停检查配置**
|
|
769
|
+
|
|
770
|
+
**没有失败的测试,不许写生产代码(参见 IRON-LAW 区块)**
|
|
771
|
+
|
|
772
|
+
## 红线
|
|
773
|
+
|
|
774
|
+
- 3 次生成失败 → 暂停,检查测试框架配置
|
|
775
|
+
- 不生成与现有风格不一致的测试
|
|
776
|
+
- 不跳过 UI 测试询问(前端项目)
|
|
777
|
+
- 不删除现有的通过的测试
|
|
778
|
+
- **验证必须自动判断,不得依赖用户手动确认**
|
|
779
|
+
- **验证失败自动循环,不得跳过或手动绕过**
|
|
780
|
+
- **达到 3 次重试必须暂停,不得继续生成**
|
|
781
|
+
|
|
782
|
+
## 红旗警告 - 停止并回归流程
|
|
783
|
+
|
|
784
|
+
**如果发现自己在想:**
|
|
785
|
+
- "直接生成测试,不用分析"
|
|
786
|
+
- "跳过 UI 测试询问"
|
|
787
|
+
- "测试看起来很简单,不用验证"
|
|
788
|
+
- "验证失败了,让用户手动修"
|
|
789
|
+
- "重试超过 3 次继续生成"
|
|
790
|
+
- "跳过自动验证"
|
|
791
|
+
- 只测试函数调用而不是业务场景
|
|
792
|
+
- 生成的测试与项目风格不一致
|
|
793
|
+
- "我先写实现,再补测试"
|
|
794
|
+
- "这个测试一次就能过,不用看失败"
|
|
795
|
+
- "测试代码不重要,能过就行"
|
|
796
|
+
- "边界情况太多了,只测主流程"
|
|
797
|
+
- "删除这个失败的测试用例算了"
|
|
798
|
+
- "Mock 返回什么都行,只要测试通过"
|
|
799
|
+
- 测试名字描述实现细节而非业务行为
|
|
800
|
+
- 一个测试验证多个不相关的事情
|
|
801
|
+
- 测试依赖执行顺序或共享状态
|
|
802
|
+
- 使用 `any` 类型绕过类型检查
|
|
803
|
+
|
|
804
|
+
**这些都意味着:停止。回到 Step 2 或执行自动验证循环。**
|
|
805
|
+
|
|
806
|
+
## 测试生成原则
|
|
807
|
+
|
|
808
|
+
### 业务角度测试
|
|
809
|
+
|
|
810
|
+
```
|
|
811
|
+
// ❌ 错误:测试语法
|
|
812
|
+
describe('login function', () => {
|
|
813
|
+
it('should exist', () => {
|
|
814
|
+
expect(login).toBeDefined();
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
|
|
818
|
+
// ✅ 正确:测试业务场景
|
|
819
|
+
describe('用户登录', () => {
|
|
820
|
+
it('正确密码应该成功登录', async () => {
|
|
821
|
+
const result = await login('user', 'correct-password');
|
|
822
|
+
expect(result.success).toBe(true);
|
|
823
|
+
expect(result.token).toBeDefined();
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
it('错误密码应该拒绝登录', async () => {
|
|
827
|
+
const result = await login('user', 'wrong-password');
|
|
828
|
+
expect(result.success).toBe(false);
|
|
829
|
+
expect(result.error).toBe('密码错误');
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
### 保持风格一致
|
|
835
|
+
|
|
836
|
+
- 使用项目的命名约定 (describe-it 或 test)
|
|
837
|
+
- 使用相同的断言库 (expect/assert/should)
|
|
838
|
+
- 保持文件后缀一致 (.test.ts/.spec.ts)
|
|
839
|
+
- 保持文件位置风格 (同目录或独立目录)
|
|
840
|
+
|
|
841
|
+
## 分层原则
|
|
842
|
+
|
|
843
|
+
**CLI 只负责:**
|
|
844
|
+
- 扫描项目结构
|
|
845
|
+
- 检测测试框架
|
|
846
|
+
- 运行测试验证
|
|
847
|
+
- 输出结构化 JSON 数据
|
|
848
|
+
|
|
849
|
+
**Skill AI 负责:**
|
|
850
|
+
- 分析业务逻辑
|
|
851
|
+
- 发现测试缺失
|
|
852
|
+
- 推荐测试类型
|
|
853
|
+
- 生成测试代码
|
|
854
|
+
- 处理验证失败
|
|
855
|
+
|
|
856
|
+
**反模式(禁止):**
|
|
857
|
+
```typescript
|
|
858
|
+
// ❌ 错误:CLI 硬编码推荐逻辑
|
|
859
|
+
function recommendTestFramework(projectType) {
|
|
860
|
+
if (projectType === 'typescript') return 'vitest';
|
|
861
|
+
// ...更多 if/else
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// ✅ 正确:CLI 只输出原始数据,AI 自己判断
|
|
865
|
+
// AI 看到 frameworks 数组,自己决定使用哪个
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
## 实际影响
|
|
869
|
+
|
|
870
|
+
来自测试生成实践:
|
|
871
|
+
- 业务角度测试:更易维护,更有价值
|
|
872
|
+
- 自动验证循环:减少手动调试时间
|
|
873
|
+
- 风格一致性:团队协作更顺畅
|
|
874
|
+
- 首次生成成功率:85%+
|
|
875
|
+
- 3 次循环成功率:95%+
|
|
876
876
|
</notes>
|