test-migration.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #!/usr/bin/env node
  2. /**
  3. * Zustand 迁移自动化测试脚本
  4. * 测试范围:P0 核心配置 + P1 主要页面
  5. */
  6. import http from 'http';
  7. import assert from 'assert';
  8. // 配置
  9. const BASE_URL = 'http://localhost:3100';
  10. const TIMEOUT = 10000;
  11. // 颜色输出
  12. const colors = {
  13. reset: '\x1b[0m',
  14. green: '\x1b[32m',
  15. red: '\x1b[31m',
  16. yellow: '\x1b[33m',
  17. blue: '\x1b[34m',
  18. };
  19. // 测试工具
  20. const TestUtil = {
  21. // HTTP GET 请求
  22. async get(path) {
  23. return new Promise((resolve, reject) => {
  24. const url = new URL(path, BASE_URL);
  25. http.get(url, (res) => {
  26. let data = '';
  27. res.on('data', (chunk) => data += chunk);
  28. res.on('end', () => {
  29. resolve({
  30. statusCode: res.statusCode,
  31. headers: res.headers,
  32. body: data,
  33. });
  34. });
  35. }).on('error', reject);
  36. setTimeout(() => {
  37. reject(new Error(`Request timeout: ${path}`));
  38. }, TIMEOUT);
  39. });
  40. },
  41. // 断言页面正常加载
  42. assertPageLoaded(response, pageName) {
  43. assert.strictEqual(
  44. response.statusCode,
  45. 200,
  46. `${pageName} 页面加载失败,状态码:${response.statusCode}`
  47. );
  48. assert.ok(
  49. response.body.length > 0,
  50. `${pageName} 页面内容为空`
  51. );
  52. },
  53. // 断言无 MobX 错误
  54. assertNoMobxError(response, pageName) {
  55. if (response.body.toLowerCase().includes('mobx')) {
  56. console.warn(`${colors.yellow}警告:${pageName} 页面仍包含 MobX 引用${colors.reset}`);
  57. }
  58. },
  59. // 断言使用 Zustand
  60. assertUsesZustand(response, pageName) {
  61. // 检查是否使用了 Zustand store
  62. if (response.body.includes('useAppStore') ||
  63. response.body.includes('useLoginStore') ||
  64. response.body.includes('useLayoutStore') ||
  65. response.body.includes('useHomeStore') ||
  66. response.body.includes('useKnowledgeLibListStore') ||
  67. response.body.includes('useQuestionAnswerInfoStore') ||
  68. response.body.includes('useChatStore')) {
  69. console.log(` ✅ ${pageName} 使用 Zustand`);
  70. }
  71. },
  72. };
  73. // 测试用例
  74. const tests = [
  75. {
  76. name: 'P0 - 登录页面',
  77. path: '/login',
  78. test: async (response) => {
  79. TestUtil.assertPageLoaded(response, '登录页面');
  80. TestUtil.assertNoMobxError(response, '登录页面');
  81. TestUtil.assertUsesZustand(response, '登录页面');
  82. // 检查是否自动跳转(Demo 模式)
  83. if (response.body.includes('useLoginStore')) {
  84. console.log(' ✅ 登录页面使用 useLoginStore');
  85. }
  86. },
  87. },
  88. {
  89. name: 'P0 - 应用广场',
  90. path: '/appCenter',
  91. test: async (response) => {
  92. TestUtil.assertPageLoaded(response, '应用广场');
  93. TestUtil.assertNoMobxError(response, '应用广场');
  94. TestUtil.assertUsesZustand(response, '应用广场');
  95. if (response.body.includes('useAppStore')) {
  96. console.log(' ✅ 应用广场使用 useAppStore');
  97. }
  98. },
  99. },
  100. {
  101. name: 'P0 - 首页/控制台',
  102. path: '/overview',
  103. test: async (response) => {
  104. TestUtil.assertPageLoaded(response, '首页');
  105. TestUtil.assertNoMobxError(response, '首页');
  106. TestUtil.assertUsesZustand(response, '首页');
  107. if (response.body.includes('useHomeStore')) {
  108. console.log(' ✅ 首页使用 useHomeStore');
  109. }
  110. },
  111. },
  112. {
  113. name: 'P1 - 我创建的应用',
  114. path: '/appCenter/questionAnswer',
  115. test: async (response) => {
  116. TestUtil.assertPageLoaded(response, '我创建的应用');
  117. TestUtil.assertNoMobxError(response, '我创建的应用');
  118. TestUtil.assertUsesZustand(response, '我创建的应用');
  119. },
  120. },
  121. {
  122. name: 'P1 - 创建应用',
  123. path: '/appCenter/questionAnswer/create',
  124. test: async (response) => {
  125. TestUtil.assertPageLoaded(response, '创建应用');
  126. TestUtil.assertNoMobxError(response, '创建应用');
  127. TestUtil.assertUsesZustand(response, '创建应用');
  128. if (response.body.includes('useQuestionAnswerInfoStore')) {
  129. console.log(' ✅ 创建应用使用 useQuestionAnswerInfoStore');
  130. }
  131. },
  132. },
  133. {
  134. name: 'P1 - 知识库列表',
  135. path: '/knowledge/knowledgeLib',
  136. test: async (response) => {
  137. TestUtil.assertPageLoaded(response, '知识库列表');
  138. TestUtil.assertNoMobxError(response, '知识库列表');
  139. TestUtil.assertUsesZustand(response, '知识库列表');
  140. if (response.body.includes('useKnowledgeLibListStore')) {
  141. console.log(' ✅ 知识库列表使用 useKnowledgeLibListStore');
  142. }
  143. },
  144. },
  145. {
  146. name: 'P1 - API Key 管理',
  147. path: '/system/apiKey',
  148. test: async (response) => {
  149. TestUtil.assertPageLoaded(response, 'API Key 管理');
  150. TestUtil.assertNoMobxError(response, 'API Key 管理');
  151. },
  152. },
  153. {
  154. name: 'P1 - 应用审核',
  155. path: '/system/audit',
  156. test: async (response) => {
  157. TestUtil.assertPageLoaded(response, '应用审核');
  158. TestUtil.assertNoMobxError(response, '应用审核');
  159. },
  160. },
  161. ];
  162. // 主函数
  163. async function runTests() {
  164. console.log(`\n${colors.blue}================================${colors.reset}`);
  165. console.log(`${colors.blue}Zustand 迁移自动化测试${colors.reset}`);
  166. console.log(`${colors.blue}================================${colors.reset}\n`);
  167. console.log(`测试目标:${BASE_URL}`);
  168. console.log(`测试范围:P0 核心配置 + P1 主要页面\n`);
  169. const results = {
  170. passed: 0,
  171. failed: 0,
  172. warnings: 0,
  173. };
  174. for (const test of tests) {
  175. try {
  176. console.log(`运行测试:${test.name}`);
  177. const response = await TestUtil.get(test.path);
  178. await test.test(response);
  179. console.log(`${colors.green}✅ 通过${colors.reset}\n`);
  180. results.passed++;
  181. } catch (error) {
  182. console.log(`${colors.red}❌ 失败:${error.message}${colors.reset}\n`);
  183. results.failed++;
  184. }
  185. }
  186. // 输出总结
  187. console.log(`\n${colors.blue}================================${colors.reset}`);
  188. console.log(`${colors.blue}测试总结${colors.reset}`);
  189. console.log(`${colors.blue}================================${colors.reset}`);
  190. console.log(`总测试数:${tests.length}`);
  191. console.log(`${colors.green}通过:${results.passed}${colors.reset}`);
  192. console.log(`${colors.red}失败:${results.failed}${colors.reset}`);
  193. console.log(`${colors.yellow}警告:${results.warnings}${colors.reset}`);
  194. console.log(`成功率:${((results.passed / tests.length) * 100).toFixed(1)}%\n`);
  195. // 退出码
  196. process.exit(results.failed > 0 ? 1 : 0);
  197. }
  198. // 运行测试
  199. runTests().catch((error) => {
  200. console.error(`${colors.red}测试执行失败:${error.message}${colors.reset}`);
  201. process.exit(1);
  202. });