channel.integration.test.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. import { describe, it, expect, beforeEach } from 'vitest';
  2. import { testClient } from 'hono/testing';
  3. import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
  4. import { JWTUtil } from '@d8d/shared-utils';
  5. import { UserEntity, Role } from '@d8d/user-module';
  6. import { File } from '@d8d/file-module';
  7. import channelRoutes from '../../src/routes/channel.routes';
  8. import { Channel } from '../../src/entities/channel.entity';
  9. // 设置集成测试钩子
  10. setupIntegrationDatabaseHooksWithEntities([UserEntity, File, Role, Channel])
  11. describe('渠道管理API集成测试', () => {
  12. let client: ReturnType<typeof testClient<typeof channelRoutes>>;
  13. let testToken: string;
  14. let testUser: UserEntity;
  15. beforeEach(async () => {
  16. // 创建测试客户端
  17. client = testClient(channelRoutes);
  18. // 获取数据源
  19. const dataSource = await IntegrationTestDatabase.getDataSource();
  20. // 创建测试用户
  21. const userRepository = dataSource.getRepository(UserEntity);
  22. testUser = userRepository.create({
  23. username: `test_user_${Date.now()}`,
  24. password: 'test_password',
  25. nickname: '测试用户',
  26. registrationSource: 'web'
  27. });
  28. await userRepository.save(testUser);
  29. // 生成测试用户的token
  30. testToken = JWTUtil.generateToken({
  31. id: testUser.id,
  32. username: testUser.username,
  33. roles: [{name:'user'}]
  34. });
  35. });
  36. describe('POST /channel/createChannel', () => {
  37. it('应该成功创建渠道', async () => {
  38. const createData = {
  39. channelName: '微信小程序渠道',
  40. channelType: '小程序',
  41. contactPerson: '张三',
  42. contactPhone: '13800138000',
  43. description: '微信小程序渠道描述'
  44. };
  45. const response = await client.createChannel.$post({
  46. json: createData
  47. }, {
  48. headers: {
  49. 'Authorization': `Bearer ${testToken}`
  50. }
  51. });
  52. console.debug('创建渠道响应状态:', response.status);
  53. expect(response.status).toBe(200);
  54. if (response.status === 200) {
  55. const data = await response.json();
  56. expect(data.channelName).toBe(createData.channelName);
  57. expect(data.channelType).toBe(createData.channelType);
  58. }
  59. });
  60. it('应该验证渠道名称重复', async () => {
  61. // 先创建一个渠道
  62. const dataSource = await IntegrationTestDatabase.getDataSource();
  63. const channelRepository = dataSource.getRepository(Channel);
  64. const existingChannel = channelRepository.create({
  65. channelName: '微信小程序渠道',
  66. channelType: '小程序',
  67. contactPerson: '张三',
  68. contactPhone: '13800138000',
  69. status: 1
  70. });
  71. await channelRepository.save(existingChannel);
  72. // 尝试创建同名渠道
  73. const createData = {
  74. channelName: '微信小程序渠道', // 重复的名称
  75. channelType: '小程序',
  76. contactPerson: '李四',
  77. contactPhone: '13900139000'
  78. };
  79. const response = await client.createChannel.$post({
  80. json: createData
  81. }, {
  82. headers: {
  83. 'Authorization': `Bearer ${testToken}`
  84. }
  85. });
  86. expect(response.status).toBe(400);
  87. if (response.status === 400) {
  88. const data = await response.json();
  89. expect(data.message).toContain('渠道名称已存在');
  90. }
  91. });
  92. it('应该拒绝未认证用户的访问', async () => {
  93. const createData = {
  94. channelName: '测试渠道',
  95. channelType: '测试'
  96. };
  97. const response = await client.createChannel.$post({
  98. json: createData
  99. });
  100. expect(response.status).toBe(401);
  101. });
  102. });
  103. describe('POST /channel/deleteChannel', () => {
  104. it('应该成功删除渠道', async () => {
  105. // 先创建一个渠道
  106. const dataSource = await IntegrationTestDatabase.getDataSource();
  107. const channelRepository = dataSource.getRepository(Channel);
  108. const testChannel = channelRepository.create({
  109. channelName: `待删除渠道_${Date.now()}`,
  110. channelType: '测试',
  111. contactPerson: '张三',
  112. contactPhone: '13800138000',
  113. status: 1
  114. });
  115. await channelRepository.save(testChannel);
  116. const deleteData = {
  117. id: testChannel.id
  118. };
  119. const response = await client.deleteChannel.$post({
  120. json: deleteData
  121. }, {
  122. headers: {
  123. 'Authorization': `Bearer ${testToken}`
  124. }
  125. });
  126. console.debug('删除渠道响应状态:', response.status);
  127. expect(response.status).toBe(200);
  128. if (response.status === 200) {
  129. const data = await response.json();
  130. expect(data.success).toBe(true);
  131. }
  132. // 验证渠道状态变为0(软删除)
  133. const deletedChannel = await channelRepository.findOne({
  134. where: { id: testChannel.id }
  135. });
  136. expect(deletedChannel?.status).toBe(0);
  137. });
  138. });
  139. describe('POST /channel/updateChannel', () => {
  140. it('应该成功更新渠道', async () => {
  141. // 先创建一个渠道
  142. const dataSource = await IntegrationTestDatabase.getDataSource();
  143. const channelRepository = dataSource.getRepository(Channel);
  144. const testChannel = channelRepository.create({
  145. channelName: `原始渠道_${Date.now()}`,
  146. channelType: '原始类型',
  147. contactPerson: '张三',
  148. contactPhone: '13800138000',
  149. status: 1
  150. });
  151. await channelRepository.save(testChannel);
  152. const updateData = {
  153. id: testChannel.id,
  154. channelName: '更新后的渠道名称',
  155. channelType: '更新类型',
  156. contactPerson: '李四',
  157. contactPhone: '13900139000'
  158. };
  159. const response = await client.updateChannel.$post({
  160. json: updateData
  161. }, {
  162. headers: {
  163. 'Authorization': `Bearer ${testToken}`
  164. }
  165. });
  166. console.debug('更新渠道响应状态:', response.status);
  167. if (response.status !== 200) {
  168. const errorData = await response.json();
  169. console.debug('更新渠道错误:', errorData);
  170. }
  171. expect(response.status).toBe(200);
  172. if (response.status === 200) {
  173. const data = await response.json();
  174. expect(data.channelName).toBe(updateData.channelName);
  175. expect(data.channelType).toBe(updateData.channelType);
  176. }
  177. // 验证渠道已更新
  178. const updatedChannel = await channelRepository.findOne({
  179. where: { id: testChannel.id }
  180. });
  181. expect(updatedChannel?.channelName).toBe(updateData.channelName);
  182. expect(updatedChannel?.channelType).toBe(updateData.channelType);
  183. });
  184. it('应该验证更新时的渠道名称重复', async () => {
  185. // 创建两个渠道
  186. const dataSource = await IntegrationTestDatabase.getDataSource();
  187. const channelRepository = dataSource.getRepository(Channel);
  188. const channel1 = channelRepository.create({
  189. channelName: '渠道A',
  190. channelType: '类型A',
  191. status: 1
  192. });
  193. await channelRepository.save(channel1);
  194. const channel2 = channelRepository.create({
  195. channelName: '渠道B',
  196. channelType: '类型B',
  197. status: 1
  198. });
  199. await channelRepository.save(channel2);
  200. // 尝试将渠道B的名称改为渠道A的名称
  201. const updateData = {
  202. id: channel2.id,
  203. channelName: '渠道A' // 重复的名称
  204. };
  205. const response = await client.updateChannel.$post({
  206. json: updateData
  207. }, {
  208. headers: {
  209. 'Authorization': `Bearer ${testToken}`
  210. }
  211. });
  212. expect(response.status).toBe(400);
  213. if (response.status === 400) {
  214. const data = await response.json();
  215. expect(data.message).toContain('渠道名称已存在');
  216. }
  217. });
  218. });
  219. describe('GET /channel/getAllChannels', () => {
  220. it('应该返回渠道列表', async () => {
  221. // 创建一些测试渠道
  222. const dataSource = await IntegrationTestDatabase.getDataSource();
  223. const channelRepository = dataSource.getRepository(Channel);
  224. for (let i = 0; i < 3; i++) {
  225. const channel = channelRepository.create({
  226. channelName: `测试渠道${i}`,
  227. channelType: '测试',
  228. contactPerson: `联系人${i}`,
  229. contactPhone: `1380013800${i}`,
  230. status: 1
  231. });
  232. await channelRepository.save(channel);
  233. }
  234. const response = await client.getAllChannels.$get({
  235. query: { skip: 0, take: 10 }
  236. }, {
  237. headers: {
  238. 'Authorization': `Bearer ${testToken}`
  239. }
  240. });
  241. console.debug('渠道列表响应状态:', response.status);
  242. expect(response.status).toBe(200);
  243. if (response.status === 200) {
  244. const data = await response.json();
  245. expect(data).toHaveProperty('data');
  246. expect(data).toHaveProperty('total');
  247. expect(Array.isArray(data.data)).toBe(true);
  248. expect(data.total).toBeGreaterThanOrEqual(3);
  249. }
  250. });
  251. it('应该支持分页参数', async () => {
  252. const response = await client.getAllChannels.$get({
  253. query: { skip: 0, take: 5 }
  254. }, {
  255. headers: {
  256. 'Authorization': `Bearer ${testToken}`
  257. }
  258. });
  259. expect(response.status).toBe(200);
  260. });
  261. it('应该过滤已删除的渠道(status=0)', async () => {
  262. // 创建测试数据:3个正常渠道,2个已删除渠道
  263. const dataSource = await IntegrationTestDatabase.getDataSource();
  264. const channelRepository = dataSource.getRepository(Channel);
  265. // 创建3个正常渠道
  266. for (let i = 1; i <= 3; i++) {
  267. const channel = channelRepository.create({
  268. channelName: `正常渠道${i}`,
  269. channelType: `类型${i}`,
  270. contactPerson: `联系人${i}`,
  271. contactPhone: `1380013800${i}`,
  272. status: 1
  273. });
  274. await channelRepository.save(channel);
  275. }
  276. // 创建2个已删除渠道
  277. for (let i = 4; i <= 5; i++) {
  278. const channel = channelRepository.create({
  279. channelName: `已删除渠道${i}`,
  280. channelType: `类型${i}`,
  281. contactPerson: `联系人${i}`,
  282. contactPhone: `1380013800${i}`,
  283. status: 0
  284. });
  285. await channelRepository.save(channel);
  286. }
  287. const response = await client.getAllChannels.$get({
  288. query: { skip: 0, take: 10 }
  289. }, {
  290. headers: {
  291. 'Authorization': `Bearer ${testToken}`
  292. }
  293. });
  294. expect(response.status).toBe(200);
  295. if (response.status === 200) {
  296. const data = await response.json();
  297. // 应该只返回3个正常渠道,不返回已删除的渠道
  298. expect(data.data).toHaveLength(3);
  299. expect(data.total).toBe(3);
  300. // 验证返回的都是正常渠道
  301. data.data.forEach((channel: any) => {
  302. expect(channel.status).toBe(1);
  303. expect(channel.channelName).toMatch(/^正常渠道/);
  304. });
  305. }
  306. });
  307. });
  308. describe('GET /channel/searchChannels', () => {
  309. it('应该按名称搜索渠道', async () => {
  310. // 创建测试渠道
  311. const dataSource = await IntegrationTestDatabase.getDataSource();
  312. const channelRepository = dataSource.getRepository(Channel);
  313. const channel = channelRepository.create({
  314. channelName: '微信小程序搜索测试',
  315. channelType: '小程序',
  316. contactPerson: '张三',
  317. contactPhone: '13800138000',
  318. status: 1
  319. });
  320. await channelRepository.save(channel);
  321. const response = await client.searchChannels.$get({
  322. query: { name: '微信', skip: 0, take: 10 }
  323. }, {
  324. headers: {
  325. 'Authorization': `Bearer ${testToken}`
  326. }
  327. });
  328. console.debug('搜索渠道响应状态:', response.status);
  329. expect(response.status).toBe(200);
  330. if (response.status === 200) {
  331. const data = await response.json();
  332. expect(data.data.length).toBeGreaterThan(0);
  333. expect(data.data[0].channelName).toContain('微信');
  334. }
  335. });
  336. it('应该过滤已删除的渠道(搜索时)', async () => {
  337. // 创建测试数据
  338. const dataSource = await IntegrationTestDatabase.getDataSource();
  339. const channelRepository = dataSource.getRepository(Channel);
  340. // 创建正常渠道
  341. const normalChannel = channelRepository.create({
  342. channelName: '测试搜索渠道正常',
  343. channelType: '正常类型',
  344. contactPerson: '张三',
  345. contactPhone: '13800138000',
  346. status: 1
  347. });
  348. await channelRepository.save(normalChannel);
  349. // 创建已删除的渠道(不同名称)
  350. const deletedChannel = channelRepository.create({
  351. channelName: '测试搜索渠道已删除',
  352. channelType: '删除类型',
  353. contactPerson: '李四',
  354. contactPhone: '13900139000',
  355. status: 0
  356. });
  357. await channelRepository.save(deletedChannel);
  358. const response = await client.searchChannels.$get({
  359. query: { name: '测试搜索', skip: 0, take: 10 }
  360. }, {
  361. headers: {
  362. 'Authorization': `Bearer ${testToken}`
  363. }
  364. });
  365. expect(response.status).toBe(200);
  366. if (response.status === 200) {
  367. const data = await response.json();
  368. // 应该只返回1个正常渠道,不返回已删除的渠道
  369. expect(data.data).toHaveLength(1);
  370. expect(data.total).toBe(1);
  371. expect(data.data[0].channelName).toBe('测试搜索渠道正常');
  372. expect(data.data[0].status).toBe(1);
  373. expect(data.data[0].contactPerson).toBe('张三'); // 正常渠道的联系人
  374. }
  375. });
  376. });
  377. describe('GET /channel/getChannel/:id', () => {
  378. it('应该返回指定渠道的详情', async () => {
  379. // 先创建一个渠道
  380. const dataSource = await IntegrationTestDatabase.getDataSource();
  381. const channelRepository = dataSource.getRepository(Channel);
  382. const testChannel = channelRepository.create({
  383. channelName: `详情测试渠道_${Date.now()}`,
  384. channelType: '测试',
  385. contactPerson: '张三',
  386. contactPhone: '13800138000',
  387. status: 1
  388. });
  389. await channelRepository.save(testChannel);
  390. const response = await client.getChannel[':id'].$get({
  391. param: { id: testChannel.id }
  392. }, {
  393. headers: {
  394. 'Authorization': `Bearer ${testToken}`
  395. }
  396. });
  397. console.debug('渠道详情响应状态:', response.status);
  398. expect(response.status).toBe(200);
  399. if (response.status === 200) {
  400. const data = await response.json();
  401. expect(data!.id).toBe(testChannel.id);
  402. expect(data!.channelName).toBe(testChannel.channelName);
  403. }
  404. });
  405. it('应该处理不存在的渠道', async () => {
  406. const response = await client.getChannel[':id'].$get({
  407. param: { id: 999999 }
  408. }, {
  409. headers: {
  410. 'Authorization': `Bearer ${testToken}`
  411. }
  412. });
  413. expect(response.status).toBe(200);
  414. const data = await response.json();
  415. expect(data).toBeNull();
  416. });
  417. });
  418. });