2
0
Эх сурвалжийг харах

✨ feat(test-utils): add client testing utilities and enhance server test tools

- add new client test utilities for React components, React Query and React Router
- add client test configuration with ClientTestConfig interface and default values
- enhance server test tools with more granular exports and additional mock services
- add new dev dependencies including @types/react, @tanstack/react-query and react-router-dom
- refactor index.ts exports to provide more structured and explicit API surface

✨ feat(test-utils): add new server test utilities

- add database testing utilities: createMockDataSource, createMockRepository and setupDatabaseHooks
- add authentication testing utilities: createMockAuthContext and createMockJwtPayload
- add service mocking utilities for various services including HTTP, auth and email services
- add error mocking utilities: mockNetworkError and mockServerError
- add server test configuration with ServerTestConfig interface and default values
yourname 1 сар өмнө
parent
commit
8db90d5b4e

+ 7 - 1
packages/test-utils/package.json

@@ -37,7 +37,13 @@
   },
   "devDependencies": {
     "typescript": "^5.8.3",
-    "vitest": "^2.0.5"
+    "vitest": "^2.0.5",
+    "@types/react": "^19.0.2",
+    "@types/react-dom": "^19.0.2",
+    "@tanstack/react-query": "^5.83.0",
+    "react-router-dom": "^6.28.0",
+    "typeorm": "^0.3.25",
+    "@hono/zod-openapi": "^0.18.2"
   },
   "peerDependencies": {
     "@d8d/server": "workspace:*",

+ 60 - 0
packages/test-utils/src/client/index.ts

@@ -0,0 +1,60 @@
+/**
+ * 客户端测试工具
+ *
+ * 为 React 组件和前端测试提供工具函数
+ */
+
+/**
+ * React Query 测试工具
+ */
+export {
+  createTestQueryClient,
+  TestQueryProvider,
+  mockUseQuery,
+  mockUseMutation,
+  waitForQueryToFinish,
+  mockNetworkError,
+  mockServerError
+} from './test-query.js';
+
+/**
+ * React 渲染测试工具
+ */
+export {
+  createTestRenderer,
+  createTestRouterRenderer
+} from './test-render.js';
+
+/**
+ * React Router 测试工具
+ */
+export {
+  createTestRouter,
+  TestRouterProvider
+} from './test-router.js';
+
+/**
+ * 客户端测试配置
+ */
+export interface ClientTestConfig {
+  /** 是否启用严格模式 */
+  strictMode?: boolean;
+  /** 路由配置 */
+  router?: {
+    initialEntries?: string[];
+    initialIndex?: number;
+  };
+  /** 查询客户端配置 */
+  queryClient?: any;
+}
+
+/**
+ * 默认客户端测试配置
+ */
+export const defaultClientTestConfig: ClientTestConfig = {
+  strictMode: true,
+  router: {
+    initialEntries: ['/'],
+    initialIndex: 0
+  }
+};

+ 19 - 4
packages/test-utils/src/index.ts

@@ -5,14 +5,29 @@
  */
 
 // 通用测试工具
-export * from './test-utils.js';
+export {
+  createTestServer,
+  createMockUser,
+  wait
+} from './test-utils.js';
 export * from './setup.js';
 
 // 服务器测试工具
-export * from './server/index.js';
+export {
+  createMockDataSource,
+  createMockRepository,
+  createMockAuthContext,
+  mockNetworkError,
+  mockServerError
+} from './server/index.js';
 
-// 客户端测试工具
-export * from './client/index.js';
+// 客户端测试配置
+export type { ClientTestConfig } from './client/index.js';
+export { defaultClientTestConfig } from './client/index.js';
+
+// 服务器测试配置
+export type { ServerTestConfig } from './server/index.js';
+export { defaultServerTestConfig } from './server/index.js';
 
 /**
  * 测试工具包配置接口

+ 43 - 6
packages/test-utils/src/server/index.ts

@@ -7,32 +7,69 @@
 /**
  * 集成测试数据库工具
  */
-export * from './integration-test-db.js';
+export {
+  setupIntegrationDatabaseHooks
+} from './integration-test-db.js';
 
 /**
  * 集成测试工具函数
  */
-export * from './integration-test-utils.js';
+export {
+  mockNetworkError,
+  mockServerError
+} from './integration-test-utils.js';
 
 /**
  * 认证测试工具
  */
-export * from './test-auth.js';
+export {
+  createMockAuthContext,
+  createMockJwtPayload,
+  createMockAuthMiddleware,
+  createMockPermissionMiddleware
+} from './test-auth.js';
 
 /**
  * 数据库测试工具
  */
-export * from './test-db.js';
+export {
+  createMockDataSource,
+  createMockEntityManager,
+  createMockRepository,
+  createMockQueryBuilder,
+  setupDatabaseHooks
+} from './test-db.js';
 
 /**
  * 服务模拟工具
  */
-export * from './service-mocks.js';
+export {
+  createHttpServiceMock,
+  createAuthServiceMock,
+  createEmailServiceMock,
+  createStorageServiceMock,
+  createPaymentServiceMock,
+  createSmsServiceMock,
+  createThirdPartyApiMock,
+  mockNetworkDelay,
+  mockHttpError,
+  mockTimeoutError,
+  mockNetworkError
+} from './service-mocks.js';
 
 /**
  * 服务存根工具
  */
-export * from './service-stubs.js';
+export {
+  createMockUserService,
+  createMockAuthService,
+  createMockRoleService,
+  createMockCrudService,
+  createMockEmailService,
+  createMockFileService,
+  serviceStubs,
+  setupServiceMocks
+} from './service-stubs.js';
 
 /**
  * 服务器测试配置

+ 84 - 0
pnpm-lock.yaml

@@ -308,6 +308,24 @@ importers:
         specifier: ^19.1.0
         version: 19.2.0(react@19.2.0)
     devDependencies:
+      '@hono/zod-openapi':
+        specifier: ^0.18.2
+        version: 0.18.4(hono@4.8.5)(zod@4.1.12)
+      '@tanstack/react-query':
+        specifier: ^5.83.0
+        version: 5.90.5(react@19.2.0)
+      '@types/react':
+        specifier: ^19.0.2
+        version: 19.2.2
+      '@types/react-dom':
+        specifier: ^19.0.2
+        version: 19.2.2(@types/react@19.2.2)
+      react-router-dom:
+        specifier: ^6.28.0
+        version: 6.30.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
+      typeorm:
+        specifier: ^0.3.25
+        version: 0.3.27(ioredis@5.8.2)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.2.2)
       typescript:
         specifier: ^5.8.3
         version: 5.8.3
@@ -685,6 +703,11 @@ packages:
   '@ast-core/escape@1.0.1':
     resolution: {integrity: sha512-/kVjBkDzYrSW1S+gTBCuOfhnNkge9qZFJgLT+MOZdmPN4Vts36S60uU5br3ozoxpJ1eRGe6pGy7/EfcOpFFHlA==}
 
+  '@asteasolutions/zod-to-openapi@7.3.4':
+    resolution: {integrity: sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA==}
+    peerDependencies:
+      zod: ^3.20.2
+
   '@asteasolutions/zod-to-openapi@8.1.0':
     resolution: {integrity: sha512-tQFxVs05J/6QXXqIzj6rTRk3nj1HFs4pe+uThwE95jL5II2JfpVXkK+CqkO7aT0Do5AYqO6LDrKpleLUFXgY+g==}
     peerDependencies:
@@ -2069,6 +2092,13 @@ packages:
     peerDependencies:
       hono: '*'
 
+  '@hono/zod-openapi@0.18.4':
+    resolution: {integrity: sha512-6NHMHU96Hh32B1yDhb94Z4Z5/POsmEu2AXpWLWcBq9arskRnOMt2752yEoXoADV8WUAc7H1IkNaQHGj1ytXbYw==}
+    engines: {node: '>=16.0.0'}
+    peerDependencies:
+      hono: '>=4.3.6'
+      zod: 3.*
+
   '@hono/zod-openapi@1.0.2':
     resolution: {integrity: sha512-zbxUZEnA+NaeotXRI2YPL5GEbz38DiO7Zp1nx/7yXOA2ITkcASYsYe/My/I38c44GCu+oUVM899zn4TBVn7JRg==}
     engines: {node: '>=16.0.0'}
@@ -2083,6 +2113,12 @@ packages:
       hono: '>=4.3.6'
       zod: ^4.0.0
 
+  '@hono/zod-validator@0.4.3':
+    resolution: {integrity: sha512-xIgMYXDyJ4Hj6ekm9T9Y27s080Nl9NXHcJkOvkXPhubOLj8hZkOL8pDnnXfvCf5xEE8Q4oMFenQUZZREUY2gqQ==}
+    peerDependencies:
+      hono: '>=3.9.0'
+      zod: ^3.19.1
+
   '@hono/zod-validator@0.7.4':
     resolution: {integrity: sha512-biKGn3BRJVaftZlIPMyK+HCe/UHAjJ6sH0UyXe3+v0OcgVr9xfImDROTJFLtn9e3XEEAHGZIM9U6evu85abm8Q==}
     peerDependencies:
@@ -2995,6 +3031,10 @@ packages:
     peerDependencies:
       '@redis/client': ^1.0.0
 
+  '@remix-run/router@1.23.0':
+    resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==}
+    engines: {node: '>=14.0.0'}
+
   '@rnx-kit/babel-preset-metro-react-native@1.1.8':
     resolution: {integrity: sha512-8DotuBK1ZgV0H/tmCmtW/3ofA7JR/8aPqSu9lKnuqwBfq4bxz+w1sMyfFl89m4teWlkhgyczWBGD6NCLqTgi9A==}
     peerDependencies:
@@ -8501,6 +8541,13 @@ packages:
       react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
       react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
 
+  react-router-dom@6.30.1:
+    resolution: {integrity: sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      react: '>=16.8'
+      react-dom: '>=16.8'
+
   react-router-dom@7.9.4:
     resolution: {integrity: sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==}
     engines: {node: '>=20.0.0'}
@@ -8508,6 +8555,12 @@ packages:
       react: '>=18'
       react-dom: '>=18'
 
+  react-router@6.30.1:
+    resolution: {integrity: sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      react: '>=16.8'
+
   react-router@7.9.4:
     resolution: {integrity: sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==}
     engines: {node: '>=20.0.0'}
@@ -10191,6 +10244,11 @@ snapshots:
 
   '@ast-core/escape@1.0.1': {}
 
+  '@asteasolutions/zod-to-openapi@7.3.4(zod@4.1.12)':
+    dependencies:
+      openapi3-ts: 4.5.0
+      zod: 4.1.12
+
   '@asteasolutions/zod-to-openapi@8.1.0(zod@4.1.12)':
     dependencies:
       openapi3-ts: 4.5.0
@@ -11711,6 +11769,13 @@ snapshots:
     dependencies:
       hono: 4.8.5
 
+  '@hono/zod-openapi@0.18.4(hono@4.8.5)(zod@4.1.12)':
+    dependencies:
+      '@asteasolutions/zod-to-openapi': 7.3.4(zod@4.1.12)
+      '@hono/zod-validator': 0.4.3(hono@4.8.5)(zod@4.1.12)
+      hono: 4.8.5
+      zod: 4.1.12
+
   '@hono/zod-openapi@1.0.2(hono@4.8.5)(zod@4.1.12)':
     dependencies:
       '@asteasolutions/zod-to-openapi': 8.1.0(zod@4.1.12)
@@ -11727,6 +11792,11 @@ snapshots:
       openapi3-ts: 4.5.0
       zod: 4.1.12
 
+  '@hono/zod-validator@0.4.3(hono@4.8.5)(zod@4.1.12)':
+    dependencies:
+      hono: 4.8.5
+      zod: 4.1.12
+
   '@hono/zod-validator@0.7.4(hono@4.8.5)(zod@4.1.12)':
     dependencies:
       hono: 4.8.5
@@ -12673,6 +12743,8 @@ snapshots:
     dependencies:
       '@redis/client': 1.6.1
 
+  '@remix-run/router@1.23.0': {}
+
   '@rnx-kit/babel-preset-metro-react-native@1.1.8(@babel/core@7.28.4)(@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.4))(@babel/runtime@7.28.4)':
     dependencies:
       '@babel/core': 7.28.4
@@ -18870,12 +18942,24 @@ snapshots:
       react: 19.2.0
       react-dom: 19.2.0(react@19.2.0)
 
+  react-router-dom@6.30.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
+    dependencies:
+      '@remix-run/router': 1.23.0
+      react: 19.2.0
+      react-dom: 19.2.0(react@19.2.0)
+      react-router: 6.30.1(react@19.2.0)
+
   react-router-dom@7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
     dependencies:
       react: 19.2.0
       react-dom: 19.2.0(react@19.2.0)
       react-router: 7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
 
+  react-router@6.30.1(react@19.2.0):
+    dependencies:
+      '@remix-run/router': 1.23.0
+      react: 19.2.0
+
   react-router@7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0):
     dependencies:
       cookie: 1.0.2