integration-test-utils.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import { IntegrationTestDatabase } from './integration-test-db';
  2. import { EntityTarget, ObjectLiteral } from 'typeorm';
  3. /**
  4. * 集成测试断言工具
  5. * 通用版本,不依赖特定实体
  6. */
  7. export class IntegrationTestAssertions {
  8. /**
  9. * 断言响应状态码
  10. */
  11. static expectStatus(response: { status: number }, expectedStatus: number): void {
  12. if (response.status !== expectedStatus) {
  13. throw new Error(`Expected status ${expectedStatus}, but got ${response.status}`);
  14. }
  15. }
  16. /**
  17. * 断言响应包含特定字段
  18. */
  19. static expectResponseToHave(response: { data: any }, expectedFields: Record<string, any>): void {
  20. for (const [key, value] of Object.entries(expectedFields)) {
  21. if (response.data[key] !== value) {
  22. throw new Error(`Expected field ${key} to be ${value}, but got ${response.data[key]}`);
  23. }
  24. }
  25. }
  26. /**
  27. * 断言响应包含特定结构
  28. */
  29. static expectResponseStructure(response: { data: any }, structure: Record<string, any>): void {
  30. for (const key of Object.keys(structure)) {
  31. if (!(key in response.data)) {
  32. throw new Error(`Expected response to have key: ${key}`);
  33. }
  34. }
  35. }
  36. /**
  37. * 断言实体存在于数据库中
  38. */
  39. static async expectEntityToExist<T extends ObjectLiteral>(
  40. entity: EntityTarget<T>,
  41. condition: Partial<T>
  42. ): Promise<void> {
  43. const dataSource = await IntegrationTestDatabase.getDataSource();
  44. if (!dataSource) {
  45. throw new Error('Database not initialized');
  46. }
  47. const repository = dataSource.getRepository(entity);
  48. const entityInstance = await repository.findOne({ where: condition });
  49. if (!entityInstance) {
  50. throw new Error(`Expected entity to exist in database with condition: ${JSON.stringify(condition)}`);
  51. }
  52. }
  53. /**
  54. * 断言实体不存在于数据库中
  55. */
  56. static async expectEntityNotToExist<T extends ObjectLiteral>(
  57. entity: EntityTarget<T>,
  58. condition: Partial<T>
  59. ): Promise<void> {
  60. const dataSource = await IntegrationTestDatabase.getDataSource();
  61. if (!dataSource) {
  62. throw new Error('Database not initialized');
  63. }
  64. const repository = dataSource.getRepository(entity);
  65. const entityInstance = await repository.findOne({ where: condition });
  66. if (entityInstance) {
  67. throw new Error(`Expected entity not to exist in database with condition: ${JSON.stringify(condition)}`);
  68. }
  69. }
  70. /**
  71. * 断言响应包含错误信息
  72. */
  73. static expectErrorResponse(response: { data: any }, expectedError: string): void {
  74. if (!response.data || !response.data.error || !response.data.error.includes(expectedError)) {
  75. throw new Error(`Expected error response to contain "${expectedError}", but got: ${JSON.stringify(response.data)}`);
  76. }
  77. }
  78. /**
  79. * 断言响应包含成功信息
  80. */
  81. static expectSuccessResponse(response: { data: any }): void {
  82. if (!response.data || response.data.error) {
  83. throw new Error(`Expected success response, but got: ${JSON.stringify(response.data)}`);
  84. }
  85. }
  86. /**
  87. * 断言列表响应包含特定数量的项目
  88. */
  89. static expectListResponseCount(response: { data: any }, expectedCount: number): void {
  90. if (!Array.isArray(response.data)) {
  91. throw new Error(`Expected array response, but got: ${typeof response.data}`);
  92. }
  93. if (response.data.length !== expectedCount) {
  94. throw new Error(`Expected ${expectedCount} items, but got ${response.data.length}`);
  95. }
  96. }
  97. /**
  98. * 断言响应包含分页信息
  99. */
  100. static expectPaginationResponse(response: { data: any }): void {
  101. if (!response.data || typeof response.data !== 'object') {
  102. throw new Error(`Expected object response, but got: ${typeof response.data}`);
  103. }
  104. const requiredFields = ['data', 'total', 'page', 'pageSize'];
  105. for (const field of requiredFields) {
  106. if (!(field in response.data)) {
  107. throw new Error(`Expected pagination response to have field: ${field}`);
  108. }
  109. }
  110. if (!Array.isArray(response.data.data)) {
  111. throw new Error(`Expected pagination data to be an array, but got: ${typeof response.data.data}`);
  112. }
  113. }
  114. }
  115. /**
  116. * API 响应断言工具
  117. */
  118. export class ApiResponseAssertions {
  119. /**
  120. * 断言成功的 API 响应
  121. */
  122. static expectSuccess(response: { status: number; data: any }): void {
  123. IntegrationTestAssertions.expectStatus(response, 200);
  124. IntegrationTestAssertions.expectSuccessResponse(response);
  125. }
  126. /**
  127. * 断言创建的 API 响应
  128. */
  129. static expectCreated(response: { status: number; data: any }): void {
  130. IntegrationTestAssertions.expectStatus(response, 201);
  131. IntegrationTestAssertions.expectSuccessResponse(response);
  132. }
  133. /**
  134. * 断言未授权的 API 响应
  135. */
  136. static expectUnauthorized(response: { status: number; data: any }): void {
  137. IntegrationTestAssertions.expectStatus(response, 401);
  138. IntegrationTestAssertions.expectErrorResponse(response, 'Unauthorized');
  139. }
  140. /**
  141. * 断言禁止访问的 API 响应
  142. */
  143. static expectForbidden(response: { status: number; data: any }): void {
  144. IntegrationTestAssertions.expectStatus(response, 403);
  145. IntegrationTestAssertions.expectErrorResponse(response, 'Forbidden');
  146. }
  147. /**
  148. * 断言未找到的 API 响应
  149. */
  150. static expectNotFound(response: { status: number; data: any }): void {
  151. IntegrationTestAssertions.expectStatus(response, 404);
  152. IntegrationTestAssertions.expectErrorResponse(response, 'not found');
  153. }
  154. /**
  155. * 断言验证错误的 API 响应
  156. */
  157. static expectValidationError(response: { status: number; data: any }): void {
  158. IntegrationTestAssertions.expectStatus(response, 400);
  159. IntegrationTestAssertions.expectErrorResponse(response, 'Validation');
  160. }
  161. }