@gadmin2n/schematics 0.0.88 → 0.0.89
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/dist/lib/application/files/gadmin2-game-angle-demo/.dockerignore +16 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.codegen +40 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.server +76 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.web +53 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/Jenkinsfile +219 -33
- package/dist/lib/application/files/gadmin2-game-angle-demo/compose-ctl.sh +250 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +4 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/dev/postgres/init.sql +12 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.md +170 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.yml +254 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +8 -7
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/lib/page-helpers.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/prismaModels.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/agenda.seed.ts +39 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/audit.seed.ts +40 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/bootstrap.ts +56 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/canvas.seed.ts +39 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/{scripts/sync-data-mngt-pages.ts → seed/data-mngt.seed.ts} +36 -20
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/game.seed.ts +44 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +30 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permission.seed.ts +130 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-event-trigger.ts +60 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +11 -25
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +108 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/main.ts +1 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.service.spec.ts +41 -57
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.service.spec.ts +309 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.service.spec.ts +315 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.service.spec.ts +312 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.service.spec.ts +317 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.service.spec.ts +309 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.service.spec.ts +299 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.service.spec.ts +307 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.spec.ts +31 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.spec.ts +309 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +205 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.ts +116 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.spec.ts +158 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +110 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/webhook-signature.util.spec.ts +79 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/webhook-signature.util.ts +54 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +34 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +457 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +241 -4
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +34 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +24 -30
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.spec.ts +34 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +36 -36
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.spec.ts +34 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.service.spec.ts +48 -24
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/README.md +312 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/TODO.md +152 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/.dockerignore +12 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/Dockerfile +79 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/GRACEFUL-DEPLOYMENT.md +270 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/index.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/reporting.ts +23 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/index.ts +70 -5
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/outbox-poller.ts +246 -90
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/cron-trigger-workflow.test.ts +20 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/workflows/dsl-workflow.ts +96 -8
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/nginx.conf +74 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/ElementInspector.tsx +18 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/promptGenerator.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/form.tsx +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +3 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +3 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +4 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasEditPage.tsx +9 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +156 -139
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasPage.tsx +14 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasToolbar.tsx +62 -0
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/PublishModal.tsx +4 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasApi.ts +18 -27
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasDefaults.ts +32 -11
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/demos.ts +48 -61
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas-page/index.tsx +3 -6
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +16 -16
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +28 -35
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +34 -3
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd.css +6 -0
- package/package.json +1 -1
- package/dist/lib/application/files/gadmin2-game-angle-demo/.gitattributes +0 -2
- package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile +0 -63
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/sync-resources.ts +0 -100
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permissions.ts +0 -302
- package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.spec.ts +0 -20
- package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/sql/create-event-trigger.sql +0 -87
- /package/dist/lib/application/files/gadmin2-game-angle-demo/{GRACEFUL-DEPLOYMENT.md → server/GRACEFUL-DEPLOYMENT.md} +0 -0
|
@@ -71,14 +71,11 @@ describe('AuditService', () => {
|
|
|
71
71
|
it('should create a single audit record', async () => {
|
|
72
72
|
const createArgs = {
|
|
73
73
|
data: {
|
|
74
|
-
|
|
75
|
-
authorId: '
|
|
76
|
-
authorName: 'Test User',
|
|
77
|
-
resource: 'auth',
|
|
78
|
-
resourceId: '1',
|
|
74
|
+
creator: 'test_creator',
|
|
75
|
+
authorId: 'test_authorId',
|
|
79
76
|
},
|
|
80
|
-
};
|
|
81
|
-
const expectedResult = { id:
|
|
77
|
+
} as any;
|
|
78
|
+
const expectedResult = { id: 1, ...createArgs.data };
|
|
82
79
|
|
|
83
80
|
prisma.audit.create.mockResolvedValue(expectedResult);
|
|
84
81
|
|
|
@@ -92,13 +89,10 @@ describe('AuditService', () => {
|
|
|
92
89
|
it('should throw error when create fails', async () => {
|
|
93
90
|
const createArgs = {
|
|
94
91
|
data: {
|
|
95
|
-
|
|
96
|
-
authorId: '
|
|
97
|
-
authorName: 'Test User',
|
|
98
|
-
resource: 'auth',
|
|
99
|
-
resourceId: '1',
|
|
92
|
+
creator: 'test_creator',
|
|
93
|
+
authorId: 'test_authorId',
|
|
100
94
|
},
|
|
101
|
-
};
|
|
95
|
+
} as any;
|
|
102
96
|
const error = new Error('Database connection failed');
|
|
103
97
|
|
|
104
98
|
prisma.audit.create.mockRejectedValue(error);
|
|
@@ -113,20 +107,14 @@ describe('AuditService', () => {
|
|
|
113
107
|
it('should create multiple audit records with skipDuplicates', async () => {
|
|
114
108
|
const data = [
|
|
115
109
|
{
|
|
116
|
-
|
|
117
|
-
authorId: '
|
|
118
|
-
authorName: 'User 1',
|
|
119
|
-
resource: 'auth',
|
|
120
|
-
resourceId: '1',
|
|
110
|
+
creator: 'test_creator',
|
|
111
|
+
authorId: 'test_authorId',
|
|
121
112
|
},
|
|
122
113
|
{
|
|
123
|
-
|
|
124
|
-
authorId: '
|
|
125
|
-
authorName: 'User 2',
|
|
126
|
-
resource: 'auth',
|
|
127
|
-
resourceId: '2',
|
|
114
|
+
creator: 'test_creator',
|
|
115
|
+
authorId: 'test_authorId',
|
|
128
116
|
},
|
|
129
|
-
];
|
|
117
|
+
] as any;
|
|
130
118
|
const expectedResult = { count: 2 };
|
|
131
119
|
|
|
132
120
|
prisma.audit.createMany.mockResolvedValue(expectedResult);
|
|
@@ -144,14 +132,11 @@ describe('AuditService', () => {
|
|
|
144
132
|
describe('findMany', () => {
|
|
145
133
|
it('should return entities with itemCount', async () => {
|
|
146
134
|
const findArgs = {
|
|
147
|
-
where: {
|
|
135
|
+
where: {},
|
|
148
136
|
take: 10,
|
|
149
137
|
skip: 0,
|
|
150
|
-
};
|
|
151
|
-
const mockEntities = [
|
|
152
|
-
{ id: BigInt(1), action: 'LOGIN', authorId: 'user123' },
|
|
153
|
-
{ id: BigInt(2), action: 'LOGOUT', authorId: 'user123' },
|
|
154
|
-
];
|
|
138
|
+
} as any;
|
|
139
|
+
const mockEntities = [{ id: 1 }, { id: 2 }];
|
|
155
140
|
|
|
156
141
|
prisma.audit.count.mockResolvedValue(2);
|
|
157
142
|
prisma.audit.findMany.mockResolvedValue(mockEntities);
|
|
@@ -169,7 +154,7 @@ describe('AuditService', () => {
|
|
|
169
154
|
});
|
|
170
155
|
|
|
171
156
|
it('should return empty result when no records found', async () => {
|
|
172
|
-
const findArgs = { where: {
|
|
157
|
+
const findArgs = { where: {} } as any;
|
|
173
158
|
|
|
174
159
|
prisma.audit.count.mockResolvedValue(0);
|
|
175
160
|
prisma.audit.findMany.mockResolvedValue([]);
|
|
@@ -183,12 +168,8 @@ describe('AuditService', () => {
|
|
|
183
168
|
describe('findUnique', () => {
|
|
184
169
|
it('should find a single audit record by id', async () => {
|
|
185
170
|
const id = 1;
|
|
186
|
-
const select = { id: true
|
|
187
|
-
const expectedResult = {
|
|
188
|
-
id: BigInt(1),
|
|
189
|
-
action: 'LOGIN',
|
|
190
|
-
authorId: 'user123',
|
|
191
|
-
};
|
|
171
|
+
const select = { id: true };
|
|
172
|
+
const expectedResult = { id: 1 };
|
|
192
173
|
|
|
193
174
|
prisma.audit.findUnique.mockResolvedValue(expectedResult);
|
|
194
175
|
|
|
@@ -204,7 +185,7 @@ describe('AuditService', () => {
|
|
|
204
185
|
it('should return null when record not found', async () => {
|
|
205
186
|
prisma.audit.findUnique.mockResolvedValue(null);
|
|
206
187
|
|
|
207
|
-
const result = await service.findUnique(
|
|
188
|
+
const result = await service.findUnique(1, { id: true });
|
|
208
189
|
|
|
209
190
|
expect(result).toBeNull();
|
|
210
191
|
});
|
|
@@ -213,8 +194,11 @@ describe('AuditService', () => {
|
|
|
213
194
|
describe('updateUnique', () => {
|
|
214
195
|
it('should update a single audit record', async () => {
|
|
215
196
|
const id = 1;
|
|
216
|
-
const data = {
|
|
217
|
-
|
|
197
|
+
const data = {
|
|
198
|
+
creator: 'test_creator',
|
|
199
|
+
authorId: 'test_authorId',
|
|
200
|
+
} as any;
|
|
201
|
+
const expectedResult = { id: 1, ...data };
|
|
218
202
|
|
|
219
203
|
prisma.audit.update.mockResolvedValue(expectedResult);
|
|
220
204
|
|
|
@@ -231,9 +215,12 @@ describe('AuditService', () => {
|
|
|
231
215
|
describe('updateMany', () => {
|
|
232
216
|
it('should update multiple audit records', async () => {
|
|
233
217
|
const updateArgs = {
|
|
234
|
-
where: {
|
|
235
|
-
data: {
|
|
236
|
-
|
|
218
|
+
where: {},
|
|
219
|
+
data: {
|
|
220
|
+
creator: 'test_creator',
|
|
221
|
+
authorId: 'test_authorId',
|
|
222
|
+
},
|
|
223
|
+
} as any;
|
|
237
224
|
const expectedResult = { count: 5 };
|
|
238
225
|
|
|
239
226
|
prisma.audit.updateMany.mockResolvedValue(expectedResult);
|
|
@@ -249,7 +236,7 @@ describe('AuditService', () => {
|
|
|
249
236
|
it('should delete a single audit record and return count', async () => {
|
|
250
237
|
const id = 1;
|
|
251
238
|
|
|
252
|
-
prisma.audit.delete.mockResolvedValue({ id:
|
|
239
|
+
prisma.audit.delete.mockResolvedValue({ id: 1 });
|
|
253
240
|
|
|
254
241
|
const result = await service.deleteUnique(id);
|
|
255
242
|
|
|
@@ -260,7 +247,7 @@ describe('AuditService', () => {
|
|
|
260
247
|
|
|
261
248
|
describe('deleteMany', () => {
|
|
262
249
|
it('should delete multiple audit records', async () => {
|
|
263
|
-
const deleteArgs = { where: {
|
|
250
|
+
const deleteArgs = { where: {} } as any;
|
|
264
251
|
const expectedResult = { count: 3 };
|
|
265
252
|
|
|
266
253
|
prisma.audit.deleteMany.mockResolvedValue(expectedResult);
|
|
@@ -274,7 +261,7 @@ describe('AuditService', () => {
|
|
|
274
261
|
|
|
275
262
|
describe('count', () => {
|
|
276
263
|
it('should count audit records with filter', async () => {
|
|
277
|
-
const countArgs = { where: {
|
|
264
|
+
const countArgs = { where: {} } as any;
|
|
278
265
|
|
|
279
266
|
prisma.audit.count.mockResolvedValue(10);
|
|
280
267
|
|
|
@@ -297,17 +284,14 @@ describe('AuditService', () => {
|
|
|
297
284
|
describe('groupBy', () => {
|
|
298
285
|
it('should group audit records by specified field', async () => {
|
|
299
286
|
const groupByArgs = {
|
|
300
|
-
by: ['
|
|
301
|
-
_count: {
|
|
302
|
-
};
|
|
303
|
-
const expectedResult = [
|
|
304
|
-
{ action: 'LOGIN', _count: { action: 50 } },
|
|
305
|
-
{ action: 'LOGOUT', _count: { action: 30 } },
|
|
306
|
-
];
|
|
287
|
+
by: ['id'],
|
|
288
|
+
_count: { id: true },
|
|
289
|
+
} as any;
|
|
290
|
+
const expectedResult = [{ id: 1, _count: { id: 50 } }];
|
|
307
291
|
|
|
308
292
|
prisma.audit.groupBy.mockResolvedValue(expectedResult);
|
|
309
293
|
|
|
310
|
-
const result = await service.groupBy(groupByArgs
|
|
294
|
+
const result = await service.groupBy(groupByArgs);
|
|
311
295
|
|
|
312
296
|
expect(prisma.audit.groupBy).toHaveBeenCalledWith(groupByArgs);
|
|
313
297
|
expect(result).toEqual(expectedResult);
|
|
@@ -320,11 +304,11 @@ describe('AuditService', () => {
|
|
|
320
304
|
_count: true,
|
|
321
305
|
_max: { id: true },
|
|
322
306
|
_min: { id: true },
|
|
323
|
-
} as
|
|
307
|
+
} as any;
|
|
324
308
|
const expectedResult = {
|
|
325
309
|
_count: 100,
|
|
326
|
-
_max: { id:
|
|
327
|
-
_min: { id:
|
|
310
|
+
_max: { id: 1 },
|
|
311
|
+
_min: { id: 1 },
|
|
328
312
|
};
|
|
329
313
|
|
|
330
314
|
prisma.audit.aggregate.mockResolvedValue(expectedResult);
|
|
@@ -1,15 +1,44 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
1
3
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
4
|
+
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
2
5
|
import { GameController } from './game.controller';
|
|
3
6
|
import { GameService } from './game.service';
|
|
4
7
|
|
|
8
|
+
// Mock GameService:用空对象屏蔽真实 Service 的依赖(PrismaService 等),
|
|
9
|
+
// 避免 NestJS 在测试模块编译时去解析 Service 的构造参数。
|
|
10
|
+
const mockGameService = {};
|
|
11
|
+
|
|
12
|
+
// Mock ConfigService
|
|
13
|
+
const mockConfigService = {
|
|
14
|
+
get: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Mock Logger
|
|
18
|
+
const mockLogger = {
|
|
19
|
+
child: jest.fn().mockReturnThis(),
|
|
20
|
+
info: jest.fn(),
|
|
21
|
+
error: jest.fn(),
|
|
22
|
+
warn: jest.fn(),
|
|
23
|
+
debug: jest.fn(),
|
|
24
|
+
};
|
|
25
|
+
|
|
5
26
|
describe('GameController', () => {
|
|
6
27
|
let controller: GameController;
|
|
7
28
|
|
|
8
29
|
beforeEach(async () => {
|
|
9
30
|
const module: TestingModule = await Test.createTestingModule({
|
|
10
31
|
controllers: [GameController],
|
|
11
|
-
providers: [
|
|
12
|
-
|
|
32
|
+
providers: [
|
|
33
|
+
{ provide: GameService, useValue: mockGameService },
|
|
34
|
+
{ provide: ConfigService, useValue: mockConfigService },
|
|
35
|
+
{ provide: WINSTON_MODULE_PROVIDER, useValue: mockLogger },
|
|
36
|
+
],
|
|
37
|
+
})
|
|
38
|
+
// 兜底:自动 mock 任何未显式提供的依赖
|
|
39
|
+
// (例如 ACGuard 内部的 __roles_builder__ token)
|
|
40
|
+
.useMocker(() => ({}))
|
|
41
|
+
.compile();
|
|
13
42
|
|
|
14
43
|
controller = module.get<GameController>(GameController);
|
|
15
44
|
});
|
|
@@ -1,18 +1,326 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
1
3
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
4
|
+
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
5
|
+
|
|
6
|
+
// Mock nestjs-prisma 模块
|
|
7
|
+
jest.mock('nestjs-prisma', () => ({
|
|
8
|
+
PrismaService: jest.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
import { PrismaService } from 'nestjs-prisma';
|
|
2
12
|
import { GameService } from './game.service';
|
|
3
13
|
|
|
14
|
+
// Mock PrismaService
|
|
15
|
+
const mockPrismaService = {
|
|
16
|
+
game: {
|
|
17
|
+
create: jest.fn(),
|
|
18
|
+
createMany: jest.fn(),
|
|
19
|
+
findMany: jest.fn(),
|
|
20
|
+
findUnique: jest.fn(),
|
|
21
|
+
update: jest.fn(),
|
|
22
|
+
updateMany: jest.fn(),
|
|
23
|
+
delete: jest.fn(),
|
|
24
|
+
deleteMany: jest.fn(),
|
|
25
|
+
count: jest.fn(),
|
|
26
|
+
groupBy: jest.fn(),
|
|
27
|
+
aggregate: jest.fn(),
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Mock Logger
|
|
32
|
+
const mockLogger = {
|
|
33
|
+
child: jest.fn().mockReturnThis(),
|
|
34
|
+
info: jest.fn(),
|
|
35
|
+
error: jest.fn(),
|
|
36
|
+
warn: jest.fn(),
|
|
37
|
+
debug: jest.fn(),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Mock ConfigService
|
|
41
|
+
const mockConfigService = {
|
|
42
|
+
get: jest.fn(),
|
|
43
|
+
};
|
|
44
|
+
|
|
4
45
|
describe('GameService', () => {
|
|
5
46
|
let service: GameService;
|
|
47
|
+
let prisma: typeof mockPrismaService;
|
|
6
48
|
|
|
7
49
|
beforeEach(async () => {
|
|
50
|
+
// 每个测试前重置所有 mock
|
|
51
|
+
jest.clearAllMocks();
|
|
52
|
+
|
|
8
53
|
const module: TestingModule = await Test.createTestingModule({
|
|
9
|
-
providers: [
|
|
54
|
+
providers: [
|
|
55
|
+
GameService,
|
|
56
|
+
{ provide: PrismaService, useValue: mockPrismaService },
|
|
57
|
+
{ provide: ConfigService, useValue: mockConfigService },
|
|
58
|
+
{ provide: WINSTON_MODULE_PROVIDER, useValue: mockLogger },
|
|
59
|
+
],
|
|
10
60
|
}).compile();
|
|
11
61
|
|
|
12
62
|
service = module.get<GameService>(GameService);
|
|
63
|
+
prisma = mockPrismaService;
|
|
13
64
|
});
|
|
14
65
|
|
|
15
66
|
it('should be defined', () => {
|
|
16
67
|
expect(service).toBeDefined();
|
|
17
68
|
});
|
|
69
|
+
|
|
70
|
+
describe('createOne', () => {
|
|
71
|
+
it('should create a single game record', async () => {
|
|
72
|
+
const createArgs = {
|
|
73
|
+
data: {
|
|
74
|
+
unified_editionid: 'test_unified_editionid',
|
|
75
|
+
name: 'test_name',
|
|
76
|
+
creator: 'test_creator',
|
|
77
|
+
},
|
|
78
|
+
} as any;
|
|
79
|
+
const expectedResult = { id: 1, ...createArgs.data };
|
|
80
|
+
|
|
81
|
+
prisma.game.create.mockResolvedValue(expectedResult);
|
|
82
|
+
|
|
83
|
+
const result = await service.createOne(createArgs);
|
|
84
|
+
|
|
85
|
+
expect(prisma.game.create).toHaveBeenCalledWith(createArgs);
|
|
86
|
+
expect(prisma.game.create).toHaveBeenCalledTimes(1);
|
|
87
|
+
expect(result).toEqual(expectedResult);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should throw error when create fails', async () => {
|
|
91
|
+
const createArgs = {
|
|
92
|
+
data: {
|
|
93
|
+
unified_editionid: 'test_unified_editionid',
|
|
94
|
+
name: 'test_name',
|
|
95
|
+
creator: 'test_creator',
|
|
96
|
+
},
|
|
97
|
+
} as any;
|
|
98
|
+
const error = new Error('Database connection failed');
|
|
99
|
+
|
|
100
|
+
prisma.game.create.mockRejectedValue(error);
|
|
101
|
+
|
|
102
|
+
await expect(service.createOne(createArgs)).rejects.toThrow(
|
|
103
|
+
'Database connection failed',
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('createMany', () => {
|
|
109
|
+
it('should create multiple game records with skipDuplicates', async () => {
|
|
110
|
+
const data = [
|
|
111
|
+
{
|
|
112
|
+
unified_editionid: 'test_unified_editionid',
|
|
113
|
+
name: 'test_name',
|
|
114
|
+
creator: 'test_creator',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
unified_editionid: 'test_unified_editionid',
|
|
118
|
+
name: 'test_name',
|
|
119
|
+
creator: 'test_creator',
|
|
120
|
+
},
|
|
121
|
+
] as any;
|
|
122
|
+
const expectedResult = { count: 2 };
|
|
123
|
+
|
|
124
|
+
prisma.game.createMany.mockResolvedValue(expectedResult);
|
|
125
|
+
|
|
126
|
+
const result = await service.createMany(data);
|
|
127
|
+
|
|
128
|
+
expect(prisma.game.createMany).toHaveBeenCalledWith({
|
|
129
|
+
data,
|
|
130
|
+
skipDuplicates: true,
|
|
131
|
+
});
|
|
132
|
+
expect(result).toEqual(expectedResult);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('findMany', () => {
|
|
137
|
+
it('should return entities with itemCount', async () => {
|
|
138
|
+
const findArgs = {
|
|
139
|
+
where: {},
|
|
140
|
+
take: 10,
|
|
141
|
+
skip: 0,
|
|
142
|
+
} as any;
|
|
143
|
+
const mockEntities = [{ id: 1 }, { id: 2 }];
|
|
144
|
+
|
|
145
|
+
prisma.game.count.mockResolvedValue(2);
|
|
146
|
+
prisma.game.findMany.mockResolvedValue(mockEntities);
|
|
147
|
+
|
|
148
|
+
const result = await service.findMany(findArgs);
|
|
149
|
+
|
|
150
|
+
expect(prisma.game.count).toHaveBeenCalledWith({ where: findArgs.where });
|
|
151
|
+
expect(prisma.game.findMany).toHaveBeenCalledWith(findArgs);
|
|
152
|
+
expect(result).toEqual({
|
|
153
|
+
itemCount: 2,
|
|
154
|
+
entities: mockEntities,
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should return empty result when no records found', async () => {
|
|
159
|
+
const findArgs = { where: {} } as any;
|
|
160
|
+
|
|
161
|
+
prisma.game.count.mockResolvedValue(0);
|
|
162
|
+
prisma.game.findMany.mockResolvedValue([]);
|
|
163
|
+
|
|
164
|
+
const result = await service.findMany(findArgs);
|
|
165
|
+
|
|
166
|
+
expect(result).toEqual({ itemCount: 0, entities: [] });
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('findUnique', () => {
|
|
171
|
+
it('should find a single game record by id', async () => {
|
|
172
|
+
const id = 1;
|
|
173
|
+
const select = { id: true };
|
|
174
|
+
const expectedResult = { id: 1 };
|
|
175
|
+
|
|
176
|
+
prisma.game.findUnique.mockResolvedValue(expectedResult);
|
|
177
|
+
|
|
178
|
+
const result = await service.findUnique(id, select);
|
|
179
|
+
|
|
180
|
+
expect(prisma.game.findUnique).toHaveBeenCalledWith({
|
|
181
|
+
where: { id },
|
|
182
|
+
select,
|
|
183
|
+
});
|
|
184
|
+
expect(result).toEqual(expectedResult);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should return null when record not found', async () => {
|
|
188
|
+
prisma.game.findUnique.mockResolvedValue(null);
|
|
189
|
+
|
|
190
|
+
const result = await service.findUnique(1, { id: true });
|
|
191
|
+
|
|
192
|
+
expect(result).toBeNull();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('updateUnique', () => {
|
|
197
|
+
it('should update a single game record', async () => {
|
|
198
|
+
const id = 1;
|
|
199
|
+
const data = {
|
|
200
|
+
unified_editionid: 'test_unified_editionid',
|
|
201
|
+
name: 'test_name',
|
|
202
|
+
creator: 'test_creator',
|
|
203
|
+
} as any;
|
|
204
|
+
const expectedResult = { id: 1, ...data };
|
|
205
|
+
|
|
206
|
+
prisma.game.update.mockResolvedValue(expectedResult);
|
|
207
|
+
|
|
208
|
+
const result = await service.updateUnique(id, data);
|
|
209
|
+
|
|
210
|
+
expect(prisma.game.update).toHaveBeenCalledWith({
|
|
211
|
+
where: { id },
|
|
212
|
+
data,
|
|
213
|
+
});
|
|
214
|
+
expect(result).toEqual(expectedResult);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe('updateMany', () => {
|
|
219
|
+
it('should update multiple game records', async () => {
|
|
220
|
+
const updateArgs = {
|
|
221
|
+
where: {},
|
|
222
|
+
data: {
|
|
223
|
+
unified_editionid: 'test_unified_editionid',
|
|
224
|
+
name: 'test_name',
|
|
225
|
+
creator: 'test_creator',
|
|
226
|
+
},
|
|
227
|
+
} as any;
|
|
228
|
+
const expectedResult = { count: 5 };
|
|
229
|
+
|
|
230
|
+
prisma.game.updateMany.mockResolvedValue(expectedResult);
|
|
231
|
+
|
|
232
|
+
const result = await service.updateMany(updateArgs);
|
|
233
|
+
|
|
234
|
+
expect(prisma.game.updateMany).toHaveBeenCalledWith(updateArgs);
|
|
235
|
+
expect(result).toEqual(expectedResult);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('deleteUnique', () => {
|
|
240
|
+
it('should delete a single game record and return count', async () => {
|
|
241
|
+
const id = 1;
|
|
242
|
+
|
|
243
|
+
prisma.game.delete.mockResolvedValue({ id: 1 });
|
|
244
|
+
|
|
245
|
+
const result = await service.deleteUnique(id);
|
|
246
|
+
|
|
247
|
+
expect(prisma.game.delete).toHaveBeenCalledWith({ where: { id } });
|
|
248
|
+
expect(result).toEqual({ count: 1 });
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('deleteMany', () => {
|
|
253
|
+
it('should delete multiple game records', async () => {
|
|
254
|
+
const deleteArgs = { where: {} } as any;
|
|
255
|
+
const expectedResult = { count: 3 };
|
|
256
|
+
|
|
257
|
+
prisma.game.deleteMany.mockResolvedValue(expectedResult);
|
|
258
|
+
|
|
259
|
+
const result = await service.deleteMany(deleteArgs);
|
|
260
|
+
|
|
261
|
+
expect(prisma.game.deleteMany).toHaveBeenCalledWith(deleteArgs);
|
|
262
|
+
expect(result).toEqual(expectedResult);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe('count', () => {
|
|
267
|
+
it('should count game records with filter', async () => {
|
|
268
|
+
const countArgs = { where: {} } as any;
|
|
269
|
+
|
|
270
|
+
prisma.game.count.mockResolvedValue(10);
|
|
271
|
+
|
|
272
|
+
const result = await service.count(countArgs);
|
|
273
|
+
|
|
274
|
+
expect(prisma.game.count).toHaveBeenCalledWith(countArgs);
|
|
275
|
+
expect(result).toBe(10);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should count all records when no filter provided', async () => {
|
|
279
|
+
prisma.game.count.mockResolvedValue(100);
|
|
280
|
+
|
|
281
|
+
const result = await service.count();
|
|
282
|
+
|
|
283
|
+
expect(prisma.game.count).toHaveBeenCalledWith(undefined);
|
|
284
|
+
expect(result).toBe(100);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe('groupBy', () => {
|
|
289
|
+
it('should group game records by specified field', async () => {
|
|
290
|
+
const groupByArgs = {
|
|
291
|
+
by: ['id'],
|
|
292
|
+
_count: { id: true },
|
|
293
|
+
} as any;
|
|
294
|
+
const expectedResult = [{ id: 1, _count: { id: 50 } }];
|
|
295
|
+
|
|
296
|
+
prisma.game.groupBy.mockResolvedValue(expectedResult);
|
|
297
|
+
|
|
298
|
+
const result = await service.groupBy(groupByArgs);
|
|
299
|
+
|
|
300
|
+
expect(prisma.game.groupBy).toHaveBeenCalledWith(groupByArgs);
|
|
301
|
+
expect(result).toEqual(expectedResult);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
describe('aggregate', () => {
|
|
306
|
+
it('should aggregate game records', async () => {
|
|
307
|
+
const aggregateArgs = {
|
|
308
|
+
_count: true,
|
|
309
|
+
_max: { id: true },
|
|
310
|
+
_min: { id: true },
|
|
311
|
+
} as any;
|
|
312
|
+
const expectedResult = {
|
|
313
|
+
_count: 100,
|
|
314
|
+
_max: { id: 1 },
|
|
315
|
+
_min: { id: 1 },
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
prisma.game.aggregate.mockResolvedValue(expectedResult);
|
|
319
|
+
|
|
320
|
+
const result = await service.aggregate(aggregateArgs);
|
|
321
|
+
|
|
322
|
+
expect(prisma.game.aggregate).toHaveBeenCalledWith(aggregateArgs);
|
|
323
|
+
expect(result).toEqual(expectedResult);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
18
326
|
});
|
|
@@ -1,15 +1,44 @@
|
|
|
1
|
+
/// <reference types="jest" />
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
1
3
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
4
|
+
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
2
5
|
import { PageController } from './page.controller';
|
|
3
6
|
import { PageService } from './page.service';
|
|
4
7
|
|
|
8
|
+
// Mock PageService:用空对象屏蔽真实 Service 的依赖(PrismaService 等),
|
|
9
|
+
// 避免 NestJS 在测试模块编译时去解析 Service 的构造参数。
|
|
10
|
+
const mockPageService = {};
|
|
11
|
+
|
|
12
|
+
// Mock ConfigService
|
|
13
|
+
const mockConfigService = {
|
|
14
|
+
get: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Mock Logger
|
|
18
|
+
const mockLogger = {
|
|
19
|
+
child: jest.fn().mockReturnThis(),
|
|
20
|
+
info: jest.fn(),
|
|
21
|
+
error: jest.fn(),
|
|
22
|
+
warn: jest.fn(),
|
|
23
|
+
debug: jest.fn(),
|
|
24
|
+
};
|
|
25
|
+
|
|
5
26
|
describe('PageController', () => {
|
|
6
27
|
let controller: PageController;
|
|
7
28
|
|
|
8
29
|
beforeEach(async () => {
|
|
9
30
|
const module: TestingModule = await Test.createTestingModule({
|
|
10
31
|
controllers: [PageController],
|
|
11
|
-
providers: [
|
|
12
|
-
|
|
32
|
+
providers: [
|
|
33
|
+
{ provide: PageService, useValue: mockPageService },
|
|
34
|
+
{ provide: ConfigService, useValue: mockConfigService },
|
|
35
|
+
{ provide: WINSTON_MODULE_PROVIDER, useValue: mockLogger },
|
|
36
|
+
],
|
|
37
|
+
})
|
|
38
|
+
// 兜底:自动 mock 任何未显式提供的依赖
|
|
39
|
+
// (例如 ACGuard 内部的 __roles_builder__ token)
|
|
40
|
+
.useMocker(() => ({}))
|
|
41
|
+
.compile();
|
|
13
42
|
|
|
14
43
|
controller = module.get<PageController>(PageController);
|
|
15
44
|
});
|