create-dp-koa 1.0.0 → 1.0.2
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/package.json +2 -2
- package/template/.cursor/commands/cheatsheet-backend-controller.md +45 -0
- package/template/.cursor/commands/implement-backend-api-controller.md +60 -0
- package/template/.cursor/commands/plan-backend.md +97 -0
- package/template/.cursor/rules/00-backend-core.skill.md +61 -0
- package/template/.cursor/rules/01-backend-skill-router.skill.md +57 -0
- package/template/.cursor/rules/10-backend-api.skill.md +55 -0
- package/template/.cursor/rules/11-backend-controller-recipes.skill.md +188 -0
- package/template/.cursor/rules/20-backend-repository.skill.md +25 -0
- package/template/.cursor/rules/21-backend-service.skill.md +137 -0
- package/template/.cursor/rules/25-backend-comments-and-doc.skill.md +98 -0
- package/template/.cursor/rules/30-backend-validation.skill.md +342 -0
- package/template/.cursor/rules/40-backend-error-logging.skill.md +21 -0
- package/template/.cursor/rules/50-backend-bootstrap-lifecycle.skill.md +105 -0
- package/template/.cursor/rules/60-backend-router-registration.skill.md +73 -0
- package/template/.cursor/rules/70-backend-middleware.skill.md +100 -0
- package/template/.cursor/rules/80-backend-utils-and-libs.skill.md +108 -0
- package/template/.cursor/rules/85-backend-plugins.rule.md +65 -0
- package/template/.cursor/rules/90-backend-testing.skill.md +29 -0
- package/template/.cursor/rules/README.md +49 -0
- package/template/.trae/skills/11-backend-controller-recipes.skill.md +91 -10
- package/template/scripts/sync-template.mjs +0 -1
- package/template/src/controllers/example/ExampleController.ts +14 -0
- package/template/src/entity/index.ts +1 -15
- package/template/src/framework/decorator/processor/AnnotationProcessor.ts +5 -1
- package/template/src/routers/index.ts +0 -35
- package/template/src/utils/testDataInitializer.ts +2 -269
- package/template/test/controllers/example/ExampleController.test.ts +29 -31
- package/template/test/framework/annotation/AnnotationDecorators.test.ts +15 -15
- package/template/test/framework/annotation/AnnotationExecutor.test.ts +27 -32
- package/template/test/framework/annotation/AnnotationProcessor.test.ts +25 -24
- package/template/test/framework/annotation/CustomProcessors.test.ts +15 -25
- package/template/test/framework/annotation/NewRouter.test.ts +9 -7
- package/template/test/framework/annotation/ProcessorManager.test.ts +14 -27
- package/template/test/framework/databaseConfig.test.ts +2 -2
- package/template/test/integration/integration.test.ts +15 -72
- package/template/src/controllers/cacheManagement.controller.ts +0 -131
- package/template/src/controllers/captcha.controller.ts +0 -57
- package/template/src/controllers/example/NewAnnotationExampleController.ts +0 -159
- package/template/src/controllers/example/SwaggerExampleController.ts +0 -205
- package/template/src/controllers/example/TransactionExample.controller.ts +0 -336
- package/template/src/controllers/health.controller.ts +0 -235
- package/template/src/controllers/home/register.controller.ts +0 -58
- package/template/src/controllers/home/ytGoods.controller.ts +0 -92
- package/template/src/controllers/home/ytShop.controller.ts +0 -135
- package/template/src/controllers/home/ytUser.controller.ts +0 -89
- package/template/src/controllers/logManagement.controller.ts +0 -396
- package/template/src/controllers/public/emailSend.controller.ts +0 -65
- package/template/src/controllers/public/ytUserAuth.controller.ts +0 -174
- package/template/src/controllers/testData.controller.ts +0 -253
- package/template/src/dto/controller/example/NewAnnotationExampleController.dto.ts +0 -73
- package/template/src/dto/controller/home/emailSend.controller.dto.ts +0 -40
- package/template/src/dto/controller/home/register.controller.dto.ts +0 -45
- package/template/src/dto/controller/home/ytGoods.controller.dto.ts +0 -55
- package/template/src/dto/controller/home/ytShop.controller.dto.ts +0 -69
- package/template/src/dto/controller/home/ytUser.controller.dto.ts +0 -44
- package/template/src/dto/controller/public/ytUserAuth.controller.dto.ts +0 -63
- package/template/src/dto/goods.dto.ts +0 -212
- package/template/src/dto/service/ytService.dto.ts +0 -13
- package/template/src/dto/user.dto.ts +0 -177
- package/template/src/entity/columnTypes.ts +0 -13
- package/template/src/entity/goodsImagesUnlockKey.entity.ts +0 -33
- package/template/src/entity/goodsUnlocker.entity.ts +0 -34
- package/template/src/entity/shop.entity.ts +0 -52
- package/template/src/entity/shopUser.entity.ts +0 -41
- package/template/src/entity/ytGoods.entity.ts +0 -94
- package/template/src/entity/ytUser.entity.ts +0 -96
- package/template/src/examples/SwaggerProcessorExample.ts +0 -169
- package/template/src/examples/TransactionManagerDemo.ts +0 -377
- package/template/src/framework/utils/dynamicSwagger.ts +0 -410
- package/template/src/repository/UserRepository.ts +0 -122
- package/template/src/service/paramValidateTest.service.ts +0 -139
- package/template/src/service/ytGoods.service.ts +0 -42
- package/template/src/service/ytShop.service.ts +0 -90
- package/template/src/service/ytUser.service.ts +0 -451
- package/template/src/test/swaggerParameterTest.ts +0 -90
- package/template/test/controllers/controllers.test.ts +0 -173
- package/template/test/controllers/example/NewAnnotationExampleController.test.ts +0 -200
- package/template/test/framework/TransactionManagerDemo.test.ts +0 -363
- package/template/test/service/business.test.ts +0 -87
- package/template/test/service/paramValidateTest.service.test.ts +0 -184
- package/template/test/service/ytUser.service.test.ts +0 -566
|
@@ -1,363 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TransactionManager Demo 单元测试
|
|
3
|
-
* 测试各种事务管理器的使用场景
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { TestDatabaseHelper } from '../utils/testHelpers';
|
|
7
|
-
import { transactionManager } from '../../src/framework/utils/TransactionManager';
|
|
8
|
-
import { YtUserEntity } from '../../src/entity/ytUser.entity';
|
|
9
|
-
import { getDataSource } from '../../src/framework/utils/db';
|
|
10
|
-
|
|
11
|
-
describe('TransactionManager Demo 测试', () => {
|
|
12
|
-
let dataSource: any;
|
|
13
|
-
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
await TestDatabaseHelper.initTestDatabase();
|
|
16
|
-
dataSource = getDataSource();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterAll(async () => {
|
|
20
|
-
await TestDatabaseHelper.cleanupTestDatabase();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
await TestDatabaseHelper.resetTestData();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('示例 1: 基本事务', () => {
|
|
28
|
-
test('应该能够成功执行基本事务', async () => {
|
|
29
|
-
const result = await transactionManager.executeInTransaction(async (manager) => {
|
|
30
|
-
const user = new YtUserEntity();
|
|
31
|
-
user.email = 'test@example.com';
|
|
32
|
-
user.telnumber = '13800138000';
|
|
33
|
-
user.password = 'hashed';
|
|
34
|
-
|
|
35
|
-
return await manager.save(user);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
expect(result).toBeDefined();
|
|
39
|
-
expect(result.email).toBe('test@example.com');
|
|
40
|
-
expect(result.telnumber).toBe('13800138000');
|
|
41
|
-
|
|
42
|
-
// 验证数据已保存到数据库
|
|
43
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
44
|
-
where: { email: 'test@example.com' }
|
|
45
|
-
});
|
|
46
|
-
expect(savedUser).toBeDefined();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('事务失败时应该自动回滚', async () => {
|
|
50
|
-
await expect(
|
|
51
|
-
transactionManager.executeInTransaction(async (manager) => {
|
|
52
|
-
const user = new YtUserEntity();
|
|
53
|
-
user.email = 'test-rollback@example.com';
|
|
54
|
-
user.telnumber = '13800138001';
|
|
55
|
-
user.password = 'hashed';
|
|
56
|
-
await manager.save(user);
|
|
57
|
-
|
|
58
|
-
// 故意抛出错误
|
|
59
|
-
throw new Error('模拟错误');
|
|
60
|
-
})
|
|
61
|
-
).rejects.toThrow('模拟错误');
|
|
62
|
-
|
|
63
|
-
// 验证数据已被回滚(未保存到数据库)
|
|
64
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
65
|
-
where: { email: 'test-rollback@example.com' }
|
|
66
|
-
});
|
|
67
|
-
expect(savedUser).toBeNull();
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('示例 2: 嵌套事务', () => {
|
|
72
|
-
test('应该能够处理嵌套事务', async () => {
|
|
73
|
-
const result = await transactionManager.executeInTransaction(async (manager) => {
|
|
74
|
-
// 外层事务:创建主用户
|
|
75
|
-
const mainUser = new YtUserEntity();
|
|
76
|
-
mainUser.email = 'main-user@example.com';
|
|
77
|
-
mainUser.telnumber = '13800138020';
|
|
78
|
-
mainUser.password = 'hashed';
|
|
79
|
-
const savedUser = await manager.save(mainUser);
|
|
80
|
-
|
|
81
|
-
// 嵌套事务:创建相关用户
|
|
82
|
-
await transactionManager.executeNestedTransaction(async (nestedManager) => {
|
|
83
|
-
const relatedUser = new YtUserEntity();
|
|
84
|
-
relatedUser.email = 'related-user@example.com';
|
|
85
|
-
relatedUser.telnumber = '13800138021';
|
|
86
|
-
relatedUser.password = 'hashed';
|
|
87
|
-
await nestedManager.save(relatedUser);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return savedUser;
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
expect(result).toBeDefined();
|
|
94
|
-
expect(result.email).toBe('main-user@example.com');
|
|
95
|
-
|
|
96
|
-
// 验证所有数据都已保存
|
|
97
|
-
const mainUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
98
|
-
where: { email: 'main-user@example.com' }
|
|
99
|
-
});
|
|
100
|
-
const relatedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
101
|
-
where: { email: 'related-user@example.com' }
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
expect(mainUser).toBeDefined();
|
|
105
|
-
expect(relatedUser).toBeDefined();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('嵌套事务失败应该回滚外层事务', async () => {
|
|
109
|
-
await expect(
|
|
110
|
-
transactionManager.executeInTransaction(async (manager) => {
|
|
111
|
-
// 外层事务
|
|
112
|
-
const mainUser = new YtUserEntity();
|
|
113
|
-
mainUser.email = 'main-fail@example.com';
|
|
114
|
-
mainUser.telnumber = '13800138022';
|
|
115
|
-
mainUser.password = 'hashed';
|
|
116
|
-
await manager.save(mainUser);
|
|
117
|
-
|
|
118
|
-
// 嵌套事务:故意失败
|
|
119
|
-
await transactionManager.executeNestedTransaction(async (nestedManager) => {
|
|
120
|
-
throw new Error('嵌套事务失败');
|
|
121
|
-
});
|
|
122
|
-
})
|
|
123
|
-
).rejects.toThrow('嵌套事务失败');
|
|
124
|
-
|
|
125
|
-
// 验证外层事务也被回滚
|
|
126
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
127
|
-
where: { email: 'main-fail@example.com' }
|
|
128
|
-
});
|
|
129
|
-
expect(savedUser).toBeNull();
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
describe('示例 3: 批量操作事务', () => {
|
|
134
|
-
test('应该能够批量创建用户', async () => {
|
|
135
|
-
const operations = [
|
|
136
|
-
async (manager: any) => {
|
|
137
|
-
const user = new YtUserEntity();
|
|
138
|
-
user.email = 'batch-1@example.com';
|
|
139
|
-
user.telnumber = '13800138010';
|
|
140
|
-
user.password = 'hashed';
|
|
141
|
-
return await manager.save(user);
|
|
142
|
-
},
|
|
143
|
-
async (manager: any) => {
|
|
144
|
-
const user = new YtUserEntity();
|
|
145
|
-
user.email = 'batch-2@example.com';
|
|
146
|
-
user.telnumber = '13800138011';
|
|
147
|
-
user.password = 'hashed';
|
|
148
|
-
return await manager.save(user);
|
|
149
|
-
},
|
|
150
|
-
async (manager: any) => {
|
|
151
|
-
const user = new YtUserEntity();
|
|
152
|
-
user.email = 'batch-3@example.com';
|
|
153
|
-
user.telnumber = '13800138012';
|
|
154
|
-
user.password = 'hashed';
|
|
155
|
-
return await manager.save(user);
|
|
156
|
-
}
|
|
157
|
-
];
|
|
158
|
-
|
|
159
|
-
const results = await transactionManager.executeBatchTransaction(operations);
|
|
160
|
-
|
|
161
|
-
expect(results).toHaveLength(3);
|
|
162
|
-
expect(results[0].email).toBe('batch-1@example.com');
|
|
163
|
-
expect(results[1].email).toBe('batch-2@example.com');
|
|
164
|
-
expect(results[2].email).toBe('batch-3@example.com');
|
|
165
|
-
|
|
166
|
-
// 验证所有数据都已保存
|
|
167
|
-
const savedUsers = await dataSource.manager.find(YtUserEntity, {
|
|
168
|
-
where: [
|
|
169
|
-
{ email: 'batch-1@example.com' },
|
|
170
|
-
{ email: 'batch-2@example.com' },
|
|
171
|
-
{ email: 'batch-3@example.com' }
|
|
172
|
-
] as any
|
|
173
|
-
});
|
|
174
|
-
expect(savedUsers).toHaveLength(3);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test('批量操作中任一失败应该全部回滚', async () => {
|
|
178
|
-
const operations = [
|
|
179
|
-
async (manager: any) => {
|
|
180
|
-
const user = new YtUserEntity();
|
|
181
|
-
user.email = 'batch-ok@example.com';
|
|
182
|
-
user.telnumber = '13800138013';
|
|
183
|
-
user.password = 'hashed';
|
|
184
|
-
return await manager.save(user);
|
|
185
|
-
},
|
|
186
|
-
async (manager: any) => {
|
|
187
|
-
// 故意抛出错误
|
|
188
|
-
throw new Error('批量操作失败');
|
|
189
|
-
}
|
|
190
|
-
];
|
|
191
|
-
|
|
192
|
-
await expect(
|
|
193
|
-
transactionManager.executeBatchTransaction(operations)
|
|
194
|
-
).rejects.toThrow('批量操作失败');
|
|
195
|
-
|
|
196
|
-
// 验证没有数据被保存(全部回滚)
|
|
197
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
198
|
-
where: { email: 'batch-ok@example.com' }
|
|
199
|
-
});
|
|
200
|
-
expect(savedUser).toBeNull();
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
describe('示例 4: 复杂业务场景', () => {
|
|
205
|
-
test('应该能够处理复杂的多步骤业务场景', async () => {
|
|
206
|
-
const result = await transactionManager.executeInTransaction(async (manager) => {
|
|
207
|
-
// 步骤 1: 创建主用户
|
|
208
|
-
const mainUser = new YtUserEntity();
|
|
209
|
-
mainUser.email = 'complex-1@example.com';
|
|
210
|
-
mainUser.telnumber = '13800138040';
|
|
211
|
-
mainUser.password = 'hashed';
|
|
212
|
-
const savedMainUser = await manager.save(mainUser);
|
|
213
|
-
|
|
214
|
-
// 步骤 2: 创建第二个用户
|
|
215
|
-
const secondUser = new YtUserEntity();
|
|
216
|
-
secondUser.email = 'complex-2@example.com';
|
|
217
|
-
secondUser.telnumber = '13800138041';
|
|
218
|
-
secondUser.password = 'hashed';
|
|
219
|
-
const savedSecondUser = await manager.save(secondUser);
|
|
220
|
-
|
|
221
|
-
// 步骤 3: 更新主用户
|
|
222
|
-
savedMainUser.email = 'complex-1-updated@example.com';
|
|
223
|
-
const updatedMainUser = await manager.save(savedMainUser);
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
mainUser: updatedMainUser,
|
|
227
|
-
secondUser: savedSecondUser
|
|
228
|
-
};
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
expect(result).toBeDefined();
|
|
232
|
-
expect(result.mainUser.email).toBe('complex-1-updated@example.com');
|
|
233
|
-
expect(result.secondUser.email).toBe('complex-2@example.com');
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
test('复杂场景失败时应该回滚所有步骤', async () => {
|
|
237
|
-
await expect(
|
|
238
|
-
transactionManager.executeInTransaction(async (manager) => {
|
|
239
|
-
// 步骤 1
|
|
240
|
-
const user1 = new YtUserEntity();
|
|
241
|
-
user1.email = 'fail-step1@example.com';
|
|
242
|
-
user1.telnumber = '13800138050';
|
|
243
|
-
user1.password = 'hashed';
|
|
244
|
-
await manager.save(user1);
|
|
245
|
-
|
|
246
|
-
// 步骤 2
|
|
247
|
-
const user2 = new YtUserEntity();
|
|
248
|
-
user2.email = 'fail-step2@example.com';
|
|
249
|
-
user2.telnumber = '13800138051';
|
|
250
|
-
user2.password = 'hashed';
|
|
251
|
-
await manager.save(user2);
|
|
252
|
-
|
|
253
|
-
// 步骤 3: 失败
|
|
254
|
-
throw new Error('第三步失败');
|
|
255
|
-
})
|
|
256
|
-
).rejects.toThrow('第三步失败');
|
|
257
|
-
|
|
258
|
-
// 验证所有步骤都被回滚
|
|
259
|
-
const user1 = await dataSource.manager.findOne(YtUserEntity, {
|
|
260
|
-
where: { email: 'fail-step1@example.com' }
|
|
261
|
-
});
|
|
262
|
-
const user2 = await dataSource.manager.findOne(YtUserEntity, {
|
|
263
|
-
where: { email: 'fail-step2@example.com' }
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
expect(user1).toBeNull();
|
|
267
|
-
expect(user2).toBeNull();
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
describe('示例 5: 条件事务', () => {
|
|
272
|
-
test('应该能够根据条件控制事务提交', async () => {
|
|
273
|
-
const result = await transactionManager.executeInTransaction(async (manager) => {
|
|
274
|
-
const user = new YtUserEntity();
|
|
275
|
-
user.email = 'conditional@example.com';
|
|
276
|
-
user.telnumber = '13800138060';
|
|
277
|
-
user.password = 'hashed';
|
|
278
|
-
|
|
279
|
-
return await manager.save(user);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
expect(result).toBeDefined();
|
|
283
|
-
|
|
284
|
-
// 验证数据已保存
|
|
285
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
286
|
-
where: { email: 'conditional@example.com' }
|
|
287
|
-
});
|
|
288
|
-
expect(savedUser).toBeDefined();
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
test('条件不满足时应该回滚事务', async () => {
|
|
292
|
-
await expect(
|
|
293
|
-
transactionManager.executeInTransaction(async (manager) => {
|
|
294
|
-
const user = new YtUserEntity();
|
|
295
|
-
user.email = 'conditional-fail@example.com';
|
|
296
|
-
user.telnumber = '13800138061';
|
|
297
|
-
user.password = 'hashed';
|
|
298
|
-
await manager.save(user);
|
|
299
|
-
|
|
300
|
-
// 模拟条件判断
|
|
301
|
-
if (true) { // 条件不满足
|
|
302
|
-
throw new Error('不符合提交条件');
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return user;
|
|
306
|
-
})
|
|
307
|
-
).rejects.toThrow('不符合提交条件');
|
|
308
|
-
|
|
309
|
-
// 验证数据已被回滚
|
|
310
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
311
|
-
where: { email: 'conditional-fail@example.com' }
|
|
312
|
-
});
|
|
313
|
-
expect(savedUser).toBeNull();
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
describe('性能测试', () => {
|
|
318
|
-
test('批量操作性能', async () => {
|
|
319
|
-
const operationCount = 5; // 减少数量以加快测试
|
|
320
|
-
const operations = Array.from({ length: operationCount }, (_, i) => {
|
|
321
|
-
return async (manager: any) => {
|
|
322
|
-
const user = new YtUserEntity();
|
|
323
|
-
user.email = `perf-${i}@example.com`;
|
|
324
|
-
user.telnumber = `13800138${String(i).padStart(3, '0')}`;
|
|
325
|
-
user.password = 'hashed';
|
|
326
|
-
return await manager.save(user);
|
|
327
|
-
};
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const startTime = Date.now();
|
|
331
|
-
const results = await transactionManager.executeBatchTransaction(operations);
|
|
332
|
-
const endTime = Date.now();
|
|
333
|
-
|
|
334
|
-
expect(results).toHaveLength(operationCount);
|
|
335
|
-
expect(endTime - startTime).toBeLessThan(3000); // 应该在3秒内完成
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
describe('错误处理测试', () => {
|
|
340
|
-
test('应该能够正确处理回滚', async () => {
|
|
341
|
-
try {
|
|
342
|
-
await transactionManager.executeInTransaction(async (manager) => {
|
|
343
|
-
const user = new YtUserEntity();
|
|
344
|
-
user.email = 'rollback-test@example.com';
|
|
345
|
-
user.telnumber = '13800138030';
|
|
346
|
-
user.password = 'hashed';
|
|
347
|
-
await manager.save(user);
|
|
348
|
-
|
|
349
|
-
// 模拟业务规则错误
|
|
350
|
-
throw new Error('业务规则:测试用户不允许');
|
|
351
|
-
});
|
|
352
|
-
} catch (error) {
|
|
353
|
-
expect(error).toBeDefined();
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// 验证数据已被回滚
|
|
357
|
-
const savedUser = await dataSource.manager.findOne(YtUserEntity, {
|
|
358
|
-
where: { email: 'rollback-test@example.com' }
|
|
359
|
-
});
|
|
360
|
-
expect(savedUser).toBeNull();
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { TestDatabaseHelper, TestUtils } from '../utils/testHelpers';
|
|
2
|
-
import { YtUserService } from '../../src/service/ytUser.service';
|
|
3
|
-
import { YtShopService } from '../../src/service/ytShop.service';
|
|
4
|
-
import { YtGoodsService } from '../../src/service/ytGoods.service';
|
|
5
|
-
import { Provider } from 'dp-ioc2';
|
|
6
|
-
|
|
7
|
-
describe('业务服务测试', () => {
|
|
8
|
-
beforeAll(async () => {
|
|
9
|
-
await TestDatabaseHelper.initTestDatabase();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
afterAll(async () => {
|
|
13
|
-
await TestDatabaseHelper.cleanupTestDatabase();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
await TestDatabaseHelper.resetTestData();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('店铺服务测试', () => {
|
|
21
|
-
let shopService: YtShopService;
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
shopService = Provider(YtShopService);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('应该能够获取店铺商品列表', async () => {
|
|
28
|
-
const result = await shopService.getGoodsListByShopId(1, 1, 10);
|
|
29
|
-
expect(result.code).toBe('SUCCESS');
|
|
30
|
-
expect(result.data).toBeDefined();
|
|
31
|
-
expect(Array.isArray(result.data?.[0])).toBe(true);
|
|
32
|
-
expect(typeof result.data?.[1]).toBe('number');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('应该能够获取店铺用户信息', async () => {
|
|
36
|
-
const result = await shopService.getShopUserInfo(1);
|
|
37
|
-
expect(result.code).toBe('SUCCESS');
|
|
38
|
-
expect(result.data).toBeDefined();
|
|
39
|
-
expect(result.data?.id).toBeDefined();
|
|
40
|
-
expect(result.data?.nickName).toBeDefined();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('应该能够检查用户是否有店铺', async () => {
|
|
44
|
-
const result = await shopService.checkHasShop(1);
|
|
45
|
-
expect(result.code).toBe('SUCCESS');
|
|
46
|
-
expect(result.data).toBeDefined();
|
|
47
|
-
expect(typeof result.data).toBe('number');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('应该返回null当用户没有店铺时', async () => {
|
|
51
|
-
const result = await shopService.checkHasShop(999);
|
|
52
|
-
expect(result.code).toBe('SUCCESS');
|
|
53
|
-
expect(result.data).toBeNull();
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe('商品服务测试', () => {
|
|
58
|
-
let goodsService: YtGoodsService;
|
|
59
|
-
|
|
60
|
-
beforeEach(() => {
|
|
61
|
-
goodsService = Provider(YtGoodsService);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('应该能够解锁商品图片', async () => {
|
|
65
|
-
const result = await goodsService.unlockGoodsImage(1, 1, 'TEST_KEY_001');
|
|
66
|
-
expect(result.code).toBe('SUCCESS');
|
|
67
|
-
expect(result.data).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('应该拒绝无效的解锁密钥', async () => {
|
|
71
|
-
const result = await goodsService.unlockGoodsImage(1, 1, 'INVALID_KEY');
|
|
72
|
-
expect(result.code).toBe('FAIL');
|
|
73
|
-
expect(result.data).toBe(false);
|
|
74
|
-
expect(result.message).toBe('无效的解锁key');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('应该拒绝已使用的解锁密钥', async () => {
|
|
78
|
-
// 先使用一次密钥
|
|
79
|
-
await goodsService.unlockGoodsImage(3, 1, 'USED_KEY_001');
|
|
80
|
-
|
|
81
|
-
// 再次使用应该失败
|
|
82
|
-
const result = await goodsService.unlockGoodsImage(3, 1, 'USED_KEY_001');
|
|
83
|
-
expect(result.code).toBe('FAIL');
|
|
84
|
-
expect(result.data).toBe(false);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
});
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 参数校验测试
|
|
3
|
-
* 测试 dp-ioc2 的 @ParamValidate 装饰器功能
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Provider } from 'dp-ioc2';
|
|
7
|
-
import { ParamValidateTestService, CreateTestUserDto, UpdateTestUserDto } from '../../src/service/paramValidateTest.service';
|
|
8
|
-
import { TestDatabaseHelper } from '../utils/testHelpers';
|
|
9
|
-
import { IOCValidationError } from 'dp-ioc2';
|
|
10
|
-
|
|
11
|
-
describe('ParamValidate 参数校验测试', () => {
|
|
12
|
-
let service: ParamValidateTestService;
|
|
13
|
-
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
// 初始化测试数据库
|
|
16
|
-
await TestDatabaseHelper.initTestDatabase();
|
|
17
|
-
|
|
18
|
-
// 使用 Provider 实例化 Service(dp-ioc2 要求)
|
|
19
|
-
service = Provider<ParamValidateTestService>(ParamValidateTestService);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterAll(async () => {
|
|
23
|
-
await TestDatabaseHelper.cleanupTestDatabase();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
describe('测试1:对象参数校验(class-validator)', () => {
|
|
27
|
-
test('应该能够成功创建用户(参数有效)', async () => {
|
|
28
|
-
const dto: CreateTestUserDto = {
|
|
29
|
-
name: '测试用户',
|
|
30
|
-
email: 'test@example.com',
|
|
31
|
-
age: 25
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const result = await service.createUser(dto);
|
|
35
|
-
|
|
36
|
-
expect(result.code).toBe('SUCCESS');
|
|
37
|
-
expect(result.data).toBeDefined();
|
|
38
|
-
expect(result.data?.name).toBe('测试用户');
|
|
39
|
-
expect(result.data?.email).toBe('test@example.com');
|
|
40
|
-
expect(result.data?.age).toBe(25);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('应该拒绝无效的用户名(长度不足)', async () => {
|
|
44
|
-
const dto: CreateTestUserDto = {
|
|
45
|
-
name: 'ab', // 长度不足3
|
|
46
|
-
email: 'test@example.com',
|
|
47
|
-
age: 25
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// @ParamValidate 在方法调用前就抛出异常,需要在调用方捕获
|
|
51
|
-
await expect(service.createUser(dto)).rejects.toThrow(IOCValidationError);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('应该拒绝无效的邮箱格式', async () => {
|
|
55
|
-
const dto: CreateTestUserDto = {
|
|
56
|
-
name: '测试用户',
|
|
57
|
-
email: 'invalid-email', // 无效邮箱
|
|
58
|
-
age: 25
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
await expect(service.createUser(dto)).rejects.toThrow(IOCValidationError);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('应该拒绝年龄小于18', async () => {
|
|
65
|
-
const dto: CreateTestUserDto = {
|
|
66
|
-
name: '测试用户',
|
|
67
|
-
email: 'test@example.com',
|
|
68
|
-
age: 17 // 小于18
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
await expect(service.createUser(dto)).rejects.toThrow(IOCValidationError);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test('应该拒绝年龄大于100', async () => {
|
|
75
|
-
const dto: CreateTestUserDto = {
|
|
76
|
-
name: '测试用户',
|
|
77
|
-
email: 'test@example.com',
|
|
78
|
-
age: 101 // 大于100
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
await expect(service.createUser(dto)).rejects.toThrow(IOCValidationError);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('应该支持普通对象自动转换为 DTO 实例', async () => {
|
|
85
|
-
// 传入普通对象,dp-ioc2 会自动转换为 DTO 实例
|
|
86
|
-
const plainObject = {
|
|
87
|
-
name: '测试用户',
|
|
88
|
-
email: 'test@example.com',
|
|
89
|
-
age: 25
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const result = await service.createUser(plainObject as any);
|
|
93
|
-
|
|
94
|
-
expect(result.code).toBe('SUCCESS');
|
|
95
|
-
expect(result.data).toBeDefined();
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe('测试2:基本类型参数校验(Joi)', () => {
|
|
100
|
-
test('应该能够成功获取用户(有效ID)', async () => {
|
|
101
|
-
const result = await service.getUserById(123);
|
|
102
|
-
|
|
103
|
-
expect(result.code).toBe('SUCCESS');
|
|
104
|
-
expect(result.data).toBeDefined();
|
|
105
|
-
expect(result.data?.id).toBe(123);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('应该拒绝负数ID', async () => {
|
|
109
|
-
await expect(service.getUserById(-1)).rejects.toThrow(IOCValidationError);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test('应该拒绝零值ID', async () => {
|
|
113
|
-
await expect(service.getUserById(0)).rejects.toThrow(IOCValidationError);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('应该拒绝非整数ID', async () => {
|
|
117
|
-
// TypeScript 类型检查会阻止传入非数字,但运行时可能传入
|
|
118
|
-
await expect(service.getUserById(1.5 as any)).rejects.toThrow(IOCValidationError);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('测试3:混合参数校验', () => {
|
|
123
|
-
test('应该能够成功更新用户(所有参数有效)', async () => {
|
|
124
|
-
const dto: UpdateTestUserDto = {
|
|
125
|
-
name: '更新后的用户名',
|
|
126
|
-
email: 'updated@example.com'
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const result = await service.updateUser(123, dto);
|
|
130
|
-
|
|
131
|
-
expect(result.code).toBe('SUCCESS');
|
|
132
|
-
expect(result.data).toBeDefined();
|
|
133
|
-
expect(result.data?.id).toBe(123);
|
|
134
|
-
expect(result.data?.name).toBe('更新后的用户名');
|
|
135
|
-
expect(result.data?.email).toBe('updated@example.com');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('应该拒绝无效的用户ID(负数)', async () => {
|
|
139
|
-
const dto: UpdateTestUserDto = {
|
|
140
|
-
name: '更新后的用户名'
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
await expect(service.updateUser(-1, dto)).rejects.toThrow(IOCValidationError);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('应该拒绝无效的邮箱格式', async () => {
|
|
147
|
-
const dto: UpdateTestUserDto = {
|
|
148
|
-
email: 'invalid-email'
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
await expect(service.updateUser(123, dto)).rejects.toThrow(IOCValidationError);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe('测试4:无校验参数(对比测试)', () => {
|
|
156
|
-
test('无校验的方法应该接受任何参数', async () => {
|
|
157
|
-
// 这个方法没有 @ParamValidate,所以不会进行校验
|
|
158
|
-
const result = await service.getUserWithoutValidation(-1);
|
|
159
|
-
|
|
160
|
-
expect(result.code).toBe('SUCCESS');
|
|
161
|
-
// 即使传入负数,方法也会执行(因为没有校验)
|
|
162
|
-
expect(result.data?.id).toBe(-1);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
describe('测试5:异常信息验证', () => {
|
|
167
|
-
test('应该包含详细的校验错误信息', async () => {
|
|
168
|
-
const invalidDto = {
|
|
169
|
-
name: 'ab', // 无效
|
|
170
|
-
email: 'invalid',
|
|
171
|
-
age: 10
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
await service.createUser(invalidDto as any);
|
|
176
|
-
fail('应该抛出 IOCValidationError');
|
|
177
|
-
} catch (error) {
|
|
178
|
-
expect(error).toBeInstanceOf(IOCValidationError);
|
|
179
|
-
expect((error as IOCValidationError).message).toContain('Validation failed');
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|