Skip to content

Commit fa17377

Browse files
committed
提示词文档+AI生成蓝本自测通过74/74+修复evaluate自动加return
1 parent 65ecd8b commit fa17377

5 files changed

Lines changed: 482 additions & 13 deletions

File tree

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
# 微信小程序蓝本生成提示词(给编程AI用)
2+
3+
> 本文档是给编程AI(Cascade/Cursor/Copilot等)的系统提示词,用于生成 TestPilot AI 的小程序测试蓝本(testpilot.json)。
4+
> 编程AI在生成蓝本时**必须严格遵守**以下所有规则,否则执行器会报错。
5+
6+
---
7+
8+
## 一、蓝本JSON结构
9+
10+
```json
11+
{
12+
"app_name": "应用名称",
13+
"description": "应用功能描述",
14+
"base_url": "miniprogram://绝对路径/到/小程序项目目录",
15+
"version": "1.0",
16+
"platform": "miniprogram",
17+
"pages": [
18+
{
19+
"url": "/pages/xxx/xxx",
20+
"title": "页面标题",
21+
"description": "页面功能描述",
22+
"scenarios": [
23+
{
24+
"name": "场景名称",
25+
"description": "场景描述",
26+
"steps": [
27+
{ "action": "步骤类型", "target": "选择器", "value": "", "expected": "预期", "description": "描述" }
28+
]
29+
}
30+
]
31+
}
32+
]
33+
}
34+
```
35+
36+
**结构规则:**
37+
- `pages`数组:每个元素代表一个页面,包含`url``title``description``scenarios`
38+
- `scenarios`数组:每个元素代表一个测试场景,包含`name``description``steps`
39+
- `steps`数组:每个元素是一个测试步骤
40+
- 每个步骤必须有`action`字段,其余字段根据action类型决定是否必填
41+
42+
---
43+
44+
## 二、可用步骤类型(共15种)
45+
46+
### 2.1 页面导航
47+
48+
| action | 用途 | 必填字段 | 说明 |
49+
|--------|------|---------|------|
50+
| `navigate` | reLaunch跳页面(清空页面栈) | value=页面路径 |`/pages/index/index` |
51+
| `navigate_to` | navigateTo跳页面(保留页面栈) | value=页面路径 | 可以返回上一页 |
52+
| `reset_state` | 重置全局状态+回首页 | 无(可选value自定义重置代码) | **每个场景的第一步必须是这个** |
53+
54+
### 2.2 元素交互
55+
56+
| action | 用途 | 必填字段 | 说明 |
57+
|--------|------|---------|------|
58+
| `click` | 点击元素 | target=CSS选择器 |`#btn-add``.btn-primary` |
59+
| `tap_multiple` | 连续点击N次 | target=选择器, value=次数 | 如点击加购按钮12次 |
60+
| `fill` | 输入文本 | target=选择器, value=文本 | 用于input元素 |
61+
| `scroll` | 滚动页面 | value=滚动距离(px) | 默认400 |
62+
63+
### 2.3 数据读取和查询
64+
65+
| action | 用途 | 必填字段 | 说明 |
66+
|--------|------|---------|------|
67+
| `read_text` | 读取元素文本(带3次重试) | target=选择器 | 可选expected做包含断言 |
68+
| `page_query` | 查询元素(Node端automator API) | target=选择器, value=操作类型 | 操作类型见下方详解 |
69+
| `evaluate` | 在小程序端执行JavaScript | value=JS代码 | ⚠️ 有严格格式要求,见铁律 |
70+
| `call_method` | 调用页面方法 | target=方法名, value=参数JSON | 如调用 `onSearch` |
71+
72+
### 2.4 断言
73+
74+
| action | 用途 | 必填字段 | 说明 |
75+
|--------|------|---------|------|
76+
| `assert_text` | 文本包含断言 | target=选择器, expected=预期文本 | 验证元素文本包含expected |
77+
| `assert_compare` | 数值比较断言 | target=选择器, value=比较表达式 |`<=10``==0``>=100` |
78+
79+
### 2.5 辅助
80+
81+
| action | 用途 | 必填字段 | 说明 |
82+
|--------|------|---------|------|
83+
| `screenshot` | 截图 || description会作为截图标注 |
84+
| `wait` | 等待 | value=毫秒数 |`500``2000` |
85+
86+
---
87+
88+
## 三、page_query 详解
89+
90+
`page_query` 在Node.js端使用 miniprogram-automator 的 `page.$``page.$$` API查询元素。
91+
92+
**value字段的三种操作:**
93+
- `"text"` — 读取单个元素的文本(默认)
94+
- `"count"` — 统计匹配元素的数量
95+
- `"texts"` — 读取所有匹配元素的文本数组
96+
97+
**示例:**
98+
```json
99+
{"action": "page_query", "target": ".product", "value": "count", "description": "统计商品数量"}
100+
{"action": "page_query", "target": ".p-price", "value": "texts", "description": "读取所有价格"}
101+
{"action": "page_query", "target": ".btn-checkout", "value": "count", "expected": "0", "description": "验证结算按钮不存在"}
102+
```
103+
104+
---
105+
106+
## 四、⚠️ 铁律(违反必报错)
107+
108+
### 铁律1:evaluate的代码格式
109+
110+
**正确格式(两种):**
111+
112+
**简单表达式(无声明语句):**
113+
```json
114+
{"action": "evaluate", "value": "getApp().globalData.products.length"}
115+
```
116+
117+
**复杂逻辑(有const/let/var/for)必须用IIFE包裹:**
118+
```json
119+
{"action": "evaluate", "value": "(() => { const app=getApp(); app.globalData.cart=[]; return 'ok'; })()"}
120+
```
121+
122+
**❌ 错误格式(会报错):**
123+
```json
124+
{"action": "evaluate", "value": "const g = getApp().globalData; g.cart = [];"}
125+
{"action": "evaluate", "value": "var x = 1; return x;"}
126+
```
127+
128+
**原因:** 执行器用 `new Function(代码)` 构造函数传给 `mp.evaluate()`。裸声明语句在函数体内执行时,automator的字符串序列化会出问题。IIFE或简单表达式则没问题。
129+
130+
### 铁律2:小程序没有document对象
131+
132+
**❌ 绝对不能在evaluate里用:**
133+
- `document.querySelector()`
134+
- `document.getElementById()`
135+
- `document.getElementsByClassName()`
136+
- 任何DOM API
137+
138+
**✅ evaluate里只能用:**
139+
- `getApp()` — 获取App实例
140+
- `getApp().globalData` — 读写全局数据
141+
- `getCurrentPages()` — 获取当前页面栈
142+
- `wx.xxx` — 微信API(如 `wx.reLaunch``wx.navigateTo`
143+
144+
**✅ 查询页面元素用 `page_query``read_text`**
145+
```json
146+
{"action": "page_query", "target": ".product", "value": "count"}
147+
{"action": "read_text", "target": "#price-1"}
148+
```
149+
150+
### 铁律3:每个场景必须以reset_state开头
151+
152+
```json
153+
{
154+
"name": "场景N:xxx验证",
155+
"steps": [
156+
{"action": "reset_state", "description": "重置状态回首页"},
157+
... 后续步骤
158+
]
159+
}
160+
```
161+
162+
`reset_state` 做了三件事:
163+
1. 清空全局状态(购物车、优惠券、地址等)
164+
2. `wx.reLaunch` 回首页
165+
3. 等待2秒让页面渲染完成
166+
167+
**不加reset_state会导致:** 上一个场景的残留数据影响当前场景。
168+
169+
### 铁律4:跨页面测试必须用navigate_to
170+
171+
不能在首页场景里直接读取购物车页的元素。需要:
172+
```json
173+
{"action": "navigate_to", "value": "/pages/cart/cart", "description": "跳转购物车"},
174+
{"action": "read_text", "target": "#subtotal", "description": "读取总计"}
175+
```
176+
177+
### 铁律5:call_method的参数必须是JSON字符串
178+
179+
```json
180+
{"action": "call_method", "target": "onSearch", "value": "{\"detail\":{\"value\":\"苹果\"}}"}
181+
{"action": "call_method", "target": "onDeliveryChange", "value": "{\"detail\":{\"value\":0}}"}
182+
```
183+
184+
注意value是**字符串**,里面是合法JSON,双引号需要转义为`\"`
185+
186+
### 铁律6:assert_compare的格式
187+
188+
`value` 字段格式为 `运算符+数字`(中间无空格):
189+
```json
190+
{"action": "assert_compare", "target": "#cartCount", "value": "<=10"}
191+
{"action": "assert_compare", "target": "#deliveryFee", "value": "==0"}
192+
{"action": "assert_compare", "target": "#total", "value": ">=100"}
193+
```
194+
195+
支持的运算符:`==``!=``<``<=``>``>=`
196+
197+
### 铁律7:选择器必须是小程序wxml中实际存在的
198+
199+
小程序用的是CSS选择器语法,但针对的是wxml中的class和id:
200+
- `#price-1` — id选择器
201+
- `.btn-primary` — class选择器
202+
- `.product .p-name` — 后代选择器
203+
- `#product-7 .btn-primary` — 组合选择器
204+
205+
**生成蓝本前必须先阅读wxml文件**,确认选择器存在。
206+
207+
---
208+
209+
## 五、踩坑记录(曾经导致失败的错误)
210+
211+
### 踩坑1:evaluate用字符串传声明语句
212+
```
213+
错误:mp.evaluate("var g = getApp()...")
214+
报错:Unexpected token 'var'
215+
原因:automator字符串evaluate不支持声明语句
216+
修复:用IIFE包裹 (() => { ... })()
217+
```
218+
219+
### 踩坑2:evaluate用字符串传URL路径
220+
```
221+
错误:mp.evaluate(`wx.reLaunch({ url: "${url}" })`)
222+
报错:Arg string terminates parameters early
223+
原因:URL中的/字符导致automator字符串解析中断
224+
修复:执行器已改用new Function,蓝本里的evaluate不需要写wx.reLaunch
225+
```
226+
227+
### 踩坑3:evaluate里用document.querySelector
228+
```
229+
错误:evaluate里写 document.querySelector('.price')
230+
报错:document is not defined
231+
原因:小程序环境没有DOM,不是浏览器
232+
修复:改用page_query步骤读取元素
233+
```
234+
235+
### 踩坑4:callMethod('onShow')超时
236+
```
237+
错误:reset_state里调用 homePage.callMethod('onShow')
238+
现象:后续步骤卡死100秒
239+
原因:SDK方法会超时
240+
修复:去掉callMethod,reLaunch+sleep(2000)足够
241+
```
242+
243+
### 踩坑5:空购物车点不存在的按钮
244+
```
245+
错误:空购物车时点击 .btn-checkout
246+
报错:元素未找到: .btn-checkout
247+
原因:空购物车时wx:if条件为false,按钮不渲染
248+
修复:用page_query检查count==0验证按钮不存在
249+
```
250+
251+
### 踩坑6:场景间状态污染
252+
```
253+
错误:场景2没有reset_state,上一场景的购物车数据还在
254+
现象:断言失败,数据不符合预期
255+
修复:每个场景第一步必须reset_state
256+
```
257+
258+
---
259+
260+
## 六、蓝本生成示例任务
261+
262+
### 任务描述给AI的格式
263+
264+
```
265+
请为以下微信小程序生成测试蓝本(testpilot.json):
266+
267+
项目路径:D:/projects/TestPilotAI/miniprogram-demo
268+
页面文件:
269+
- pages/index/index.wxml(首页)
270+
- pages/cart/cart.wxml(购物车)
271+
- pages/checkout/checkout.wxml(结算页)
272+
273+
[这里粘贴wxml和js文件的完整内容]
274+
275+
请严格按照 TestPilot AI 小程序蓝本格式生成,遵守所有铁律。
276+
要求:
277+
1. 每个场景以reset_state开头
278+
2. evaluate用IIFE格式
279+
3. 不使用document对象
280+
4. 选择器来自wxml中实际的id和class
281+
5. 覆盖尽可能多的业务逻辑和边界情况
282+
```
283+
284+
---
285+
286+
## 七、附:执行器步骤类型与执行环境对照
287+
288+
| 步骤类型 | 执行环境 | 能访问什么 |
289+
|---------|---------|-----------|
290+
| `evaluate` | 小程序端(微信JS沙箱) | `getApp()``wx.xxx``getCurrentPages()` |
291+
| `page_query` | Node.js端(automator) | `page.$``page.$$`、元素的`.text()` |
292+
| `read_text` | Node.js端(automator) | `page.$``.text()`,带3次重试 |
293+
| `call_method` | automator桥接 | 调用页面实例方法 |
294+
| `click`/`tap_multiple` | automator桥接 | `page.$``.tap()` |
295+
| `navigate`/`navigate_to` | 小程序端(通过new Function) | `wx.reLaunch`/`wx.navigateTo` |
296+
| `reset_state` | 小程序端+automator | 清全局数据+reLaunch回首页 |
297+
| `assert_text`/`assert_compare` | Node.js端 | 读元素文本做断言 |
298+
| `screenshot` | automator | 截图保存到screenshots目录 |
299+

0 commit comments

Comments
 (0)