speccore 8.3.149 → 8.3.151

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.
@@ -1,76 +1,104 @@
1
- # VERIFY_SPEC.yaml — 企业级 UI 冒烟测试规格(完整示例)
1
+ # VERIFY_SPEC.yaml — UI 冒烟测试规格(真实值示例版)
2
2
  # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3
3
  # 格式类型: VERIFY_SPEC 格式(scenarios + actions + assertions 结构)
4
- # 适用场景: 精细 UI 交互测试(填写表单、点击按钮、断言元素状态)
5
4
  # 对应命令:
6
- # • speccore verify --ui --spec ./tests/smoke.yaml ← 推荐,原生支持完整交互逻辑
7
- # • speccore verify --ui --config ./tests/smoke.yaml ← 兼容,自动转换为批量页面测试
8
- # 按模块过滤: speccore verify --ui --spec ./tests/smoke.yaml --module=auth
5
+ # • speccore verify --ui --spec ./tests/smoke.yaml ← 推荐
6
+ # • speccore verify --ui --config ./tests/smoke.yaml ← 兼容
7
+ # 按模块过滤: speccore verify --ui --spec ./tests/smoke.yaml --module=login
9
8
  #
10
- # ⚠️ 格式说明:
11
- # VERIFY_SPEC 格式 = scenarios + actions + assertions(本文件,支持完整交互)
12
- # TestConfig 格式 = tests + routes + type(用于批量页面/API测试,见 pr.yaml/release.yaml)
13
- # 两种格式 speccore verify --config 均可自动识别。
9
+ # 本文件所有 value / selector 均为真实示例值,使用时替换为你的实际值即可。
10
+ # 选择器建议优先使用 data-testid(最稳定),其次 name / id,避免随机 class。
14
11
  #
15
- # 本示例覆盖:
16
- # • 全部 ActionType: fill, click, select, check, uncheck, hover, focus, blur, press,
17
- # wait, navigate, screenshot, cookie, localStorage, script, scroll, upload, iframe,
18
- # waitForRequest, waitForResponse, drag
19
- # • 全部 AssertionType: visible, hidden, text, value, url, count, attribute, style, visual
20
- # • 业务模块: 登录认证 / 用户中心 / 商品 / 购物车 / 订单 / 消息通知 / 后台管理
21
12
  #
22
- # v8.3.95+ 支持: cookie / localStorage / script / scroll / upload / iframe / waitForRequest / waitForResponse / drag
13
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
14
+ # 【重要】关于"需要登录的场景"怎么处理?
15
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ #
17
+ # 本文件场景1-9 是测试"登录功能本身"的,必须走完整的登录流程。
18
+ # 场景10-42 是测试"登录后的业务功能"(如个人资料、订单、购物车),这些场景默认已登录。
19
+ #
20
+ # 你有两种方式让"业务场景"拿到登录态:
21
+ #
22
+ # 方式A: Cookie/Token 注入(推荐,最简洁)
23
+ # 把「场景13: Token注入免登录」或「场景33: Cookie注入免登录」复制到业务场景前面,
24
+ # 作为第一个场景执行。注入后同一浏览器会话内后续场景共享登录态。
25
+ # 示例顺序:
26
+ # 1. Token注入免登录(注入 accessToken + refreshToken)
27
+ # 2. 个人资料修改
28
+ # 3. 商品列表浏览
29
+ # 4. 创建订单...
30
+ #
31
+ # 方式B: 每个业务场景自己注入(最独立,适合并行执行)
32
+ # 在每个需要登录的场景的 actions 开头加 cookie 或 localStorage 注入:
33
+ # actions:
34
+ # - type: localStorage
35
+ # selector: accessToken
36
+ # value: 'Bearer eyJhbGci...'
37
+ # - type: navigate
38
+ # value: /profile
39
+ #
40
+ # 方式C: 先执行登录场景,再执行业务场景(顺序依赖)
41
+ # 把「场景1: 账号密码登录」放第一个,登录成功后同一浏览器会话内后续场景共享登录态。
42
+ # 注意: 如果登录有验证码/短信,这种方式不稳定,建议用方式A。
43
+ #
44
+ # ⚠️ 每个 scenario 独立执行,但 cookie/localStorage 在同一浏览器会话内共享。
23
45
 
24
- name: 示例项目冒烟测试(完整版)
46
+ name: 示例项目冒烟测试
25
47
  platform: h5-mobile
26
48
  url: /
27
49
 
28
- # ─────────────────────────────────────────────────────────────────────────────
29
- # 一、登录认证模块 (auth)
30
- # ─────────────────────────────────────────────────────────────────────────────
31
50
  scenarios:
51
+
52
+ # ═══════════════════════════════════════════════════════════════════════════
53
+ # 一、登录认证 (auth)
54
+ # ═══════════════════════════════════════════════════════════════════════════
55
+
32
56
  # ── 场景1: 账号密码登录 ──
57
+ # 说明: 最基础的登录方式,填写用户名密码后点击登录
58
+ # 如何替换: 把 selector 换成你页面上的真实选择器,value 换成你的测试账号
33
59
  - name: 登录-账号密码登录
34
60
  description: 模块:auth 页面:/login
35
61
  actions:
36
62
  - type: navigate
37
- value: /login
63
+ value: /login # 登录页路由
38
64
  - type: fill
39
- selector: 'input[name="username"]'
40
- value: test_user
65
+ selector: 'input[name="username"]' # 用户名输入框(换成你实际的,如 '#username' / '[data-testid="user-input"]')
66
+ value: test_user # 测试账号用户名
41
67
  - type: fill
42
- selector: 'input[name="password"]'
43
- value: test_password
68
+ selector: 'input[name="password"]' # 密码输入框
69
+ value: Test@123456 # 测试账号密码
44
70
  - type: click
45
- selector: 'button[type="submit"]'
46
- waitFor: '.dashboard-container'
71
+ selector: 'button[type="submit"]' # 登录按钮
72
+ waitFor: '.dashboard-container' # 登录成功后出现的元素(用于等待跳转完成)
47
73
  assertions:
48
74
  - type: url
49
- contains: /dashboard
75
+ contains: /dashboard # 断言 URL 跳转到控制台
50
76
  - type: visible
51
- selector: '.dashboard-container'
77
+ selector: '.dashboard-container' # 断言控制台容器可见
52
78
  - type: text
53
- selector: '.user-name'
54
- contains: test_user
79
+ selector: '.user-name' # 断言页面显示用户名
80
+ contains: test_user # 预期显示的用户名
55
81
 
56
82
  # ── 场景2: 手机号+验证码登录 ──
83
+ # 说明: 输入手机号 → 点击获取验证码 → 输入验证码 → 登录
84
+ # 如何替换: 测试环境通常有固定验证码(如123456),或需要 mock 验证码接口
57
85
  - name: 登录-手机号验证码
58
86
  description: 模块:auth 页面:/login/phone
59
87
  actions:
60
88
  - type: navigate
61
- value: /login/phone
89
+ value: /login/phone # 手机号登录页路由
62
90
  - type: fill
63
- selector: 'input[name="phone"]'
64
- value: '13800138000'
91
+ selector: 'input[name="phone"]' # 手机号输入框
92
+ value: '13800138000' # 测试手机号
65
93
  - type: click
66
- selector: '.send-code-btn'
94
+ selector: '.send-code-btn' # 获取验证码按钮
67
95
  - type: wait
68
- delay: 2000
96
+ delay: 2000 # 等待短信发送(测试环境可缩短)
69
97
  - type: fill
70
- selector: 'input[name="verifyCode"]'
71
- value: '123456'
98
+ selector: 'input[name="verifyCode"]' # 验证码输入框
99
+ value: '123456' # 测试环境固定验证码
72
100
  - type: click
73
- selector: 'button[type="submit"]'
101
+ selector: 'button[type="submit"]' # 登录按钮
74
102
  waitFor: '.dashboard-container'
75
103
  assertions:
76
104
  - type: url
@@ -79,35 +107,39 @@ scenarios:
79
107
  selector: '.dashboard-container'
80
108
 
81
109
  # ── 场景3: 微信 OAuth 登录 ──
110
+ # 说明: 点击微信登录按钮 → 跳转微信授权页 → 授权后回调
111
+ # 如何替换: 需配置微信开放平台测试账号,回调域名需与测试环境一致
82
112
  - name: 登录-微信OAuth
83
113
  description: 模块:auth 页面:/login 第三方登录
84
114
  actions:
85
115
  - type: navigate
86
- value: /login
116
+ value: /login # 登录页
87
117
  - type: click
88
- selector: '.wechat-login-btn'
118
+ selector: '.wechat-login-btn' # 微信登录按钮(如 [data-testid="wechat-login"])
89
119
  - type: waitForRequest
90
- selector: 'https://open.weixin.qq.com/connect/oauth2/authorize'
120
+ selector: 'https://open.weixin.qq.com/connect/oauth2/authorize' # 等待跳转微信授权页
91
121
  timeout: 5000
92
122
  - type: wait
93
- delay: 3000
123
+ delay: 3000 # 等待授权回调
94
124
  assertions:
95
125
  - type: url
96
- contains: wechat
126
+ contains: wechat # 断言 URL 包含微信域名
97
127
 
98
128
  # ── 场景4: 企业微信 SSO 登录 ──
129
+ # 说明: 页面内嵌 iframe 展示企业微信登录 → 填写企业 ID → 授权
130
+ # 如何替换: 企业 ID 从企业微信管理后台获取(格式: wwxxxxxxxxxxxxxxxx)
99
131
  - name: 登录-企业微信SSO
100
132
  description: 模块:auth 页面:/login/sso
101
133
  actions:
102
134
  - type: navigate
103
- value: /login/sso
135
+ value: /login/sso # SSO 登录页
104
136
  - type: iframe
105
- selector: '#sso-frame'
137
+ selector: '#sso-frame' # iframe 选择器(切换上下文到 iframe 内部)
106
138
  - type: fill
107
- selector: 'input[name="corpId"]'
108
- value: 'ww1234567890abcdef'
139
+ selector: 'input[name="corpId"]' # 企业 ID 输入框(在 iframe 内)
140
+ value: 'ww1234567890abcdef' # 企业微信企业 ID
109
141
  - type: click
110
- selector: '.sso-submit-btn'
142
+ selector: '.sso-submit-btn' # 确认按钮(在 iframe 内)
111
143
  waitFor: '.dashboard-container'
112
144
  assertions:
113
145
  - type: url
@@ -116,24 +148,28 @@ scenarios:
116
148
  selector: '.dashboard-container'
117
149
 
118
150
  # ── 场景5: 扫码登录 ──
151
+ # 说明: 进入扫码页 → 二维码渲染 → 等待扫码 → 登录成功
152
+ # 如何替换: 测试环境可用 mock 接口模拟扫码成功,避免人工操作
119
153
  - name: 登录-扫码登录
120
154
  description: 模块:auth 页面:/login/qrcode
121
155
  actions:
122
156
  - type: navigate
123
- value: /login/qrcode
157
+ value: /login/qrcode # 扫码登录页
124
158
  - type: visible
125
- selector: '.qrcode-img'
159
+ selector: '.qrcode-img' # 断言二维码图片已渲染
126
160
  - type: wait
127
- delay: 5000
161
+ delay: 5000 # 等待扫码(测试环境可 mock 缩短)
128
162
  assertions:
129
163
  - type: visible
130
164
  selector: '.qrcode-img'
131
165
  - type: attribute
132
- selector: '.qrcode-img'
133
- attribute: src
134
- contains: data:image
166
+ selector: '.qrcode-img' # 断言二维码图片
167
+ attribute: src # 检查 src 属性
168
+ contains: data:image # 包含 base64 图片数据
135
169
 
136
170
  # ── 场景6: 登录失败-密码错误 ──
171
+ # 说明: 故意输错密码,验证错误提示是否正确
172
+ # 如何替换: value 填存在的账号 + 错误的密码
137
173
  - name: 登录-密码错误提示
138
174
  description: 模块:auth 页面:/login 异常场景
139
175
  actions:
@@ -141,22 +177,23 @@ scenarios:
141
177
  value: /login
142
178
  - type: fill
143
179
  selector: 'input[name="username"]'
144
- value: test_user
180
+ value: test_user # 存在的用户名
145
181
  - type: fill
146
182
  selector: 'input[name="password"]'
147
- value: wrong_password
183
+ value: wrong_password # 故意填错密码
148
184
  - type: click
149
185
  selector: 'button[type="submit"]'
150
186
  - type: wait
151
- delay: 1000
187
+ delay: 1000 # 等待错误提示出现
152
188
  assertions:
153
189
  - type: visible
154
- selector: '.error-message'
190
+ selector: '.error-message' # 错误提示元素
155
191
  - type: text
156
192
  selector: '.error-message'
157
- contains: 密码错误
193
+ contains: 密码错误 # 根据实际文案调整(如"用户名或密码错误")
158
194
 
159
195
  # ── 场景7: 登录失败-账号锁定 ──
196
+ # 说明: 使用被锁定的账号登录,验证锁定提示
160
197
  - name: 登录-账号锁定提示
161
198
  description: 模块:auth 页面:/login 异常场景
162
199
  actions:
@@ -164,10 +201,10 @@ scenarios:
164
201
  value: /login
165
202
  - type: fill
166
203
  selector: 'input[name="username"]'
167
- value: locked_user
204
+ value: locked_user # 被锁定的测试账号
168
205
  - type: fill
169
206
  selector: 'input[name="password"]'
170
- value: any_password
207
+ value: any_password # 任意密码
171
208
  - type: click
172
209
  selector: 'button[type="submit"]'
173
210
  - type: wait
@@ -177,114 +214,122 @@ scenarios:
177
214
  selector: '.error-message'
178
215
  - type: text
179
216
  selector: '.error-message'
180
- contains: 账号已被锁定
217
+ contains: 账号已被锁定 # 根据实际文案调整
181
218
 
182
- # ── 场景8: 记住密码功能 ──
219
+ # ── 场景8: 记住密码 ──
220
+ # 说明: 勾选记住密码 → 登录 → 验证 Cookie 中写入记住密码标记
183
221
  - name: 登录-记住密码
184
222
  description: 模块:auth 页面:/login 记住密码勾选
185
223
  actions:
186
224
  - type: navigate
187
225
  value: /login
188
226
  - type: check
189
- selector: 'input[name="rememberMe"]'
227
+ selector: 'input[name="rememberMe"]' # 记住密码复选框
190
228
  - type: fill
191
229
  selector: 'input[name="username"]'
192
230
  value: test_user
193
231
  - type: fill
194
232
  selector: 'input[name="password"]'
195
- value: test_password
233
+ value: Test@123456
196
234
  - type: click
197
235
  selector: 'button[type="submit"]'
198
236
  waitFor: '.dashboard-container'
199
237
  assertions:
200
238
  - type: cookie
201
- selector: remember_me
202
- contains: 'true'
239
+ selector: remember_me # Cookie 名称
240
+ contains: 'true' # Cookie 值包含 true
203
241
 
204
242
  # ── 场景9: 退出登录 ──
243
+ # 说明: 点击用户头像展开菜单 → 点击退出 → 验证跳回登录页
205
244
  - name: 登录-退出登录
206
245
  description: 模块:auth 页面:/dashboard
207
246
  actions:
208
247
  - type: navigate
209
- value: /dashboard
248
+ value: /dashboard # 已登录后的首页
210
249
  - type: click
211
- selector: '.user-avatar'
250
+ selector: '.user-avatar' # 用户头像/菜单触发器
212
251
  - type: click
213
- selector: '.logout-btn'
252
+ selector: '.logout-btn' # 退出按钮
214
253
  - type: wait
215
- delay: 1000
254
+ delay: 1000 # 等待跳转
216
255
  assertions:
217
256
  - type: url
218
- contains: /login
257
+ contains: /login # 断言回到登录页
219
258
  - type: visible
220
- selector: '.login-form'
259
+ selector: '.login-form' # 断言登录表单可见
221
260
 
222
- # ─────────────────────────────────────────────────────────────────────────────
223
- # 二、用户中心模块 (user)
224
- # ─────────────────────────────────────────────────────────────────────────────
261
+ # ═══════════════════════════════════════════════════════════════════════════
262
+ # 二、用户中心 (user)
263
+ # ═══════════════════════════════════════════════════════════════════════════
225
264
 
226
- # ── 场景10: 个人资料修改 ──
265
+ # ── 场景10: 修改个人资料 ──
266
+ # 说明: 修改昵称、性别、邮箱,点击保存
267
+ # ⚠️ 前置条件: 用户已登录。如需登录态,参考文件开头「方式A」把「场景13: Token注入」放第一个
268
+ # select 说明: value 填 option 的 value 属性(不是显示文本)
227
269
  - name: 用户-修改个人资料
228
270
  description: 模块:user 页面:/profile/edit
229
271
  actions:
230
272
  - type: navigate
231
- value: /profile/edit
273
+ value: /profile/edit # 个人资料编辑页
232
274
  - type: fill
233
- selector: 'input[name="nickname"]'
234
- value: 新昵称测试
275
+ selector: 'input[name="nickname"]' # 昵称输入框
276
+ value: 新昵称测试 # 新昵称
235
277
  - type: select
236
- selector: 'select[name="gender"]'
237
- value: female
278
+ selector: 'select[name="gender"]' # 性别下拉框
279
+ value: female # option 的 value 值(如 female/male/unknown)
238
280
  - type: fill
239
- selector: 'input[name="email"]'
240
- value: 'newemail@example.com'
281
+ selector: 'input[name="email"]' # 邮箱输入框
282
+ value: 'newemail@example.com' # 新邮箱
241
283
  - type: click
242
- selector: '.save-profile-btn'
284
+ selector: '.save-profile-btn' # 保存按钮
243
285
  - type: wait
244
- delay: 1500
286
+ delay: 1500 # 等待保存接口返回
245
287
  assertions:
246
288
  - type: visible
247
- selector: '.toast-success'
289
+ selector: '.toast-success' # 成功提示元素
248
290
  - type: text
249
291
  selector: '.toast-success'
250
- contains: 保存成功
292
+ contains: 保存成功 # 预期提示文案
251
293
 
252
- # ── 场景11: 头像上传 ──
294
+ # ── 场景11: 上传头像 ──
295
+ # 说明: 选择本地图片文件上传,验证预览图更新
296
+ # upload 说明: value 为本地文件路径(相对项目根目录或绝对路径)
253
297
  - name: 用户-上传头像
254
298
  description: 模块:user 页面:/profile/edit 头像上传
255
299
  actions:
256
300
  - type: navigate
257
301
  value: /profile/edit
258
302
  - type: upload
259
- selector: 'input[type="file"].avatar-upload'
260
- value: ./fixtures/test-avatar.png
303
+ selector: 'input[type="file"].avatar-upload' # 文件输入框
304
+ value: ./fixtures/test-avatar.png # 本地图片路径(确保文件存在)
261
305
  - type: wait
262
- delay: 2000
306
+ delay: 2000 # 等待上传完成
263
307
  assertions:
264
308
  - type: visible
265
- selector: '.avatar-preview img'
309
+ selector: '.avatar-preview img' # 头像预览图
266
310
  - type: attribute
267
311
  selector: '.avatar-preview img'
268
- attribute: src
269
- contains: avatar
312
+ attribute: src # 断言 src 属性已更新
313
+ contains: avatar # 包含 avatar 路径
270
314
 
271
315
  # ── 场景12: 修改密码 ──
316
+ # 说明: 填写旧密码 + 新密码 + 确认密码,点击修改
272
317
  - name: 用户-修改密码
273
318
  description: 模块:user 页面:/profile/security
274
319
  actions:
275
320
  - type: navigate
276
- value: /profile/security
321
+ value: /profile/security # 安全设置页
277
322
  - type: fill
278
- selector: 'input[name="oldPassword"]'
279
- value: old_pass_123
323
+ selector: 'input[name="oldPassword"]' # 旧密码
324
+ value: OldPass123 # 当前密码
280
325
  - type: fill
281
- selector: 'input[name="newPassword"]'
282
- value: new_pass_456
326
+ selector: 'input[name="newPassword"]' # 新密码
327
+ value: NewPass456 # 新密码
283
328
  - type: fill
284
- selector: 'input[name="confirmPassword"]'
285
- value: new_pass_456
329
+ selector: 'input[name="confirmPassword"]' # 确认密码
330
+ value: NewPass456 # 与新密码保持一致
286
331
  - type: click
287
- selector: '.change-password-btn'
332
+ selector: '.change-password-btn' # 确认修改按钮
288
333
  - type: wait
289
334
  delay: 1500
290
335
  assertions:
@@ -294,100 +339,107 @@ scenarios:
294
339
  selector: '.toast-success'
295
340
  contains: 密码修改成功
296
341
 
297
- # ── 场景13: Token 注入免登录(localStorage) ──
342
+ # ── 场景13: Token 注入免登录 ──
343
+ # 说明: 直接通过 localStorage 注入 JWT,跳过登录流程
344
+ # ⚠️ 核心用途: 作为「前置场景」放在业务场景(场景10-42)之前,为后续场景提供登录态
345
+ # 适用场景: 测试环境已有固定账号,不需重复测试登录。把这个场景放第一个,后面所有场景共享登录态
298
346
  - name: 用户-Token注入免登录
299
347
  description: 模块:user 页面:/profile Token注入方式
300
348
  actions:
301
349
  - type: localStorage
302
- selector: accessToken
303
- value: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
350
+ selector: accessToken # localStorage key 名
351
+ value: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEwMDg2fQ.test' # JWT Token
304
352
  - type: localStorage
305
- selector: refreshToken
306
- value: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
353
+ selector: refreshToken # 同时注入 refreshToken
354
+ value: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoicmVmcmVzaCJ9.test'
307
355
  - type: navigate
308
- value: /profile
356
+ value: /profile # 直接访问需要登录的页面
309
357
  - type: wait
310
358
  delay: 800
311
359
  assertions:
312
360
  - type: visible
313
- selector: '.profile-header'
361
+ selector: '.profile-header' # 断言个人中心头部可见
314
362
  - type: text
315
- selector: '.username'
363
+ selector: '.username' # 断言显示用户名
316
364
  contains: test_user
317
365
 
318
- # ─────────────────────────────────────────────────────────────────────────────
319
- # 三、商品模块 (product)
320
- # ─────────────────────────────────────────────────────────────────────────────
366
+ # ═══════════════════════════════════════════════════════════════════════════
367
+ # 三、商品模块 (product)
368
+ # ═══════════════════════════════════════════════════════════════════════════
321
369
 
322
370
  # ── 场景14: 商品列表浏览 ──
371
+ # 说明: 进入商品列表 → 滚动到底部 → 验证商品数量
323
372
  - name: 商品-列表浏览
324
373
  description: 模块:product 页面:/products
325
374
  actions:
326
375
  - type: navigate
327
- value: /products
376
+ value: /products # 商品列表页
328
377
  - type: scroll
329
- selector: bottom
378
+ selector: bottom # 滚动到页面底部(触发懒加载)
330
379
  - type: wait
331
380
  delay: 1000
332
381
  assertions:
333
382
  - type: visible
334
- selector: '.product-list'
383
+ selector: '.product-list' # 商品列表容器
335
384
  - type: count
336
- selector: '.product-item'
337
- count: 10
385
+ selector: '.product-item' # 商品卡片
386
+ count: 10 # 预期至少 10 个商品
338
387
 
339
388
  # ── 场景15: 商品搜索 ──
389
+ # 说明: 输入关键词 → 按回车 → 验证搜索结果
340
390
  - name: 商品-搜索
341
391
  description: 模块:product 页面:/products 搜索功能
342
392
  actions:
343
393
  - type: navigate
344
394
  value: /products
345
395
  - type: fill
346
- selector: 'input[name="keyword"]'
347
- value: iPhone
396
+ selector: 'input[name="keyword"]' # 搜索框
397
+ value: iPhone # 搜索关键词
348
398
  - type: press
349
- key: Enter
399
+ key: Enter # 按回车触发搜索
350
400
  - type: wait
351
- delay: 1500
401
+ delay: 1500 # 等待搜索结果返回
352
402
  assertions:
353
403
  - type: visible
354
- selector: '.search-result-list'
404
+ selector: '.search-result-list' # 搜索结果列表
355
405
  - type: count
356
406
  selector: '.product-item'
357
- count: 3
407
+ count: 3 # 预期至少 3 个结果
358
408
 
359
409
  # ── 场景16: 商品详情 ──
410
+ # 说明: 点击商品标题进入详情页,验证详情信息展示
360
411
  - name: 商品-详情页
361
412
  description: 模块:product 页面:/products/:id
362
413
  actions:
363
414
  - type: navigate
364
415
  value: /products
365
416
  - type: click
366
- selector: '.product-item:first-child .product-title'
417
+ selector: '.product-item:first-child .product-title' # 点击第一个商品的标题
367
418
  - type: wait
368
419
  delay: 1000
369
420
  assertions:
370
421
  - type: visible
371
- selector: '.product-detail'
422
+ selector: '.product-detail' # 详情页容器
372
423
  - type: text
373
- selector: '.product-name'
374
- contains: iPhone
424
+ selector: '.product-name' # 商品名称
425
+ contains: iPhone # 包含搜索关键词
375
426
  - type: visible
376
- selector: '.product-price'
427
+ selector: '.product-price' # 价格元素
377
428
 
378
- # ── 场景17: 商品筛选 ──
429
+ # ── 场景17: 商品多条件筛选 ──
430
+ # 说明: 同时选择分类 + 库存状态,验证筛选结果
379
431
  - name: 商品-多条件筛选
380
432
  description: 模块:product 页面:/products 筛选功能
381
433
  actions:
382
434
  - type: navigate
383
435
  value: /products
384
436
  - type: select
385
- selector: 'select[name="category"]'
386
- value: electronics
437
+ selector: 'select[name="category"]' # 分类下拉框
438
+ value: electronics # option value(如 electronics/clothing/food)
387
439
  - type: check
388
- selector: 'input[value="inStock"]'
440
+ selector: 'input[value="inStock"]' # 仅看有库存(复选框)
389
441
  - type: click
390
- selector: '.filter-submit-btn'
442
+ selector: '.filter-submit-btn' # 确认筛选按钮
391
443
  - type: wait
392
444
  delay: 1200
393
445
  assertions:
@@ -395,155 +447,162 @@ scenarios:
395
447
  selector: '.product-list'
396
448
  - type: count
397
449
  selector: '.product-item'
398
- count: 5
450
+ count: 5 # 筛选后预期 5 个商品
399
451
 
400
452
  # ── 场景18: 商品收藏 ──
453
+ # 说明: 点击收藏按钮,验证按钮颜色变为红色(已收藏状态)
401
454
  - name: 商品-收藏/取消收藏
402
455
  description: 模块:product 页面:/products/:id 收藏功能
403
456
  actions:
404
457
  - type: navigate
405
- value: /products/123
458
+ value: /products/123 # 某个商品详情页(123 为商品 ID)
406
459
  - type: click
407
- selector: '.favorite-btn'
460
+ selector: '.favorite-btn' # 收藏按钮(空心)
408
461
  - type: wait
409
462
  delay: 500
410
463
  assertions:
411
464
  - type: style
412
- selector: '.favorite-btn'
413
- style: color
414
- value: rgb(255, 77, 79)
465
+ selector: '.favorite-btn' # 断言按钮样式变化
466
+ style: color # CSS 属性: 颜色
467
+ value: rgb(255, 77, 79) # 预期变为红色(根据实际样式调整)
415
468
 
416
- # ─────────────────────────────────────────────────────────────────────────────
417
- # 四、购物车模块 (cart)
418
- # ─────────────────────────────────────────────────────────────────────────────
469
+ # ═══════════════════════════════════════════════════════════════════════════
470
+ # 四、购物车 (cart)
471
+ # ═══════════════════════════════════════════════════════════════════════════
419
472
 
420
473
  # ── 场景19: 添加商品到购物车 ──
474
+ # 说明: 商品详情页点击加购,验证购物车角标数字更新
421
475
  - name: 购物车-添加商品
422
476
  description: 模块:cart 页面:/products/:id
423
477
  actions:
424
478
  - type: navigate
425
- value: /products/123
479
+ value: /products/123 # 商品详情页
426
480
  - type: click
427
- selector: '.add-to-cart-btn'
481
+ selector: '.add-to-cart-btn' # 加入购物车按钮
428
482
  - type: wait
429
- delay: 800
483
+ delay: 800 # 等待加购动画/接口
430
484
  assertions:
431
485
  - type: visible
432
- selector: '.cart-badge'
486
+ selector: '.cart-badge' # 购物车角标
433
487
  - type: text
434
488
  selector: '.cart-badge'
435
- contains: '1'
489
+ contains: '1' # 角标显示 1
436
490
 
437
- # ── 场景20: 购物车数量修改 ──
491
+ # ── 场景20: 修改购物车商品数量 ──
492
+ # 说明: 修改数量输入框 → 失去焦点触发计算 → 验证小计金额更新
438
493
  - name: 购物车-修改数量
439
494
  description: 模块:cart 页面:/cart
440
495
  actions:
441
496
  - type: navigate
442
- value: /cart
497
+ value: /cart # 购物车页面
443
498
  - type: fill
444
- selector: '.cart-item:first-child .quantity-input'
445
- value: '3'
499
+ selector: '.cart-item:first-child .quantity-input' # 第一个商品的数量输入框
500
+ value: '3' # 修改为 3 件
446
501
  - type: blur
447
- selector: '.cart-item:first-child .quantity-input'
502
+ selector: '.cart-item:first-child .quantity-input' # 触发 blur 事件(触发价格重算)
448
503
  - type: wait
449
504
  delay: 800
450
505
  assertions:
451
506
  - type: text
452
- selector: '.cart-item:first-child .subtotal'
453
- contains: '¥'
507
+ selector: '.cart-item:first-child .subtotal' # 小计金额
508
+ contains: '¥' # 包含人民币符号(断言金额已更新)
454
509
 
455
- # ── 场景21: 购物车结算 ──
510
+ # ── 场景21: 购物车去结算 ──
511
+ # 说明: 勾选商品 → 点击结算 → 验证跳转到结算页
456
512
  - name: 购物车-去结算
457
513
  description: 模块:cart 页面:/cart
458
514
  actions:
459
515
  - type: navigate
460
516
  value: /cart
461
517
  - type: check
462
- selector: '.cart-item:first-child .item-checkbox'
518
+ selector: '.cart-item:first-child .item-checkbox' # 勾选第一个商品
463
519
  - type: click
464
- selector: '.checkout-btn'
520
+ selector: '.checkout-btn' # 去结算按钮
465
521
  - type: wait
466
522
  delay: 1500
467
523
  assertions:
468
524
  - type: url
469
- contains: /checkout
525
+ contains: /checkout # 断言跳转到结算页
470
526
  - type: visible
471
- selector: '.checkout-form'
527
+ selector: '.checkout-form' # 结算表单
472
528
 
473
- # ── 场景22: 购物车删除商品 ──
529
+ # ── 场景22: 删除购物车商品 ──
530
+ # 说明: 点击删除按钮,验证商品被移除
474
531
  - name: 购物车-删除商品
475
532
  description: 模块:cart 页面:/cart
476
533
  actions:
477
534
  - type: navigate
478
535
  value: /cart
479
536
  - type: click
480
- selector: '.cart-item:first-child .delete-btn'
537
+ selector: '.cart-item:first-child .delete-btn' # 删除按钮
481
538
  - type: wait
482
539
  delay: 800
483
540
  assertions:
484
541
  - type: count
485
- selector: '.cart-item'
486
- count: 0
542
+ selector: '.cart-item' # 断言购物车商品数量
543
+ count: 0 # 预期为 0(空购物车)
487
544
 
488
- # ─────────────────────────────────────────────────────────────────────────────
489
- # 五、订单模块 (order)
490
- # ─────────────────────────────────────────────────────────────────────────────
545
+ # ═══════════════════════════════════════════════════════════════════════════
546
+ # 五、订单模块 (order)
547
+ # ═══════════════════════════════════════════════════════════════════════════
491
548
 
492
- # ── 场景23: 订单创建 ──
549
+ # ── 场景23: 创建订单 ──
550
+ # 说明: 填写收货信息 → 提交订单 → 验证订单创建成功
493
551
  - name: 订单-创建订单
494
552
  description: 模块:order 页面:/checkout
495
553
  actions:
496
554
  - type: navigate
497
- value: /checkout
555
+ value: /checkout # 结算页
498
556
  - type: fill
499
- selector: 'input[name="receiverName"]'
500
- value: 张三
557
+ selector: 'input[name="receiverName"]' # 收货人姓名
558
+ value: 张三 # 真实姓名或测试姓名
501
559
  - type: fill
502
- selector: 'input[name="phone"]'
560
+ selector: 'input[name="phone"]' # 手机号
503
561
  value: '13800138000'
504
562
  - type: fill
505
- selector: 'input[name="address"]'
506
- value: 北京市朝阳区测试街道123号
563
+ selector: 'input[name="address"]' # 详细地址
564
+ value: 北京市朝阳区测试街道123号 # 测试地址
507
565
  - type: click
508
- selector: '.submit-order-btn'
566
+ selector: '.submit-order-btn' # 提交订单按钮
509
567
  - type: wait
510
- delay: 2000
568
+ delay: 2000 # 等待订单创建接口
511
569
  assertions:
512
570
  - type: url
513
- contains: /order/success
571
+ contains: /order/success # 断言跳转到成功页
514
572
  - type: visible
515
- selector: '.order-success'
573
+ selector: '.order-success' # 成功提示
516
574
  - type: text
517
575
  selector: '.order-success'
518
576
  contains: 订单提交成功
519
577
 
520
578
  # ── 场景24: 订单支付 ──
579
+ # 说明: 选择支付方式 → 确认支付 → 等待支付接口返回 → 验证成功
521
580
  - name: 订单-支付订单
522
581
  description: 模块:order 页面:/pay/:orderId
523
582
  actions:
524
583
  - type: navigate
525
- value: /pay/ORD202409110001
584
+ value: /pay/ORD202409110001 # 支付页(ORD202409110001 为订单号)
526
585
  - type: click
527
- selector: '.pay-method-wechat'
586
+ selector: '.pay-method-wechat' # 选择微信支付
528
587
  - type: click
529
- selector: '.confirm-pay-btn'
588
+ selector: '.confirm-pay-btn' # 确认支付按钮
530
589
  - type: waitForResponse
531
- selector: '/api/pay/create'
532
- timeout: 10000
590
+ selector: '/api/pay/create' # 等待支付创建接口返回
591
+ timeout: 10000 # 支付接口较慢,超时设 10 秒
533
592
  - type: wait
534
593
  delay: 2000
535
594
  assertions:
536
595
  - type: url
537
- contains: /pay/success
596
+ contains: /pay/success # 断言跳转到支付成功页
538
597
  - type: visible
539
598
  selector: '.pay-success'
540
599
 
541
- # ── 场景25: 订单列表 ──
600
+ # ── 场景25: 订单列表查询 ──
542
601
  - name: 订单-列表查询
543
602
  description: 模块:order 页面:/orders
544
603
  actions:
545
604
  - type: navigate
546
- value: /orders
605
+ value: /orders # 订单列表页
547
606
  - type: wait
548
607
  delay: 1000
549
608
  assertions:
@@ -551,54 +610,55 @@ scenarios:
551
610
  selector: '.order-list'
552
611
  - type: count
553
612
  selector: '.order-item'
554
- count: 5
613
+ count: 5 # 预期至少 5 个订单
555
614
 
556
- # ── 场景26: 订单详情 ──
615
+ # ── 场景26: 订单详情查看 ──
557
616
  - name: 订单-详情查看
558
617
  description: 模块:order 页面:/orders/:id
559
618
  actions:
560
619
  - type: navigate
561
620
  value: /orders
562
621
  - type: click
563
- selector: '.order-item:first-child .view-detail-btn'
622
+ selector: '.order-item:first-child .view-detail-btn' # 查看第一个订单详情
564
623
  - type: wait
565
624
  delay: 800
566
625
  assertions:
567
626
  - type: visible
568
627
  selector: '.order-detail'
569
628
  - type: text
570
- selector: '.order-status'
571
- contains: 待付款
629
+ selector: '.order-status' # 订单状态
630
+ contains: 待付款 # 预期状态文案
572
631
 
573
- # ── 场景27: 订单取消 ──
632
+ # ── 场景27: 取消订单 ──
633
+ # 说明: 点击取消 → 确认取消 → 验证状态变为已取消
574
634
  - name: 订单-取消订单
575
635
  description: 模块:order 页面:/orders/:id
576
636
  actions:
577
637
  - type: navigate
578
- value: /orders/ORD202409110001
638
+ value: /orders/ORD202409110001 # 某个待付款订单
579
639
  - type: click
580
- selector: '.cancel-order-btn'
640
+ selector: '.cancel-order-btn' # 取消订单按钮
581
641
  - type: wait
582
- delay: 500
642
+ delay: 500 # 等待确认弹窗
583
643
  - type: click
584
- selector: '.confirm-cancel-btn'
644
+ selector: '.confirm-cancel-btn' # 确认取消按钮
585
645
  - type: wait
586
- delay: 1500
646
+ delay: 1500 # 等待取消接口返回
587
647
  assertions:
588
648
  - type: text
589
649
  selector: '.order-status'
590
- contains: 已取消
650
+ contains: 已取消 # 状态变为已取消
591
651
 
592
- # ─────────────────────────────────────────────────────────────────────────────
593
- # 六、消息通知模块 (notification)
594
- # ─────────────────────────────────────────────────────────────────────────────
652
+ # ═══════════════════════════════════════════════════════════════════════════
653
+ # 六、消息通知 (notification)
654
+ # ═══════════════════════════════════════════════════════════════════════════
595
655
 
596
- # ── 场景28: 消息列表 ──
656
+ # ── 场景28: 消息列表查看 ──
597
657
  - name: 消息-列表查看
598
658
  description: 模块:notification 页面:/notifications
599
659
  actions:
600
660
  - type: navigate
601
- value: /notifications
661
+ value: /notifications # 消息中心
602
662
  - type: wait
603
663
  delay: 1000
604
664
  assertions:
@@ -606,98 +666,104 @@ scenarios:
606
666
  selector: '.notification-list'
607
667
  - type: count
608
668
  selector: '.notification-item'
609
- count: 3
669
+ count: 3 # 预期 3 条未读消息
610
670
 
611
671
  # ── 场景29: 消息标记已读 ──
672
+ # 说明: 点击消息 → 验证字体从粗体变为正常(已读状态)
612
673
  - name: 消息-标记已读
613
674
  description: 模块:notification 页面:/notifications
614
675
  actions:
615
676
  - type: navigate
616
677
  value: /notifications
617
678
  - type: click
618
- selector: '.notification-item:first-child'
679
+ selector: '.notification-item:first-child' # 点击第一条消息
619
680
  - type: wait
620
681
  delay: 500
621
682
  assertions:
622
683
  - type: style
623
684
  selector: '.notification-item:first-child'
624
- style: font-weight
625
- value: '400'
685
+ style: font-weight # CSS 属性: 字重
686
+ value: '400' # 400 = normal(已读),700 = bold(未读)
626
687
 
627
- # ─────────────────────────────────────────────────────────────────────────────
628
- # 七、后台管理模块 (admin)
629
- # ─────────────────────────────────────────────────────────────────────────────
688
+ # ═══════════════════════════════════════════════════════════════════════════
689
+ # 七、后台管理 (admin)
690
+ # ═══════════════════════════════════════════════════════════════════════════
630
691
 
631
692
  # ── 场景30: 用户管理列表 ──
632
693
  - name: 后台-用户管理
633
694
  description: 模块:admin 页面:/admin/users
634
695
  actions:
635
696
  - type: navigate
636
- value: /admin/users
697
+ value: /admin/users # 后台用户管理页
637
698
  - type: wait
638
- delay: 1500
699
+ delay: 1500 # 等待表格数据加载
639
700
  assertions:
640
701
  - type: visible
641
- selector: '.user-table'
702
+ selector: '.user-table' # 用户表格
642
703
  - type: count
643
- selector: '.user-table tbody tr'
644
- count: 10
704
+ selector: '.user-table tbody tr' # 表格行数
705
+ count: 10 # 预期 10 条用户数据
645
706
 
646
707
  # ── 场景31: 数据报表(iframe 嵌入) ──
708
+ # 说明: 后台报表通常用 iframe 嵌入第三方 BI 工具(如帆软、Tableau)
647
709
  - name: 后台-数据报表iframe
648
710
  description: 模块:admin 页面:/admin/reports iframe嵌入
649
711
  actions:
650
712
  - type: navigate
651
- value: /admin/reports
713
+ value: /admin/reports # 报表页面
652
714
  - type: iframe
653
- selector: '#report-frame'
715
+ selector: '#report-frame' # 报表 iframe
654
716
  - type: wait
655
- delay: 2000
717
+ delay: 2000 # 等待 iframe 内报表加载
656
718
  assertions:
657
719
  - type: visible
658
- selector: '.chart-container'
720
+ selector: '.chart-container' # 图表容器(在 iframe 内)
659
721
  - type: count
660
- selector: '.chart-item'
661
- count: 4
722
+ selector: '.chart-item' # 图表数量
723
+ count: 4 # 预期 4 个图表
662
724
 
663
725
  # ── 场景32: 拖拽排序 ──
726
+ # 说明: 拖拽分类/菜单项调整顺序
664
727
  - name: 后台-拖拽排序
665
728
  description: 模块:admin 页面:/admin/categories 拖拽排序
666
729
  actions:
667
730
  - type: navigate
668
- value: /admin/categories
731
+ value: /admin/categories # 分类管理页
669
732
  - type: drag
670
- selector: '.category-item:first-child'
671
- toSelector: '.category-item:last-child'
733
+ selector: '.category-item:first-child' # 拖拽第一个分类
734
+ toSelector: '.category-item:last-child' # 放到最后一个位置
672
735
  - type: wait
673
- delay: 1000
736
+ delay: 1000 # 等待保存接口
674
737
  assertions:
675
738
  - type: text
676
- selector: '.category-item:last-child .category-name'
677
- contains: 原第一个分类
739
+ selector: '.category-item:last-child .category-name' # 断言最后一个分类的名称
740
+ contains: 原第一个分类 # 确认拖拽成功
678
741
 
679
- # ─────────────────────────────────────────────────────────────────────────────
680
- # 八、通用能力与高级特性
681
- # ─────────────────────────────────────────────────────────────────────────────
742
+ # ═══════════════════════════════════════════════════════════════════════════
743
+ # 八、通用能力
744
+ # ═══════════════════════════════════════════════════════════════════════════
682
745
 
683
746
  # ── 场景33: Cookie 注入免登录 ──
747
+ # 说明: 直接注入 session Cookie,跳过登录页,适合批量测试业务模块
748
+ # ⚠️ 核心用途: 作为「前置场景」放在业务场景(场景10-42)之前,为后续场景提供登录态
749
+ # 如何获取 Cookie: 在浏览器开发者工具 → Application → Cookies 中复制
684
750
  - name: 通用-Cookie注入免登录
685
751
  description: 模块:common Cookie注入跳过登录
686
752
  actions:
687
753
  - type: cookie
688
- selector: session_token
689
- value: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
690
- domain: example.com
691
- path: /
692
- secure: true
693
- httpOnly: true
754
+ selector: session_token # Cookie 名称
755
+ value: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEwMDg2fQ.test' # Cookie 值
756
+ domain: example.com # Cookie 域名(必须与测试站点一致)
757
+ path: / # Cookie 路径
758
+ secure: true # 仅 HTTPS 传输
759
+ httpOnly: true # 禁止 JS 读取
694
760
  - type: cookie
695
- selector: user_id
761
+ selector: user_id # 同时注入 user_id
696
762
  value: '10086'
697
763
  domain: example.com
698
764
  path: /
699
765
  - type: navigate
700
- value: /dashboard
766
+ value: /dashboard # 直接访问需登录页面
701
767
  - type: wait
702
768
  delay: 1000
703
769
  assertions:
@@ -714,21 +780,22 @@ scenarios:
714
780
  - type: navigate
715
781
  value: /
716
782
  - type: scroll
717
- selector: bottom
783
+ selector: bottom # 滚动到底部
718
784
  - type: wait
719
785
  delay: 1500
720
786
  - type: scroll
721
- selector: bottom
787
+ selector: bottom # 再次滚动(触发第二轮加载)
722
788
  - type: wait
723
789
  delay: 1500
724
790
  assertions:
725
791
  - type: visible
726
- selector: '.load-more-btn'
792
+ selector: '.load-more-btn' # 加载更多按钮
727
793
  - type: count
728
- selector: '.product-card'
729
- count: 20
794
+ selector: '.product-card' # 商品卡片总数
795
+ count: 20 # 预期加载了 20 个商品
730
796
 
731
797
  # ── 场景35: 样式断言 ──
798
+ # 说明: 验证按钮颜色、圆角等样式是否符合设计稿
732
799
  - name: 通用-按钮样式检查
733
800
  description: 模块:ui 页面:/
734
801
  actions:
@@ -736,39 +803,42 @@ scenarios:
736
803
  value: /
737
804
  assertions:
738
805
  - type: style
739
- selector: '.primary-btn'
740
- style: background-color
741
- value: rgb(24, 144, 255)
806
+ selector: '.primary-btn' # 主按钮
807
+ style: background-color # CSS 属性: 背景色
808
+ value: rgb(24, 144, 255) # 预期颜色(根据设计稿调整)
742
809
  - type: style
743
810
  selector: '.primary-btn'
744
- style: border-radius
745
- value: 4px
811
+ style: border-radius # CSS 属性: 圆角
812
+ value: 4px # 预期 4px 圆角
746
813
 
747
814
  # ── 场景36: 视觉对比测试 ──
815
+ # 说明: 截图后与基线图片对比,检测 UI 回归
816
+ # 前置条件: 先执行一次生成基线图片,后续对比以此为准
748
817
  - name: 通用-视觉对比测试
749
818
  description: 模块:ui 页面:/ 视觉回归
750
819
  actions:
751
820
  - type: navigate
752
821
  value: /
753
- - type: screenshot
822
+ - type: screenshot # 页面截图
754
823
  assertions:
755
824
  - type: visual
756
- selector: 'body'
757
- threshold: normal
825
+ selector: 'body' # 对比整个页面
826
+ threshold: normal # 阈值: strict/normal/loose
758
827
 
759
828
  # ── 场景37: 键盘操作 ──
829
+ # 说明: 聚焦搜索框 → 输入关键词 → 按回车触发搜索
760
830
  - name: 通用-键盘操作
761
831
  description: 模块:common 页面:/products 键盘导航
762
832
  actions:
763
833
  - type: navigate
764
834
  value: /products
765
835
  - type: focus
766
- selector: 'input[name="keyword"]'
836
+ selector: 'input[name="keyword"]' # 聚焦搜索框
767
837
  - type: fill
768
838
  selector: 'input[name="keyword"]'
769
839
  value: MacBook
770
840
  - type: press
771
- key: Enter
841
+ key: Enter # 按回车
772
842
  - type: wait
773
843
  delay: 1500
774
844
  assertions:
@@ -776,37 +846,40 @@ scenarios:
776
846
  selector: '.search-result-list'
777
847
  - type: count
778
848
  selector: '.product-item'
779
- count: 2
849
+ count: 2 # 预期 2 个结果
780
850
 
781
851
  # ── 场景38: hover 效果 ──
852
+ # 说明: 鼠标悬停在商品卡片上,验证阴影/边框等 hover 样式
782
853
  - name: 通用-hover效果
783
854
  description: 模块:ui 页面:/products hover交互
784
855
  actions:
785
856
  - type: navigate
786
857
  value: /products
787
858
  - type: hover
788
- selector: '.product-item:first-child'
859
+ selector: '.product-item:first-child' # 悬停在第一个商品
789
860
  - type: wait
790
- delay: 500
861
+ delay: 500 # 等待 hover 动画
791
862
  assertions:
792
863
  - type: style
793
864
  selector: '.product-item:first-child'
794
- style: box-shadow
795
- contains: rgba
865
+ style: box-shadow # CSS 属性: 阴影
866
+ contains: rgba # 包含 rgba(有阴影)
796
867
 
797
868
  # ── 场景39: 元素隐藏检查 ──
869
+ # 说明: 验证未登录状态下,用户菜单和退出按钮不显示
798
870
  - name: 通用-元素隐藏
799
871
  description: 模块:ui 页面:/login 未登录状态
800
872
  actions:
801
873
  - type: navigate
802
- value: /login
874
+ value: /login # 未登录页面
803
875
  assertions:
804
876
  - type: hidden
805
- selector: '.user-menu'
877
+ selector: '.user-menu' # 用户菜单应隐藏
806
878
  - type: hidden
807
- selector: '.logout-btn'
879
+ selector: '.logout-btn' # 退出按钮应隐藏
808
880
 
809
881
  # ── 场景40: 表单值断言 ──
882
+ # 说明: 验证表单字段的默认值是否正确
810
883
  - name: 通用-表单值检查
811
884
  description: 模块:user 页面:/profile/edit 表单默认值
812
885
  actions:
@@ -814,30 +887,33 @@ scenarios:
814
887
  value: /profile/edit
815
888
  assertions:
816
889
  - type: value
817
- selector: 'input[name="username"]'
818
- equals: test_user
890
+ selector: 'input[name="username"]' # 断言表单值
891
+ equals: test_user # 精确匹配
819
892
  - type: value
820
893
  selector: 'input[name="email"]'
821
- contains: '@'
894
+ contains: '@' # 包含 @ 符号
822
895
 
823
896
  # ── 场景41: JavaScript 注入执行 ──
897
+ # 说明: 执行自定义 JS,如修改全局变量、调用前端方法
824
898
  - name: 通用-JS脚本注入
825
899
  description: 模块:common 页面:/ JS注入测试
826
900
  actions:
827
901
  - type: navigate
828
902
  value: /
829
903
  - type: script
830
- value: 'window.testFlag = "injected";'
904
+ value: 'window.testFlag = "injected";' # 设置全局变量
831
905
  - type: wait
832
906
  delay: 500
833
907
  - type: script
834
- value: 'return window.testFlag;'
908
+ value: 'return window.testFlag;' # 读取全局变量(返回给引擎)
835
909
  assertions:
836
910
  - type: text
837
911
  selector: 'body'
838
- contains: injected
912
+ contains: injected # 断言页面包含 injected 文本
839
913
 
840
- # ── 场景42: 响应式断点测试 ──
914
+ # ── 场景42: 响应式布局测试 ──
915
+ # 说明: 验证移动端下显示移动端导航,隐藏桌面端侧边栏
916
+ # 注意: Playwright 可通过 viewport 配置模拟不同设备尺寸
841
917
  - name: 通用-响应式布局
842
918
  description: 模块:ui 页面:/ 移动端适配
843
919
  actions:
@@ -847,6 +923,6 @@ scenarios:
847
923
  delay: 800
848
924
  assertions:
849
925
  - type: visible
850
- selector: '.mobile-nav'
926
+ selector: '.mobile-nav' # 移动端导航应可见
851
927
  - type: hidden
852
- selector: '.desktop-sidebar'
928
+ selector: '.desktop-sidebar' # 桌面端侧边栏应隐藏