run-api-tests-v3-file.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /**
  2. * CFC API v3 快速测试 - 文件输出版
  3. * 运行: node tests/run-api-tests-v3-file.js
  4. */
  5. const fs = require('fs');
  6. const path = require('path');
  7. const BASE = 'http://cfc.iwintrue.com:80';
  8. const ADMIN = { phone: '13800138000', userId: 7 };
  9. let adminToken = null;
  10. const results = [];
  11. function log(msg) { results.push(`[LOG] ${msg}`); }
  12. function pass(name, detail) { results.push(`PASS|${name}|${detail || ''}`); }
  13. function fail(name, err, detail) { results.push(`FAIL|${name}|${err.message}${detail ? '|' + detail : ''}`); }
  14. function skip(name, reason) { results.push(`SKIP|${name}|${reason}`); }
  15. async function api(path, body, headers = {}) {
  16. try {
  17. const resp = await fetch(`${BASE}${path}`, {
  18. method: 'POST',
  19. headers: { 'Content-Type': 'application/json', ...headers },
  20. body: body ? JSON.stringify(body) : undefined,
  21. });
  22. const text = await resp.text();
  23. let data;
  24. try { data = JSON.parse(text); } catch { data = null; }
  25. return { status: resp.status, data, ok: resp.ok, raw: text.substring(0, 200) };
  26. } catch (err) {
  27. return { ok: false, data: null, error: err.message };
  28. }
  29. }
  30. async function adminApi(path, body) {
  31. if (!adminToken) return { ok: false, data: null, error: '无token' };
  32. return api(path, body, { Authorization: `Bearer ${adminToken}` });
  33. }
  34. async function main() {
  35. log('=== 登录 ===');
  36. await api('/api/admin-auth/send-code', { phone: ADMIN.phone });
  37. const loginResp = await api('/api/admin-auth/login', { phone: ADMIN.phone, code: '123456' });
  38. if (loginResp.data?.data?.token) {
  39. adminToken = loginResp.data.data.token;
  40. pass('Admin登录', `userId=${loginResp.data.data.adminId}`);
  41. } else {
  42. fail('Admin登录', new Error('无token'), loginResp.raw);
  43. }
  44. // NEW-01: 能量规则创建
  45. log('=== NEW-01: 能量规则创建 ===');
  46. let ruleId = null;
  47. const er = await adminApi('/api/admin/energy-rule/create', {
  48. ruleName: '自动化测试规则_NEW01_' + Date.now(),
  49. dimensionCode: 'body', eventType: 'checkin', energyValue: 5, status: 1,
  50. });
  51. if (er.ok || er.data?.code === 200) {
  52. ruleId = er.data?.data?.id || er.data?.id;
  53. pass('NEW-01 创建能量规则', `id=${ruleId}`);
  54. } else {
  55. fail('NEW-01 创建能量规则', new Error(`code=${er.data?.code} msg=${er.data?.message || ''}`));
  56. }
  57. // NEW-02: SKU列表
  58. log('=== NEW-02: SKU列表 ===');
  59. const sku = await adminApi('/api/admin/product/sku/list', { productId: 1 });
  60. if (sku.ok || sku.data?.code === 200) {
  61. const count = Array.isArray(sku.data?.data) ? sku.data.data.length : 0;
  62. pass('NEW-02 SKU列表', `count=${count}`);
  63. } else {
  64. fail('NEW-02 SKU列表', new Error(`code=${sku.data?.code} msg=${sku.data?.message || ''}`));
  65. }
  66. // NEW-03: 活动发布
  67. log('=== NEW-03: 活动发布 ===');
  68. let actId = null;
  69. const act = await adminApi('/api/activity/create', {
  70. title: '自动化E2E测试活动_NEW03_' + Date.now(),
  71. description: 'NEW-03修复验证',
  72. dimensionCode: 'body',
  73. startTime: new Date(Date.now() + 86400000 * 7).toISOString().replace('T', ' ').split('.')[0],
  74. endTime: new Date(Date.now() + 86400000 * 8).toISOString().replace('T', ' ').split('.')[0],
  75. location: '线上直播', maxParticipants: 30,
  76. });
  77. if (act.ok || act.data?.code === 200) {
  78. actId = act.data?.data?.id || act.data?.id;
  79. pass('创建测试活动', `id=${actId}`);
  80. } else {
  81. fail('创建测试活动', new Error(`code=${act.data?.code} msg=${act.data?.message || ''}`));
  82. }
  83. if (actId) {
  84. const pub = await adminApi('/api/activity/publish', { id: actId });
  85. if (pub.ok || pub.data?.code === 200) {
  86. pass('NEW-03 发布活动', `id=${actId}`);
  87. } else {
  88. fail('NEW-03 发布活动', new Error(`code=${pub.data?.code} msg=${pub.data?.message || ''}`));
  89. }
  90. }
  91. // ISSUE-001: 供应商下架
  92. log('=== ISSUE-001: 供应商下架 ===');
  93. const vs = await api('/api/product/shelve', { productId: 7, action: 'unshelve' }, { 'X-User-Id': '81069' });
  94. if (vs.ok || vs.data?.code === 200) {
  95. pass('ISSUE-001 供应商下架', 'ok');
  96. } else {
  97. fail('ISSUE-001 供应商下架', new Error(`code=${vs.data?.code} msg=${vs.data?.message || ''}`));
  98. }
  99. // ISSUE-003: 创建用户
  100. log('=== ISSUE-003: 创建用户 ===');
  101. const phone = '139' + String(Math.floor(Math.random() * 1e9)).padStart(9, '0');
  102. const cu = await adminApi('/api/admin/users/create', {
  103. phone, password: 'Test123456', name: '自动化测试用户', role: 'parent',
  104. });
  105. if (cu.ok || cu.data?.code === 200) {
  106. pass('ISSUE-003 创建用户', `userId=${cu.data?.data?.id || cu.data?.id}`);
  107. } else {
  108. fail('ISSUE-003 创建用户', new Error(`code=${cu.data?.code} msg=${cu.data?.message || ''}`));
  109. }
  110. // 新API: grantEnergy
  111. log('=== 新增API: energy.grantEnergy ===');
  112. const ge = await adminApi('/api/energy/grantEnergy', { childId: 1, taskId: 1, amount: 10, dimensionCode: 'body' });
  113. if (ge.ok || ge.data?.code === 200) {
  114. pass('energy.grantEnergy', 'ok');
  115. } else {
  116. fail('energy.grantEnergy', new Error(`code=${ge.data?.code} msg=${ge.data?.message || ''}`));
  117. }
  118. // 新API: points.checkAndGrantReward
  119. log('=== 新增API: points.checkAndGrantReward ===');
  120. const pr = await adminApi('/api/points/checkAndGrantReward', { childId: 1, amount: 5 });
  121. if (pr.ok || pr.data?.code === 200 || pr.data?.data === -1) {
  122. pass('points.checkAndGrantReward', `result=${pr.data?.data}`);
  123. } else {
  124. fail('points.checkAndGrantReward', new Error(`code=${pr.data?.code} msg=${pr.data?.message || ''}`));
  125. }
  126. // 新API: growth.getRecordsByChild
  127. log('=== 新增API: growth.getRecordsByChild ===');
  128. const gr = await adminApi('/api/growth/record/child/1', {});
  129. if (gr.ok || gr.data?.code === 200) {
  130. const count = Array.isArray(gr.data?.data) ? gr.data.data.length : 0;
  131. pass('growth.getRecordsByChild', `count=${count}`);
  132. } else {
  133. fail('growth.getRecordsByChild', new Error(`code=${gr.data?.code} msg=${gr.data?.message || ''}`));
  134. }
  135. // 生成报告
  136. const passed = results.filter(r => r.startsWith('PASS')).length;
  137. const failed = results.filter(r => r.startsWith('FAIL')).length;
  138. const skipped = results.filter(r => r.startsWith('SKIP')).length;
  139. let report = `API 测试结果 - ${new Date().toLocaleString()}\n`;
  140. report += `========================================\n\n`;
  141. results.forEach(r => { report += r + '\n'; });
  142. report += `\n========================================\n`;
  143. report += `总计: ${passed} PASS / ${failed} FAIL / ${skipped} SKIP\n`;
  144. const reportPath = path.join(__dirname, 'v3_results.txt');
  145. fs.writeFileSync(reportPath, report, 'utf8');
  146. console.log('Report: ' + reportPath);
  147. console.log('PASS=' + passed + ' FAIL=' + failed + ' SKIP=' + skipped);
  148. }
  149. main().catch(err => {
  150. const msg = 'ERROR: ' + err.message;
  151. console.log(msg);
  152. fs.writeFileSync(path.join(__dirname, 'v3_results.txt'), msg, 'utf8');
  153. });