nodejs-quickstart-structure 1.18.1 → 1.19.0

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.
Files changed (104) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +2 -1
  3. package/lib/modules/caching-setup.js +76 -73
  4. package/lib/modules/kafka-setup.js +249 -191
  5. package/lib/modules/project-setup.js +1 -0
  6. package/package.json +13 -2
  7. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  8. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  9. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  10. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  11. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  12. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  13. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  14. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  15. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  16. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  17. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  18. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  19. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  20. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  21. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  22. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  23. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  24. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  25. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  26. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  27. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  28. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  29. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  30. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  31. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  32. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  33. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  34. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  35. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  36. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  37. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  38. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  39. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  40. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  41. package/templates/common/.gitattributes +46 -0
  42. package/templates/common/README.md.ejs +294 -270
  43. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  44. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  45. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  46. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  47. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  48. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  49. package/templates/common/database/js/models/User.js.ejs +79 -53
  50. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  51. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  52. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  53. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  54. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  55. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  56. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  57. package/templates/common/jest.e2e.config.js.ejs +8 -8
  58. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  59. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  60. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  61. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  62. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  63. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  64. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  65. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  66. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  67. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  68. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  69. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  70. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  71. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  72. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  73. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  74. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  75. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  76. package/templates/common/swagger.yml.ejs +118 -66
  77. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  78. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  79. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  80. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  81. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  82. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  83. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  84. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  85. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  86. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  87. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  88. package/templates/mvc/js/src/routes/api.js +10 -8
  89. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  90. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  91. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  92. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  93. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  94. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  95. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  96. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  97. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  98. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  99. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  100. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  101. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  102. package/templates/mvc/ts/src/routes/api.ts +12 -10
  103. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  104. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -1,203 +1,481 @@
1
- <% if (communication !== 'GraphQL') { -%>
2
- import { Request, Response, NextFunction } from 'express';
3
- import { HTTP_STATUS } from '@/utils/httpCodes';
4
- <% } -%>
5
- import { UserController } from '@/controllers/userController';
6
- import User from '@/models/User';
7
- <%_ if (caching === 'Redis') { -%>
8
- import cacheService from '@/config/redisClient';
9
- <%_ } else if (caching === 'Memory Cache') { -%>
10
- import cacheService from '@/config/memoryCache';
11
- <%_ } -%>
12
-
13
- // Mock dependencies
14
- jest.mock('@/models/User');
15
- <%_ if (caching === 'Redis') { -%>
16
- jest.mock('@/config/redisClient', () => ({
17
- getOrSet: jest.fn(),
18
- del: jest.fn()
19
- }));
20
- <%_ } else if (caching === 'Memory Cache') { -%>
21
- jest.mock('@/config/memoryCache', () => ({
22
- getOrSet: jest.fn(),
23
- del: jest.fn()
24
- }));
25
- <%_ } -%>
26
- jest.mock('@/utils/logger');
27
- <%_ if (communication === 'Kafka') { -%>
28
- jest.mock('@/services/kafkaService', () => {
29
- const mockSendMessage = jest.fn().mockResolvedValue(undefined);
30
- return {
31
- kafkaService: {
32
- sendMessage: mockSendMessage
33
- },
34
- KafkaService: jest.fn().mockImplementation(() => ({
35
- sendMessage: mockSendMessage
36
- }))
37
- };
38
- });
39
- <%_ } -%>
40
-
41
-
42
- describe('UserController', () => {
43
- let userController: UserController;
44
- <% if (communication !== 'GraphQL') { -%>
45
- let mockRequest: Partial<Request>;
46
- let mockResponse: Partial<Response>;
47
- let mockNext: NextFunction;
48
- <% } -%>
49
-
50
- beforeEach(() => {
51
- userController = new UserController();
52
- <% if (communication !== 'GraphQL') { -%>
53
- mockRequest = {};
54
- mockResponse = {
55
- json: jest.fn(),
56
- status: jest.fn().mockReturnThis(),
57
- };
58
- mockNext = jest.fn();
59
- <% } -%>
60
- });
61
-
62
- afterEach(() => {
63
- jest.clearAllMocks();
64
- });
65
-
66
- describe('getUsers', () => {
67
- it('should return successfully (Happy Path)', async () => {
68
- // Arrange
69
- const usersMock = [{ id: '1', name: 'Test', email: 'test@example.com' }];
70
- <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
71
- (cacheService.getOrSet as jest.Mock).mockResolvedValue(usersMock);
72
- <%_ } else { -%>
73
- <%_ if (database === 'MongoDB' || database === 'None') { -%>
74
- (User.find as jest.Mock).mockResolvedValue(usersMock);
75
- <%_ } else { -%>
76
- (User.findAll as jest.Mock).mockResolvedValue(usersMock);
77
- <%_ } -%>
78
- <%_ } -%>
79
-
80
- // Act
81
- <% if (communication === 'GraphQL') { -%>
82
- const result = await userController.getUsers();
83
-
84
- // Assert
85
- expect(result).toEqual(usersMock);
86
- <% } else { -%>
87
- await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
88
-
89
- // Assert
90
- expect(mockResponse.json).toHaveBeenCalledWith(usersMock);
91
- <% } -%>
92
- <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
93
- expect(cacheService.getOrSet).toHaveBeenCalled();
94
- <%_ } else { -%>
95
- <%_ if (database === 'MongoDB') { -%>
96
- expect(User.find).toHaveBeenCalled();
97
- <%_ } else if (database === 'None') { -%>
98
- // No DB mock logic
99
- <%_ } else { -%>
100
- expect(User.findAll).toHaveBeenCalled();
101
- <%_ } -%>
102
- <%_ } -%>
103
- });
104
-
105
- it('should handle errors correctly (Error Handling)', async () => {
106
- // Arrange
107
- const error = new Error('Database Error');
108
- <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
109
- (cacheService.getOrSet as jest.Mock).mockRejectedValue(error);
110
- <%_ } else { -%>
111
- <%_ if (database === 'MongoDB' || database === 'None') { -%>
112
- (User.find as jest.Mock).mockRejectedValue(error);
113
- <%_ } else { -%>
114
- (User.findAll as jest.Mock).mockRejectedValue(error);
115
- <%_ } -%>
116
- <%_ } -%>
117
-
118
- // Act & Assert
119
- <% if (communication === 'GraphQL') { -%>
120
- await expect(userController.getUsers()).rejects.toThrow(error);
121
- <% } else { -%>
122
- await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
123
- expect(mockNext).toHaveBeenCalledWith(error);
124
- <% } -%>
125
- });
126
- });
127
-
128
- describe('createUser', () => {
129
- it('should successfully create a new user (Happy Path)', async () => {
130
- // Arrange
131
- const payload = { name: 'Alice', email: 'alice@example.com' };
132
- <% if (communication === 'GraphQL') { -%>
133
- const dataArg = payload;
134
- <% } else { -%>
135
- mockRequest.body = payload;
136
- <% } -%>
137
-
138
- <%_ if (database === 'MongoDB' || database === 'None') { -%>
139
- const expectedUser = { id: '1', ...payload };
140
- (User.create as jest.Mock).mockResolvedValue(expectedUser);
141
- <%_ if (database === 'None') { -%>User.mockData = [expectedUser];<%_ } -%>
142
- <%_ } else { -%>
143
- const expectedUser = { id: '1', ...payload };
144
- (User.create as jest.Mock).mockResolvedValue(expectedUser);
145
- <%_ } -%>
146
-
147
- // Act
148
- <% if (communication === 'GraphQL') { -%>
149
- const result = await userController.createUser(dataArg);
150
-
151
- // Assert
152
- <%_ if (database === 'None') { -%>
153
- expect(result.name).toBe(payload.name);
154
- expect(result.email).toBe(payload.email);
155
- expect(User.mockData.length).toBe(1);
156
- <%_ } else { -%>
157
- expect(result).toEqual(expectedUser);
158
- expect(User.create).toHaveBeenCalledWith(payload);
159
- <%_ } -%>
160
- <% } else { -%>
161
- await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
162
-
163
- // Assert
164
- expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.CREATED);
165
- <%_ if (database === 'None') { -%>
166
- expect(mockResponse.json).toHaveBeenCalled();
167
- expect(User.mockData.length).toBe(1);
168
- <%_ } else { -%>
169
- expect(mockResponse.json).toHaveBeenCalledWith(expectedUser);
170
- expect(User.create).toHaveBeenCalledWith(payload);
171
- <%_ } -%>
172
- <% } -%>
173
- <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
174
- expect(cacheService.del).toHaveBeenCalledWith('users:all');
175
- <%_ } -%>
176
- <%_ if (communication === 'Kafka') { -%>
177
- const { kafkaService } = require('@/services/kafkaService');
178
- expect(kafkaService.sendMessage).toHaveBeenCalled();
179
- <%_ } -%>
180
- });
181
-
182
- it('should handle errors when creation fails (Error Handling)', async () => {
183
- // Arrange
184
- const error = new Error('Creation Error');
185
- const payload = { name: 'Bob', email: 'bob@example.com' };
186
- <% if (communication === 'GraphQL') { -%>
187
- const dataArg = payload;
188
- <% } else { -%>
189
- mockRequest.body = payload;
190
- <% } -%>
191
-
192
- (User.create as jest.Mock).mockRejectedValue(error);
193
-
194
- // Act & Assert
195
- <% if (communication === 'GraphQL') { -%>
196
- await expect(userController.createUser(dataArg)).rejects.toThrow(error);
197
- <% } else { -%>
198
- await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
199
- expect(mockNext).toHaveBeenCalledWith(error);
200
- <% } -%>
201
- });
202
- });
203
- });
1
+ import { HTTP_STATUS } from '@/utils/httpCodes';
2
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
3
+ <% if (communication !== 'GraphQL') { -%>
4
+ import { Request, Response, NextFunction } from 'express';
5
+ <% } -%>
6
+ import { UserController } from '@/controllers/userController';
7
+ <%_ if (caching === 'Redis') { -%>
8
+ import cacheService from '@/config/redisClient';
9
+ <%_ } else if (caching === 'Memory Cache') { -%>
10
+ import cacheService from '@/config/memoryCache';
11
+ <%_ } -%>
12
+
13
+ // Mock dependencies
14
+ jest.mock('@/models/User', () => {
15
+ return {
16
+ create: jest.fn(),
17
+ find: jest.fn(),
18
+ findAll: jest.fn(),
19
+ findById: jest.fn(),
20
+ findByIdAndUpdate: jest.fn(),
21
+ findByIdAndDelete: jest.fn(),
22
+ findByPk: jest.fn(),
23
+ update: jest.fn(),
24
+ destroy: jest.fn(),
25
+ mockData: []
26
+ };
27
+ });
28
+ const User = require('@/models/User');
29
+ <%_ if (caching === 'Redis') { -%>
30
+ jest.mock('@/config/redisClient', () => ({
31
+ getOrSet: jest.fn((_key, fetcher) => fetcher()),
32
+ del: jest.fn(),
33
+ flush: jest.fn()
34
+ }));
35
+ <%_ } else if (caching === 'Memory Cache') { -%>
36
+ jest.mock('@/config/memoryCache', () => ({
37
+ getOrSet: jest.fn((_key, fetcher) => fetcher()),
38
+ del: jest.fn(),
39
+ flush: jest.fn()
40
+ }));
41
+ <%_ } -%>
42
+ jest.mock('@/utils/logger');
43
+ <%_ if (communication === 'Kafka') { -%>
44
+ jest.mock('@/services/kafkaService', () => {
45
+ const mockSendMessage = jest.fn().mockResolvedValue(undefined);
46
+ return {
47
+ sendMessage: mockSendMessage,
48
+ kafkaService: {
49
+ sendMessage: mockSendMessage
50
+ },
51
+ KafkaService: jest.fn().mockImplementation(() => ({
52
+ sendMessage: mockSendMessage
53
+ }))
54
+ };
55
+ });
56
+ import { kafkaService } from '@/services/kafkaService';
57
+ <%_ } -%>
58
+
59
+
60
+ describe('UserController', () => {
61
+ let userController: UserController;
62
+ <% if (communication !== 'GraphQL') { -%>
63
+ let mockRequest: Partial<Request>;
64
+ let mockResponse: Partial<Response>;
65
+ let mockNext: NextFunction;
66
+ <% } -%>
67
+
68
+ beforeEach(() => {
69
+ userController = new UserController();
70
+ <% if (communication !== 'GraphQL') { -%>
71
+ mockRequest = {
72
+ body: {}
73
+ };
74
+ mockResponse = {
75
+ json: jest.fn(),
76
+ status: jest.fn().mockReturnThis(),
77
+ };
78
+ mockNext = jest.fn();
79
+ <% } -%>
80
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
81
+ (cacheService.getOrSet as jest.Mock).mockImplementation((_key, fetcher) => fetcher());
82
+ (cacheService.flush as jest.Mock).mockClear();
83
+ <%_ } -%>
84
+ });
85
+
86
+ afterEach(() => {
87
+ jest.clearAllMocks();
88
+ <%_ if (database === 'None') { -%>
89
+ (User as any).mockData = [];
90
+ <%_ } -%>
91
+ });
92
+
93
+ describe('getUsers', () => {
94
+ it('should return successfully (Happy Path)', async () => {
95
+ // Arrange
96
+ const usersMock = [{ id: '1', name: 'Test', email: 'test@example.com' }];
97
+ <%_ if (database === 'MongoDB' || database === 'None') { -%>
98
+ (User.find as jest.Mock).mockResolvedValue(usersMock);
99
+ <%_ } else { -%>
100
+ (User.findAll as jest.Mock).mockResolvedValue(usersMock);
101
+ <%_ } -%>
102
+
103
+ // Act
104
+ <% if (communication === 'GraphQL') { -%>
105
+ const result = await userController.getUsers();
106
+
107
+ // Assert
108
+ expect(result!).toEqual(usersMock);
109
+ <% } else { -%>
110
+ await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
111
+
112
+ // Assert
113
+ expect(mockResponse.json).toHaveBeenCalledWith(usersMock);
114
+ <% } -%>
115
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
116
+ expect(cacheService.getOrSet).toHaveBeenCalled();
117
+ <%_ } else { -%>
118
+ <%_ if (database === 'MongoDB') { -%>
119
+ expect(User.find).toHaveBeenCalled();
120
+ <%_ } else if (database === 'None') { -%>
121
+ // No DB mock logic
122
+ <%_ } else { -%>
123
+ expect(User.findAll).toHaveBeenCalled();
124
+ <%_ } -%>
125
+ <%_ } -%>
126
+ });
127
+
128
+ it('should return an empty array when no users found', async () => {
129
+ // Arrange
130
+ const usersMock: any[] = [];
131
+ <%_ if (database === 'MongoDB' || database === 'None') { -%>
132
+ (User.find as jest.Mock).mockResolvedValue(usersMock);
133
+ <%_ } else { -%>
134
+ (User.findAll as jest.Mock).mockResolvedValue(usersMock);
135
+ <%_ } -%>
136
+
137
+ // Act
138
+ <% if (communication === 'GraphQL') { -%>
139
+ const result = await userController.getUsers();
140
+
141
+ // Assert
142
+ expect(result!).toEqual(usersMock);
143
+ <% } else { -%>
144
+ await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
145
+
146
+ // Assert
147
+ expect(mockResponse.json).toHaveBeenCalledWith(usersMock);
148
+ <% } -%>
149
+ });
150
+
151
+ it('should handle errors correctly (Error Handling)', async () => {
152
+ // Arrange
153
+ const error = new Error('Database Error');
154
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
155
+ // Simulating error inside the fetcher by making User.findAll fail
156
+ <%_ if (database === 'MongoDB' || database === 'None') { -%>
157
+ (User.find as jest.Mock).mockRejectedValue(error);
158
+ <%_ } else { -%>
159
+ (User.findAll as jest.Mock).mockRejectedValue(error);
160
+ <%_ } -%>
161
+ <%_ } else { -%>
162
+ <%_ if (database === 'MongoDB' || database === 'None') { -%>
163
+ (User.find as jest.Mock).mockRejectedValue(error);
164
+ <%_ } else { -%>
165
+ (User.findAll as jest.Mock).mockRejectedValue(error);
166
+ <%_ } -%>
167
+ <%_ } -%>
168
+
169
+ // Act & Assert
170
+ <% if (communication === 'GraphQL') { -%>
171
+ await expect(userController.getUsers()).rejects.toThrow(error);
172
+ <% } else { -%>
173
+ await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
174
+ expect(mockNext).toHaveBeenCalledWith(error);
175
+ <% } -%>
176
+ });
177
+ });
178
+
179
+ describe('createUser', () => {
180
+ it('should successfully create a new user (Happy Path)', async () => {
181
+ // Arrange
182
+ const payload = { name: 'Alice', email: 'alice@example.com' };
183
+ <% if (communication === 'GraphQL') { -%>
184
+ const dataArg = payload;
185
+ <% } else { -%>
186
+ mockRequest.body = payload;
187
+ <% } -%>
188
+
189
+ const expectedUser = { id: '1', ...payload };
190
+ <%_ if (database === 'MongoDB') { -%>
191
+ (User.create as jest.Mock).mockResolvedValue(expectedUser);
192
+ <%_ } else if (database === 'None') { -%>
193
+ (User.create as jest.Mock).mockResolvedValue(expectedUser);
194
+ <%_ } else { -%>
195
+ (User.create as jest.Mock).mockResolvedValue(expectedUser);
196
+ <%_ } -%>
197
+
198
+ // Act
199
+ <% if (communication === 'GraphQL') { -%>
200
+ const result = await userController.createUser(dataArg) as any;
201
+
202
+ // Assert
203
+ expect(result!).toEqual(expectedUser);
204
+ <% } else { -%>
205
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
206
+
207
+ // Assert
208
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.CREATED);
209
+ expect(mockResponse.json).toHaveBeenCalledWith(expectedUser);
210
+ expect(User.create).toHaveBeenCalledWith(payload);
211
+ <% } -%>
212
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
213
+ expect(cacheService.del).toHaveBeenCalledWith('users:all');
214
+ <%_ } -%>
215
+ <%_ if (communication === 'Kafka') { -%>
216
+ expect(kafkaService.sendMessage).toHaveBeenCalled();
217
+ <%_ } -%>
218
+ });
219
+
220
+ it('should handle errors when creation fails (Error Handling)', async () => {
221
+ // Arrange
222
+ const error = new Error('Creation Error');
223
+ const payload = { name: 'Bob', email: 'bob@example.com' };
224
+ <% if (communication === 'GraphQL') { -%>
225
+ const dataArg = payload;
226
+ <% } else { -%>
227
+ mockRequest.body = payload;
228
+ <% } -%>
229
+
230
+ (User.create as jest.Mock).mockRejectedValue(error);
231
+
232
+ // Act & Assert
233
+ <% if (communication === 'GraphQL') { -%>
234
+ await expect(userController.createUser(dataArg)).rejects.toThrow(error);
235
+ <% } else { -%>
236
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
237
+ expect(mockNext).toHaveBeenCalledWith(error);
238
+ <% } -%>
239
+ });
240
+ });
241
+
242
+ describe('updateUser', () => {
243
+ it('should successfully update a user (Happy Path)', async () => {
244
+ // Arrange
245
+ const id = '1';
246
+ const payload = { name: 'Alice Updated' };
247
+ <% if (communication === 'GraphQL') { -%>
248
+ const idArg = id;
249
+ const dataArg = payload;
250
+ <% } else { -%>
251
+ mockRequest.params = { id };
252
+ mockRequest.body = payload;
253
+ <% } -%>
254
+
255
+ const expectedUser = { id, ...payload, email: 'alice@example.com' };
256
+ <%_ if (database === 'MongoDB') { -%>
257
+ (User.findByIdAndUpdate as jest.Mock).mockResolvedValue(expectedUser);
258
+ (User.findById as jest.Mock).mockResolvedValue(expectedUser);
259
+ <%_ } else if (database === 'None') { -%>
260
+ (User.update as jest.Mock).mockResolvedValue(expectedUser);
261
+ (User.findByPk as jest.Mock).mockResolvedValue(expectedUser);
262
+ <%_ } else { -%>
263
+ const userMock = { ...expectedUser, update: jest.fn().mockResolvedValue(true) };
264
+ (User.findByPk as jest.Mock).mockResolvedValue(userMock);
265
+ <%_ } -%>
266
+
267
+ // Act
268
+ <% if (communication === 'GraphQL') { -%>
269
+ const result = await userController.updateUser(idArg, dataArg);
270
+
271
+ // Assert
272
+ <%_ if (database === 'None' || database === 'MongoDB') { -%>
273
+ expect(result!).toEqual(expectedUser);
274
+ <%_ } else { -%>
275
+ expect(result!).toMatchObject(payload);
276
+ expect(User.findByPk).toHaveBeenCalledWith(id);
277
+ <%_ } -%>
278
+ <% } else { -%>
279
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
280
+
281
+ // Assert
282
+ <%_ if (database === 'None' || database === 'MongoDB') { -%>
283
+ expect(mockResponse.json).toHaveBeenCalledWith(expectedUser);
284
+ <%_ } else { -%>
285
+ expect(mockResponse.json).toHaveBeenCalled();
286
+ expect(User.findByPk).toHaveBeenCalledWith(id);
287
+ <%_ } -%>
288
+ <% } -%>
289
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
290
+ expect(cacheService.del).toHaveBeenCalledWith('users:all');
291
+ <%_ } -%>
292
+ <%_ if (communication === 'Kafka') { -%>
293
+ expect(kafkaService.sendMessage).toHaveBeenCalled();
294
+ <%_ } -%>
295
+ });
296
+
297
+ it('should handle 404/errors when user not found or update fails', async () => {
298
+ // Arrange
299
+ const id = '999';
300
+ <%_ if (communication === 'GraphQL') { -%>
301
+ const idArg = id;
302
+ const dataArg = { name: 'Fail' };
303
+ <%_ if (database === 'MongoDB') { -%>
304
+ (User.findByIdAndUpdate as jest.Mock).mockResolvedValue(null);
305
+ <%_ } else { -%>
306
+ (User.findByPk as jest.Mock).mockResolvedValue(null);
307
+ <%_ } -%>
308
+ await expect(userController.updateUser(idArg, dataArg)).rejects.toThrow(ERROR_MESSAGES.USER_NOT_FOUND);
309
+ <%_ } else { -%>
310
+ mockRequest.params = { id };
311
+ mockRequest.body = { name: 'Fail' };
312
+ <%_ if (database === 'MongoDB') { -%>
313
+ (User.findByIdAndUpdate as jest.Mock).mockResolvedValue(null);
314
+ <%_ } else if (database === 'None') { -%>
315
+ (User.findByPk as jest.Mock).mockResolvedValue(null);
316
+ <%_ } else { -%>
317
+ (User.findByPk as jest.Mock).mockResolvedValue(null);
318
+ <%_ } -%>
319
+
320
+ // Act
321
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
322
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.NOT_FOUND);
323
+ <%_ } -%>
324
+ });
325
+
326
+ it('should handle database errors during update (Error Handling)', async () => {
327
+ // Arrange
328
+ const id = '1';
329
+ const error = new Error('Database Error');
330
+ <%_ if (database === 'MongoDB') { -%>
331
+ (User.findByIdAndUpdate as jest.Mock).mockRejectedValue(error);
332
+ <%_ } else { -%>
333
+ (User.findByPk as jest.Mock).mockRejectedValue(error);
334
+ <%_ } -%>
335
+ <%_ if (communication === 'GraphQL') { -%>
336
+ await expect(userController.updateUser(id, { name: 'Fail' })).rejects.toThrow(error);
337
+ <%_ } else { -%>
338
+ mockRequest.params = { id };
339
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
340
+ expect(mockNext).toHaveBeenCalledWith(error);
341
+ <%_ } -%>
342
+ });
343
+ });
344
+
345
+ describe('deleteUser', () => {
346
+ it('should successfully delete a user (Happy Path)', async () => {
347
+ // Arrange
348
+ const id = '1';
349
+ <% if (communication === 'GraphQL') { -%>
350
+ const idArg = id;
351
+ <% } else { -%>
352
+ mockRequest.params = { id };
353
+ <% } -%>
354
+
355
+ <%_ if (database === 'MongoDB') { -%>
356
+ (User.findByIdAndDelete as jest.Mock).mockResolvedValue(true);
357
+ <%_ } else if (database === 'None') { -%>
358
+ (User.destroy as jest.Mock).mockResolvedValue(true);
359
+ <%_ } else { -%>
360
+ const userMock = { id, destroy: jest.fn().mockResolvedValue(true) };
361
+ (User.findByPk as jest.Mock).mockResolvedValue(userMock);
362
+ <%_ } -%>
363
+
364
+ // Act
365
+ <% if (communication === 'GraphQL') { -%>
366
+ const result = await userController.deleteUser(idArg);
367
+ expect(result).toBe(true);
368
+ <% } else { -%>
369
+ await userController.deleteUser(mockRequest as Request, mockResponse as Response, mockNext);
370
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.OK);
371
+ <% } -%>
372
+
373
+ <%_ if (database === 'None') { -%>
374
+ expect(User.destroy).toHaveBeenCalledWith(id);
375
+ <%_ } -%>
376
+ <%_ if (caching === 'Redis' || caching === 'Memory Cache') { -%>
377
+ expect(cacheService.del).toHaveBeenCalledWith('users:all');
378
+ <%_ } -%>
379
+ <%_ if (communication === 'Kafka') { -%>
380
+ expect(kafkaService.sendMessage).toHaveBeenCalled();
381
+ <%_ } -%>
382
+ });
383
+
384
+ <% if (communication === 'GraphQL') { -%>
385
+ it('should handle user not found during deletion (Error Handling)', async () => {
386
+ const id = '999';
387
+ <%_ if (database === 'MongoDB') { -%>
388
+ (User.findByIdAndDelete as jest.Mock).mockResolvedValue(null);
389
+ <%_ } else if (database === 'None') { -%>
390
+ (User.destroy as jest.Mock).mockResolvedValue(false);
391
+ <%_ } else { -%>
392
+ (User.findByPk as jest.Mock).mockResolvedValue(null);
393
+ <%_ } -%>
394
+ await expect(userController.deleteUser(id)).rejects.toThrow(ERROR_MESSAGES.USER_NOT_FOUND);
395
+ });
396
+
397
+ it('should handle database errors during deletion (Error Handling)', async () => {
398
+ const id = '1';
399
+ const error = new Error('Database Error');
400
+ <%_ if (database === 'MongoDB') { -%>
401
+ (User.findByIdAndDelete as jest.Mock).mockRejectedValue(error);
402
+ <%_ } else if (database === 'None') { -%>
403
+ (User.destroy as jest.Mock).mockRejectedValue(error);
404
+ <%_ } else { -%>
405
+ (User.findByPk as jest.Mock).mockRejectedValue(error);
406
+ <%_ } -%>
407
+ await expect(userController.deleteUser(id)).rejects.toThrow(error);
408
+ });
409
+ <% } else { -%>
410
+ it('should handle user not found during deletion (Error Handling)', async () => {
411
+ // Arrange
412
+ const id = '999';
413
+ mockRequest.params = { id };
414
+ <%_ if (database === 'MongoDB') { -%>
415
+ (User.findByIdAndDelete as jest.Mock).mockResolvedValue(null);
416
+ <%_ } else if (database === 'None') { -%>
417
+ (User.destroy as jest.Mock).mockResolvedValue(false);
418
+ <%_ } else { -%>
419
+ (User.findByPk as jest.Mock).mockResolvedValue(null);
420
+ <%_ } -%>
421
+ await userController.deleteUser(mockRequest as Request, mockResponse as Response, mockNext);
422
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.NOT_FOUND);
423
+ });
424
+
425
+ it('should handle database errors during deletion (Error Handling)', async () => {
426
+ // Arrange
427
+ const id = '1';
428
+ mockRequest.params = { id };
429
+ const error = new Error('Database Error');
430
+ <%_ if (database === 'MongoDB') { -%>
431
+ (User.findByIdAndDelete as jest.Mock).mockRejectedValue(error);
432
+ <%_ } else if (database === 'None') { -%>
433
+ (User.destroy as jest.Mock).mockRejectedValue(error);
434
+ <%_ } else { -%>
435
+ (User.findByPk as jest.Mock).mockRejectedValue(error);
436
+ <%_ } -%>
437
+ await userController.deleteUser(mockRequest as Request, mockResponse as Response, mockNext);
438
+ expect(mockNext).toHaveBeenCalledWith(error);
439
+ });
440
+ <% } -%>
441
+ });
442
+
443
+ describe('createUser Error Paths', () => {
444
+ it('should handle database errors during creation (Error Handling)', async () => {
445
+ const error = new Error('Database Error');
446
+ (User.create as jest.Mock).mockRejectedValue(error);
447
+ <% if (communication === 'GraphQL') { -%>
448
+ await expect(userController.createUser({ name: 'Alice', email: 'alice@example.com' })).rejects.toThrow(error);
449
+ <% } else { -%>
450
+ mockRequest.body = { name: 'Alice', email: 'alice@example.com' };
451
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
452
+ expect(mockNext).toHaveBeenCalledWith(error);
453
+ <% } -%>
454
+ });
455
+ });
456
+
457
+ describe('updateUser Error Paths', () => {
458
+ it('should handle database errors during update (Error Handling)', async () => {
459
+ const id = '1';
460
+ const error = new Error('Database Error');
461
+ <%_ if (database === 'MongoDB') { -%>
462
+ (User.findById as jest.Mock).mockResolvedValue({ id });
463
+ (User.findByIdAndUpdate as jest.Mock).mockRejectedValue(error);
464
+ <%_ } else if (database === 'None') { -%>
465
+ (User.findByPk as jest.Mock).mockResolvedValue({ id });
466
+ (User.update as jest.Mock).mockRejectedValue(error);
467
+ <%_ } else { -%>
468
+ const userMock = { id, update: jest.fn().mockRejectedValue(error) };
469
+ (User.findByPk as jest.Mock).mockResolvedValue(userMock);
470
+ <%_ } -%>
471
+ <% if (communication === 'GraphQL') { -%>
472
+ await expect(userController.updateUser(id, { name: 'Bob' })).rejects.toThrow(error);
473
+ <% } else { -%>
474
+ mockRequest.params = { id };
475
+ mockRequest.body = { name: 'Bob' };
476
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
477
+ expect(mockNext).toHaveBeenCalledWith(error);
478
+ <% } -%>
479
+ });
480
+ });
481
+ });