@taicode/common-server 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/output/schema/index.d.ts +29 -2
- package/output/schema/index.d.ts.map +1 -1
- package/output/schema/index.js +20 -2
- package/package.json +1 -1
- package/output/mock/function/function.d.ts +0 -30
- package/output/mock/function/function.d.ts.map +0 -1
- package/output/mock/function/function.js +0 -58
- package/output/mock/function/function.test.d.ts +0 -2
- package/output/mock/function/function.test.d.ts.map +0 -1
- package/output/mock/function/function.test.js +0 -55
- package/output/mock/function/index.d.ts +0 -2
- package/output/mock/function/index.d.ts.map +0 -1
- package/output/mock/function/index.js +0 -1
- package/output/mock/index.d.ts +0 -3
- package/output/mock/index.d.ts.map +0 -1
- package/output/mock/index.js +0 -3
- package/output/mock/prismaClient/index.d.ts +0 -2
- package/output/mock/prismaClient/index.d.ts.map +0 -1
- package/output/mock/prismaClient/index.js +0 -1
- package/output/mock/prismaClient/prismaClient.d.ts +0 -257
- package/output/mock/prismaClient/prismaClient.d.ts.map +0 -1
- package/output/mock/prismaClient/prismaClient.js +0 -399
- package/output/mock/prismaClient/prismaClient.test.d.ts +0 -2
- package/output/mock/prismaClient/prismaClient.test.d.ts.map +0 -1
- package/output/mock/prismaClient/prismaClient.test.js +0 -91
package/output/schema/index.d.ts
CHANGED
|
@@ -77,15 +77,42 @@ export declare function fuzzQueryBodySchema<F extends ZodType, E extends ZodEnum
|
|
|
77
77
|
range: z.ZodTuple<[z.ZodISODateTime, z.ZodISODateTime], null>;
|
|
78
78
|
}, z.core.$strip>;
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
80
|
+
* 标准响应数据内容 Schema
|
|
81
81
|
* 用于定义统一的 API 响应结构
|
|
82
82
|
* @param t - 响应数据的类型
|
|
83
83
|
* @param s - 状态码的枚举类型
|
|
84
84
|
* @returns 标准响应的 Schema
|
|
85
85
|
*/
|
|
86
|
-
export declare function
|
|
86
|
+
export declare function responseDataSchema<T extends ZodType, S extends ZodEnum>(t: T, s: S): z.ZodObject<{
|
|
87
87
|
data: T;
|
|
88
88
|
status: S;
|
|
89
89
|
message: z.ZodString;
|
|
90
90
|
}, z.core.$strip>;
|
|
91
|
+
export declare function responseSchema<T extends ZodType, S extends ZodEnum, E extends ZodEnum>(t: T, u: S, e: E): {
|
|
92
|
+
'200': z.ZodObject<{
|
|
93
|
+
data: T;
|
|
94
|
+
status: z.ZodEnum<{
|
|
95
|
+
SUCCESS: "SUCCESS";
|
|
96
|
+
}>;
|
|
97
|
+
message: z.ZodString;
|
|
98
|
+
}, z.core.$strip>;
|
|
99
|
+
'400': z.ZodObject<{
|
|
100
|
+
data: z.ZodNull;
|
|
101
|
+
status: S;
|
|
102
|
+
message: z.ZodString;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
'500': z.ZodObject<{
|
|
105
|
+
data: z.ZodNull;
|
|
106
|
+
status: E;
|
|
107
|
+
message: z.ZodString;
|
|
108
|
+
}, z.core.$strip>;
|
|
109
|
+
};
|
|
110
|
+
interface RouterSchema {
|
|
111
|
+
tags: string[];
|
|
112
|
+
summary: string;
|
|
113
|
+
operationId: string;
|
|
114
|
+
description: string;
|
|
115
|
+
}
|
|
116
|
+
export declare function routerSchema<T extends RouterSchema>(schema: T & RouterSchema): T & RouterSchema;
|
|
117
|
+
export {};
|
|
91
118
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AA2BzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKxD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;;;;kBAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMrF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMpF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AA2BzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKxD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC;;;kBAKvD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;;;;kBAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMrF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;kBAMpF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;;;;kBAMlF;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;EAMvG;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,YAAY,EAAE,MAAM,EAAE,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,YAAY,CAY/F"}
|
package/output/schema/index.js
CHANGED
|
@@ -89,16 +89,34 @@ export function fuzzQueryBodySchema(f, e) {
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
|
-
*
|
|
92
|
+
* 标准响应数据内容 Schema
|
|
93
93
|
* 用于定义统一的 API 响应结构
|
|
94
94
|
* @param t - 响应数据的类型
|
|
95
95
|
* @param s - 状态码的枚举类型
|
|
96
96
|
* @returns 标准响应的 Schema
|
|
97
97
|
*/
|
|
98
|
-
export function
|
|
98
|
+
export function responseDataSchema(t, s) {
|
|
99
99
|
return z.object({
|
|
100
100
|
data: t.describe('响应数据'),
|
|
101
101
|
status: s.describe('响应状态码'),
|
|
102
102
|
message: z.string().describe('响应消息'),
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
|
+
export function responseSchema(t, u, e) {
|
|
106
|
+
return {
|
|
107
|
+
'200': responseDataSchema(t, z.enum(['SUCCESS'])),
|
|
108
|
+
'400': responseDataSchema(z.null(), u),
|
|
109
|
+
'500': responseDataSchema(z.null(), e),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export function routerSchema(schema) {
|
|
113
|
+
// 验证必需字段
|
|
114
|
+
if (!schema.operationId) {
|
|
115
|
+
throw new Error('routerSchema requires operationId');
|
|
116
|
+
}
|
|
117
|
+
// 如果没有提供 tags,设置默认值
|
|
118
|
+
if (!schema.tags) {
|
|
119
|
+
schema.tags = ['默认'];
|
|
120
|
+
}
|
|
121
|
+
return { ...schema };
|
|
122
|
+
}
|
package/package.json
CHANGED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mockFunction 主要用于在不依赖特定测试工具(如 jest、vitest)的情况下
|
|
3
|
-
* 实现通用的 mock 能力,便于在多种环境下进行函数模拟、调用记录和行为控制。
|
|
4
|
-
* 适用于需要脱离测试框架、或在生产/脚本环境下也能复用的场景。
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Mock 函数接口
|
|
8
|
-
*/
|
|
9
|
-
interface MockFunction {
|
|
10
|
-
(...args: any[]): any;
|
|
11
|
-
mockCalls: any[][];
|
|
12
|
-
mockResults: Array<{
|
|
13
|
-
type: 'return' | 'throw';
|
|
14
|
-
value: any;
|
|
15
|
-
}>;
|
|
16
|
-
mockImplementation: (fn: Function) => MockFunction;
|
|
17
|
-
mockReturnValue: (value: any) => MockFunction;
|
|
18
|
-
mockResolvedValue: (value: any) => MockFunction;
|
|
19
|
-
mockRejectedValue: (error: any) => MockFunction;
|
|
20
|
-
mockClear: () => void;
|
|
21
|
-
mockReset: () => void;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* 创建 Mock 函数
|
|
25
|
-
* 可记录调用参数、返回值、异常,并支持动态切换实现、固定返回、异步返回、异常抛出等能力。
|
|
26
|
-
* 适合在无测试框架依赖的环境下灵活使用。
|
|
27
|
-
*/
|
|
28
|
-
export declare function mockFunction(implementation?: Function): MockFunction;
|
|
29
|
-
export {};
|
|
30
|
-
//# sourceMappingURL=function.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../../../source/mock/function/function.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,UAAU,YAAY;IACpB,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAA;IACrB,SAAS,EAAE,GAAG,EAAE,EAAE,CAAA;IAClB,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,KAAK,EAAE,GAAG,CAAA;KAAE,CAAC,CAAA;IAC5D,kBAAkB,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,YAAY,CAAA;IAClD,eAAe,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,YAAY,CAAA;IAC7C,iBAAiB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,YAAY,CAAA;IAC/C,iBAAiB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,YAAY,CAAA;IAC/C,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,cAAc,CAAC,EAAE,QAAQ,GAAG,YAAY,CAyDpE"}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mockFunction 主要用于在不依赖特定测试工具(如 jest、vitest)的情况下
|
|
3
|
-
* 实现通用的 mock 能力,便于在多种环境下进行函数模拟、调用记录和行为控制。
|
|
4
|
-
* 适用于需要脱离测试框架、或在生产/脚本环境下也能复用的场景。
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* 创建 Mock 函数
|
|
8
|
-
* 可记录调用参数、返回值、异常,并支持动态切换实现、固定返回、异步返回、异常抛出等能力。
|
|
9
|
-
* 适合在无测试框架依赖的环境下灵活使用。
|
|
10
|
-
*/
|
|
11
|
-
export function mockFunction(implementation) {
|
|
12
|
-
const mockCalls = [];
|
|
13
|
-
const mockResults = [];
|
|
14
|
-
let mockImpl = implementation;
|
|
15
|
-
const mockFn = function (...args) {
|
|
16
|
-
mockCalls.push(args);
|
|
17
|
-
if (mockImpl) {
|
|
18
|
-
try {
|
|
19
|
-
const result = mockImpl(...args);
|
|
20
|
-
mockResults.push({ type: 'return', value: result });
|
|
21
|
-
return result;
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
mockResults.push({ type: 'throw', value: error });
|
|
25
|
-
throw error;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return undefined;
|
|
29
|
-
};
|
|
30
|
-
mockFn.mockCalls = mockCalls;
|
|
31
|
-
mockFn.mockResults = mockResults;
|
|
32
|
-
mockFn.mockImplementation = (fn) => {
|
|
33
|
-
mockImpl = fn;
|
|
34
|
-
return mockFn;
|
|
35
|
-
};
|
|
36
|
-
mockFn.mockReturnValue = (value) => {
|
|
37
|
-
mockImpl = () => value;
|
|
38
|
-
return mockFn;
|
|
39
|
-
};
|
|
40
|
-
mockFn.mockResolvedValue = (value) => {
|
|
41
|
-
mockImpl = () => Promise.resolve(value);
|
|
42
|
-
return mockFn;
|
|
43
|
-
};
|
|
44
|
-
mockFn.mockRejectedValue = (error) => {
|
|
45
|
-
mockImpl = () => Promise.reject(error);
|
|
46
|
-
return mockFn;
|
|
47
|
-
};
|
|
48
|
-
mockFn.mockClear = () => {
|
|
49
|
-
mockCalls.length = 0;
|
|
50
|
-
mockResults.length = 0;
|
|
51
|
-
};
|
|
52
|
-
mockFn.mockReset = () => {
|
|
53
|
-
mockCalls.length = 0;
|
|
54
|
-
mockResults.length = 0;
|
|
55
|
-
mockImpl = implementation;
|
|
56
|
-
};
|
|
57
|
-
return mockFn;
|
|
58
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"function.test.d.ts","sourceRoot":"","sources":["../../../source/mock/function/function.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mockFunction } from './function';
|
|
3
|
-
describe('mockFunction', () => {
|
|
4
|
-
it('应能记录调用参数和返回值', () => {
|
|
5
|
-
const fn = mockFunction((a, b) => a + b);
|
|
6
|
-
expect(fn(1, 2)).toBe(3);
|
|
7
|
-
expect(fn(2, 3)).toBe(5);
|
|
8
|
-
expect(fn.mockCalls).toEqual([[1, 2], [2, 3]]);
|
|
9
|
-
expect(fn.mockResults[0]).toEqual({ type: 'return', value: 3 });
|
|
10
|
-
expect(fn.mockResults[1]).toEqual({ type: 'return', value: 5 });
|
|
11
|
-
});
|
|
12
|
-
it('应能记录抛出的异常', () => {
|
|
13
|
-
const error = new Error('fail');
|
|
14
|
-
const fn = mockFunction(() => { throw error; });
|
|
15
|
-
expect(() => fn(1)).toThrow(error);
|
|
16
|
-
expect(fn.mockResults[0]).toEqual({ type: 'throw', value: error });
|
|
17
|
-
});
|
|
18
|
-
it('mockImplementation 可动态替换实现', () => {
|
|
19
|
-
const fn = mockFunction((x) => x + 1);
|
|
20
|
-
expect(fn(1)).toBe(2);
|
|
21
|
-
fn.mockImplementation((x) => x * 2);
|
|
22
|
-
expect(fn(2)).toBe(4);
|
|
23
|
-
});
|
|
24
|
-
it('mockReturnValue 可设置固定返回值', () => {
|
|
25
|
-
const fn = mockFunction().mockReturnValue(42);
|
|
26
|
-
expect(fn()).toBe(42);
|
|
27
|
-
expect(fn(1, 2)).toBe(42);
|
|
28
|
-
});
|
|
29
|
-
it('mockResolvedValue 应返回 Promise.resolve', async () => {
|
|
30
|
-
const fn = mockFunction().mockResolvedValue('ok');
|
|
31
|
-
await expect(fn()).resolves.toBe('ok');
|
|
32
|
-
});
|
|
33
|
-
it('mockRejectedValue 应返回 Promise.reject', async () => {
|
|
34
|
-
const fn = mockFunction().mockRejectedValue('fail');
|
|
35
|
-
await expect(fn()).rejects.toBe('fail');
|
|
36
|
-
});
|
|
37
|
-
it('mockClear 应清空调用记录', () => {
|
|
38
|
-
const fn = mockFunction((x) => x);
|
|
39
|
-
fn(1);
|
|
40
|
-
fn(2);
|
|
41
|
-
fn.mockClear();
|
|
42
|
-
expect(fn.mockCalls.length).toBe(0);
|
|
43
|
-
expect(fn.mockResults.length).toBe(0);
|
|
44
|
-
});
|
|
45
|
-
it('mockReset 应重置实现和调用记录', () => {
|
|
46
|
-
const fn = mockFunction((x) => x + 1);
|
|
47
|
-
fn(1);
|
|
48
|
-
fn.mockImplementation((x) => x + 10);
|
|
49
|
-
fn(2);
|
|
50
|
-
fn.mockReset();
|
|
51
|
-
expect(fn.mockCalls.length).toBe(0);
|
|
52
|
-
expect(fn.mockResults.length).toBe(0);
|
|
53
|
-
expect(fn(3)).toBe(4); // 恢复为初始实现
|
|
54
|
-
});
|
|
55
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/mock/function/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { mockFunction } from './function';
|
package/output/mock/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/mock/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
package/output/mock/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/mock/prismaClient/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { mockPrismaClient } from './prismaClient';
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
import { PrismaClient } from '@prisma/client';
|
|
2
|
-
/**
|
|
3
|
-
* Prisma 支持的数据库操作方法列表
|
|
4
|
-
* 包含所有常用的 CRUD 和聚合操作
|
|
5
|
-
*/
|
|
6
|
-
declare const DB_METHODS: readonly ["create", "createMany", "findFirst", "findUnique", "findMany", "update", "updateMany", "delete", "deleteMany", "upsert", "count", "aggregate", "groupBy", "findFirstOrThrow", "findUniqueOrThrow"];
|
|
7
|
-
type DbMethod = typeof DB_METHODS[number];
|
|
8
|
-
/**
|
|
9
|
-
* 数据库调用记录接口
|
|
10
|
-
* 记录每次数据库操作的详细信息
|
|
11
|
-
*/
|
|
12
|
-
interface CallRecord {
|
|
13
|
-
/** 调用的方法名 */
|
|
14
|
-
method: DbMethod;
|
|
15
|
-
/** 调用时间戳 */
|
|
16
|
-
timestamp: Date;
|
|
17
|
-
/** 调用参数 */
|
|
18
|
-
args: any[];
|
|
19
|
-
/** 调用返回值(如果有的话) */
|
|
20
|
-
returnValue?: any;
|
|
21
|
-
/** 调用是否抛出异常 */
|
|
22
|
-
isError?: boolean;
|
|
23
|
-
/** 异常信息(如果有的话) */
|
|
24
|
-
error?: any;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Mock 返回值配置接口
|
|
28
|
-
*/
|
|
29
|
-
interface MockReturnConfig {
|
|
30
|
-
/** 返回值 */
|
|
31
|
-
value?: any;
|
|
32
|
-
/** 是否抛出异常 */
|
|
33
|
-
shouldThrow?: boolean;
|
|
34
|
-
/** 是否返回 Promise */
|
|
35
|
-
isAsync?: boolean;
|
|
36
|
-
/** 调用次数限制(可选) */
|
|
37
|
-
times?: number;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* 扩展的 Mock Prisma Client 接口
|
|
41
|
-
* 在原有 PrismaClient 基础上添加测试辅助方法
|
|
42
|
-
*/
|
|
43
|
-
interface MockPrismaClient extends PrismaClient {
|
|
44
|
-
/**
|
|
45
|
-
* 获取调用历史记录
|
|
46
|
-
* @param table 可选,指定表名过滤
|
|
47
|
-
* @param method 可选,指定方法名过滤
|
|
48
|
-
* @returns 调用记录数组
|
|
49
|
-
*/
|
|
50
|
-
__getCallHistory(table?: string, method?: DbMethod): CallRecord[];
|
|
51
|
-
/**
|
|
52
|
-
* 清空调用历史记录
|
|
53
|
-
* @param table 可选,指定表名。不传则清空所有记录
|
|
54
|
-
*/
|
|
55
|
-
__clearCallHistory(table?: string): void;
|
|
56
|
-
/**
|
|
57
|
-
* 获取最后一次调用记录
|
|
58
|
-
* @param table 表名
|
|
59
|
-
* @param method 方法名
|
|
60
|
-
* @returns 最后一次调用记录或 undefined
|
|
61
|
-
*/
|
|
62
|
-
__getLastCall(table: string, method: DbMethod): CallRecord | undefined;
|
|
63
|
-
/**
|
|
64
|
-
* 获取指定方法的调用次数
|
|
65
|
-
* @param table 表名
|
|
66
|
-
* @param method 方法名
|
|
67
|
-
* @returns 调用次数
|
|
68
|
-
*/
|
|
69
|
-
__getCallCount(table: string, method: DbMethod): number;
|
|
70
|
-
/**
|
|
71
|
-
* 设置方法的返回值(同步)
|
|
72
|
-
* @param table 表名
|
|
73
|
-
* @param method 方法名
|
|
74
|
-
* @param value 返回值
|
|
75
|
-
*/
|
|
76
|
-
__mockReturnValue(table: string, method: DbMethod, value: any): void;
|
|
77
|
-
/**
|
|
78
|
-
* 设置方法的返回值(异步成功)
|
|
79
|
-
* @param table 表名
|
|
80
|
-
* @param method 方法名
|
|
81
|
-
* @param value 返回值
|
|
82
|
-
*/
|
|
83
|
-
__mockResolvedValue(table: string, method: DbMethod, value: any): void;
|
|
84
|
-
/**
|
|
85
|
-
* 设置方法抛出异常(异步失败)
|
|
86
|
-
* @param table 表名
|
|
87
|
-
* @param method 方法名
|
|
88
|
-
* @param error 异常
|
|
89
|
-
*/
|
|
90
|
-
__mockRejectedValue(table: string, method: DbMethod, error: any): void;
|
|
91
|
-
/**
|
|
92
|
-
* 高级 Mock 配置
|
|
93
|
-
* @param table 表名
|
|
94
|
-
* @param method 方法名
|
|
95
|
-
* @param config Mock 配置
|
|
96
|
-
*/
|
|
97
|
-
__mockAdvanced(table: string, method: DbMethod, config: MockReturnConfig): void;
|
|
98
|
-
/**
|
|
99
|
-
* 重置所有 Mock 配置
|
|
100
|
-
* @param table 可选,指定表名。不传则重置所有表
|
|
101
|
-
*/
|
|
102
|
-
__resetMocks(table?: string): void;
|
|
103
|
-
/**
|
|
104
|
-
* 获取所有被访问过的表名
|
|
105
|
-
* @returns 表名数组
|
|
106
|
-
*/
|
|
107
|
-
__getAccessedTables(): string[];
|
|
108
|
-
/**
|
|
109
|
-
* 验证方法是否被调用
|
|
110
|
-
* @param table 表名
|
|
111
|
-
* @param method 方法名
|
|
112
|
-
* @param times 可选,期望的调用次数
|
|
113
|
-
* @returns 是否符合期望
|
|
114
|
-
*/
|
|
115
|
-
__wasCalledWith(table: string, method: DbMethod, times?: number): boolean;
|
|
116
|
-
/**
|
|
117
|
-
* 验证方法是否被特定参数调用
|
|
118
|
-
* @param table 表名
|
|
119
|
-
* @param method 方法名
|
|
120
|
-
* @param expectedArgs 期望的参数
|
|
121
|
-
* @returns 是否符合期望
|
|
122
|
-
*/
|
|
123
|
-
__wasCalledWithArgs(table: string, method: DbMethod, expectedArgs: any): boolean;
|
|
124
|
-
/**
|
|
125
|
-
* 创建数据快照,用于测试前后数据对比
|
|
126
|
-
* @returns 当前调用历史的快照
|
|
127
|
-
*/
|
|
128
|
-
__createSnapshot(): string;
|
|
129
|
-
/**
|
|
130
|
-
* 恢复到指定快照状态
|
|
131
|
-
* @param snapshot 快照字符串
|
|
132
|
-
*/
|
|
133
|
-
__restoreSnapshot(snapshot: string): void;
|
|
134
|
-
/**
|
|
135
|
-
* 批量设置多个表的 mock 返回值
|
|
136
|
-
* @param configs 批量配置对象
|
|
137
|
-
* @example
|
|
138
|
-
* mockDb.__batchMock({
|
|
139
|
-
* 'user.findMany': { value: [{ id: 1, name: 'John' }] },
|
|
140
|
-
* 'post.create': { value: { id: 1, title: 'Hello' } }
|
|
141
|
-
* })
|
|
142
|
-
*/
|
|
143
|
-
__batchMock(configs: Record<string, MockReturnConfig>): void;
|
|
144
|
-
/**
|
|
145
|
-
* 等待异步操作完成(用于复杂异步测试场景)
|
|
146
|
-
* @param ms 等待毫秒数
|
|
147
|
-
*/
|
|
148
|
-
__waitForAsyncOperations(ms?: number): Promise<void>;
|
|
149
|
-
/**
|
|
150
|
-
* 验证调用序列是否符合预期
|
|
151
|
-
* @param expectedSequence 期望的调用序列
|
|
152
|
-
* @returns 是否符合期望
|
|
153
|
-
* @example
|
|
154
|
-
* mockDb.__verifyCallSequence([
|
|
155
|
-
* { table: 'user', method: 'findUnique' },
|
|
156
|
-
* { table: 'post', method: 'create' }
|
|
157
|
-
* ])
|
|
158
|
-
*/
|
|
159
|
-
__verifyCallSequence(expectedSequence: Array<{
|
|
160
|
-
table: string;
|
|
161
|
-
method: DbMethod;
|
|
162
|
-
}>): boolean;
|
|
163
|
-
/**
|
|
164
|
-
* 获取详细的调用统计信息
|
|
165
|
-
* @returns 调用统计数据
|
|
166
|
-
*/
|
|
167
|
-
__getCallStatistics(): {
|
|
168
|
-
totalCalls: number;
|
|
169
|
-
tableStats: Record<string, number>;
|
|
170
|
-
methodStats: Record<string, number>;
|
|
171
|
-
timeRange: {
|
|
172
|
-
earliest: Date;
|
|
173
|
-
latest: Date;
|
|
174
|
-
} | null;
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* 创建模拟的 Prisma Client
|
|
179
|
-
* 提供完整的数据库操作模拟能力和测试辅助功能
|
|
180
|
-
*
|
|
181
|
-
* 主要特性:
|
|
182
|
-
* - 动态创建数据库表代理,支持所有 Prisma 操作
|
|
183
|
-
* - 记录所有方法调用历史,包括参数、返回值、异常等
|
|
184
|
-
* - 支持灵活的 mock 返回值配置(同步/异步/异常)
|
|
185
|
-
* - 提供丰富的断言和验证方法
|
|
186
|
-
* - 支持调用序列验证和统计分析
|
|
187
|
-
* - 支持快照和批量操作
|
|
188
|
-
*
|
|
189
|
-
* @example 基础用法
|
|
190
|
-
* ```typescript
|
|
191
|
-
* const mockDb = createPrismaClient()
|
|
192
|
-
*
|
|
193
|
-
* // 设置返回值
|
|
194
|
-
* mockDb.__mockResolvedValue('user', 'findMany', [{ id: 1, name: 'John' }])
|
|
195
|
-
*
|
|
196
|
-
* // 执行操作
|
|
197
|
-
* const users = await mockDb.user.findMany()
|
|
198
|
-
*
|
|
199
|
-
* // 验证调用
|
|
200
|
-
* expect(mockDb.__getCallCount('user', 'findMany')).toBe(1)
|
|
201
|
-
* expect(users).toEqual([{ id: 1, name: 'John' }])
|
|
202
|
-
* ```
|
|
203
|
-
*
|
|
204
|
-
* @example 高级 mock 配置
|
|
205
|
-
* ```typescript
|
|
206
|
-
* // 限制调用次数的 mock
|
|
207
|
-
* mockDb.__mockAdvanced('user', 'create', {
|
|
208
|
-
* value: { id: 1, name: 'John' },
|
|
209
|
-
* times: 2 // 只在前2次调用时返回此值
|
|
210
|
-
* })
|
|
211
|
-
*
|
|
212
|
-
* // 批量设置 mock
|
|
213
|
-
* mockDb.__batchMock({
|
|
214
|
-
* 'user.findMany': { value: [] },
|
|
215
|
-
* 'post.create': { value: { id: 1, title: 'Hello' } },
|
|
216
|
-
* 'comment.delete': { shouldThrow: true, value: new Error('删除失败') }
|
|
217
|
-
* })
|
|
218
|
-
* ```
|
|
219
|
-
*
|
|
220
|
-
* @example 调用验证和统计
|
|
221
|
-
* ```typescript
|
|
222
|
-
* // 验证调用历史
|
|
223
|
-
* expect(mockDb.__wasCalledWith('user', 'findMany')).toBe(true)
|
|
224
|
-
* expect(mockDb.__wasCalledWithArgs('user', 'create', [{ name: 'John' }])).toBe(true)
|
|
225
|
-
*
|
|
226
|
-
* // 验证调用序列
|
|
227
|
-
* expect(mockDb.__verifyCallSequence([
|
|
228
|
-
* { table: 'user', method: 'findUnique' },
|
|
229
|
-
* { table: 'post', method: 'create' }
|
|
230
|
-
* ])).toBe(true)
|
|
231
|
-
*
|
|
232
|
-
* // 获取统计信息
|
|
233
|
-
* const stats = mockDb.__getCallStatistics()
|
|
234
|
-
* console.log(`总调用次数: ${stats.totalCalls}`)
|
|
235
|
-
* ```
|
|
236
|
-
*
|
|
237
|
-
* @example 快照和重置
|
|
238
|
-
* ```typescript
|
|
239
|
-
* // 创建快照
|
|
240
|
-
* const snapshot = mockDb.__createSnapshot()
|
|
241
|
-
*
|
|
242
|
-
* // 执行一些操作...
|
|
243
|
-
* await mockDb.user.create({ data: { name: 'John' } })
|
|
244
|
-
*
|
|
245
|
-
* // 恢复到快照状态
|
|
246
|
-
* mockDb.__restoreSnapshot(snapshot)
|
|
247
|
-
*
|
|
248
|
-
* // 重置特定表的 mock
|
|
249
|
-
* mockDb.__resetMocks('user')
|
|
250
|
-
*
|
|
251
|
-
* // 清空所有调用历史
|
|
252
|
-
* mockDb.__clearCallHistory()
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
export declare function mockPrismaClient(): MockPrismaClient;
|
|
256
|
-
export {};
|
|
257
|
-
//# sourceMappingURL=prismaClient.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prismaClient.d.ts","sourceRoot":"","sources":["../../../source/mock/prismaClient/prismaClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
import { mockFunction } from '../function/function';
|
|
2
|
-
/**
|
|
3
|
-
* Prisma 支持的数据库操作方法列表
|
|
4
|
-
* 包含所有常用的 CRUD 和聚合操作
|
|
5
|
-
*/
|
|
6
|
-
const DB_METHODS = [
|
|
7
|
-
'create', 'createMany',
|
|
8
|
-
'findFirst', 'findUnique', 'findMany',
|
|
9
|
-
'update', 'updateMany',
|
|
10
|
-
'delete', 'deleteMany',
|
|
11
|
-
'upsert', 'count', 'aggregate',
|
|
12
|
-
'groupBy', 'findFirstOrThrow', 'findUniqueOrThrow'
|
|
13
|
-
];
|
|
14
|
-
/**
|
|
15
|
-
* 创建模拟的 Prisma Client
|
|
16
|
-
* 提供完整的数据库操作模拟能力和测试辅助功能
|
|
17
|
-
*
|
|
18
|
-
* 主要特性:
|
|
19
|
-
* - 动态创建数据库表代理,支持所有 Prisma 操作
|
|
20
|
-
* - 记录所有方法调用历史,包括参数、返回值、异常等
|
|
21
|
-
* - 支持灵活的 mock 返回值配置(同步/异步/异常)
|
|
22
|
-
* - 提供丰富的断言和验证方法
|
|
23
|
-
* - 支持调用序列验证和统计分析
|
|
24
|
-
* - 支持快照和批量操作
|
|
25
|
-
*
|
|
26
|
-
* @example 基础用法
|
|
27
|
-
* ```typescript
|
|
28
|
-
* const mockDb = createPrismaClient()
|
|
29
|
-
*
|
|
30
|
-
* // 设置返回值
|
|
31
|
-
* mockDb.__mockResolvedValue('user', 'findMany', [{ id: 1, name: 'John' }])
|
|
32
|
-
*
|
|
33
|
-
* // 执行操作
|
|
34
|
-
* const users = await mockDb.user.findMany()
|
|
35
|
-
*
|
|
36
|
-
* // 验证调用
|
|
37
|
-
* expect(mockDb.__getCallCount('user', 'findMany')).toBe(1)
|
|
38
|
-
* expect(users).toEqual([{ id: 1, name: 'John' }])
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* @example 高级 mock 配置
|
|
42
|
-
* ```typescript
|
|
43
|
-
* // 限制调用次数的 mock
|
|
44
|
-
* mockDb.__mockAdvanced('user', 'create', {
|
|
45
|
-
* value: { id: 1, name: 'John' },
|
|
46
|
-
* times: 2 // 只在前2次调用时返回此值
|
|
47
|
-
* })
|
|
48
|
-
*
|
|
49
|
-
* // 批量设置 mock
|
|
50
|
-
* mockDb.__batchMock({
|
|
51
|
-
* 'user.findMany': { value: [] },
|
|
52
|
-
* 'post.create': { value: { id: 1, title: 'Hello' } },
|
|
53
|
-
* 'comment.delete': { shouldThrow: true, value: new Error('删除失败') }
|
|
54
|
-
* })
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* @example 调用验证和统计
|
|
58
|
-
* ```typescript
|
|
59
|
-
* // 验证调用历史
|
|
60
|
-
* expect(mockDb.__wasCalledWith('user', 'findMany')).toBe(true)
|
|
61
|
-
* expect(mockDb.__wasCalledWithArgs('user', 'create', [{ name: 'John' }])).toBe(true)
|
|
62
|
-
*
|
|
63
|
-
* // 验证调用序列
|
|
64
|
-
* expect(mockDb.__verifyCallSequence([
|
|
65
|
-
* { table: 'user', method: 'findUnique' },
|
|
66
|
-
* { table: 'post', method: 'create' }
|
|
67
|
-
* ])).toBe(true)
|
|
68
|
-
*
|
|
69
|
-
* // 获取统计信息
|
|
70
|
-
* const stats = mockDb.__getCallStatistics()
|
|
71
|
-
* console.log(`总调用次数: ${stats.totalCalls}`)
|
|
72
|
-
* ```
|
|
73
|
-
*
|
|
74
|
-
* @example 快照和重置
|
|
75
|
-
* ```typescript
|
|
76
|
-
* // 创建快照
|
|
77
|
-
* const snapshot = mockDb.__createSnapshot()
|
|
78
|
-
*
|
|
79
|
-
* // 执行一些操作...
|
|
80
|
-
* await mockDb.user.create({ data: { name: 'John' } })
|
|
81
|
-
*
|
|
82
|
-
* // 恢复到快照状态
|
|
83
|
-
* mockDb.__restoreSnapshot(snapshot)
|
|
84
|
-
*
|
|
85
|
-
* // 重置特定表的 mock
|
|
86
|
-
* mockDb.__resetMocks('user')
|
|
87
|
-
*
|
|
88
|
-
* // 清空所有调用历史
|
|
89
|
-
* mockDb.__clearCallHistory()
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
export function mockPrismaClient() {
|
|
93
|
-
const callHistory = new Map();
|
|
94
|
-
const mockReturnValues = new Map();
|
|
95
|
-
const accessedTables = new Set();
|
|
96
|
-
/**
|
|
97
|
-
* 记录方法调用
|
|
98
|
-
*/
|
|
99
|
-
function recordCall(table, method, args, returnValue, error) {
|
|
100
|
-
accessedTables.add(table);
|
|
101
|
-
if (!callHistory.has(table)) {
|
|
102
|
-
callHistory.set(table, []);
|
|
103
|
-
}
|
|
104
|
-
callHistory.get(table).push({
|
|
105
|
-
method,
|
|
106
|
-
args: JSON.parse(JSON.stringify(args)), // 深拷贝避免引用问题
|
|
107
|
-
timestamp: new Date(),
|
|
108
|
-
returnValue,
|
|
109
|
-
isError: !!error,
|
|
110
|
-
error
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* 获取默认返回值
|
|
115
|
-
* 根据不同的数据库操作类型返回合理的默认值
|
|
116
|
-
*/
|
|
117
|
-
function getDefaultReturnValue(method) {
|
|
118
|
-
switch (method) {
|
|
119
|
-
case 'count':
|
|
120
|
-
return Promise.resolve(0);
|
|
121
|
-
case 'aggregate':
|
|
122
|
-
return Promise.resolve({});
|
|
123
|
-
case 'findMany':
|
|
124
|
-
return Promise.resolve([]);
|
|
125
|
-
case 'findFirst':
|
|
126
|
-
case 'findUnique':
|
|
127
|
-
return Promise.resolve(null);
|
|
128
|
-
case 'findFirstOrThrow':
|
|
129
|
-
case 'findUniqueOrThrow':
|
|
130
|
-
return Promise.resolve({ id: 'mock-id', createdAt: new Date(), updatedAt: new Date() });
|
|
131
|
-
case 'create':
|
|
132
|
-
case 'update':
|
|
133
|
-
case 'upsert':
|
|
134
|
-
return Promise.resolve({ id: 'mock-id', createdAt: new Date(), updatedAt: new Date() });
|
|
135
|
-
case 'createMany':
|
|
136
|
-
return Promise.resolve({ count: 1 });
|
|
137
|
-
case 'delete':
|
|
138
|
-
case 'deleteMany':
|
|
139
|
-
case 'updateMany':
|
|
140
|
-
return Promise.resolve({ count: 1 });
|
|
141
|
-
case 'groupBy':
|
|
142
|
-
return Promise.resolve([]);
|
|
143
|
-
default:
|
|
144
|
-
return Promise.resolve(null);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* 创建方法的 mock 函数
|
|
149
|
-
* 支持复杂的 mock 行为配置,包括调用次数限制、异常处理等
|
|
150
|
-
*/
|
|
151
|
-
function createMethodMock(table, method) {
|
|
152
|
-
return mockFunction(async (...args) => {
|
|
153
|
-
const key = `${table}.${method}`;
|
|
154
|
-
const config = mockReturnValues.get(key);
|
|
155
|
-
try {
|
|
156
|
-
let result;
|
|
157
|
-
if (config) {
|
|
158
|
-
// 检查调用次数限制
|
|
159
|
-
if (config.times !== undefined) {
|
|
160
|
-
const currentCount = callHistory.get(table)?.filter(c => c.method === method).length || 0;
|
|
161
|
-
if (currentCount >= config.times) {
|
|
162
|
-
// 超过限制次数,使用默认返回值
|
|
163
|
-
result = getDefaultReturnValue(method);
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
if (config.shouldThrow) {
|
|
167
|
-
throw config.value;
|
|
168
|
-
}
|
|
169
|
-
result = config.isAsync ? Promise.resolve(config.value) : config.value;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
if (config.shouldThrow) {
|
|
174
|
-
throw config.value;
|
|
175
|
-
}
|
|
176
|
-
result = config.isAsync ? Promise.resolve(config.value) : config.value;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
result = getDefaultReturnValue(method);
|
|
181
|
-
}
|
|
182
|
-
// 确保返回 Promise
|
|
183
|
-
const finalResult = result instanceof Promise ? await result : result;
|
|
184
|
-
recordCall(table, method, args, finalResult);
|
|
185
|
-
return finalResult;
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
recordCall(table, method, args, undefined, error);
|
|
189
|
-
throw error;
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* 动态创建表代理
|
|
195
|
-
*/
|
|
196
|
-
function createTableProxy(tableName) {
|
|
197
|
-
return new Proxy({}, {
|
|
198
|
-
get(target, prop) {
|
|
199
|
-
if (typeof prop === 'string' && DB_METHODS.includes(prop)) {
|
|
200
|
-
if (!target[prop]) {
|
|
201
|
-
target[prop] = createMethodMock(tableName, prop);
|
|
202
|
-
}
|
|
203
|
-
return target[prop];
|
|
204
|
-
}
|
|
205
|
-
// 支持其他可能的 Prisma 属性
|
|
206
|
-
if (typeof prop === 'string') {
|
|
207
|
-
return target[prop] || mockFunction();
|
|
208
|
-
}
|
|
209
|
-
return target[prop];
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* 创建主数据库代理
|
|
215
|
-
*/
|
|
216
|
-
const dbProxy = new Proxy({}, {
|
|
217
|
-
get(target, prop) {
|
|
218
|
-
if (typeof prop === 'string') {
|
|
219
|
-
// 测试辅助方法实现
|
|
220
|
-
switch (prop) {
|
|
221
|
-
case '__getCallHistory':
|
|
222
|
-
return (table, method) => {
|
|
223
|
-
if (!table) {
|
|
224
|
-
const allCalls = [];
|
|
225
|
-
for (const [tableName, calls] of callHistory.entries()) {
|
|
226
|
-
allCalls.push(...calls.map(call => ({ ...call, table: tableName })));
|
|
227
|
-
}
|
|
228
|
-
return allCalls.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
229
|
-
}
|
|
230
|
-
const calls = callHistory.get(table) || [];
|
|
231
|
-
return method ? calls.filter(call => call.method === method) : calls;
|
|
232
|
-
};
|
|
233
|
-
case '__clearCallHistory':
|
|
234
|
-
return (table) => {
|
|
235
|
-
if (table) {
|
|
236
|
-
callHistory.delete(table);
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
callHistory.clear();
|
|
240
|
-
accessedTables.clear();
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
case '__getLastCall':
|
|
244
|
-
return (table, method) => {
|
|
245
|
-
const calls = callHistory.get(table) || [];
|
|
246
|
-
const methodCalls = calls.filter(call => call.method === method);
|
|
247
|
-
return methodCalls[methodCalls.length - 1];
|
|
248
|
-
};
|
|
249
|
-
case '__getCallCount':
|
|
250
|
-
return (table, method) => {
|
|
251
|
-
const calls = callHistory.get(table) || [];
|
|
252
|
-
return calls.filter(call => call.method === method).length;
|
|
253
|
-
};
|
|
254
|
-
case '__mockReturnValue':
|
|
255
|
-
return (table, method, value) => {
|
|
256
|
-
mockReturnValues.set(`${table}.${method}`, { value, isAsync: false });
|
|
257
|
-
};
|
|
258
|
-
case '__mockResolvedValue':
|
|
259
|
-
return (table, method, value) => {
|
|
260
|
-
mockReturnValues.set(`${table}.${method}`, { value, isAsync: true });
|
|
261
|
-
};
|
|
262
|
-
case '__mockRejectedValue':
|
|
263
|
-
return (table, method, error) => {
|
|
264
|
-
mockReturnValues.set(`${table}.${method}`, { value: error, shouldThrow: true, isAsync: true });
|
|
265
|
-
};
|
|
266
|
-
case '__mockAdvanced':
|
|
267
|
-
return (table, method, config) => {
|
|
268
|
-
mockReturnValues.set(`${table}.${method}`, { ...config });
|
|
269
|
-
};
|
|
270
|
-
case '__resetMocks':
|
|
271
|
-
return (table) => {
|
|
272
|
-
if (table) {
|
|
273
|
-
const keysToDelete = Array.from(mockReturnValues.keys()).filter(key => key.startsWith(`${table}.`));
|
|
274
|
-
keysToDelete.forEach(key => mockReturnValues.delete(key));
|
|
275
|
-
}
|
|
276
|
-
else {
|
|
277
|
-
mockReturnValues.clear();
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
case '__getAccessedTables':
|
|
281
|
-
return () => Array.from(accessedTables);
|
|
282
|
-
case '__wasCalledWith':
|
|
283
|
-
return (table, method, times) => {
|
|
284
|
-
const callCount = callHistory.get(table)?.filter(call => call.method === method).length || 0;
|
|
285
|
-
return times !== undefined ? callCount === times : callCount > 0;
|
|
286
|
-
};
|
|
287
|
-
case '__wasCalledWithArgs':
|
|
288
|
-
return (table, method, expectedArgs) => {
|
|
289
|
-
const calls = callHistory.get(table) || [];
|
|
290
|
-
return calls.some(call => call.method === method &&
|
|
291
|
-
JSON.stringify(call.args) === JSON.stringify(expectedArgs));
|
|
292
|
-
};
|
|
293
|
-
case '__createSnapshot':
|
|
294
|
-
return () => {
|
|
295
|
-
return JSON.stringify({
|
|
296
|
-
callHistory: Array.from(callHistory.entries()),
|
|
297
|
-
mockReturnValues: Array.from(mockReturnValues.entries()),
|
|
298
|
-
accessedTables: Array.from(accessedTables)
|
|
299
|
-
});
|
|
300
|
-
};
|
|
301
|
-
case '__restoreSnapshot':
|
|
302
|
-
return (snapshot) => {
|
|
303
|
-
try {
|
|
304
|
-
const data = JSON.parse(snapshot);
|
|
305
|
-
callHistory.clear();
|
|
306
|
-
mockReturnValues.clear();
|
|
307
|
-
accessedTables.clear();
|
|
308
|
-
data.callHistory.forEach(([table, calls]) => {
|
|
309
|
-
callHistory.set(table, calls.map(call => ({
|
|
310
|
-
...call,
|
|
311
|
-
timestamp: new Date(call.timestamp)
|
|
312
|
-
})));
|
|
313
|
-
});
|
|
314
|
-
data.mockReturnValues.forEach(([key, config]) => {
|
|
315
|
-
mockReturnValues.set(key, config);
|
|
316
|
-
});
|
|
317
|
-
data.accessedTables.forEach((table) => {
|
|
318
|
-
accessedTables.add(table);
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
catch (error) {
|
|
322
|
-
throw new Error('无效的快照数据');
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
case '__batchMock':
|
|
326
|
-
return (configs) => {
|
|
327
|
-
Object.entries(configs).forEach(([key, config]) => {
|
|
328
|
-
mockReturnValues.set(key, { ...config });
|
|
329
|
-
});
|
|
330
|
-
};
|
|
331
|
-
case '__waitForAsyncOperations':
|
|
332
|
-
return async (ms = 10) => {
|
|
333
|
-
await new Promise(resolve => setTimeout(resolve, ms));
|
|
334
|
-
};
|
|
335
|
-
case '__verifyCallSequence':
|
|
336
|
-
return (expectedSequence) => {
|
|
337
|
-
const allCalls = [];
|
|
338
|
-
for (const [tableName, calls] of callHistory.entries()) {
|
|
339
|
-
allCalls.push(...calls.map(call => ({
|
|
340
|
-
table: tableName,
|
|
341
|
-
method: call.method,
|
|
342
|
-
timestamp: call.timestamp
|
|
343
|
-
})));
|
|
344
|
-
}
|
|
345
|
-
// 按时间戳排序
|
|
346
|
-
allCalls.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
347
|
-
if (allCalls.length < expectedSequence.length) {
|
|
348
|
-
return false;
|
|
349
|
-
}
|
|
350
|
-
// 检查序列是否匹配
|
|
351
|
-
for (let i = 0; i < expectedSequence.length; i++) {
|
|
352
|
-
const expected = expectedSequence[i];
|
|
353
|
-
const actual = allCalls[i];
|
|
354
|
-
if (actual.table !== expected.table || actual.method !== expected.method) {
|
|
355
|
-
return false;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
return true;
|
|
359
|
-
};
|
|
360
|
-
case '__getCallStatistics':
|
|
361
|
-
return () => {
|
|
362
|
-
let totalCalls = 0;
|
|
363
|
-
const tableStats = {};
|
|
364
|
-
const methodStats = {};
|
|
365
|
-
let earliest = null;
|
|
366
|
-
let latest = null;
|
|
367
|
-
for (const [tableName, calls] of callHistory.entries()) {
|
|
368
|
-
tableStats[tableName] = calls.length;
|
|
369
|
-
totalCalls += calls.length;
|
|
370
|
-
calls.forEach(call => {
|
|
371
|
-
const methodKey = `${tableName}.${call.method}`;
|
|
372
|
-
methodStats[methodKey] = (methodStats[methodKey] || 0) + 1;
|
|
373
|
-
if (!earliest || call.timestamp < earliest) {
|
|
374
|
-
earliest = call.timestamp;
|
|
375
|
-
}
|
|
376
|
-
if (!latest || call.timestamp > latest) {
|
|
377
|
-
latest = call.timestamp;
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
return {
|
|
382
|
-
totalCalls,
|
|
383
|
-
tableStats,
|
|
384
|
-
methodStats,
|
|
385
|
-
timeRange: earliest && latest ? { earliest, latest } : null
|
|
386
|
-
};
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
// 数据库表代理
|
|
390
|
-
if (!target[prop]) {
|
|
391
|
-
target[prop] = createTableProxy(prop);
|
|
392
|
-
}
|
|
393
|
-
return target[prop];
|
|
394
|
-
}
|
|
395
|
-
return target[prop];
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
return dbProxy;
|
|
399
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prismaClient.test.d.ts","sourceRoot":"","sources":["../../../source/mock/prismaClient/prismaClient.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { mockPrismaClient } from './prismaClient';
|
|
3
|
-
describe('mockPrismaClient', () => {
|
|
4
|
-
let db;
|
|
5
|
-
beforeEach(() => {
|
|
6
|
-
db = mockPrismaClient();
|
|
7
|
-
});
|
|
8
|
-
it('应支持 mockResolvedValue 并记录调用', async () => {
|
|
9
|
-
db.__mockResolvedValue('user', 'findMany', [{ id: 1, name: '张三' }]);
|
|
10
|
-
const users = await db.user.findMany();
|
|
11
|
-
expect(users).toEqual([{ id: 1, name: '张三' }]);
|
|
12
|
-
expect(db.__getCallCount('user', 'findMany')).toBe(1);
|
|
13
|
-
const lastCall = db.__getLastCall('user', 'findMany');
|
|
14
|
-
expect(lastCall?.args).toEqual([]);
|
|
15
|
-
expect(lastCall?.returnValue).toEqual([{ id: 1, name: '张三' }]);
|
|
16
|
-
});
|
|
17
|
-
it('应支持 mockRejectedValue 并捕获异常', async () => {
|
|
18
|
-
db.__mockRejectedValue('user', 'create', new Error('创建失败'));
|
|
19
|
-
await expect(db.user.create({ data: { name: '李四' } })).rejects.toThrow('创建失败');
|
|
20
|
-
expect(db.__getCallCount('user', 'create')).toBe(1);
|
|
21
|
-
const lastCall = db.__getLastCall('user', 'create');
|
|
22
|
-
expect(lastCall?.isError).toBe(true);
|
|
23
|
-
expect(lastCall?.error).toBeInstanceOf(Error);
|
|
24
|
-
});
|
|
25
|
-
it('应支持 mockReturnValue 返回同步值', async () => {
|
|
26
|
-
db.__mockReturnValue('post', 'count', 5);
|
|
27
|
-
const count = await db.post.count();
|
|
28
|
-
expect(count).toBe(5);
|
|
29
|
-
});
|
|
30
|
-
it('应支持 __getCallHistory 和 __clearCallHistory', async () => {
|
|
31
|
-
db.__mockResolvedValue('user', 'findMany', []);
|
|
32
|
-
await db.user.findMany();
|
|
33
|
-
await db.user.findMany({ where: { id: 1 } });
|
|
34
|
-
expect(db.__getCallHistory('user', 'findMany').length).toBe(2);
|
|
35
|
-
db.__clearCallHistory('user');
|
|
36
|
-
expect(db.__getCallHistory('user', 'findMany').length).toBe(0);
|
|
37
|
-
});
|
|
38
|
-
it('应支持 __resetMocks', async () => {
|
|
39
|
-
db.__mockReturnValue('user', 'count', 10);
|
|
40
|
-
await db.user.count();
|
|
41
|
-
db.__resetMocks('user');
|
|
42
|
-
const count = await db.user.count();
|
|
43
|
-
expect(count).toBe(0); // 恢复为默认值
|
|
44
|
-
});
|
|
45
|
-
it('应支持 __batchMock 批量设置', async () => {
|
|
46
|
-
db.__batchMock({
|
|
47
|
-
'user.findMany': { value: [{ id: 1 }], isAsync: true },
|
|
48
|
-
'post.create': { value: { id: 2 }, isAsync: true }
|
|
49
|
-
});
|
|
50
|
-
expect(await db.user.findMany()).toEqual([{ id: 1 }]);
|
|
51
|
-
expect(await db.post.create({ data: { title: 't' } })).toEqual({ id: 2 });
|
|
52
|
-
});
|
|
53
|
-
it('应支持 __createSnapshot 和 __restoreSnapshot', async () => {
|
|
54
|
-
db.__mockReturnValue('user', 'count', 7);
|
|
55
|
-
await db.user.count();
|
|
56
|
-
const snapshot = db.__createSnapshot();
|
|
57
|
-
db.__mockReturnValue('user', 'count', 1);
|
|
58
|
-
await db.user.count();
|
|
59
|
-
db.__restoreSnapshot(snapshot);
|
|
60
|
-
expect(await db.user.count()).toBe(7);
|
|
61
|
-
});
|
|
62
|
-
it('应支持 __wasCalledWith 和 __wasCalledWithArgs', async () => {
|
|
63
|
-
db.__mockResolvedValue('user', 'findUnique', { id: 1 });
|
|
64
|
-
await db.user.findUnique({ where: { id: 1 } });
|
|
65
|
-
expect(db.__wasCalledWith('user', 'findUnique')).toBe(true);
|
|
66
|
-
expect(db.__wasCalledWithArgs('user', 'findUnique', [{ where: { id: 1 } }])).toBe(true);
|
|
67
|
-
});
|
|
68
|
-
it('应支持 __verifyCallSequence', async () => {
|
|
69
|
-
db.__mockResolvedValue('user', 'findUnique', { id: 1 });
|
|
70
|
-
db.__mockResolvedValue('post', 'create', { id: 2 });
|
|
71
|
-
await db.user.findUnique({ where: { id: 1 } });
|
|
72
|
-
await db.post.create({ data: { title: 't' } });
|
|
73
|
-
expect(db.__verifyCallSequence([
|
|
74
|
-
{ table: 'user', method: 'findUnique' },
|
|
75
|
-
{ table: 'post', method: 'create' }
|
|
76
|
-
])).toBe(true);
|
|
77
|
-
});
|
|
78
|
-
it('应支持 __getCallStatistics', async () => {
|
|
79
|
-
db.__mockResolvedValue('user', 'findMany', []);
|
|
80
|
-
db.__mockResolvedValue('post', 'count', 3);
|
|
81
|
-
await db.user.findMany();
|
|
82
|
-
await db.post.count();
|
|
83
|
-
const stats = db.__getCallStatistics();
|
|
84
|
-
expect(stats.totalCalls).toBe(2);
|
|
85
|
-
expect(stats.tableStats.user).toBe(1);
|
|
86
|
-
expect(stats.tableStats.post).toBe(1);
|
|
87
|
-
expect(stats.methodStats['user.findMany']).toBe(1);
|
|
88
|
-
expect(stats.methodStats['post.count']).toBe(1);
|
|
89
|
-
expect(stats.timeRange).not.toBeNull();
|
|
90
|
-
});
|
|
91
|
-
});
|