nodejs-quickstart-structure 1.18.0 → 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 (113) hide show
  1. package/CHANGELOG.md +17 -4
  2. package/README.md +2 -1
  3. package/bin/index.js +93 -92
  4. package/lib/generator.js +1 -1
  5. package/lib/modules/caching-setup.js +76 -73
  6. package/lib/modules/config-files.js +4 -0
  7. package/lib/modules/kafka-setup.js +249 -191
  8. package/lib/modules/project-setup.js +1 -0
  9. package/package.json +13 -2
  10. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  11. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  12. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  13. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  14. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  15. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  16. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +1 -1
  17. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  18. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  19. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  20. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  21. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  22. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  23. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  24. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  25. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  26. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  27. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  28. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  29. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  30. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  31. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  32. package/templates/clean-architecture/ts/src/index.ts.ejs +1 -1
  33. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  34. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  35. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  36. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  37. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  38. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  39. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  40. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  41. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  42. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  43. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  44. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  45. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  46. package/templates/common/.gitattributes +46 -0
  47. package/templates/common/.snyk.ejs +45 -0
  48. package/templates/common/Dockerfile +17 -9
  49. package/templates/common/README.md.ejs +295 -263
  50. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  51. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  52. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  53. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  54. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  55. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  56. package/templates/common/database/js/models/User.js.ejs +79 -53
  57. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  58. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  59. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  60. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  61. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  62. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  63. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  64. package/templates/common/jest.e2e.config.js.ejs +8 -8
  65. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  66. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  67. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  68. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  69. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  70. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  71. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  72. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  73. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  74. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  75. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  76. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  77. package/templates/common/package.json.ejs +10 -2
  78. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  79. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  80. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  81. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  82. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  83. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  84. package/templates/common/swagger.yml.ejs +118 -66
  85. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  86. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  87. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  88. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  89. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  90. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  91. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  92. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  93. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  94. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  95. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  96. package/templates/mvc/js/src/index.js.ejs +1 -1
  97. package/templates/mvc/js/src/routes/api.js +10 -8
  98. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  99. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  100. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  101. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  102. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  103. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  104. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  105. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  106. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  107. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  108. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  109. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  110. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  111. package/templates/mvc/ts/src/routes/api.ts +12 -10
  112. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  113. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -1,185 +1,331 @@
1
- <% if (communication !== 'GraphQL') { -%>
2
- import { Request, Response, NextFunction } from 'express';
3
- import { HTTP_STATUS } from '@/utils/httpCodes';
4
- <% } -%>
5
- import { UserController } from '@/interfaces/controllers/userController';
6
- import CreateUser from '@/usecases/createUser';
7
- import GetAllUsers from '@/usecases/getAllUsers';
8
-
9
- // Mock dependencies
10
- jest.mock('@/infrastructure/repositories/UserRepository');
11
- jest.mock('@/usecases/createUser');
12
- jest.mock('@/usecases/getAllUsers');
13
- jest.mock('@/infrastructure/log/logger');
14
- <%_ if (communication === 'Kafka') { -%>
15
- jest.mock('@/infrastructure/messaging/kafkaClient', () => {
16
- const mockSendMessage = jest.fn().mockResolvedValue(undefined);
17
- return {
18
- kafkaService: {
19
- sendMessage: mockSendMessage
20
- },
21
- KafkaService: jest.fn().mockImplementation(() => ({
22
- sendMessage: mockSendMessage
23
- }))
24
- };
25
- });
26
- <%_ } -%>
27
-
28
-
29
- describe('UserController (Clean Architecture)', () => {
30
- let userController: UserController;
31
- let mockCreateUserUseCase: jest.Mocked<CreateUser>;
32
- let mockGetAllUsersUseCase: jest.Mocked<GetAllUsers>;
33
- <% if (communication !== 'GraphQL') { -%>
34
- let mockRequest: Partial<Request>;
35
- let mockResponse: Partial<Response>;
36
- let mockNext: NextFunction;
37
- <% } -%>
38
-
39
- beforeEach(() => {
40
- // Clear all mocks
41
- jest.clearAllMocks();
42
-
43
- userController = new UserController();
44
-
45
- // Retrieve the mocked instances created inside UserController constructor
46
- mockCreateUserUseCase = (CreateUser as jest.Mock).mock.instances[0] as jest.Mocked<CreateUser>;
47
- mockGetAllUsersUseCase = (GetAllUsers as jest.Mock).mock.instances[0] as jest.Mocked<GetAllUsers>;
48
-
49
- <% if (communication !== 'GraphQL') { -%>
50
- mockRequest = {};
51
- mockResponse = {
52
- json: jest.fn(),
53
- status: jest.fn().mockReturnThis(),
54
- };
55
- mockNext = jest.fn();
56
- <% } -%>
57
- });
58
-
59
- describe('getUsers', () => {
60
- it('should return successfully (Happy Path)', async () => {
61
- // Arrange
62
- const usersMock = [{ id: '1', name: 'Test', email: 'test@example.com' }];
63
- mockGetAllUsersUseCase.execute.mockResolvedValue(usersMock);
64
-
65
- // Act
66
- <% if (communication === 'GraphQL') { -%>
67
- const result = await userController.getUsers();
68
-
69
- // Assert
70
- expect(result).toEqual(usersMock);
71
- <% } else { -%>
72
- await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
73
-
74
- // Assert
75
- expect(mockResponse.json).toHaveBeenCalledWith(usersMock);
76
- <% } -%>
77
- expect(mockGetAllUsersUseCase.execute).toHaveBeenCalled();
78
- });
79
-
80
- it('should handle errors correctly (Error Handling)', async () => {
81
- // Arrange
82
- const error = new Error('UseCase Error');
83
- mockGetAllUsersUseCase.execute.mockRejectedValue(error);
84
-
85
- // Act & Assert
86
- <% if (communication === 'GraphQL') { -%>
87
- await expect(userController.getUsers()).rejects.toThrow(error);
88
- <% } else { -%>
89
- await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
90
- expect(mockNext).toHaveBeenCalledWith(error);
91
- <% } -%>
92
- });
93
-
94
- it('should handle non-Error objects in catch block', async () => {
95
- // Arrange
96
- const error = 'String Error';
97
- mockGetAllUsersUseCase.execute.mockRejectedValue(error);
98
-
99
- // Act & Assert
100
- <% if (communication === 'GraphQL') { -%>
101
- await expect(userController.getUsers()).rejects.toEqual(error);
102
- <% } else { -%>
103
- await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
104
- expect(mockNext).toHaveBeenCalledWith(error);
105
- <% } -%>
106
- });
107
- });
108
-
109
- describe('createUser', () => {
110
- it('should successfully create a new user (Happy Path)', async () => {
111
- // Arrange
112
- const payload = { name: 'Alice', email: 'alice@example.com' };
113
- <% if (communication === 'GraphQL') { -%>
114
- const dataArg = payload;
115
- <% } else { -%>
116
- mockRequest.body = payload;
117
- <% } -%>
118
- const expectedUser = { id: '1', ...payload };
119
-
120
- mockCreateUserUseCase.execute.mockResolvedValue(expectedUser);
121
-
122
- // Act
123
- <% if (communication === 'GraphQL') { -%>
124
- const result = await userController.createUser(dataArg);
125
-
126
- // Assert
127
- expect(result).toEqual(expectedUser);
128
- <% } else { -%>
129
- await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
130
-
131
- // Assert
132
- <%_ if (communication === 'Kafka') { -%>
133
- const { kafkaService } = require('@/infrastructure/messaging/kafkaClient');
134
- expect(kafkaService.sendMessage).toHaveBeenCalled();
135
- <%_ } -%>
136
- expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.CREATED);
137
-
138
- expect(mockResponse.json).toHaveBeenCalledWith(expectedUser);
139
- <% } -%>
140
- expect(mockCreateUserUseCase.execute).toHaveBeenCalledWith(payload.name, payload.email);
141
- });
142
-
143
- it('should handle errors when creation fails (Error Handling)', async () => {
144
- // Arrange
145
- const error = new Error('Creation Error');
146
- const payload = { name: 'Bob', email: 'bob@example.com' };
147
- <% if (communication === 'GraphQL') { -%>
148
- const dataArg = payload;
149
- <% } else { -%>
150
- mockRequest.body = payload;
151
- <% } -%>
152
-
153
- mockCreateUserUseCase.execute.mockRejectedValue(error);
154
-
155
- // Act & Assert
156
- <% if (communication === 'GraphQL') { -%>
157
- await expect(userController.createUser(dataArg)).rejects.toThrow(error);
158
- <% } else { -%>
159
- await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
160
- expect(mockNext).toHaveBeenCalledWith(error);
161
- <% } -%>
162
- });
163
-
164
- it('should handle non-Error objects in catch block when creation fails', async () => {
165
- // Arrange
166
- const error = 'Creation String Error';
167
- const payload = { name: 'Bob', email: 'bob@example.com' };
168
- <% if (communication === 'GraphQL') { -%>
169
- const dataArg = payload;
170
- <% } else { -%>
171
- mockRequest.body = payload;
172
- <% } -%>
173
-
174
- mockCreateUserUseCase.execute.mockRejectedValue(error);
175
-
176
- // Act & Assert
177
- <% if (communication === 'GraphQL') { -%>
178
- await expect(userController.createUser(dataArg)).rejects.toEqual(error);
179
- <% } else { -%>
180
- await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
181
- expect(mockNext).toHaveBeenCalledWith(error);
182
- <% } -%>
183
- });
184
- });
185
- });
1
+ <% if (communication !== 'GraphQL') { -%>
2
+ import { Request, Response, NextFunction } from 'express';
3
+ import { HTTP_STATUS } from '@/utils/httpCodes';
4
+ <% } -%>
5
+ import { ERROR_MESSAGES } from '@/utils/errorMessages';
6
+ import { UserController } from '@/interfaces/controllers/userController';
7
+ import CreateUser from '@/usecases/createUser';
8
+ import GetAllUsers from '@/usecases/getAllUsers';
9
+ import UpdateUser from '@/usecases/updateUser';
10
+ import DeleteUser from '@/usecases/deleteUser';
11
+
12
+ // Mock dependencies
13
+ jest.mock('@/infrastructure/repositories/UserRepository');
14
+ jest.mock('@/usecases/createUser');
15
+ jest.mock('@/usecases/getAllUsers');
16
+ jest.mock('@/usecases/updateUser');
17
+ jest.mock('@/usecases/deleteUser');
18
+ jest.mock('@/infrastructure/log/logger');
19
+ <%_ if (communication === 'Kafka') { -%>
20
+ jest.mock('@/infrastructure/messaging/kafkaClient', () => ({
21
+ kafkaService: {
22
+ sendMessage: jest.fn().mockResolvedValue(undefined)
23
+ },
24
+ KafkaService: jest.fn().mockImplementation(() => ({
25
+ sendMessage: jest.fn().mockResolvedValue(undefined)
26
+ }))
27
+ }));
28
+ const { kafkaService } = require('@/infrastructure/messaging/kafkaClient');
29
+ <%_ } -%>
30
+
31
+
32
+ describe('UserController (Clean Architecture)', () => {
33
+ let userController: UserController;
34
+ let mockCreateUserUseCase: jest.Mocked<CreateUser>;
35
+ let mockGetAllUsersUseCase: jest.Mocked<GetAllUsers>;
36
+ let mockUpdateUserUseCase: jest.Mocked<UpdateUser>;
37
+ let mockDeleteUserUseCase: jest.Mocked<DeleteUser>;
38
+ <% if (communication !== 'GraphQL') { -%>
39
+ let mockRequest: Partial<Request>;
40
+ let mockResponse: Partial<Response>;
41
+ let mockNext: NextFunction;
42
+ <% } -%>
43
+
44
+ beforeEach(() => {
45
+ // Clear all mocks
46
+ jest.resetAllMocks();
47
+
48
+ userController = new UserController();
49
+
50
+ // Retrieve the mocked instances created inside UserController constructor
51
+ mockCreateUserUseCase = (CreateUser as jest.Mock).mock.instances[0] as jest.Mocked<CreateUser>;
52
+ mockGetAllUsersUseCase = (GetAllUsers as jest.Mock).mock.instances[0] as jest.Mocked<GetAllUsers>;
53
+ mockUpdateUserUseCase = (UpdateUser as jest.Mock).mock.instances[0] as jest.Mocked<UpdateUser>;
54
+ mockDeleteUserUseCase = (DeleteUser as jest.Mock).mock.instances[0] as jest.Mocked<DeleteUser>;
55
+
56
+ <% if (communication !== 'GraphQL') { -%>
57
+ mockRequest = {
58
+ body: {}
59
+ };
60
+ mockResponse = {
61
+ json: jest.fn(),
62
+ status: jest.fn().mockReturnThis(),
63
+ };
64
+ mockNext = jest.fn();
65
+ <% } -%>
66
+ });
67
+
68
+ describe('getUsers', () => {
69
+ it('should return successfully (Happy Path)', async () => {
70
+ // Arrange
71
+ const usersMock = [{ id: '1', name: 'Test', email: 'test@example.com' }];
72
+ mockGetAllUsersUseCase.execute.mockResolvedValue(usersMock);
73
+
74
+ // Act
75
+ <% if (communication === 'GraphQL') { -%>
76
+ const result = await userController.getUsers();
77
+
78
+ // Assert
79
+ expect(result).toEqual(usersMock);
80
+ <% } else { -%>
81
+ await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
82
+
83
+ // Assert
84
+ expect(mockResponse.json).toHaveBeenCalledWith(usersMock);
85
+ <% } -%>
86
+ expect(mockGetAllUsersUseCase.execute).toHaveBeenCalled();
87
+ });
88
+
89
+ it('should handle errors correctly (Error Handling)', async () => {
90
+ // Arrange
91
+ const error = new Error('UseCase Error');
92
+ mockGetAllUsersUseCase.execute.mockRejectedValue(error);
93
+
94
+ // Act & Assert
95
+ <% if (communication === 'GraphQL') { -%>
96
+ await expect(userController.getUsers()).rejects.toThrow(error);
97
+ <% } else { -%>
98
+ await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
99
+ expect(mockNext).toHaveBeenCalledWith(error);
100
+ <% } -%>
101
+ });
102
+
103
+ it('should handle non-Error objects in catch block', async () => {
104
+ // Arrange
105
+ const error = 'String Error';
106
+ mockGetAllUsersUseCase.execute.mockRejectedValue(error);
107
+
108
+ // Act & Assert
109
+ <% if (communication === 'GraphQL') { -%>
110
+ await expect(userController.getUsers()).rejects.toEqual(error);
111
+ <% } else { -%>
112
+ await userController.getUsers(mockRequest as Request, mockResponse as Response, mockNext);
113
+ expect(mockNext).toHaveBeenCalledWith(error);
114
+ <% } -%>
115
+ });
116
+ });
117
+
118
+ describe('createUser', () => {
119
+ it('should successfully create a new user (Happy Path)', async () => {
120
+ // Arrange
121
+ const payload = { name: 'Alice', email: 'alice@example.com' };
122
+ <% if (communication === 'GraphQL') { -%>
123
+ const dataArg = payload;
124
+ <% } else { -%>
125
+ mockRequest.body = payload;
126
+ <% } -%>
127
+ const expectedUser = { id: '1', ...payload };
128
+
129
+ mockCreateUserUseCase.execute.mockResolvedValue(expectedUser);
130
+
131
+ // Act
132
+ <% if (communication === 'GraphQL') { -%>
133
+ const result = await userController.createUser(dataArg);
134
+
135
+ // Assert
136
+ expect(result).toEqual(expectedUser);
137
+ <% } else { -%>
138
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
139
+
140
+ // Assert
141
+ <%_ if (communication === 'Kafka') { -%>
142
+ const { kafkaService } = require('@/infrastructure/messaging/kafkaClient');
143
+ expect(kafkaService.sendMessage).toHaveBeenCalled();
144
+ <%_ } -%>
145
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.CREATED);
146
+
147
+ expect(mockResponse.json).toHaveBeenCalledWith(expectedUser);
148
+ <% } -%>
149
+ expect(mockCreateUserUseCase.execute).toHaveBeenCalledWith(payload.name, payload.email);
150
+ });
151
+
152
+ it('should handle errors when creation fails (Error Handling)', async () => {
153
+ // Arrange
154
+ const error = new Error('Creation Error');
155
+ const payload = { name: 'Bob', email: 'bob@example.com' };
156
+ <% if (communication === 'GraphQL') { -%>
157
+ const dataArg = payload;
158
+ <% } else { -%>
159
+ mockRequest.body = payload;
160
+ <% } -%>
161
+
162
+ mockCreateUserUseCase.execute.mockRejectedValue(error);
163
+
164
+ // Act & Assert
165
+ <% if (communication === 'GraphQL') { -%>
166
+ await expect(userController.createUser(dataArg)).rejects.toThrow(error);
167
+ <% } else { -%>
168
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
169
+ expect(mockNext).toHaveBeenCalledWith(error);
170
+ <% } -%>
171
+ });
172
+
173
+ it('should handle non-Error objects in catch block when creation fails', async () => {
174
+ // Arrange
175
+ const error = 'Creation String Error';
176
+ const payload = { name: 'Bob', email: 'bob@example.com' };
177
+ <% if (communication === 'GraphQL') { -%>
178
+ const dataArg = payload;
179
+ <% } else { -%>
180
+ mockRequest.body = payload;
181
+ <% } -%>
182
+
183
+ mockCreateUserUseCase.execute.mockRejectedValue(error);
184
+
185
+ // Act & Assert
186
+ <% if (communication === 'GraphQL') { -%>
187
+ await expect(userController.createUser(dataArg)).rejects.toEqual(error);
188
+ <% } else { -%>
189
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
190
+ expect(mockNext).toHaveBeenCalledWith(error);
191
+ <% } -%>
192
+ });
193
+ });
194
+
195
+ describe('updateUser', () => {
196
+ it('should successfully update a user (Happy Path)', async () => {
197
+ // Arrange
198
+ const id = '1';
199
+ const payload = { name: 'Alice Updated' };
200
+ <% if (communication === 'GraphQL') { -%>
201
+ const idArg = id;
202
+ const dataArg = payload;
203
+ <% } else { -%>
204
+ mockRequest.params = { id };
205
+ mockRequest.body = payload;
206
+ <% } -%>
207
+ const expectedUser = { id, name: 'Alice Updated', email: 'alice@example.com' };
208
+
209
+ mockUpdateUserUseCase.execute.mockResolvedValue(expectedUser as any);
210
+
211
+ // Act
212
+ <% if (communication === 'GraphQL') { -%>
213
+ const result = await userController.updateUser(idArg, dataArg);
214
+ expect(result).toEqual(expectedUser);
215
+ <% } else { -%>
216
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
217
+ expect(mockResponse.json).toHaveBeenCalledWith(expectedUser);
218
+ <% } -%>
219
+
220
+ <%_ if (communication === 'Kafka') { -%>
221
+ const { kafkaService } = require('@/infrastructure/messaging/kafkaClient');
222
+ expect(kafkaService.sendMessage).toHaveBeenCalled();
223
+ <%_ } -%>
224
+ expect(mockUpdateUserUseCase.execute).toHaveBeenCalledWith(id, payload);
225
+ });
226
+
227
+ it('should handle 404/errors when user not found or update fails', async () => {
228
+ // Arrange
229
+ const id = '999';
230
+ <%_ if (communication === 'GraphQL') { -%>
231
+ const idArg = id;
232
+ const dataArg = { name: 'Fail' };
233
+ mockUpdateUserUseCase.execute.mockResolvedValue(null);
234
+ await expect(userController.updateUser(idArg, dataArg)).rejects.toThrow(ERROR_MESSAGES.USER_NOT_FOUND);
235
+ <%_ } else { -%>
236
+ mockRequest.params = { id };
237
+ mockRequest.body = { name: 'Fail' };
238
+ mockUpdateUserUseCase.execute.mockResolvedValue(null);
239
+
240
+ // Act
241
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
242
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.NOT_FOUND);
243
+ <%_ } -%>
244
+ });
245
+
246
+ it('should handle database errors during update (Error Handling)', async () => {
247
+ // Arrange
248
+ const id = '1';
249
+ const error = new Error('Database Error');
250
+ mockUpdateUserUseCase.execute.mockRejectedValue(error);
251
+ <%_ if (communication === 'GraphQL') { -%>
252
+ await expect(userController.updateUser(id, { name: 'Fail' })).rejects.toThrow(error);
253
+ <%_ } else { -%>
254
+ mockRequest.params = { id };
255
+ await userController.updateUser(mockRequest as Request, mockResponse as Response, mockNext);
256
+ expect(mockNext).toHaveBeenCalledWith(error);
257
+ <%_ } -%>
258
+ });
259
+ });
260
+
261
+ describe('deleteUser', () => {
262
+ it('should successfully delete a user (Happy Path)', async () => {
263
+ // Arrange
264
+ const id = '1';
265
+ <% if (communication === 'GraphQL') { -%>
266
+ const idArg = id;
267
+ <% } else { -%>
268
+ mockRequest.params = { id };
269
+ <% } -%>
270
+ mockDeleteUserUseCase.execute.mockResolvedValue(true);
271
+
272
+ // Act
273
+ <% if (communication === 'GraphQL') { -%>
274
+ const result = await userController.deleteUser(idArg);
275
+ expect(result).toBe(true);
276
+ <% } else { -%>
277
+ await userController.deleteUser(mockRequest as Request, mockResponse as Response, mockNext);
278
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.OK);
279
+ <% } -%>
280
+
281
+ <%_ if (communication === 'Kafka') { -%>
282
+ const { kafkaService } = require('@/infrastructure/messaging/kafkaClient');
283
+ expect(kafkaService.sendMessage).toHaveBeenCalled();
284
+ <%_ } -%>
285
+ expect(mockDeleteUserUseCase.execute).toHaveBeenCalledWith(id);
286
+ });
287
+
288
+ it('should throw error if user not found during deletion (Error Handling)', async () => {
289
+ // Arrange
290
+ const id = '999';
291
+ <%_ if (communication === 'GraphQL') { -%>
292
+ mockDeleteUserUseCase.execute.mockResolvedValue(false);
293
+ await expect(userController.deleteUser(id)).rejects.toThrow(ERROR_MESSAGES.USER_NOT_FOUND);
294
+ <%_ } else { -%>
295
+ mockRequest.params = { id };
296
+ mockDeleteUserUseCase.execute.mockResolvedValue(false);
297
+ await userController.deleteUser(mockRequest as Request, mockResponse as Response, mockNext);
298
+ expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.NOT_FOUND);
299
+ <%_ } -%>
300
+ });
301
+
302
+ it('should handle database errors during deletion (Error Handling)', async () => {
303
+ // Arrange
304
+ const id = '1';
305
+ const error = new Error('Database Error');
306
+ mockDeleteUserUseCase.execute.mockRejectedValue(error);
307
+ <%_ if (communication === 'GraphQL') { -%>
308
+ await expect(userController.deleteUser(id)).rejects.toThrow(error);
309
+ <%_ } else { -%>
310
+ mockRequest.params = { id };
311
+ await userController.deleteUser(mockRequest as Request, mockResponse as Response, mockNext);
312
+ expect(mockNext).toHaveBeenCalledWith(error);
313
+ <%_ } -%>
314
+ });
315
+ });
316
+
317
+
318
+ describe('createUser Error Paths', () => {
319
+ it('should handle database errors during creation (Error Handling)', async () => {
320
+ const error = new Error('Database Error');
321
+ mockCreateUserUseCase.execute.mockRejectedValue(error);
322
+ <%_ if (communication === 'GraphQL') { -%>
323
+ await expect(userController.createUser({ name: 'Alice', email: 'alice@example.com' })).rejects.toThrow(error);
324
+ <%_ } else { -%>
325
+ mockRequest.body = { name: 'Alice', email: 'alice@example.com' };
326
+ await userController.createUser(mockRequest as Request, mockResponse as Response, mockNext);
327
+ expect(mockNext).toHaveBeenCalledWith(error);
328
+ <%_ } -%>
329
+ });
330
+ });
331
+ });