Skip to content

Commit ad0cf8e

Browse files
committed
fix: flow模式引擎修复+提示词强化 (v1.2.8)
- 引擎: flow非首场景navigate自动跳过,标记passed - web.md: 新增React组件名选择器陷阱警告 - web.md: 新增flow非首场景禁止冗余登录步骤规则 - rulesInjector: 通用规则追加flow冗余步骤禁令+自检项 - 模板版本56, 插件版本1.2.71.2.8
1 parent e2b0e1e commit ad0cf8e

6 files changed

Lines changed: 130 additions & 4 deletions

File tree

extension/esbuild.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ esbuild.build({
1515
}).then(() => {
1616
// 自动同步到所有已安装的 IDE 扩展目录(开发便利)
1717
const home = process.env.USERPROFILE || "";
18-
const extName = "testpilot-ai.testpilot-ai-1.2.7";
18+
const extName = "testpilot-ai.testpilot-ai-1.2.8";
1919
const ideDirs = [
2020
path.join(home, ".vscode", "extensions", extName),
2121
path.join(home, ".trae", "extensions", extName),

extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "testpilot-ai",
33
"displayName": "TestPilot AI",
44
"description": "AI驱动的自动化测试机器人 — 像人类一样操作UI、发现Bug、自动修复",
5-
"version": "1.2.7",
5+
"version": "1.2.8",
66
"publisher": "testpilot-ai",
77
"engines": {
88
"vscode": "^1.85.0"

extension/src/rulesInjector.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function detectAllIDEs(): string[] {
8181
* 模板版本号。每次更新模板内容时递增。
8282
* rulesInjector 会检测已注入文件的版本号,低于此版本则自动更新。
8383
*/
84-
const TEMPLATE_VERSION = 5;
84+
const TEMPLATE_VERSION = 6;
8585

8686
/** 从文件内容中提取版本号,找不到返回 0(旧版无版本标记) */
8787
function extractVersion(content: string): number {
@@ -276,6 +276,11 @@ function getTemplateContent(): string {
276276
277277
**注意看:** 只有第1个场景做了完整的登录流程,后续场景直接在当前页面操作。navigate 步骤仍然保留(方便单独运行),但 flow 模式下引擎会自动跳过。
278278
279+
**🚨 flow 非首场景禁止冗余步骤(必须遵守!):**
280+
- flow 第2个及之后的场景,navigate 后面**直接写该场景自己的操作步骤**
281+
- **绝对禁止**在非首场景中重复写 wait→fill用户名→fill密码→click登录 等登录步骤
282+
- 引擎跳过 navigate 后从第2步开始执行,如果第2步是 \`fill 用户名\` 但页面已登录 → 找不到输入框 → 连续超时失败 → 场景被熔断
283+
279284
### flow 模式的行为
280285
281286
| 行为 | \`flow: false\`(默认) | \`flow: true\` |
@@ -291,6 +296,7 @@ function getTemplateContent(): string {
291296
生成或修改蓝本后,**按顺序**逐项检查:
292297
293298
- [ ] **【最重要】每个 page 都做了 flow 决策**:多场景共享登录状态 → \`"flow": true\`;需要干净状态的独立测试 → 不写 flow
299+
- [ ] **flow 非首场景没有冗余步骤**:只写 navigate + 该场景自己的操作,不重复登录流程
294300
- [ ] 所有用户可交互功能都有对应场景
295301
- [ ] 每个场景的第一步是 navigate(flow 模式下引擎自动跳过非首场景的 navigate)
296302
- [ ] \`platform\` 字段正确

extension/templates/platforms/web.md

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- TestPilot-Template-Version: 5 -->
1+
<!-- TestPilot-Template-Version: 6 -->
22
# Web 平台蓝本规则(platform = "web")
33

44
> 本文件定义 Web 应用(React/Vue/Angular/纯HTML)蓝本的完整规则。
@@ -95,8 +95,23 @@
9595
3. **`.class`** — 稳定 class,如 `.submit-btn``.nav-link`
9696
4. **组合选择器** — 缩小范围,如 `.form-login #username`
9797

98+
### 🚨 React/Vue/Angular 组件名陷阱(必读!)
99+
100+
**JSX/模板中的自定义组件名(如 `<Select>``<Modal>``<Dropdown>``<DatePicker>`)不会出现在渲染后的 DOM class 中!**
101+
102+
AI 常犯的错误:看到代码里 `<Select>` 组件就写 `div[class*='Select'] button`,但实际渲染后根节点可能是 `<div class="relative">`,DOM 中根本没有 "Select" 这个 class,选择器必然超时失败。
103+
104+
| ❌ 错误(基于组件名猜测) | ✅ 正确(基于实际渲染 DOM) |
105+
|---|---|
106+
| `div[class*='Select'] button` | 打开 Select.tsx 源码,发现根节点是 `<div class="relative">`,trigger 是 `<button type="button">` → 用 `div.relative > button[type='button']` |
107+
| `div[class*='Modal']` | 打开 Modal.tsx,发现渲染 `<div class="fixed inset-0">` → 用 `.fixed.inset-0` |
108+
| `div[class*='DatePicker']` | 打开 DatePicker.tsx,发现渲染 `<div class="date-picker">` → 用 `.date-picker` |
109+
110+
**强制要求**:对每个 `target`,必须打开该组件的源文件,查看其 `return (...)` 中根元素实际渲染的 class/id,然后用实际的 class 写选择器。**绝对禁止用组件名猜测 CSS class。**
111+
98112
### 绝对禁止的选择器
99113

114+
-`div[class*='ComponentName']` — 组件名不等于 CSS class,见上方陷阱说明
100115
-`div:nth-child(N)` — 脆弱,DOM 结构变化即失效
101116
-`body > div > div > form > input` — 层级太深,随改随断
102117
-`accessibility_id:xxx` — 这是手机平台选择器,Web 不支持
@@ -255,6 +270,56 @@ Web 应用通常把登录 token 存在 localStorage/sessionStorage,**即使刷
255270

256271
**重要:** flow 场景仍需写 navigate(方便单独运行),引擎在 flow 模式下自动跳过。
257272

273+
### 🚨 flow 非首场景写法(极其重要,必须遵守!)
274+
275+
**flow 模式下,第2个及之后的场景只写 navigate + 该场景自己的操作步骤,绝对禁止重复写登录步骤!**
276+
277+
引擎会跳过非首场景的 navigate,直接从第2步开始执行。如果第2步是 `fill 用户名`,但页面此时已经登录在功能页上 → 找不到输入框 → 超时失败 → 连续3步失败 → 整个场景被熔断跳过 → 后续场景全部同样失败。
278+
279+
| ❌ 错误写法(非首场景重复登录) | ✅ 正确写法(非首场景直接操作) |
280+
|---|---|
281+
| 场景2: navigate → wait → fill用户名 → fill密码 → click登录 → wait → click选择生活账本 | 场景2: navigate → click选择生活账本 → wait → assert_text |
282+
| 场景3: navigate → wait → fill用户名 → fill密码 → click登录 → wait → click选择公司账本 | 场景3: navigate → click选择公司账本 → wait → assert_text |
283+
284+
**正确的 flow 蓝本示例:**
285+
```json
286+
{
287+
"flow": true,
288+
"scenarios": [
289+
{
290+
"name": "登录进入功能页",
291+
"steps": [
292+
{"action": "navigate", "value": "http://localhost:5173"},
293+
{"action": "wait", "value": "2000"},
294+
{"action": "fill", "target": "#username", "value": "admin"},
295+
{"action": "fill", "target": "#password", "value": "123456"},
296+
{"action": "click", "target": "#loginBtn"},
297+
{"action": "wait", "value": "2000"},
298+
{"action": "assert_text", "expected": "功能页标题"}
299+
]
300+
},
301+
{
302+
"name": "操作A",
303+
"steps": [
304+
{"action": "navigate", "value": "http://localhost:5173", "description": "flow模式下自动跳过"},
305+
{"action": "click", "target": ".action-a-btn"},
306+
{"action": "assert_text", "expected": "操作A结果"}
307+
]
308+
},
309+
{
310+
"name": "操作B",
311+
"steps": [
312+
{"action": "navigate", "value": "http://localhost:5173", "description": "flow模式下自动跳过"},
313+
{"action": "click", "target": ".action-b-btn"},
314+
{"action": "assert_text", "expected": "操作B结果"}
315+
]
316+
}
317+
]
318+
}
319+
```
320+
321+
**核心原则:flow 模式下,只有第1个场景做完整的导航+登录流程,后续场景的 navigate 后面直接写该场景自己的操作。**
322+
258323
---
259324

260325
## 七、完整 JSON 模板
@@ -316,3 +381,5 @@ Web 应用通常把登录 token 存在 localStorage/sessionStorage,**即使刷
316381
| 场景间依赖登录状态 | 后续场景全部失败 | 每个场景独立登录 |
317382
| 没有 wait 就断言异步结果 | 断言时数据还没到 | 按公式计算 wait |
318383
| 选择器用了 `div:nth-child(3)` | 页面改版就断 | 用 id 或稳定 class |
384+
| **flow 非首场景重复写登录步骤** | navigate 被跳过后第2步是 fill 用户名,但页面已登录,找不到输入框,连续失败熔断 | flow 非首场景只写 navigate + 自己的操作 |
385+
| **用组件名猜 CSS class** | `div[class*='Select']` 永远不匹配,组件实际渲染 `<div class="relative">` | 打开组件源码看实际渲染的 class |

src/testing/blueprint_runner.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,35 @@ async def run(
185185
if s.action == "assert_text" and s.expected:
186186
self._anomaly_detector.suppress_error_text(s.expected)
187187

188+
flow_first_nav_done = False # 标记本场景是否已执行过navigate
188189
for step_def in scenario.steps:
189190
step_num += 1
190191
desc = step_def.description or step_def.action
191192

193+
# flow模式:非首场景的navigate自动跳过(保持前一场景页面状态)
194+
if is_flow and sc_idx > 0 and step_def.action == "navigate":
195+
if not flow_first_nav_done:
196+
flow_first_nav_done = True
197+
logger.info(" [步骤{}/{}] navigate | ⏭️ flow模式跳过(沿用上一场景页面状态)", step_num, blueprint.total_steps)
198+
try:
199+
step_action = ActionType(step_def.action)
200+
except ValueError:
201+
step_action = ActionType.SCREENSHOT
202+
result = StepResult(
203+
step=step_num, action=step_action,
204+
description=f"[flow跳过] {desc}",
205+
status=StepStatus.PASSED, duration_seconds=0,
206+
)
207+
self._hub.on_step_passed()
208+
self._hub.record_step(
209+
step_num, step_def.action, step_def.target, step_def.value,
210+
passed=True, error=None,
211+
)
212+
all_results.append(result)
213+
if self._on_step:
214+
await self._on_step(step_num, "done", desc)
215+
continue
216+
192217
# v2.0:控制器检查(暂停/停止/单步)
193218
if self._controller:
194219
await self._controller.wait_if_paused()

开发备忘录.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3038,3 +3038,31 @@ saveBugRetryMap();
30383038

30393039
插件版本 `1.2.6 → 1.2.7`,重新打包 `testpilot-ai-1.2.7.vsix`
30403040

3041+
## 24. flow模式引擎修复 + 提示词强化(2026-03-23)
3042+
3043+
### 24.1 问题
3044+
3045+
account_book 蓝本中 app-selector/life/business 三个 page 都设了 `flow: true`,但:
3046+
1. **引擎未实现 flow 跳过 navigate**:文档说"后续场景的 navigate 自动跳过",但引擎代码中没有这个逻辑,每个场景都执行了 navigate 导航回首页
3047+
2. **蓝本非首场景写了冗余登录步骤**:flow 场景2/3/4 都写了完整的 navigate→wait→fill用户名→fill密码→click登录→wait,引擎跳过 navigate 后直接执行 fill 用户名,但页面已登录在 app-selector 页 → 找不到输入框 → 连续超时 → 熔断
3048+
3. **Select 组件选择器基于组件名猜测**`div[class*='Select'] button` 永远不匹配,实际渲染 `<div class="relative">`
3049+
3050+
### 24.2 修复
3051+
3052+
**引擎修复**`src/testing/blueprint_runner.py`):
3053+
- flow 模式 + 非首场景(sc_idx > 0)+ navigate 动作 → 自动跳过,标记 passed,日志输出"flow模式跳过"
3054+
3055+
**提示词修复**`extension/templates/platforms/web.md`):
3056+
- 新增"React/Vue/Angular 组件名陷阱"章节,明确禁止用组件名猜测 CSS class
3057+
- 新增"flow 非首场景写法"章节,明确规定非首场景只写 navigate + 该场景自己的操作,禁止重复登录
3058+
- 踩坑清单增加两条:flow 冗余登录、组件名猜 class
3059+
3060+
**通用规则修复**`extension/src/rulesInjector.ts`):
3061+
- flow 示例后追加"🚨 flow 非首场景禁止冗余步骤"警告
3062+
- 自检清单追加"flow 非首场景没有冗余步骤"检查项
3063+
- TEMPLATE_VERSION 5 → 6(触发已注入项目自动更新)
3064+
3065+
### 24.3 版本
3066+
3067+
插件版本 `1.2.7 → 1.2.8`,模板版本 `5 → 6`,打包 `testpilot-ai-1.2.8.vsix`
3068+

0 commit comments

Comments
 (0)