Эх сурвалжийг харах

test(e2e): 补充近期需求变更的端到端覆盖

根据最近的需求变更扩展 flow-l1-tests.js 的 3 个流程测试,新增 12 个测试点:

家庭挑战 (d6bb7d48):
- 挑战列表带 familyId 参数(修复之前漏传导致返回空)
- 验证 targetMode/targetValue 双目标模式字段
- 验证 totalProgress/memberProgress 进度字段
- 新增 /api/health/challenge/history 历史
- 新增 /api/health/challenge/progress 进度上报(childId 已有活跃挑战时)

活动会员价 (15a93dd3 + 89673f07):
- 管理端活动列表验证 memberPrice 字段
- 管理端活动详情验证 memberPrice

文章 (ab9f4a44 + 阅读时长功能):
- admin/articles/list 带 auditStatus 参数过滤
- 文章详情返回 readTime 字段
- /api/articles/record-read 上报阅读时长(需 childId)
- /api/share/qrcode 生成小程序码(855a8df5 分享改海报)
- /api/admin/articles/upload/image 端点存在性(598e7601 + c697fb7b)

测试结果:211 passed / 0 failed / 0 skipped(原 199 → +12 新增全通过)。
Sisyphus Agent 3 сар өмнө
parent
commit
12c3dd0362

+ 94 - 3
tests/e2e/flow-l1-tests.js

@@ -1079,7 +1079,24 @@ async function testActivityFlow() {
     r = await apiCall('POST', '/api/admin/activity/list', {}, t2);
     record(F, 'admin', '管理端活动列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'admin activities OK' : r.raw);
 
-    // 活动管理员:管家后台管理
+    // 活动会员价字段验证(需求:活动新增 memberPrice)
+    var actListData = (r.body && r.body.code === 200 && r.body.data) ? r.body.data : null;
+    var actList = actListData && actListData.records ? actListData.records : (actListData && Array.isArray(actListData) ? actListData : (actListData && actListData.list ? actListData.list : []));
+    var hasMemberPrice = actList.length > 0 && actList[0].memberPrice !== undefined;
+    record(F, 'admin', '活动会员价字段', hasMemberPrice,
+      hasMemberPrice ? 'memberPrice=' + actList[0].memberPrice : 'no activities or missing memberPrice');
+    // 活动详情验证 memberPrice
+    if (actList.length > 0 && actList[0].id) {
+      r = await apiCall('POST', '/api/admin/activity/detail', { id: actList[0].id }, t2);
+      var detailOk = r.status === 200 && r.body && r.body.code === 200 && r.body.data;
+      var hasDetailMemberPrice = detailOk && r.body.data.memberPrice !== undefined;
+      record(F, 'admin', '活动详情会员价', hasDetailMemberPrice,
+        hasDetailMemberPrice ? 'memberPrice=' + r.body.data.memberPrice : 'detail missing memberPrice');
+    } else {
+      skip(F, 'admin', '活动详情会员价', '无活动数据');
+    }
+
+
     r = await apiCall('POST', '/api/admin/butler/list', {}, t2);
     record(F, 'admin', '管家列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'butler list OK' : r.raw);
   }
@@ -1108,10 +1125,39 @@ async function testContentFlow() {
   r = await apiCall('POST', '/api/articles/daily-tip', {}, t);
   record(F, 'parent', '每日贴士', r.status === 200 && r.body && r.body.code === 200, r.body ? 'daily tip OK' : r.raw);
 
+  // 文章详情 + 阅读时长字段(需求:阅读时长功能)
+  var artList = (r.body && r.body.code === 200 && r.body.data && r.body.data.records) ? r.body.data.records : [];
+  // 上面 r 是 daily-tip 的响应,重新取文章列表
+  var artListResp = await apiCall('POST', '/api/articles/list', {}, t);
+  var artData = (artListResp.body && artListResp.body.code === 200 && artListResp.body.data) ? artListResp.body.data : null;
+  var arts = artData && artData.records ? artData.records : (Array.isArray(artData) ? artData : []);
+  if (arts.length > 0 && arts[0].id) {
+    r = await apiCall('POST', '/api/articles/detail', { id: arts[0].id }, t);
+    var artDetailOk = r.status === 200 && r.body && r.body.code === 200 && r.body.data;
+    record(F, 'parent', '文章详情', artDetailOk, artDetailOk ? 'detail OK' : r.raw);
+    // readTime 字段(需求:阅读时长)
+    var hasReadTime = artDetailOk && r.body.data.readTime !== undefined;
+    record(F, 'parent', '文章阅读时长字段', hasReadTime,
+      hasReadTime ? 'readTime=' + r.body.data.readTime : 'missing readTime');
+
+    // 上报阅读时长(需求:阅读时长统计)
+    r = await apiCall('POST', '/api/articles/record-read', { id: arts[0].id, childId: 1003, durationSeconds: 30 }, t);
+    record(F, 'parent', '上报阅读时长', r.status === 200 && r.body && r.body.code === 200, r.body ? 'recorded' : r.raw);
+  } else {
+    skip(F, 'parent', '文章详情', '无文章数据');
+    skip(F, 'parent', '文章阅读时长字段', '无文章数据');
+    skip(F, 'parent', '上报阅读时长', '无文章数据');
+  }
+
   // 分享
   r = await apiCall('POST', '/api/share/my', {}, t);
   record(F, 'parent', '我的分享', r.status === 200 && r.body && r.body.code === 200, r.body ? 'my shares OK' : r.raw);
 
+  // 分享海报 — 生成小程序码(需求 855a8df5)
+  r = await apiCall('POST', '/api/share/qrcode', { page: 'pages/activity/activity-detail/activity-detail', scene: 'id=1' }, t);
+  record(F, 'parent', '分享小程序码', r.status === 200 && r.body && r.body.code === 200,
+    (r.body && r.body.data) ? 'qrcode OK' : r.raw);
+
   // 媒体(使用真实存在的taskId)
   r = await apiCall('POST', '/api/media/upload-text', { taskId: 192, creatorId: 1002, content: 'Test media text' }, t);
   record(F, 'parent', '保存文字记录', r.status === 200 && r.body && r.body.code === 200, r.body ? 'text upload OK' : r.body ? r.body.message : r.raw);
@@ -1121,6 +1167,18 @@ async function testContentFlow() {
   if (tA) {
     r = await apiCall('POST', '/api/admin/articles/list', {}, tA);
     record(F, 'admin', '文章管理列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'admin articles OK' : r.raw);
+
+    // 文章审核状态过滤(需求 ab9f4a44:admin/articles/list 支持 auditStatus 参数)
+    r = await apiCall('POST', '/api/admin/articles/list', { auditStatus: 'approved' }, tA);
+    record(F, 'admin', '文章按审核状态过滤', r.status === 200 && r.body && r.body.code === 200,
+      r.body ? 'auditStatus filter OK' : r.raw);
+
+    // 图片上传端点存在性验证(需求 598e7601 + c697fb7b:图片上传+5M限制)
+    // 不发文件只验证端点可达(无文件应返回错误而非 404)
+    r = await apiCall('POST', '/api/admin/articles/upload/image', {}, tA);
+    var uploadEndpointExists = r.status === 200 && r.body && (r.body.code === 500 || r.body.code === 200);
+    record(F, 'admin', '图片上传端点', uploadEndpointExists,
+      r.body ? 'upload endpoint reachable: ' + (r.body.message || '') : r.raw);
   }
 }
 
@@ -1332,8 +1390,41 @@ async function testCircleFlow() {
   record(F, 'parent', '联系人列表', r.status === 200 && r.body && r.body.code === 200, r.body && r.body.data ? 'contacts OK' : r.raw);
 
   // 家庭挑战
-  r = await apiCall('POST', '/api/health/challenge/list', {}, t);
-  record(F, 'parent', '家庭挑战列表', r.status === 200 && r.body && r.body.code === 200, r.body ? 'challenges OK' : r.raw);
+  // 家庭挑战 — 双目标模式字段验证
+  // 先从 /api/family/user/info 获取 familyId
+  var familyId = null;
+  var infoResp = await apiCall('POST', '/api/family/user/info', {}, t);
+  if (infoResp.body && infoResp.body.code === 200 && infoResp.body.data) {
+    familyId = infoResp.body.data.familyId || infoResp.body.data.familyId;
+  }
+  // 如果上面没拿到,用固定测试值 2001(与文件其他地方一致,如 line 333/462/520)
+  if (!familyId) familyId = 2001;
+
+  r = await apiCall('POST', '/api/health/challenge/list', { familyId: familyId }, t);
+  var challengeOk = r.status === 200 && r.body && r.body.code === 200;
+  record(F, 'parent', '家庭挑战列表', challengeOk, challengeOk ? 'list OK' : r.raw);
+  // 验证双目标字段
+  var challenges = (r.body && r.body.data) ? r.body.data : [];
+  var hasTargetFields = challenges.length > 0 && challenges[0].targetMode && challenges[0].targetValue !== undefined;
+  record(F, 'parent', '挑战目标模式字段', challengeOk && hasTargetFields,
+    hasTargetFields ? 'targetMode=' + challenges[0].targetMode + ' targetValue=' + challenges[0].targetValue : 'no active challenges or missing fields');
+  // 验证进度字段
+  var hasProgressFields = challenges.length > 0 && challenges[0].totalProgress !== undefined && Array.isArray(challenges[0].memberProgress);
+  record(F, 'parent', '挑战进度字段', challengeOk && hasProgressFields,
+    hasProgressFields ? 'totalProgress=' + challenges[0].totalProgress + ' memberProgress=' + challenges[0].memberProgress.length + '人' : 'no progress fields');
+
+  // 历史挑战
+  r = await apiCall('POST', '/api/health/challenge/history', { familyId: familyId }, t);
+  record(F, 'parent', '挑战历史', r.status === 200 && r.body && r.body.code === 200, r.body ? 'history OK' : r.raw);
+
+  // 进度上报(如存在 active 挑战,上报 delta=1)
+  if (challenges.length > 0) {
+    var ch = challenges[0];
+    r = await apiCall('POST', '/api/health/challenge/progress', { challengeId: ch.id, childId: 1003, delta: 1 }, t);
+    record(F, 'parent', '挑战进度上报', r.status === 200 && r.body && r.body.code === 200, r.body ? 'progress reported' : r.raw);
+  } else {
+    skip(F, 'parent', '挑战进度上报', '无活跃挑战');
+  }
 }
 
 // ================================================================