@gadmin2n/schematics 0.0.88 → 0.0.90
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 +7 -6
- 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/index.tsx +1 -0
- 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
|
@@ -1,18 +1,332 @@
|
|
|
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 { PageService } from './page.service';
|
|
3
13
|
|
|
14
|
+
// Mock PrismaService
|
|
15
|
+
const mockPrismaService = {
|
|
16
|
+
page: {
|
|
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('PageService', () => {
|
|
5
46
|
let service: PageService;
|
|
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
|
+
PageService,
|
|
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<PageService>(PageService);
|
|
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 page record', async () => {
|
|
72
|
+
const createArgs = {
|
|
73
|
+
data: {
|
|
74
|
+
code: 'test_code',
|
|
75
|
+
name: 'test_name',
|
|
76
|
+
path: 'test_path',
|
|
77
|
+
iframeUrl: 'test_iframeUrl',
|
|
78
|
+
},
|
|
79
|
+
} as any;
|
|
80
|
+
const expectedResult = { id: 1, ...createArgs.data };
|
|
81
|
+
|
|
82
|
+
prisma.page.create.mockResolvedValue(expectedResult);
|
|
83
|
+
|
|
84
|
+
const result = await service.createOne(createArgs);
|
|
85
|
+
|
|
86
|
+
expect(prisma.page.create).toHaveBeenCalledWith(createArgs);
|
|
87
|
+
expect(prisma.page.create).toHaveBeenCalledTimes(1);
|
|
88
|
+
expect(result).toEqual(expectedResult);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should throw error when create fails', async () => {
|
|
92
|
+
const createArgs = {
|
|
93
|
+
data: {
|
|
94
|
+
code: 'test_code',
|
|
95
|
+
name: 'test_name',
|
|
96
|
+
path: 'test_path',
|
|
97
|
+
iframeUrl: 'test_iframeUrl',
|
|
98
|
+
},
|
|
99
|
+
} as any;
|
|
100
|
+
const error = new Error('Database connection failed');
|
|
101
|
+
|
|
102
|
+
prisma.page.create.mockRejectedValue(error);
|
|
103
|
+
|
|
104
|
+
await expect(service.createOne(createArgs)).rejects.toThrow(
|
|
105
|
+
'Database connection failed',
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('createMany', () => {
|
|
111
|
+
it('should create multiple page records with skipDuplicates', async () => {
|
|
112
|
+
const data = [
|
|
113
|
+
{
|
|
114
|
+
code: 'test_code',
|
|
115
|
+
name: 'test_name',
|
|
116
|
+
path: 'test_path',
|
|
117
|
+
iframeUrl: 'test_iframeUrl',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
code: 'test_code',
|
|
121
|
+
name: 'test_name',
|
|
122
|
+
path: 'test_path',
|
|
123
|
+
iframeUrl: 'test_iframeUrl',
|
|
124
|
+
},
|
|
125
|
+
] as any;
|
|
126
|
+
const expectedResult = { count: 2 };
|
|
127
|
+
|
|
128
|
+
prisma.page.createMany.mockResolvedValue(expectedResult);
|
|
129
|
+
|
|
130
|
+
const result = await service.createMany(data);
|
|
131
|
+
|
|
132
|
+
expect(prisma.page.createMany).toHaveBeenCalledWith({
|
|
133
|
+
data,
|
|
134
|
+
skipDuplicates: true,
|
|
135
|
+
});
|
|
136
|
+
expect(result).toEqual(expectedResult);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('findMany', () => {
|
|
141
|
+
it('should return entities with itemCount', async () => {
|
|
142
|
+
const findArgs = {
|
|
143
|
+
where: {},
|
|
144
|
+
take: 10,
|
|
145
|
+
skip: 0,
|
|
146
|
+
} as any;
|
|
147
|
+
const mockEntities = [{ id: 1 }, { id: 2 }];
|
|
148
|
+
|
|
149
|
+
prisma.page.count.mockResolvedValue(2);
|
|
150
|
+
prisma.page.findMany.mockResolvedValue(mockEntities);
|
|
151
|
+
|
|
152
|
+
const result = await service.findMany(findArgs);
|
|
153
|
+
|
|
154
|
+
expect(prisma.page.count).toHaveBeenCalledWith({ where: findArgs.where });
|
|
155
|
+
expect(prisma.page.findMany).toHaveBeenCalledWith(findArgs);
|
|
156
|
+
expect(result).toEqual({
|
|
157
|
+
itemCount: 2,
|
|
158
|
+
entities: mockEntities,
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should return empty result when no records found', async () => {
|
|
163
|
+
const findArgs = { where: {} } as any;
|
|
164
|
+
|
|
165
|
+
prisma.page.count.mockResolvedValue(0);
|
|
166
|
+
prisma.page.findMany.mockResolvedValue([]);
|
|
167
|
+
|
|
168
|
+
const result = await service.findMany(findArgs);
|
|
169
|
+
|
|
170
|
+
expect(result).toEqual({ itemCount: 0, entities: [] });
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('findUnique', () => {
|
|
175
|
+
it('should find a single page record by id', async () => {
|
|
176
|
+
const id = 1;
|
|
177
|
+
const select = { id: true };
|
|
178
|
+
const expectedResult = { id: 1 };
|
|
179
|
+
|
|
180
|
+
prisma.page.findUnique.mockResolvedValue(expectedResult);
|
|
181
|
+
|
|
182
|
+
const result = await service.findUnique(id, select);
|
|
183
|
+
|
|
184
|
+
expect(prisma.page.findUnique).toHaveBeenCalledWith({
|
|
185
|
+
where: { id },
|
|
186
|
+
select,
|
|
187
|
+
});
|
|
188
|
+
expect(result).toEqual(expectedResult);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should return null when record not found', async () => {
|
|
192
|
+
prisma.page.findUnique.mockResolvedValue(null);
|
|
193
|
+
|
|
194
|
+
const result = await service.findUnique(1, { id: true });
|
|
195
|
+
|
|
196
|
+
expect(result).toBeNull();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('updateUnique', () => {
|
|
201
|
+
it('should update a single page record', async () => {
|
|
202
|
+
const id = 1;
|
|
203
|
+
const data = {
|
|
204
|
+
code: 'test_code',
|
|
205
|
+
name: 'test_name',
|
|
206
|
+
path: 'test_path',
|
|
207
|
+
iframeUrl: 'test_iframeUrl',
|
|
208
|
+
} as any;
|
|
209
|
+
const expectedResult = { id: 1, ...data };
|
|
210
|
+
|
|
211
|
+
prisma.page.update.mockResolvedValue(expectedResult);
|
|
212
|
+
|
|
213
|
+
const result = await service.updateUnique(id, data);
|
|
214
|
+
|
|
215
|
+
expect(prisma.page.update).toHaveBeenCalledWith({
|
|
216
|
+
where: { id },
|
|
217
|
+
data,
|
|
218
|
+
});
|
|
219
|
+
expect(result).toEqual(expectedResult);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('updateMany', () => {
|
|
224
|
+
it('should update multiple page records', async () => {
|
|
225
|
+
const updateArgs = {
|
|
226
|
+
where: {},
|
|
227
|
+
data: {
|
|
228
|
+
code: 'test_code',
|
|
229
|
+
name: 'test_name',
|
|
230
|
+
path: 'test_path',
|
|
231
|
+
iframeUrl: 'test_iframeUrl',
|
|
232
|
+
},
|
|
233
|
+
} as any;
|
|
234
|
+
const expectedResult = { count: 5 };
|
|
235
|
+
|
|
236
|
+
prisma.page.updateMany.mockResolvedValue(expectedResult);
|
|
237
|
+
|
|
238
|
+
const result = await service.updateMany(updateArgs);
|
|
239
|
+
|
|
240
|
+
expect(prisma.page.updateMany).toHaveBeenCalledWith(updateArgs);
|
|
241
|
+
expect(result).toEqual(expectedResult);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe('deleteUnique', () => {
|
|
246
|
+
it('should delete a single page record and return count', async () => {
|
|
247
|
+
const id = 1;
|
|
248
|
+
|
|
249
|
+
prisma.page.delete.mockResolvedValue({ id: 1 });
|
|
250
|
+
|
|
251
|
+
const result = await service.deleteUnique(id);
|
|
252
|
+
|
|
253
|
+
expect(prisma.page.delete).toHaveBeenCalledWith({ where: { id } });
|
|
254
|
+
expect(result).toEqual({ count: 1 });
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe('deleteMany', () => {
|
|
259
|
+
it('should delete multiple page records', async () => {
|
|
260
|
+
const deleteArgs = { where: {} } as any;
|
|
261
|
+
const expectedResult = { count: 3 };
|
|
262
|
+
|
|
263
|
+
prisma.page.deleteMany.mockResolvedValue(expectedResult);
|
|
264
|
+
|
|
265
|
+
const result = await service.deleteMany(deleteArgs);
|
|
266
|
+
|
|
267
|
+
expect(prisma.page.deleteMany).toHaveBeenCalledWith(deleteArgs);
|
|
268
|
+
expect(result).toEqual(expectedResult);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe('count', () => {
|
|
273
|
+
it('should count page records with filter', async () => {
|
|
274
|
+
const countArgs = { where: {} } as any;
|
|
275
|
+
|
|
276
|
+
prisma.page.count.mockResolvedValue(10);
|
|
277
|
+
|
|
278
|
+
const result = await service.count(countArgs);
|
|
279
|
+
|
|
280
|
+
expect(prisma.page.count).toHaveBeenCalledWith(countArgs);
|
|
281
|
+
expect(result).toBe(10);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('should count all records when no filter provided', async () => {
|
|
285
|
+
prisma.page.count.mockResolvedValue(100);
|
|
286
|
+
|
|
287
|
+
const result = await service.count();
|
|
288
|
+
|
|
289
|
+
expect(prisma.page.count).toHaveBeenCalledWith(undefined);
|
|
290
|
+
expect(result).toBe(100);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
describe('groupBy', () => {
|
|
295
|
+
it('should group page records by specified field', async () => {
|
|
296
|
+
const groupByArgs = {
|
|
297
|
+
by: ['id'],
|
|
298
|
+
_count: { id: true },
|
|
299
|
+
} as any;
|
|
300
|
+
const expectedResult = [{ id: 1, _count: { id: 50 } }];
|
|
301
|
+
|
|
302
|
+
prisma.page.groupBy.mockResolvedValue(expectedResult);
|
|
303
|
+
|
|
304
|
+
const result = await service.groupBy(groupByArgs);
|
|
305
|
+
|
|
306
|
+
expect(prisma.page.groupBy).toHaveBeenCalledWith(groupByArgs);
|
|
307
|
+
expect(result).toEqual(expectedResult);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe('aggregate', () => {
|
|
312
|
+
it('should aggregate page records', async () => {
|
|
313
|
+
const aggregateArgs = {
|
|
314
|
+
_count: true,
|
|
315
|
+
_max: { id: true },
|
|
316
|
+
_min: { id: true },
|
|
317
|
+
} as any;
|
|
318
|
+
const expectedResult = {
|
|
319
|
+
_count: 100,
|
|
320
|
+
_max: { id: 1 },
|
|
321
|
+
_min: { id: 1 },
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
prisma.page.aggregate.mockResolvedValue(expectedResult);
|
|
325
|
+
|
|
326
|
+
const result = await service.aggregate(aggregateArgs);
|
|
327
|
+
|
|
328
|
+
expect(prisma.page.aggregate).toHaveBeenCalledWith(aggregateArgs);
|
|
329
|
+
expect(result).toEqual(expectedResult);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
18
332
|
});
|
|
@@ -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 { PageResourceController } from './pageResource.controller';
|
|
3
6
|
import { PageResourceService } from './pageResource.service';
|
|
4
7
|
|
|
8
|
+
// Mock PageResourceService:用空对象屏蔽真实 Service 的依赖(PrismaService 等),
|
|
9
|
+
// 避免 NestJS 在测试模块编译时去解析 Service 的构造参数。
|
|
10
|
+
const mockPageResourceService = {};
|
|
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('PageResourceController', () => {
|
|
6
27
|
let controller: PageResourceController;
|
|
7
28
|
|
|
8
29
|
beforeEach(async () => {
|
|
9
30
|
const module: TestingModule = await Test.createTestingModule({
|
|
10
31
|
controllers: [PageResourceController],
|
|
11
|
-
providers: [
|
|
12
|
-
|
|
32
|
+
providers: [
|
|
33
|
+
{ provide: PageResourceService, useValue: mockPageResourceService },
|
|
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<PageResourceController>(PageResourceController);
|
|
15
44
|
});
|
|
@@ -1,18 +1,328 @@
|
|
|
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 { PageResourceService } from './pageResource.service';
|
|
3
13
|
|
|
14
|
+
// Mock PrismaService
|
|
15
|
+
const mockPrismaService = {
|
|
16
|
+
pageResource: {
|
|
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('PageResourceService', () => {
|
|
5
46
|
let service: PageResourceService;
|
|
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: [
|
|
10
|
-
|
|
54
|
+
providers: [
|
|
55
|
+
PageResourceService,
|
|
56
|
+
{ provide: PrismaService, useValue: mockPrismaService },
|
|
57
|
+
{ provide: ConfigService, useValue: mockConfigService },
|
|
58
|
+
{ provide: WINSTON_MODULE_PROVIDER, useValue: mockLogger },
|
|
59
|
+
],
|
|
60
|
+
})
|
|
61
|
+
// 兜底:自动 mock 任何未显式提供的依赖
|
|
62
|
+
// (例如手工给 service 增加的额外依赖:RoleService、其他 Service 等)
|
|
63
|
+
.useMocker(() => ({}))
|
|
64
|
+
.compile();
|
|
11
65
|
|
|
12
66
|
service = module.get<PageResourceService>(PageResourceService);
|
|
67
|
+
prisma = mockPrismaService;
|
|
13
68
|
});
|
|
14
69
|
|
|
15
70
|
it('should be defined', () => {
|
|
16
71
|
expect(service).toBeDefined();
|
|
17
72
|
});
|
|
73
|
+
|
|
74
|
+
describe('createOne', () => {
|
|
75
|
+
it('should create a single pageResource record', async () => {
|
|
76
|
+
const createArgs = {
|
|
77
|
+
data: {
|
|
78
|
+
actions: {},
|
|
79
|
+
creator: 'test_creator',
|
|
80
|
+
},
|
|
81
|
+
} as any;
|
|
82
|
+
const expectedResult = { id: 1, ...createArgs.data };
|
|
83
|
+
|
|
84
|
+
prisma.pageResource.create.mockResolvedValue(expectedResult);
|
|
85
|
+
|
|
86
|
+
const result = await service.createOne(createArgs);
|
|
87
|
+
|
|
88
|
+
expect(prisma.pageResource.create).toHaveBeenCalledWith(createArgs);
|
|
89
|
+
expect(prisma.pageResource.create).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(result).toEqual(expectedResult);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should throw error when create fails', async () => {
|
|
94
|
+
const createArgs = {
|
|
95
|
+
data: {
|
|
96
|
+
actions: {},
|
|
97
|
+
creator: 'test_creator',
|
|
98
|
+
},
|
|
99
|
+
} as any;
|
|
100
|
+
const error = new Error('Database connection failed');
|
|
101
|
+
|
|
102
|
+
prisma.pageResource.create.mockRejectedValue(error);
|
|
103
|
+
|
|
104
|
+
await expect(service.createOne(createArgs)).rejects.toThrow(
|
|
105
|
+
'Database connection failed',
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('createMany', () => {
|
|
111
|
+
it('should create multiple pageResource records with skipDuplicates', async () => {
|
|
112
|
+
const data = [
|
|
113
|
+
{
|
|
114
|
+
actions: {},
|
|
115
|
+
creator: 'test_creator',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
actions: {},
|
|
119
|
+
creator: 'test_creator',
|
|
120
|
+
},
|
|
121
|
+
] as any;
|
|
122
|
+
const expectedResult = { count: 2 };
|
|
123
|
+
|
|
124
|
+
prisma.pageResource.createMany.mockResolvedValue(expectedResult);
|
|
125
|
+
|
|
126
|
+
const result = await service.createMany(data);
|
|
127
|
+
|
|
128
|
+
expect(prisma.pageResource.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.pageResource.count.mockResolvedValue(2);
|
|
146
|
+
prisma.pageResource.findMany.mockResolvedValue(mockEntities);
|
|
147
|
+
|
|
148
|
+
const result = await service.findMany(findArgs);
|
|
149
|
+
|
|
150
|
+
expect(prisma.pageResource.count).toHaveBeenCalledWith({
|
|
151
|
+
where: findArgs.where,
|
|
152
|
+
});
|
|
153
|
+
expect(prisma.pageResource.findMany).toHaveBeenCalledWith(findArgs);
|
|
154
|
+
expect(result).toEqual({
|
|
155
|
+
itemCount: 2,
|
|
156
|
+
entities: mockEntities,
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should return empty result when no records found', async () => {
|
|
161
|
+
const findArgs = { where: {} } as any;
|
|
162
|
+
|
|
163
|
+
prisma.pageResource.count.mockResolvedValue(0);
|
|
164
|
+
prisma.pageResource.findMany.mockResolvedValue([]);
|
|
165
|
+
|
|
166
|
+
const result = await service.findMany(findArgs);
|
|
167
|
+
|
|
168
|
+
expect(result).toEqual({ itemCount: 0, entities: [] });
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('findUnique', () => {
|
|
173
|
+
it('should find a single pageResource record by id', async () => {
|
|
174
|
+
const id = 1;
|
|
175
|
+
const select = { id: true };
|
|
176
|
+
const expectedResult = { id: 1 };
|
|
177
|
+
|
|
178
|
+
prisma.pageResource.findUnique.mockResolvedValue(expectedResult);
|
|
179
|
+
|
|
180
|
+
const result = await service.findUnique(id, select);
|
|
181
|
+
|
|
182
|
+
expect(prisma.pageResource.findUnique).toHaveBeenCalledWith({
|
|
183
|
+
where: { id },
|
|
184
|
+
select,
|
|
185
|
+
});
|
|
186
|
+
expect(result).toEqual(expectedResult);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should return null when record not found', async () => {
|
|
190
|
+
prisma.pageResource.findUnique.mockResolvedValue(null);
|
|
191
|
+
|
|
192
|
+
const result = await service.findUnique(1, { id: true });
|
|
193
|
+
|
|
194
|
+
expect(result).toBeNull();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('updateUnique', () => {
|
|
199
|
+
it('should update a single pageResource record', async () => {
|
|
200
|
+
const id = 1;
|
|
201
|
+
const data = {
|
|
202
|
+
actions: {},
|
|
203
|
+
creator: 'test_creator',
|
|
204
|
+
} as any;
|
|
205
|
+
const expectedResult = { id: 1, ...data };
|
|
206
|
+
|
|
207
|
+
prisma.pageResource.update.mockResolvedValue(expectedResult);
|
|
208
|
+
|
|
209
|
+
const result = await service.updateUnique(id, data);
|
|
210
|
+
|
|
211
|
+
expect(prisma.pageResource.update).toHaveBeenCalledWith({
|
|
212
|
+
where: { id },
|
|
213
|
+
data,
|
|
214
|
+
});
|
|
215
|
+
expect(result).toEqual(expectedResult);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('updateMany', () => {
|
|
220
|
+
it('should update multiple pageResource records', async () => {
|
|
221
|
+
const updateArgs = {
|
|
222
|
+
where: {},
|
|
223
|
+
data: {
|
|
224
|
+
actions: {},
|
|
225
|
+
creator: 'test_creator',
|
|
226
|
+
},
|
|
227
|
+
} as any;
|
|
228
|
+
const expectedResult = { count: 5 };
|
|
229
|
+
|
|
230
|
+
prisma.pageResource.updateMany.mockResolvedValue(expectedResult);
|
|
231
|
+
|
|
232
|
+
const result = await service.updateMany(updateArgs);
|
|
233
|
+
|
|
234
|
+
expect(prisma.pageResource.updateMany).toHaveBeenCalledWith(updateArgs);
|
|
235
|
+
expect(result).toEqual(expectedResult);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('deleteUnique', () => {
|
|
240
|
+
it('should delete a single pageResource record and return count', async () => {
|
|
241
|
+
const id = 1;
|
|
242
|
+
|
|
243
|
+
prisma.pageResource.delete.mockResolvedValue({ id: 1 });
|
|
244
|
+
|
|
245
|
+
const result = await service.deleteUnique(id);
|
|
246
|
+
|
|
247
|
+
expect(prisma.pageResource.delete).toHaveBeenCalledWith({
|
|
248
|
+
where: { id },
|
|
249
|
+
});
|
|
250
|
+
expect(result).toEqual({ count: 1 });
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe('deleteMany', () => {
|
|
255
|
+
it('should delete multiple pageResource records', async () => {
|
|
256
|
+
const deleteArgs = { where: {} } as any;
|
|
257
|
+
const expectedResult = { count: 3 };
|
|
258
|
+
|
|
259
|
+
prisma.pageResource.deleteMany.mockResolvedValue(expectedResult);
|
|
260
|
+
|
|
261
|
+
const result = await service.deleteMany(deleteArgs);
|
|
262
|
+
|
|
263
|
+
expect(prisma.pageResource.deleteMany).toHaveBeenCalledWith(deleteArgs);
|
|
264
|
+
expect(result).toEqual(expectedResult);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe('count', () => {
|
|
269
|
+
it('should count pageResource records with filter', async () => {
|
|
270
|
+
const countArgs = { where: {} } as any;
|
|
271
|
+
|
|
272
|
+
prisma.pageResource.count.mockResolvedValue(10);
|
|
273
|
+
|
|
274
|
+
const result = await service.count(countArgs);
|
|
275
|
+
|
|
276
|
+
expect(prisma.pageResource.count).toHaveBeenCalledWith(countArgs);
|
|
277
|
+
expect(result).toBe(10);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('should count all records when no filter provided', async () => {
|
|
281
|
+
prisma.pageResource.count.mockResolvedValue(100);
|
|
282
|
+
|
|
283
|
+
const result = await service.count();
|
|
284
|
+
|
|
285
|
+
expect(prisma.pageResource.count).toHaveBeenCalledWith(undefined);
|
|
286
|
+
expect(result).toBe(100);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
describe('groupBy', () => {
|
|
291
|
+
it('should group pageResource records by specified field', async () => {
|
|
292
|
+
const groupByArgs = {
|
|
293
|
+
by: ['id'],
|
|
294
|
+
_count: { id: true },
|
|
295
|
+
} as any;
|
|
296
|
+
const expectedResult = [{ id: 1, _count: { id: 50 } }];
|
|
297
|
+
|
|
298
|
+
prisma.pageResource.groupBy.mockResolvedValue(expectedResult);
|
|
299
|
+
|
|
300
|
+
const result = await service.groupBy(groupByArgs);
|
|
301
|
+
|
|
302
|
+
expect(prisma.pageResource.groupBy).toHaveBeenCalledWith(groupByArgs);
|
|
303
|
+
expect(result).toEqual(expectedResult);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
describe('aggregate', () => {
|
|
308
|
+
it('should aggregate pageResource records', async () => {
|
|
309
|
+
const aggregateArgs = {
|
|
310
|
+
_count: true,
|
|
311
|
+
_max: { id: true },
|
|
312
|
+
_min: { id: true },
|
|
313
|
+
} as any;
|
|
314
|
+
const expectedResult = {
|
|
315
|
+
_count: 100,
|
|
316
|
+
_max: { id: 1 },
|
|
317
|
+
_min: { id: 1 },
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
prisma.pageResource.aggregate.mockResolvedValue(expectedResult);
|
|
321
|
+
|
|
322
|
+
const result = await service.aggregate(aggregateArgs);
|
|
323
|
+
|
|
324
|
+
expect(prisma.pageResource.aggregate).toHaveBeenCalledWith(aggregateArgs);
|
|
325
|
+
expect(result).toEqual(expectedResult);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
18
328
|
});
|