Răsfoiți Sursa

Merge remote-tracking branch 'origin/cfclub' into feature/coupon-merge-into-cfclub

Agnes Agent 1 săptămână în urmă
părinte
comite
10084b18c4
3 a modificat fișierele cu 226 adăugiri și 4 ștergeri
  1. 4 4
      INTERFACE_TEST_REPORT.md
  2. 215 0
      playwright_smoke.log
  3. 7 0
      playwright_smoke_report.md

+ 4 - 4
INTERFACE_TEST_REPORT.md

@@ -1,4 +1,4 @@
-# CFC 接口冒烟测试报告 (20261031_222942)
+# CFC 接口冒烟测试报告 (20261031_232536)
 
 - 目标: cfc.iwintrue.com  用例总数: **543**
 - 业务成功率(BIZ_OK): **247/543 = 45%**
@@ -19,14 +19,14 @@
 
 
 ## 测试用例完成情况
-- 自动化用例总数(可执行 `test()`):**382**(api 层 51 / 角色分包 52 / DOM 层 279)
+- 自动化用例总数(可执行 `test()`):**387**(api 层 56 / 角色分包 52 / DOM 层 279)
 - 文档化用例(设计层 TC-xxxx):**202**
-- 已完成(自动化且未被跳过):**359/382 = 93%**
+- 已完成(自动化且未被跳过):**360/387 = 93%**
 - 已实跑通过:接口冒烟 BIZ_OK **247** 端点 + API e2e 末次 **0** 通过 / 0 fixme
 
 ### 未完成 / 未开始的原因(共 4 类)
 1. [279 项] DOM 型 E2E 无法执行(CFC-ENV-001):279 个用例已编写,但远程 cfc.iwintrue.com 为纯 Spring Boot API 后端、未部署 uni-app H5 / cfc-web 前端,浏览器型用例无法运行,未开始执行。
-2. [23 项] 已知缺陷/待上线导致跳过:23 个用例被 test.skip/test.fixme 标记(能量发放 500-CFC-EN-001、昵称未持久化-CFC-FM-001 等),待后端修复后启用。
+2. [27 项] 已知缺陷/待上线导致跳过:27 个用例被 test.skip/test.fixme 标记(能量发放 500-CFC-EN-001、昵称未持久化-CFC-FM-001 等),待后端修复后启用。
 3. [6 项] 新功能待部署后验证:接口冒烟发现 6 个 NOT_FOUND 端点,对应前端页面尚未部署到测试环境,相关 E2E 暂挂起。
 4. [202 项] 文档化用例未全量自动化:202 条设计用例(TC-xxxx),核心主链路已落地 e2e,边缘/异常流仍以文档形式待补自动化。
 

+ 215 - 0
playwright_smoke.log

@@ -0,0 +1,215 @@
+
+Running 58 tests using 1 worker
+
+[1/58] [desktop] › e2e\api\api-smoke.spec.js:18:3 › API级冒烟(远程后端) › 自注册链路可用(拿到有效 token)
+[2/58] [desktop] › e2e\api\api-smoke.spec.js:24:3 › API级冒烟(远程后端) › 家庭成员列表接口可调用 (code=200)
+[3/58] [desktop] › e2e\api\api-smoke.spec.js:30:3 › API级冒烟(远程后端) › 能量概览接口可调用 (code=200)
+[4/58] [desktop] › e2e\api\api-smoke.spec.js:36:3 › API级冒烟(远程后端) › 成员列表参数校验生效(越权家庭 → 403)
+[5/58] [desktop] › e2e\api\article-api.spec.js:26:3 › 【API级】文章管理全流程 › [场景1] 查看文章列表 - 期望返回文章列表
+[6/58] [desktop] › e2e\api\article-api.spec.js:35:3 › 【API级】文章管理全流程 › [场景2] 文章分类 - 期望分类列表可用
+[7/58] [desktop] › e2e\api\article-api.spec.js:43:3 › 【API级】文章管理全流程 › [场景3] 查看文章详情 - 期望返回文章内容
+[8/58] [desktop] › e2e\api\article-api.spec.js:59:3 › 【API级】文章管理全流程 › [场景4] 我的文章 - 期望返回登录用户发布记录
+[9/58] [desktop] › e2e\api\article-api.spec.js:67:3 › 【API级】文章管理全流程 › [场景5] 发布文章缺少标题 - 期望返回错误提示
+[10/58] [desktop] › e2e\api\article-api.spec.js:73:3 › 【API级】文章管理全流程 › [场景5b] 精选文章 - 期望可获取
+[11/58] [desktop] › e2e\api\article-api.spec.js:81:3 › 【API级】文章管理全流程 › [场景6] 家长角色发布文章 - 期望受权限/审核流程约束
+[12/58] [desktop] › e2e\api\contact-api.spec.js:41:3 › 【API级】联系人管理全流程 › [场景1] 创建联系人 - 期望创建成功
+[13/58] [desktop] › e2e\api\contact-api.spec.js:51:3 › 【API级】联系人管理全流程 › [场景2] 通讯录导入 - 期望导入成功
+[14/58] [desktop] › e2e\api\contact-api.spec.js:64:3 › 【API级】联系人管理全流程 › [场景3] 记录互动 - 期望记录成功
+[15/58] [desktop] › e2e\api\contact-api.spec.js:77:3 › 【API级】联系人管理全流程 › [场景4] 编辑联系人 - 期望更新成功
+[16/58] [desktop] › e2e\api\contact-api.spec.js:88:3 › 【API级】联系人管理全流程 › [场景4b] 删除联系人 - 期望从列表中移除
+[17/58] [desktop] › e2e\api\contact-api.spec.js:103:3 › 【API级】联系人管理全流程 › [场景5b] 越权操作他人联系人 - 期望被拒绝
+[18/58] [desktop] › e2e\api\energy-api.spec.js:34:3 › 【API级】能量系统收支全流程 › [场景1] 获取家庭能量沙盘 - 期望返回五维能量数据
+[19/58] [desktop] › e2e\api\energy-api.spec.js:41:3 › 【API级】能量系统收支全流程 › [场景1b] 未加入家庭/越权访问 - 期望返回错误提示
+[20/58] [desktop] › e2e\api\energy-api.spec.js:55:3 › 【API级】能量系统收支全流程 › [场景2] 任务完成能量发放 - 期望能量增加且流水记录
+[21/58] [desktop] › e2e\api\energy-api.spec.js:77:3 › 【API级】能量系统收支全流程 › [场景2c] 已知缺陷复现 - 期望当前返回 500 服务器内部错误
+[22/58] [desktop] › e2e\api\energy-api.spec.js:89:3 › 【API级】能量系统收支全流程 › [场景2b] 能量发放缺参 - 期望返回错误提示
+[23/58] [desktop] › e2e\api\energy-api.spec.js:97:3 › 【API级】能量系统收支全流程 › [场景3] 能量兑换心愿 - 期望参数校验生效且未扣减能量
+[24/58] [desktop] › e2e\api\energy-api.spec.js:121:3 › 【API级】能量系统收支全流程 › [场景4] 查询能量流水 - 期望返回分页记录
+[25/58] [desktop] › e2e\api\energy-api.spec.js:131:3 › 【API级】能量系统收支全流程 › [场景5] 获取五维能量概览 - 期望返回五维汇总数据
+[26/58] [desktop] › e2e\api\energy-api.spec.js:146:3 › 【API级】能量系统收支全流程 › [场景6] 完整能量收支流程 - 期望全流程成功
+[27/58] [desktop] › e2e\api\family-member-api.spec.js:39:3 › 【API级】家庭成员管理全流程 › [场景1] 获取成员列表 - 期望返回成员数据
+[28/58] [desktop] › e2e\api\family-member-api.spec.js:46:3 › 【API级】家庭成员管理全流程 › [场景1b] 越权访问他人家庭 - 期望 403 拒绝
+[29/58] [desktop] › e2e\api\family-member-api.spec.js:54:3 › 【API级】家庭成员管理全流程 › [场景2] 添加新家庭成员 - 期望添加成功并返回完整信息
+[30/58] [desktop] › e2e\api\family-member-api.spec.js:63:3 › 【API级】家庭成员管理全流程 › [场景2b] 添加成员时昵称为空 - 期望返回错误提示
+[31/58] [desktop] › e2e\api\family-member-api.spec.js:74:3 › 【API级】家庭成员管理全流程 › [场景2c] 添加成员时辈分等级为空 - 期望返回错误提示
+[32/58] [desktop] › e2e\api\family-member-api.spec.js:85:3 › 【API级】家庭成员管理全流程 › [场景2d] 添加成员时辈分等级非法 - 期望返回错误提示
+[33/58] [desktop] › e2e\api\family-member-api.spec.js:98:3 › 【API级】家庭成员管理全流程 › [场景3] 查看家庭成员列表 - 期望返回所有成员及关系信息
+[34/58] [desktop] › e2e\api\family-member-api.spec.js:120:3 › 【API级】家庭成员管理全流程 › [场景4] 更新成员关系/昵称 - 期望更新成功并返回新信息
+[35/58] [desktop] › e2e\api\family-member-api.spec.js:138:3 › 【API级】家庭成员管理全流程 › [场景4c] 已知缺陷复现 - nickname 未生效但 gender/birthday 生效
+[36/58] [desktop] › e2e\api\family-member-api.spec.js:158:3 › 【API级】家庭成员管理全流程 › [场景5] 切换到成员视角 - 期望返回切换凭证
+[37/58] [desktop] › e2e\api\family-member-api.spec.js:167:3 › 【API级】家庭成员管理全流程 › [场景5b] 切换到本人视角 - 期望返回错误提示
+[38/58] [desktop] › e2e\api\family-member-api.spec.js:179:3 › 【API级】家庭成员管理全流程 › [场景6] 移除家庭成员 - 期望成员从家庭中移除
+[39/58] [desktop] › e2e\api\family-member-api.spec.js:192:3 › 【API级】家庭成员管理全流程 › [场景6b] 非管理员尝试踢人 - 期望权限不足拒绝
+[40/58] [desktop] › e2e\api\family-member-api.spec.js:202:3 › 【API级】家庭成员管理全流程 › [场景7] 完整家庭成员管理流程 - 期望全流程成功
+[41/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:56:1 › [TC-G-N03] 非微信H5兜底登录:手机号注册登录路径 UA 无关
+[42/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:63:1 › [TC-G-N02/P-N06/C-N03/T-N04/S-N03/X-N07] 多端 UA 兼容:同请求不同客户端返回一致
+[43/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:79:1 › [TC-A-N04/X-N02] 限流熔断稳定性:爆发请求下系统不死(不出现 5xx 雪崩)
+[desktop] › e2e\api\nonfunc-perf-compat.spec.js:79:1 › [TC-A-N04/X-N02] 限流熔断稳定性:爆发请求下系统不死(不出现 5xx 雪崩)
+[限流] 状态分布=[200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200] 其中429=0
+
+[44/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:92:1 › [TC-P-N02/X-N01] 并发不串数据:并行 AI 请求各自独立响应
+[45/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:106:1 › [响应时间基线] 已登录家庭列表单请求耗时冒烟 ≤ 8s
+[desktop] › e2e\api\nonfunc-perf-compat.spec.js:106:1 › [响应时间基线] 已登录家庭列表单请求耗时冒烟 ≤ 8s
+[耗时] 家庭列表 94ms
+
+[46/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:117:6 › [TC-C-N01/X-N04] 任务打卡幂等:重复提交不重复计分(需任务流夹具)
+[47/58] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:122:6 › [TC-X-N03] 活动名额并发不超卖:100 名额 / 瞬时 500 请求(需活动夹具 + 压测授权)
+[48/58] [desktop] › e2e\api\nonfunc-security.spec.js:50:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问能量概览被拒(401/403)
+  1) [desktop] › e2e\api\nonfunc-security.spec.js:50:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问能量概览被拒(401/403) 
+
+    Error: 能量概览未授权应 401/403,实际 code=500 msg=memberId不能为空
+
+    expect(received).toBeTruthy()
+
+    Received: false
+
+      50 |   test('[TC-G-N04] 未授权访问能量概览被拒(401/403)', async ({ request }) => {
+      51 |     const r = await apiPost(request, '/api/energy/overview', {}, null);
+    > 52 |     expect([401, 403].includes(r.code), `能量概览未授权应 401/403,实际 code=${r.code} msg=${r.message}`).toBeTruthy();
+         |                                                                                                ^
+      53 |   });
+      54 |
+      55 |   test('[TC-G-N04] 未授权访问家庭成员列表被拒(401/403)', async ({ request }) => {
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:52:96
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安-bdecd--G-N04-未授权访问能量概览被拒-401-403--desktop\error-context.md
+
+
+[49/58] [desktop] › e2e\api\nonfunc-security.spec.js:55:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问家庭成员列表被拒(401/403)
+  2) [desktop] › e2e\api\nonfunc-security.spec.js:55:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问家庭成员列表被拒(401/403) 
+
+    Error: 成员列表未授权应 401/403,实际 code=200 msg=success
+
+    expect(received).toBeTruthy()
+
+    Received: false
+
+      55 |   test('[TC-G-N04] 未授权访问家庭成员列表被拒(401/403)', async ({ request }) => {
+      56 |     const r = await apiPost(request, '/api/family/member/list', {}, null);
+    > 57 |     expect([401, 403].includes(r.code), `成员列表未授权应 401/403,实际 code=${r.code} msg=${r.message}`).toBeTruthy();
+         |                                                                                                ^
+      58 |   });
+      59 |
+      60 |   test('[TC-G-N04] 未授权调用 AI 健康教练被拒(401/403)', async ({ request }) => {
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:57:96
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安-ab6c7--N04-未授权访问家庭成员列表被拒-401-403--desktop\error-context.md
+
+
+[50/58] [desktop] › e2e\api\nonfunc-security.spec.js:60:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权调用 AI 健康教练被拒(401/403)
+  3) [desktop] › e2e\api\nonfunc-security.spec.js:60:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权调用 AI 健康教练被拒(401/403) 
+
+    Error: AI 教练未授权应 401/403,实际 code=200 msg=success
+
+    expect(received).toBeTruthy()
+
+    Received: false
+
+      60 |   test('[TC-G-N04] 未授权调用 AI 健康教练被拒(401/403)', async ({ request }) => {
+      61 |     const r = await apiPost(request, '/api/ai/health-coach/send', { query: '你好' }, null);
+    > 62 |     expect([401, 403].includes(r.code), `AI 教练未授权应 401/403,实际 code=${r.code} msg=${r.message}`).toBeTruthy();
+         |                                                                                                 ^
+      63 |   });
+      64 |
+      65 |   // —— IDOR 横向越权(TC-P-N09 / TC-X-N05):携带本人 token 越权访问他人 familyId → 403 ——
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:62:97
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安-d1d5f-04-未授权调用-AI-健康教练被拒-401-403--desktop\error-context.md
+
+
+[51/58] [desktop] › e2e\api\nonfunc-security.spec.js:66:3 › 非功能/安全接口冒烟 › [TC-P-N09] IDOR:越权访问他人家庭成员列表 → 403
+[52/58] [desktop] › e2e\api\nonfunc-security.spec.js:75:3 › 非功能/安全接口冒烟 › [TC-A-N05] 非管理员访问后台接口被拒(401/403)
+  4) [desktop] › e2e\api\nonfunc-security.spec.js:75:3 › 非功能/安全接口冒烟 › [TC-A-N05] 非管理员访问后台接口被拒(401/403) 
+
+    Error: 后台接口未授权应 401/403,实际 code=500 msg=手机号和验证码不能为空
+
+    expect(received).toBeTruthy()
+
+    Received: false
+
+      75 |   test('[TC-A-N05] 非管理员访问后台接口被拒(401/403)', async ({ request }) => {
+      76 |     const r = await apiPost(request, '/api/admin-auth/login', {}, null);
+    > 77 |     expect([401, 403].includes(r.code), `后台接口未授权应 401/403,实际 code=${r.code} msg=${r.message}`).toBeTruthy();
+         |                                                                                                ^
+      78 |   });
+      79 |
+      80 |   // —— 双角色铁律 / 权限提升防护(TC-C-N07)——
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:77:96
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安-1d575-A-N05-非管理员访问后台接口被拒-401-403--desktop\error-context.md
+
+
+[53/58] [desktop] › e2e\api\nonfunc-security.spec.js:81:3 › 非功能/安全接口冒烟 › [TC-C-N07] 角色切换接口未授权被拒(401/403)
+  5) [desktop] › e2e\api\nonfunc-security.spec.js:81:3 › 非功能/安全接口冒烟 › [TC-C-N07] 角色切换接口未授权被拒(401/403) 
+
+    Error: 切换角色未授权应 401/403,实际 code=500 msg=用户不存在
+
+    expect(received).toBeTruthy()
+
+    Received: false
+
+      81 |   test('[TC-C-N07] 角色切换接口未授权被拒(401/403)', async ({ request }) => {
+      82 |     const r = await apiPost(request, '/api/auth/switch-role', { role: 'parent' }, null);
+    > 83 |     expect([401, 403].includes(r.code), `切换角色未授权应 401/403,实际 code=${r.code} msg=${r.message}`).toBeTruthy();
+         |                                                                                                ^
+      84 |   });
+      85 |
+      86 |   test('[TC-C-N07] 权限提升防护:家长不可切换为未持有角色', async ({ request }) => {
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:83:96
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安-7e22b--C-N07-角色切换接口未授权被拒-401-403--desktop\error-context.md
+
+
+[54/58] [desktop] › e2e\api\nonfunc-security.spec.js:86:3 › 非功能/安全接口冒烟 › [TC-C-N07] 权限提升防护:家长不可切换为未持有角色
+  6) [desktop] › e2e\api\nonfunc-security.spec.js:86:3 › 非功能/安全接口冒烟 › [TC-C-N07] 权限提升防护:家长不可切换为未持有角色 
+
+    Error: 家长不应越权切到 admin(实际 data={"token":"eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4iLCJyb2xlcyI6WyJhZG1pbiJdLCJ1c2VySWQiOjgxODMzLCJzdWIiOiI4MTgzMyIsImlhdCI6MTc5MzQ2MDUwNCwiZXhwIjoxNzk2MDUyNTA0fQ.hM0oGttpra_2cku_LxyupwnWM2na2rKMkX6-lKrOfzw","userId":81833,"role":"admin","roles":null,"familyId":3077,"nickname":"QA-SEC","phone":"13790845473","currentMemberId":null,"isNewUser":false,"openid":null,"needsRoleSelect":null,"needsFamily":false,"teacherStatus":"pending","teacherRejectReason":null,"hasTeacherRole":false,"vendorType":null,"activityProviderStatus":null})
+
+    expect(received).toBeFalsy()
+
+    Received: "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoiYWRtaW4iLCJyb2xlcyI6WyJhZG1pbiJdLCJ1c2VySWQiOjgxODMzLCJzdWIiOiI4MTgzMyIsImlhdCI6MTc5MzQ2MDUwNCwiZXhwIjoxNzk2MDUyNTA0fQ.hM0oGttpra_2cku_LxyupwnWM2na2rKMkX6-lKrOfzw"
+
+      88 |     const ctx = await getParent(request);
+      89 |     const r = await apiPost(request, '/api/auth/switch-role', { role: 'admin' }, ctx.token);
+    > 90 |     expect(r.data && r.data.token, `家长不应越权切到 admin(实际 data=${JSON.stringify(r.data)})`).toBeFalsy();
+         |                                                                                         ^
+      91 |   });
+      92 |
+      93 |   test('[TC-C-N07] 角色切换自身合法角色正常(基线)', async ({ request }) => {
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:90:89
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安全接口冒烟-TC-C-N07-权限提升防护:家长不可切换为未持有角色-desktop\error-context.md
+
+
+[55/58] [desktop] › e2e\api\nonfunc-security.spec.js:93:3 › 非功能/安全接口冒烟 › [TC-C-N07] 角色切换自身合法角色正常(基线)
+[56/58] [desktop] › e2e\api\nonfunc-security.spec.js:101:3 › 非功能/安全接口冒烟 › [TC-P-N10] AI 健康教练 XSS:query 注入脚本不回显原始脚本且不错 500
+[57/58] [desktop] › e2e\api\nonfunc-security.spec.js:109:3 › 非功能/安全接口冒烟 › [TC-A-N06] 活动反馈存储型 XSS:提交含脚本 comment,列表不回显原始脚本
+[58/58] [desktop] › e2e\api\nonfunc-security.spec.js:121:3 › 非功能/安全接口冒烟 › [TC-P-N11] 报告上传非 PDF/恶意内容被拒(非 200)
+  7) [desktop] › e2e\api\nonfunc-security.spec.js:121:3 › 非功能/安全接口冒烟 › [TC-P-N11] 报告上传非 PDF/恶意内容被拒(非 200) 
+
+    Error: expect(received).toBeTruthy()
+
+    Received: false
+
+      129 |     // 安全合规行为:拒绝为 4xx(400/401/403/405/413/415/422)。非 200 即视为未成功落库。
+      130 |     expect(status, `报告上传非 PDF 应被拒(4xx),实际 HTTP ${status}`).not.toBe(200);
+    > 131 |     expect([400, 401, 403, 405, 413, 415, 422].includes(status)).toBeTruthy();
+          |                                                                  ^
+      132 |   });
+      133 | });
+      134 |
+        at D:\cfc\tests\e2e\api\nonfunc-security.spec.js:131:66
+
+    Error Context: .api-artifacts\api-nonfunc-security-非功能-安-18c8a-N11-报告上传非-PDF-恶意内容被拒-非-200--desktop\error-context.md
+
+
+  7 failed
+    [desktop] › e2e\api\nonfunc-security.spec.js:50:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问能量概览被拒(401/403) 
+    [desktop] › e2e\api\nonfunc-security.spec.js:55:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问家庭成员列表被拒(401/403) 
+    [desktop] › e2e\api\nonfunc-security.spec.js:60:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权调用 AI 健康教练被拒(401/403) 
+    [desktop] › e2e\api\nonfunc-security.spec.js:75:3 › 非功能/安全接口冒烟 › [TC-A-N05] 非管理员访问后台接口被拒(401/403) 
+    [desktop] › e2e\api\nonfunc-security.spec.js:81:3 › 非功能/安全接口冒烟 › [TC-C-N07] 角色切换接口未授权被拒(401/403) 
+    [desktop] › e2e\api\nonfunc-security.spec.js:86:3 › 非功能/安全接口冒烟 › [TC-C-N07] 权限提升防护:家长不可切换为未持有角色 
+    [desktop] › e2e\api\nonfunc-security.spec.js:121:3 › 非功能/安全接口冒烟 › [TC-P-N11] 报告上传非 PDF/恶意内容被拒(非 200) 
+  5 skipped
+  46 passed (1.0m)

+ 7 - 0
playwright_smoke_report.md

@@ -0,0 +1,7 @@
+
+## Playwright E2E 冒烟(api 层,独立,不阻断主闭环)
+- 执行器: /d/cfc/tests/node_modules/.bin/playwright test -c playwright.config.api.js --project=desktop
+- 结果: **46 passed / 7 failed / 5 skipped**
+- 覆盖: tests/e2e/api/*.spec.js(含 nonfunc-security 安全契约、nonfunc-perf-compat 性能兼容)
+- 说明: 红用例=已知后端缺口(权限提升/开放端点/上传未校验/缺鉴权过滤器),作持续告警;失败不阻断本闭环。
+- 明细: /d/cfc/playwright_smoke.log