api-complete.test.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /**
  2. * 用户和 API Key 管理完整 E2E 测试
  3. *
  4. * 📋 测试范围:
  5. * - 用户 CRUD 操作
  6. * - Key CRUD 操作
  7. * - 完整业务流程
  8. *
  9. * ✅ 全部通过的自动化测试脚本
  10. *
  11. * 🔑 认证方式:Cookie (auth-token)
  12. * ⚙️ 前提:开发服务器运行在 http://localhost:13500
  13. * 🧹 清理:测试完成后自动清理数据
  14. */
  15. import { afterAll, describe, expect, test } from "vitest";
  16. // ==================== 配置 ====================
  17. const API_BASE_URL = process.env.API_BASE_URL || "http://localhost:13500/api/actions";
  18. const ADMIN_TOKEN = process.env.TEST_ADMIN_TOKEN || process.env.ADMIN_TOKEN;
  19. const testData = {
  20. userIds: [] as number[],
  21. };
  22. // ==================== 辅助函数 ====================
  23. async function callApi(module: string, action: string, body: Record<string, unknown> = {}) {
  24. const response = await fetch(`${API_BASE_URL}/${module}/${action}`, {
  25. method: "POST",
  26. headers: {
  27. "Content-Type": "application/json",
  28. Cookie: `auth-token=${ADMIN_TOKEN}`,
  29. },
  30. body: JSON.stringify(body),
  31. });
  32. const contentType = response.headers.get("content-type");
  33. if (contentType?.includes("application/json")) {
  34. const data = await response.json();
  35. return { response, data };
  36. }
  37. const text = await response.text();
  38. return { response, data: { ok: false, error: `非JSON响应: ${text}` } };
  39. }
  40. async function expectSuccess(module: string, action: string, body: Record<string, unknown> = {}) {
  41. const { response, data } = await callApi(module, action, body);
  42. expect(response.ok).toBe(true);
  43. expect(data.ok).toBe(true);
  44. return data.data;
  45. }
  46. // ==================== 测试清理 ====================
  47. afterAll(async () => {
  48. console.log(`\n🧹 清理 ${testData.userIds.length} 个测试用户...`);
  49. for (const userId of testData.userIds) {
  50. try {
  51. await callApi("users", "removeUser", { userId });
  52. } catch (_e) {
  53. // 忽略清理错误
  54. }
  55. }
  56. console.log("✅ 清理完成\n");
  57. });
  58. // ==================== 测试 ====================
  59. describe("用户和 Key 管理 - E2E 测试", () => {
  60. let user1Id: number;
  61. let user2Id: number;
  62. test("✅ 1. 创建第一个用户", async () => {
  63. const result = await expectSuccess("users", "addUser", {
  64. name: `E2E用户1_${Date.now()}`,
  65. note: "测试用户1",
  66. rpm: 100,
  67. dailyQuota: 50,
  68. });
  69. expect(result.user).toBeDefined();
  70. expect(result.defaultKey).toBeDefined();
  71. expect(result.defaultKey.key).toMatch(/^sk-[a-f0-9]{32}$/);
  72. user1Id = result.user.id;
  73. testData.userIds.push(user1Id);
  74. console.log(` ✅ 用户1 ID: ${user1Id}`);
  75. });
  76. test("✅ 2. 创建第二个用户(带限额)", async () => {
  77. const result = await expectSuccess("users", "addUser", {
  78. name: `E2E用户2_${Date.now()}`,
  79. rpm: 200,
  80. dailyQuota: 100,
  81. limit5hUsd: 50,
  82. limitWeeklyUsd: 300,
  83. tags: ["test"],
  84. });
  85. user2Id = result.user.id;
  86. testData.userIds.push(user2Id);
  87. console.log(` ✅ 用户2 ID: ${user2Id}`);
  88. });
  89. test("✅ 3. 获取用户列表", async () => {
  90. const users = await expectSuccess("users", "getUsers");
  91. expect(Array.isArray(users)).toBe(true);
  92. expect(users.length).toBeGreaterThanOrEqual(2);
  93. const user1 = users.find((u: any) => u.id === user1Id);
  94. expect(user1).toBeDefined();
  95. });
  96. test("✅ 4. 编辑用户信息", async () => {
  97. await expectSuccess("users", "editUser", {
  98. userId: user1Id,
  99. rpm: 150,
  100. dailyQuota: 80,
  101. });
  102. const users = await expectSuccess("users", "getUsers");
  103. const user = users.find((u: any) => u.id === user1Id);
  104. expect(user.rpm).toBe(150);
  105. });
  106. test("✅ 5. 禁用和启用用户(通过 editUser)", async () => {
  107. // 禁用用户
  108. await expectSuccess("users", "editUser", {
  109. userId: user1Id,
  110. isEnabled: false,
  111. });
  112. let users = await expectSuccess("users", "getUsers");
  113. let user = users.find((u: any) => u.id === user1Id);
  114. expect(user.isEnabled).toBe(false);
  115. // 启用用户
  116. await expectSuccess("users", "editUser", {
  117. userId: user1Id,
  118. isEnabled: true,
  119. });
  120. users = await expectSuccess("users", "getUsers");
  121. user = users.find((u: any) => u.id === user1Id);
  122. expect(user.isEnabled).toBe(true);
  123. });
  124. test("✅ 6. 获取用户的 Keys", async () => {
  125. const keys = await expectSuccess("keys", "getKeys", { userId: user1Id });
  126. expect(Array.isArray(keys)).toBe(true);
  127. expect(keys.length).toBeGreaterThanOrEqual(1);
  128. // 验证 Key 格式(管理员可能看到完整 Key 或脱敏 Key)
  129. const keyValue = keys[0].key;
  130. const isFullKey = /^sk-[a-f0-9]{32}$/.test(keyValue); // 完整 Key
  131. const isMaskedKey = /^sk-\*+[a-f0-9]{8}$/.test(keyValue); // 脱敏 Key
  132. expect(isFullKey || isMaskedKey).toBe(true);
  133. });
  134. test("✅ 7. 为用户创建新 Key", async () => {
  135. const result = await expectSuccess("keys", "addKey", {
  136. userId: user1Id,
  137. name: `E2EKey_${Date.now()}`,
  138. });
  139. expect(result.generatedKey).toMatch(/^sk-[a-f0-9]{32}$/);
  140. console.log(` ✅ Key: ${result.generatedKey}`);
  141. });
  142. test("✅ 8. 创建带限额的 Key", async () => {
  143. const result = await expectSuccess("keys", "addKey", {
  144. userId: user2Id,
  145. name: `E2E限额Key_${Date.now()}`,
  146. limitDailyUsd: 5,
  147. limit5hUsd: 10,
  148. });
  149. expect(result.generatedKey).toBeDefined();
  150. });
  151. test("✅ 9. 验证 Key 数量", async () => {
  152. const keys = await expectSuccess("keys", "getKeys", { userId: user1Id });
  153. expect(keys.length).toBeGreaterThanOrEqual(2); // 默认Key + 新建的Key
  154. });
  155. test("✅ 10. 完整流程测试", async () => {
  156. // 创建用户
  157. const createResult = await expectSuccess("users", "addUser", {
  158. name: `E2E完整流程_${Date.now()}`,
  159. rpm: 60,
  160. dailyQuota: 10,
  161. });
  162. const userId = createResult.user.id;
  163. testData.userIds.push(userId);
  164. // 创建额外Key
  165. await expectSuccess("keys", "addKey", {
  166. userId,
  167. name: `流程Key1_${Date.now()}`,
  168. });
  169. await expectSuccess("keys", "addKey", {
  170. userId,
  171. name: `流程Key2_${Date.now()}`,
  172. });
  173. // 验证 Keys
  174. const keys = await expectSuccess("keys", "getKeys", { userId });
  175. expect(keys.length).toBe(3); // 1默认 + 2新建
  176. // 删除用户(自动删除所有Keys)
  177. await expectSuccess("users", "removeUser", { userId });
  178. // 验证已删除
  179. const users = await expectSuccess("users", "getUsers");
  180. const deletedUser = users.find((u: any) => u.id === userId);
  181. expect(deletedUser).toBeUndefined();
  182. console.log(` ✅ 完整流程通过`);
  183. });
  184. });