@creatoria/miniapp-mcp 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 +469 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +144 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/defaults.d.ts +73 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +118 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +50 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +189 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/core/element-ref.d.ts +44 -0
- package/dist/core/element-ref.d.ts.map +1 -0
- package/dist/core/element-ref.js +213 -0
- package/dist/core/element-ref.js.map +1 -0
- package/dist/core/logger.d.ts +55 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +378 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/output.d.ts +21 -0
- package/dist/core/output.d.ts.map +1 -0
- package/dist/core/output.js +56 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/report-generator.d.ts +24 -0
- package/dist/core/report-generator.d.ts.map +1 -0
- package/dist/core/report-generator.js +212 -0
- package/dist/core/report-generator.js.map +1 -0
- package/dist/core/session.d.ts +83 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +306 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/timeout.d.ts +49 -0
- package/dist/core/timeout.d.ts.map +1 -0
- package/dist/core/timeout.js +67 -0
- package/dist/core/timeout.js.map +1 -0
- package/dist/core/tool-logger.d.ts +83 -0
- package/dist/core/tool-logger.d.ts.map +1 -0
- package/dist/core/tool-logger.js +453 -0
- package/dist/core/tool-logger.js.map +1 -0
- package/dist/core/validation.d.ts +39 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +93 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +85 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/assert.d.ts +108 -0
- package/dist/tools/assert.d.ts.map +1 -0
- package/dist/tools/assert.js +291 -0
- package/dist/tools/assert.js.map +1 -0
- package/dist/tools/automator.d.ts +45 -0
- package/dist/tools/automator.d.ts.map +1 -0
- package/dist/tools/automator.js +186 -0
- package/dist/tools/automator.js.map +1 -0
- package/dist/tools/element.d.ts +253 -0
- package/dist/tools/element.d.ts.map +1 -0
- package/dist/tools/element.js +615 -0
- package/dist/tools/element.js.map +1 -0
- package/dist/tools/index.d.ts +97 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +1565 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/miniprogram.d.ts +79 -0
- package/dist/tools/miniprogram.d.ts.map +1 -0
- package/dist/tools/miniprogram.js +245 -0
- package/dist/tools/miniprogram.js.map +1 -0
- package/dist/tools/network.d.ts +65 -0
- package/dist/tools/network.d.ts.map +1 -0
- package/dist/tools/network.js +205 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/page.d.ts +108 -0
- package/dist/tools/page.d.ts.map +1 -0
- package/dist/tools/page.js +307 -0
- package/dist/tools/page.js.map +1 -0
- package/dist/tools/record.d.ts +86 -0
- package/dist/tools/record.d.ts.map +1 -0
- package/dist/tools/record.js +316 -0
- package/dist/tools/record.js.map +1 -0
- package/dist/tools/snapshot.d.ts +82 -0
- package/dist/tools/snapshot.d.ts.map +1 -0
- package/dist/tools/snapshot.js +258 -0
- package/dist/tools/snapshot.js.map +1 -0
- package/dist/types.d.ts +240 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/docs/SIMPLE_USAGE.md +210 -0
- package/docs/api/README.md +244 -0
- package/docs/api/assert.md +1015 -0
- package/docs/api/automator.md +345 -0
- package/docs/api/element.md +1454 -0
- package/docs/api/miniprogram.md +558 -0
- package/docs/api/network.md +883 -0
- package/docs/api/page.md +909 -0
- package/docs/api/record.md +963 -0
- package/docs/api/snapshot.md +792 -0
- package/docs/architecture.E-Docs.md +1359 -0
- package/docs/architecture.F1.md +720 -0
- package/docs/architecture.F2.md +871 -0
- package/docs/architecture.F3.md +905 -0
- package/docs/architecture.md +90 -0
- package/docs/charter.A1.align.yaml +170 -0
- package/docs/charter.A2.align.yaml +199 -0
- package/docs/charter.A3.align.yaml +242 -0
- package/docs/charter.A4.align.yaml +227 -0
- package/docs/charter.B1.align.yaml +179 -0
- package/docs/charter.B2.align.yaml +200 -0
- package/docs/charter.B3.align.yaml +200 -0
- package/docs/charter.B4.align.yaml +188 -0
- package/docs/charter.C1.align.yaml +190 -0
- package/docs/charter.C2.align.yaml +202 -0
- package/docs/charter.C3.align.yaml +211 -0
- package/docs/charter.C4.align.yaml +263 -0
- package/docs/charter.C5.align.yaml +220 -0
- package/docs/charter.D1.align.yaml +190 -0
- package/docs/charter.D2.align.yaml +234 -0
- package/docs/charter.D3.align.yaml +206 -0
- package/docs/charter.E-Docs.align.yaml +294 -0
- package/docs/charter.F1.align.yaml +193 -0
- package/docs/charter.F2.align.yaml +248 -0
- package/docs/charter.F3.align.yaml +287 -0
- package/docs/charter.G.align.yaml +174 -0
- package/docs/charter.align.yaml +111 -0
- package/docs/examples/session-report-usage.md +449 -0
- package/docs/maintenance.md +682 -0
- package/docs/playwright-mcp/350/260/203/347/240/224.md +53 -0
- package/docs/setup-guide.md +775 -0
- package/docs/tasks.A1.atomize.md +296 -0
- package/docs/tasks.A2.atomize.md +408 -0
- package/docs/tasks.A3.atomize.md +564 -0
- package/docs/tasks.A4.atomize.md +496 -0
- package/docs/tasks.B1.atomize.md +352 -0
- package/docs/tasks.B2.atomize.md +561 -0
- package/docs/tasks.B3.atomize.md +508 -0
- package/docs/tasks.B4.atomize.md +504 -0
- package/docs/tasks.C1.atomize.md +540 -0
- package/docs/tasks.C2.atomize.md +665 -0
- package/docs/tasks.C3.atomize.md +745 -0
- package/docs/tasks.C4.atomize.md +908 -0
- package/docs/tasks.C5.atomize.md +755 -0
- package/docs/tasks.D1.atomize.md +547 -0
- package/docs/tasks.D2.atomize.md +619 -0
- package/docs/tasks.D3.atomize.md +790 -0
- package/docs/tasks.E-Docs.atomize.md +1204 -0
- package/docs/tasks.atomize.md +189 -0
- package/docs/troubleshooting.md +855 -0
- package/docs//345/256/214/346/225/264/345/256/236/347/216/260/346/226/271/346/241/210.md +155 -0
- package/docs//345/274/200/345/217/221/344/273/273/345/212/241/350/256/241/345/210/222.md +110 -0
- package/docs//345/276/256/344/277/241/345/260/217/347/250/213/345/272/217/350/207/252/345/212/250/345/214/226API/345/256/214/346/225/264/346/226/207/346/241/243.md +894 -0
- package/docs//345/276/256/344/277/241/345/260/217/347/250/213/345/272/217/350/207/252/345/212/250/345/214/226/345/256/214/346/225/264/346/223/215/344/275/234/346/211/213/345/206/214.md +1885 -0
- package/docs//346/216/245/345/217/243/346/226/271/346/241/210.md +565 -0
- package/docs//347/254/254/344/270/200/347/211/210/346/234/254/346/226/271/346/241/210.md +380 -0
- package/package.json +87 -0
|
@@ -0,0 +1,894 @@
|
|
|
1
|
+
# 微信小程序自动化 API 完整文档
|
|
2
|
+
|
|
3
|
+
> 基于官方文档整理:https://developers.weixin.qq.com/miniprogram/dev/devtools/auto/quick-start.html
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
- [快速入门](#快速入门)
|
|
8
|
+
- [Automator API](#automator-api)
|
|
9
|
+
- [MiniProgram API](#miniprogram-api)
|
|
10
|
+
- [Page API](#page-api)
|
|
11
|
+
- [Element API](#element-api)
|
|
12
|
+
- [脚本示例](#脚本示例)
|
|
13
|
+
- [真机自动化](#真机自动化)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 快速入门
|
|
18
|
+
|
|
19
|
+
### 运行环境
|
|
20
|
+
|
|
21
|
+
- 安装 Node.js 并且版本大于 8.0
|
|
22
|
+
- 基础库版本为 `2.7.3` 及以上
|
|
23
|
+
- 开发者工具版本为 `1.02.1907232` 及以上
|
|
24
|
+
|
|
25
|
+
### 安装
|
|
26
|
+
|
|
27
|
+
使用小程序自动化 SDK,直接执行以下命令:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm i miniprogram-automator --save-dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 使用
|
|
34
|
+
|
|
35
|
+
首先开启工具安全设置中的 CLI/HTTP 调用功能。
|
|
36
|
+
|
|
37
|
+
> 必须开启以上选项,否则 SDK 将无法正常启动工具自动化功能。
|
|
38
|
+
|
|
39
|
+
然后直接引入 SDK 开始编写控制脚本,参考下边例子:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
const automator = require('miniprogram-automator')
|
|
43
|
+
|
|
44
|
+
automator.launch({
|
|
45
|
+
cliPath: 'path/to/cli', // 工具 cli 位置,如果你没有更改过默认安装位置,可以忽略此项
|
|
46
|
+
projectPath: 'path/to/project', // 项目文件地址
|
|
47
|
+
}).then(async miniProgram => {
|
|
48
|
+
const page = await miniProgram.reLaunch('/page/component/index')
|
|
49
|
+
await page.waitFor(500)
|
|
50
|
+
const element = await page.$('.kind-list-item-hd')
|
|
51
|
+
console.log(await element.attribute('class'))
|
|
52
|
+
await element.tap()
|
|
53
|
+
await miniProgram.close()
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
最后执行 `node path/to/script` 即可看到输出结果。
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Automator API
|
|
62
|
+
|
|
63
|
+
Automator 模块提供了启动及连接开发者工具的方法。
|
|
64
|
+
|
|
65
|
+
### automator.connect
|
|
66
|
+
|
|
67
|
+
连接开发者工具。
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
automator.connect(options: Object): Promise<MiniProgram>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### 参数说明
|
|
74
|
+
|
|
75
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
|
76
|
+
|------|------|------|--------|------|
|
|
77
|
+
| wsEndpoint | string | 是 | - | 开发者工具 WebSocket 地址 |
|
|
78
|
+
|
|
79
|
+
开发者工具开启自动化功能可以通过命令行调用:
|
|
80
|
+
|
|
81
|
+
- `--auto <project_root>`:打开指定项目并开启自动化功能
|
|
82
|
+
- `--auto-port <port>`:指定自动化监听端口
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cli --auto /Users/username/demo --auto-port 9420
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 示例代码
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
automator.connect({
|
|
92
|
+
wsEndpoint: 'ws://localhost:9420'
|
|
93
|
+
}).then(async miniProgram => {
|
|
94
|
+
const page = await miniProgram.navigateTo('/page/component/index')
|
|
95
|
+
await page.setData({})
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### automator.launch
|
|
100
|
+
|
|
101
|
+
启动并连接开发者工具。
|
|
102
|
+
|
|
103
|
+
> 确保工具安全设置中已开启 CLI/HTTP 调用功能。
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
automator.launch(options: Object): Promise<MiniProgram>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### 参数说明
|
|
110
|
+
|
|
111
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
|
112
|
+
|------|------|------|--------|------|
|
|
113
|
+
| cliPath | string | 否 | - | 开发者工具命令行工具绝对路径 |
|
|
114
|
+
| projectPath | string | 是 | - | 项目绝对路径 |
|
|
115
|
+
| timeout | number | 否 | 30000 | 启动最长等待时间 |
|
|
116
|
+
| port | number | 否 | - | WebSocket 端口号 |
|
|
117
|
+
| account | string | 否 | - | 用户 openid |
|
|
118
|
+
| projectConfig | Object | 否 | - | 覆盖 project.config.json 中的配置 |
|
|
119
|
+
| ticket | string | 否 | - | 开发者工具登录票据 |
|
|
120
|
+
|
|
121
|
+
cliPath 未设置时将会在以下几个位置尝试寻找:
|
|
122
|
+
|
|
123
|
+
- Mac:`/Applications/wechatwebdevtools.app/Contents/MacOS/cli`
|
|
124
|
+
- Win:`C:/Program Files (x86)/Tencent/微信web开发者工具/cli.bat`
|
|
125
|
+
|
|
126
|
+
#### 示例代码
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
automator.launch({
|
|
130
|
+
cliPath: 'path/to/cli',
|
|
131
|
+
projectPath: 'path/to/project',
|
|
132
|
+
projectConfig: {
|
|
133
|
+
setting: {
|
|
134
|
+
autoAudits: true,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
}).then(async miniProgram => {
|
|
138
|
+
const page = await miniProgram.navigateTo('/page/component/index')
|
|
139
|
+
await page.setData({})
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## MiniProgram API
|
|
146
|
+
|
|
147
|
+
MiniProgram 模块提供了控制小程序的方法。
|
|
148
|
+
|
|
149
|
+
### 方法
|
|
150
|
+
|
|
151
|
+
#### miniProgram.pageStack
|
|
152
|
+
|
|
153
|
+
获取小程序页面堆栈。
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
miniProgram.pageStack(): Promise<Page[]>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### miniProgram.navigateTo
|
|
160
|
+
|
|
161
|
+
保留当前页面,跳转到应用内的某个页面,同 `wx.navigateTo`。
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
miniProgram.navigateTo(url: string): Promise<Page>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
|
168
|
+
|------|------|------|--------|------|
|
|
169
|
+
| url | string | 是 | - | 需要跳转的应用内非 tabBar 的页面的路径 |
|
|
170
|
+
|
|
171
|
+
#### miniProgram.redirectTo
|
|
172
|
+
|
|
173
|
+
关闭当前页面,跳转到应用内的某个页面,同 `wx.redirectTo`。
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
miniProgram.redirectTo(url: string): Promise<Page>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### miniProgram.navigateBack
|
|
180
|
+
|
|
181
|
+
关闭当前页面,返回上一页面或多级页面,同 `wx.navigateBack`。
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
miniProgram.navigateBack(): Promise<Page>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### miniProgram.reLaunch
|
|
188
|
+
|
|
189
|
+
关闭所有页面,打开到应用内的某个页面,同 `wx.reLaunch`。
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
miniProgram.reLaunch(url: string): Promise<Page>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### miniProgram.switchTab
|
|
196
|
+
|
|
197
|
+
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面,同 `wx.switchTab`。
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
miniProgram.switchTab(url: string): Promise<Page>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### miniProgram.currentPage
|
|
204
|
+
|
|
205
|
+
获取当前页面。
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
miniProgram.currentPage(): Promise<Page>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### miniProgram.systemInfo
|
|
212
|
+
|
|
213
|
+
获取系统信息,同 `wx.getSystemInfo`。
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
miniProgram.systemInfo(): Promise<Object>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### miniProgram.callWxMethod
|
|
220
|
+
|
|
221
|
+
调用 wx 对象上的指定方法。
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
miniProgram.callWxMethod(method: string, ...args: any[]): Promise<any>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|
|
228
|
+
|------|------|------|--------|------|
|
|
229
|
+
| method | string | 是 | - | 需要调用的方法名 |
|
|
230
|
+
| ...args | array<any> | 否 | - | 方法参数 |
|
|
231
|
+
|
|
232
|
+
调用异步方法时无需传入 success 及 fail 回调函数。
|
|
233
|
+
|
|
234
|
+
#### miniProgram.mockWxMethod
|
|
235
|
+
|
|
236
|
+
覆盖 wx 对象上指定方法的调用结果。
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
miniProgram.mockWxMethod(method: string, result: any): Promise<void>
|
|
240
|
+
miniProgram.mockWxMethod(method: string, fn: Function | string, ...args: any[]): Promise<void>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### miniProgram.restoreWxMethod
|
|
244
|
+
|
|
245
|
+
重置 wx 指定方法,消除 mockWxMethod 调用的影响。
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
miniProgram.restoreWxMethod(method: string): Promise<void>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### miniProgram.evaluate
|
|
252
|
+
|
|
253
|
+
往 AppService 注入代码片段并返回执行结果。
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
miniProgram.evaluate(appFunction: Function | string, ...args: any[]): Promise<any>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### miniProgram.pageScrollTo
|
|
260
|
+
|
|
261
|
+
将页面滚动到目标位置,同 `wx.pageScrollTo`。
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
miniProgram.pageScrollTo(scrollTop: number): Promise<void>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### miniProgram.screenshot
|
|
268
|
+
|
|
269
|
+
对当前页面截图,目前只有开发者工具模拟器支持,客户端无法使用。
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
miniProgram.screenshot(options?: Object): Promise<string | void>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### miniProgram.exposeFunction
|
|
276
|
+
|
|
277
|
+
在 AppService 全局暴露方法,供小程序侧调用测试脚本中的方法。
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
miniProgram.exposeFunction(name: string, bindingFunction: Function): Promise<void>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### miniProgram.testAccounts
|
|
284
|
+
|
|
285
|
+
获取多账号调试中已添加的用户列表。
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
miniProgram.testAccounts(): Promise<Account[]>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### miniProgram.remote
|
|
292
|
+
|
|
293
|
+
开启工具真机调试功能。
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
miniProgram.remote(auto?: boolean): Promise<void>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
#### miniProgram.disconnect
|
|
300
|
+
|
|
301
|
+
断开与小程序运行时的连接。
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
miniProgram.disconnect(): void
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### miniProgram.close
|
|
308
|
+
|
|
309
|
+
断开与小程序运行时的连接并关闭项目窗口。
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
miniProgram.close(): Promise<void>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 事件
|
|
316
|
+
|
|
317
|
+
#### console
|
|
318
|
+
|
|
319
|
+
日志打印时触发。
|
|
320
|
+
|
|
321
|
+
传递一个 msg 参数,其字段如下:
|
|
322
|
+
|
|
323
|
+
| 字段 | 类型 | 说明 |
|
|
324
|
+
|------|------|------|
|
|
325
|
+
| type | string | 日志类型,log、info 等 |
|
|
326
|
+
| args | array<any> | 日志内容 |
|
|
327
|
+
|
|
328
|
+
#### exception
|
|
329
|
+
|
|
330
|
+
页面 JS 出错时触发。
|
|
331
|
+
|
|
332
|
+
传递一个 error 参数,其字段如下:
|
|
333
|
+
|
|
334
|
+
| 字段 | 类型 | 说明 |
|
|
335
|
+
|------|------|------|
|
|
336
|
+
| message | string | 错误信息 |
|
|
337
|
+
| stack | string | 错误堆栈 |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Page API
|
|
342
|
+
|
|
343
|
+
Page 模块提供了控制小程序页面的方法。
|
|
344
|
+
|
|
345
|
+
### 属性
|
|
346
|
+
|
|
347
|
+
#### page.path
|
|
348
|
+
|
|
349
|
+
页面路径。
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
page.path: string
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### page.query
|
|
356
|
+
|
|
357
|
+
页面参数。
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
page.query: Object
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### 方法
|
|
364
|
+
|
|
365
|
+
#### page.$
|
|
366
|
+
|
|
367
|
+
获取页面元素。
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
page.$(selector: string): Promise<Element>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### page.$$
|
|
374
|
+
|
|
375
|
+
获取页面元素数组。
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
page.$$(selector: string): Promise<Element[]>
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### page.waitFor
|
|
382
|
+
|
|
383
|
+
等待直到指定条件成立。
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
page.waitFor(condition: string | number | Function): Promise<void>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
如果条件是 string 类型,那么该参数会被当成选择器,当该选择器选中元素个数不为零时,结束等待。
|
|
390
|
+
|
|
391
|
+
如果条件是 number 类型,那么该参数会被当成超时时长,当经过指定时间后,结束等待。
|
|
392
|
+
|
|
393
|
+
如果条件是 Function 类型,那么该参数会被当成断言函数,当该函数返回真值时,结束等待。
|
|
394
|
+
|
|
395
|
+
#### page.data
|
|
396
|
+
|
|
397
|
+
获取页面渲染数据。
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
page.data(path?: string): Promise<Object>
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### page.setData
|
|
404
|
+
|
|
405
|
+
设置页面渲染数据。
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
page.setData(data: Object): Promise<void>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
#### page.size
|
|
412
|
+
|
|
413
|
+
获取页面大小。
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
page.size(): Promise<Object>
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
返回值:
|
|
420
|
+
|
|
421
|
+
| 字段 | 类型 | 说明 |
|
|
422
|
+
|------|------|------|
|
|
423
|
+
| width | number | 页面可滚动宽度 |
|
|
424
|
+
| height | number | 页面可滚动高度 |
|
|
425
|
+
|
|
426
|
+
#### page.scrollTop
|
|
427
|
+
|
|
428
|
+
获取页面滚动位置。
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
page.scrollTop(): Promise<number>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
#### page.callMethod
|
|
435
|
+
|
|
436
|
+
调用页面指定方法。
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
page.callMethod(method: string, ...args: any[]): Promise<any>
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Element API
|
|
445
|
+
|
|
446
|
+
Element 模块提供了控制小程序页面元素的方法。
|
|
447
|
+
|
|
448
|
+
### 属性
|
|
449
|
+
|
|
450
|
+
#### element.tagName
|
|
451
|
+
|
|
452
|
+
标签名,小写。
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
element.tagName: string
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### 方法
|
|
459
|
+
|
|
460
|
+
#### element.$
|
|
461
|
+
|
|
462
|
+
在元素范围内获取元素。
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
element.$(selector: string): Promise<Element>
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### element.$$
|
|
469
|
+
|
|
470
|
+
在元素范围内获取元素数组。
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
element.$$(selector: string): Promise<Element[]>
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
#### element.size
|
|
477
|
+
|
|
478
|
+
获取元素大小。
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
element.size(): Promise<Object>
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
返回值:
|
|
485
|
+
|
|
486
|
+
| 字段 | 类型 | 说明 |
|
|
487
|
+
|------|------|------|
|
|
488
|
+
| width | number | 元素宽度 |
|
|
489
|
+
| height | number | 元素高度 |
|
|
490
|
+
|
|
491
|
+
#### element.offset
|
|
492
|
+
|
|
493
|
+
获取元素绝对位置。
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
element.offset(): Promise<Object>
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
返回值:
|
|
500
|
+
|
|
501
|
+
| 字段 | 类型 | 说明 |
|
|
502
|
+
|------|------|------|
|
|
503
|
+
| left | number | 左上角 x 坐标,单位:px |
|
|
504
|
+
| top | number | 左上角 y 坐标,单位:px |
|
|
505
|
+
|
|
506
|
+
#### element.text
|
|
507
|
+
|
|
508
|
+
获取元素文本。
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
element.text(): Promise<string>
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### element.attribute
|
|
515
|
+
|
|
516
|
+
获取元素特性。
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
element.attribute(name: string): Promise<string>
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### element.property
|
|
523
|
+
|
|
524
|
+
获取元素属性。
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
element.property(name: string): Promise<any>
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
element.property 与 element.attribute 主要区别如下:
|
|
531
|
+
|
|
532
|
+
- element.attribute 获取的是标签上的值,因此它的返回类型一定是字符串,element.property 则不一定
|
|
533
|
+
- element.attribute 可以获取到 class 和 id 之类的值,element.property 不行
|
|
534
|
+
- element.property 可以获取到文档里对应组件列举的大部分属性值,比如表单 input 等组件的 value 值
|
|
535
|
+
|
|
536
|
+
#### element.wxml
|
|
537
|
+
|
|
538
|
+
获取元素 WXML。
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
element.wxml(): Promise<string>
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
#### element.outerWxml
|
|
545
|
+
|
|
546
|
+
同 wxml,只是会获取到元素本身。
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
element.outerWxml(): Promise<string>
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
#### element.value
|
|
553
|
+
|
|
554
|
+
获取元素值。
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
element.value(): Promise<string>
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
#### element.style
|
|
561
|
+
|
|
562
|
+
获取元素样式值。
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
element.style(name: string): Promise<string>
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
#### element.tap
|
|
569
|
+
|
|
570
|
+
点击元素。
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
element.tap(): Promise<void>
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### element.longpress
|
|
577
|
+
|
|
578
|
+
长按元素。
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
element.longpress(): Promise<void>
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
#### element.touchstart
|
|
585
|
+
|
|
586
|
+
手指开始触摸元素。
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
element.touchstart(options: Object): Promise<void>
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
#### element.touchmove
|
|
593
|
+
|
|
594
|
+
手指触摸元素后移动。
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
element.touchmove(options: Object): Promise<void>
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
#### element.touchend
|
|
601
|
+
|
|
602
|
+
手指结束触摸元素。
|
|
603
|
+
|
|
604
|
+
```typescript
|
|
605
|
+
element.touchend(options: Object): Promise<void>
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
#### element.trigger
|
|
609
|
+
|
|
610
|
+
触发元素事件。
|
|
611
|
+
|
|
612
|
+
```typescript
|
|
613
|
+
element.trigger(type: string, detail?: Object): Promise<void>
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
> 该方法无法改变组件状态,仅触发响应方法,也无法触发用户操作事件,即 tap,longpress 等事件,请使用对应的其它方法调用。
|
|
617
|
+
|
|
618
|
+
#### element.input
|
|
619
|
+
|
|
620
|
+
输入文本,仅 input、textarea 组件可以使用。
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
element.input(value: string): Promise<void>
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
#### element.callMethod
|
|
627
|
+
|
|
628
|
+
调用组件实例指定方法,仅自定义组件可以使用。
|
|
629
|
+
|
|
630
|
+
```typescript
|
|
631
|
+
element.callMethod(method: string, ...args: any[]): Promise<any>
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
#### element.data
|
|
635
|
+
|
|
636
|
+
获取组件实例渲染数据,仅自定义组件可以使用。
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
element.data(path?: string): Promise<Object>
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
#### element.setData
|
|
643
|
+
|
|
644
|
+
设置组件实例渲染数据,仅自定义组件可以使用。
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
element.setData(data: Object): Promise<void>
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
#### element.callContextMethod
|
|
651
|
+
|
|
652
|
+
调用上下文 Context 对象方法,仅 video 组件可以使用。
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
element.callContextMethod(method: string, ...args: any[]): Promise<any>
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
#### element.scrollWidth
|
|
659
|
+
|
|
660
|
+
获取滚动宽度,仅 scroll-view 组件可以使用。
|
|
661
|
+
|
|
662
|
+
```typescript
|
|
663
|
+
element.scrollWidth(): Promise<number>
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
#### element.scrollHeight
|
|
667
|
+
|
|
668
|
+
获取滚动高度,仅 scroll-view 组件可以使用。
|
|
669
|
+
|
|
670
|
+
```typescript
|
|
671
|
+
element.scrollHeight(): Promise<number>
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
#### element.scrollTo
|
|
675
|
+
|
|
676
|
+
滚动到指定位置,仅 scroll-view 组件可以使用。
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
element.scrollTo(x: number, y: number): Promise<void>
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
#### element.swipeTo
|
|
683
|
+
|
|
684
|
+
滑动到指定滑块,仅 swiper 组件可以使用。
|
|
685
|
+
|
|
686
|
+
```typescript
|
|
687
|
+
element.swipeTo(index: number): Promise<void>
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
#### element.moveTo
|
|
691
|
+
|
|
692
|
+
移动视图容器,仅 movable-view 组件可以使用。
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
element.moveTo(x: number, y: number): Promise<void>
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
#### element.slideTo
|
|
699
|
+
|
|
700
|
+
滑动到指定数值,仅 slider 组件可以使用。
|
|
701
|
+
|
|
702
|
+
```typescript
|
|
703
|
+
element.slideTo(value: number): Promise<void>
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## 脚本示例
|
|
709
|
+
|
|
710
|
+
小程序自动化 SDK 本身不提供测试框架。这意味着你可以将它与市面上流行的任意 Node.js 测试框架结合使用,以此来达到编写小程序测试用例的目的。接下来将使用 Jest 测试框架来编写一个实际的小程序自动化测试。
|
|
711
|
+
|
|
712
|
+
### 测试对象
|
|
713
|
+
|
|
714
|
+
这里以小程序示例为测试对象,从 GitHub 上将小程序示例的源码下载到本地,然后打开小程序工具,将该项目导入进去。
|
|
715
|
+
|
|
716
|
+
### 初始化
|
|
717
|
+
|
|
718
|
+
新建文件夹 `miniprogram-demo-test` 放置测试代码,执行以下命令安装依赖:
|
|
719
|
+
|
|
720
|
+
```bash
|
|
721
|
+
npm i miniprogram-automator jest
|
|
722
|
+
npm i jest -g
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
按照快速开始中的使用说明安装符合要求的开发者工具版本及打开安全设置 CLI/HTTP 调用功能后就可以开始编写脚本了。
|
|
726
|
+
|
|
727
|
+
### 脚本编写
|
|
728
|
+
|
|
729
|
+
现在我们准备为小程序示例的首页编写测试用例。
|
|
730
|
+
|
|
731
|
+
创建完测试文件 `index.spec.js` 后,首先要做的是:
|
|
732
|
+
|
|
733
|
+
- 启动并连接工具
|
|
734
|
+
- 重新启动小程序到首页
|
|
735
|
+
- 断开连接并关闭工具
|
|
736
|
+
|
|
737
|
+
对应脚本如下:
|
|
738
|
+
|
|
739
|
+
```javascript
|
|
740
|
+
const automator = require('miniprogram-automator')
|
|
741
|
+
|
|
742
|
+
describe('index', () => {
|
|
743
|
+
let miniProgram
|
|
744
|
+
let page
|
|
745
|
+
|
|
746
|
+
beforeAll(async () => {
|
|
747
|
+
miniProgram = await automator.launch({
|
|
748
|
+
projectPath: 'path/to/miniprogram-demo'
|
|
749
|
+
})
|
|
750
|
+
page = await miniProgram.reLaunch('/page/component/index')
|
|
751
|
+
await page.waitFor(500)
|
|
752
|
+
}, 30000)
|
|
753
|
+
|
|
754
|
+
afterAll(async () => {
|
|
755
|
+
await miniProgram.close()
|
|
756
|
+
})
|
|
757
|
+
})
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
> 工具项目窗口启动初次编译需要一定时长,Jest 默认 5 秒超时太短,需修改。
|
|
761
|
+
|
|
762
|
+
#### 1. 测试顶部描述
|
|
763
|
+
|
|
764
|
+
- 通过 .index-desc 选择器获取目标元素
|
|
765
|
+
- 目标元素应该是个 view 组件
|
|
766
|
+
- 目标元素应该包含有"以下将展示小程序官方组件能力"的文本
|
|
767
|
+
|
|
768
|
+
对应脚本如下:
|
|
769
|
+
|
|
770
|
+
```javascript
|
|
771
|
+
it('desc', async () => {
|
|
772
|
+
const desc = await page.$('.index-desc')
|
|
773
|
+
expect(desc.tagName).toBe('view')
|
|
774
|
+
expect(await desc.text()).toContain('以下将展示小程序官方组件能力')
|
|
775
|
+
})
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
#### 2. 测试列表项
|
|
779
|
+
|
|
780
|
+
- 获取列表元素集合
|
|
781
|
+
- 目标元素集的个数应该是 8 个
|
|
782
|
+
- 第一个列表元素的标题应该是"视图容器"
|
|
783
|
+
|
|
784
|
+
对应脚本如下:
|
|
785
|
+
|
|
786
|
+
```javascript
|
|
787
|
+
it('list', async () => {
|
|
788
|
+
const lists = await page.$$('.kind-list-item')
|
|
789
|
+
expect(lists.length).toBe(8)
|
|
790
|
+
const list = await lists[0].$('.kind-list-item-hd')
|
|
791
|
+
expect(await list.text()).toBe('视图容器')
|
|
792
|
+
})
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
#### 3. 测试列表项行为
|
|
796
|
+
|
|
797
|
+
- 点击列表标题应该展示或隐藏子列表
|
|
798
|
+
- 点击子列表项应该会跳转到指定页面
|
|
799
|
+
|
|
800
|
+
对应脚本如下:
|
|
801
|
+
|
|
802
|
+
```javascript
|
|
803
|
+
it('list action', async () => {
|
|
804
|
+
const listHead = await page.$('.kind-list-item-hd')
|
|
805
|
+
expect(await listHead.attribute('class')).toBe('kind-list-item-hd')
|
|
806
|
+
await listHead.tap()
|
|
807
|
+
await page.waitFor(200)
|
|
808
|
+
expect(await listHead.attribute('class')).toBe(
|
|
809
|
+
'kind-list-item-hd kind-list-item-hd-show',
|
|
810
|
+
)
|
|
811
|
+
await listHead.tap()
|
|
812
|
+
await page.waitFor(200)
|
|
813
|
+
expect(await listHead.attribute('class')).toBe('kind-list-item-hd')
|
|
814
|
+
await listHead.tap()
|
|
815
|
+
await page.waitFor(200)
|
|
816
|
+
const item = await page.$('.index-bd navigator')
|
|
817
|
+
await item.tap()
|
|
818
|
+
await page.waitFor(500)
|
|
819
|
+
expect((await miniProgram.currentPage()).path).toBe('page/component/pages/view/view')
|
|
820
|
+
})
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### 脚本执行
|
|
824
|
+
|
|
825
|
+
编写完脚本后直接执行以下脚本:
|
|
826
|
+
|
|
827
|
+
```bash
|
|
828
|
+
jest index.spec.js
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
如果看到控制台输出以下信息,说明测试成功。
|
|
832
|
+
|
|
833
|
+
```
|
|
834
|
+
PASS ./index.spec.js (5.341s)
|
|
835
|
+
index
|
|
836
|
+
√ desc (18ms)
|
|
837
|
+
√ list (14ms)
|
|
838
|
+
√ list action (1274ms)
|
|
839
|
+
|
|
840
|
+
Test Suites: 1 passed, 1 total
|
|
841
|
+
Tests: 3 passed, 3 total
|
|
842
|
+
Snapshots: 0 total
|
|
843
|
+
Time: 6.378s
|
|
844
|
+
Ran all test suites matching /index.spec.js/i.
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
---
|
|
848
|
+
|
|
849
|
+
## 真机自动化
|
|
850
|
+
|
|
851
|
+
小程序自动化除了能够控制开发者工具中的小程序模拟器,也支持通过远程调试控制真机,以达到在真机上进行自动化测试的目的。
|
|
852
|
+
|
|
853
|
+
### 运行环境
|
|
854
|
+
|
|
855
|
+
- 确保目标机器上的基础库版本为 `2.7.3` 及以上
|
|
856
|
+
|
|
857
|
+
### 使用方式
|
|
858
|
+
|
|
859
|
+
在编写完测试用例并且在工具模拟器上测试成功之后,假如想要在真机上跑自动化,可以通过以下两种方法实现。
|
|
860
|
+
|
|
861
|
+
#### 通过 SDK 启动
|
|
862
|
+
|
|
863
|
+
你可以在测试脚本开头使用 `miniProgram.remote` 接口启动工具的真机调试功能,调用成功后脚本会在控制台打印二维码。使用目标机器扫码成功连接后,脚本会继续在真机上执行下去。
|
|
864
|
+
|
|
865
|
+
脚本示例:
|
|
866
|
+
|
|
867
|
+
```javascript
|
|
868
|
+
const automator = require('miniprogram-automator')
|
|
869
|
+
|
|
870
|
+
const miniProgram = automator.launch({
|
|
871
|
+
cliPath: 'path/to/cli',
|
|
872
|
+
projectPath: 'path/to/project',
|
|
873
|
+
}).then(async miniProgram => {
|
|
874
|
+
await miniProgram.remote() // 扫码登录连接真机,在真机上执行后续测试脚本
|
|
875
|
+
const page = await miniProgram.reLaunch('/page/component/index')
|
|
876
|
+
await page.waitFor(500)
|
|
877
|
+
const element = await page.$('.kind-list-item-hd')
|
|
878
|
+
console.log(await element.attribute('class'))
|
|
879
|
+
await element.tap()
|
|
880
|
+
await miniProgram.close()
|
|
881
|
+
})
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
#### 手工启动
|
|
885
|
+
|
|
886
|
+
如果工具是打开常驻并且使用 `automator.connect` 接口进行连接,那么可以先手工启用工具的真机调试功能后再运行测试脚本,这样就可以在真机上测试小程序了。
|
|
887
|
+
|
|
888
|
+
---
|
|
889
|
+
|
|
890
|
+
## 补充说明
|
|
891
|
+
|
|
892
|
+
- 本文档基于微信小程序官方自动化文档整理
|
|
893
|
+
- 所有API均支持 Promise
|
|
894
|
+
- 更多详细信息请参考官方文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/auto/
|