nodejs-quickstart-structure 1.18.1 → 1.19.1

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 (235) hide show
  1. package/CHANGELOG.md +309 -294
  2. package/LICENSE +15 -15
  3. package/README.md +2 -1
  4. package/lib/generator.js +139 -139
  5. package/lib/modules/app-setup.js +401 -401
  6. package/lib/modules/caching-setup.js +76 -73
  7. package/lib/modules/config-files.js +151 -151
  8. package/lib/modules/database-setup.js +116 -116
  9. package/lib/modules/kafka-setup.js +249 -191
  10. package/lib/modules/project-setup.js +32 -31
  11. package/lib/prompts.js +100 -100
  12. package/package.json +78 -67
  13. package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
  14. package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
  15. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  16. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  17. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  18. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  19. package/templates/clean-architecture/js/src/index.js.ejs +55 -55
  20. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
  21. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
  22. package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
  23. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  24. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  25. package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
  26. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
  27. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
  28. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  29. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  30. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
  31. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
  32. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
  33. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
  34. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  35. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  36. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
  37. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  38. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  39. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
  40. package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
  41. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
  42. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  43. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  44. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
  45. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
  46. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  47. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  48. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  49. package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
  50. package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
  51. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
  52. package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
  53. package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
  54. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  55. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  56. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  57. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  58. package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
  59. package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
  60. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
  61. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  62. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  63. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  64. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  65. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
  66. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
  67. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
  68. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
  69. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  70. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  71. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
  72. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  73. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
  74. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  75. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
  76. package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
  77. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  78. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  79. package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
  80. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
  81. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  82. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  83. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  84. package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  85. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
  86. package/templates/common/.cursorrules.ejs +60 -60
  87. package/templates/common/.dockerignore +12 -12
  88. package/templates/common/.env.example.ejs +41 -41
  89. package/templates/common/.gitattributes +46 -0
  90. package/templates/common/.gitlab-ci.yml.ejs +86 -86
  91. package/templates/common/.lintstagedrc +6 -6
  92. package/templates/common/.prettierrc +7 -7
  93. package/templates/common/Dockerfile +73 -73
  94. package/templates/common/Jenkinsfile.ejs +87 -87
  95. package/templates/common/README.md.ejs +294 -270
  96. package/templates/common/SECURITY.md +20 -20
  97. package/templates/common/_github/workflows/ci.yml.ejs +46 -46
  98. package/templates/common/_github/workflows/security.yml.ejs +36 -36
  99. package/templates/common/_gitignore +5 -5
  100. package/templates/common/_husky/pre-commit +4 -4
  101. package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
  102. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  103. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
  104. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  105. package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
  106. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  107. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
  108. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  109. package/templates/common/caching/js/memoryCache.js.ejs +60 -60
  110. package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
  111. package/templates/common/caching/js/redisClient.js.ejs +75 -75
  112. package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
  113. package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
  114. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  115. package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
  116. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  117. package/templates/common/database/js/database.js.ejs +19 -19
  118. package/templates/common/database/js/database.spec.js.ejs +56 -56
  119. package/templates/common/database/js/models/User.js.ejs +79 -53
  120. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  121. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  122. package/templates/common/database/js/mongoose.js.ejs +33 -33
  123. package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
  124. package/templates/common/database/ts/database.spec.ts.ejs +56 -56
  125. package/templates/common/database/ts/database.ts.ejs +21 -21
  126. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  127. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  128. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  129. package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
  130. package/templates/common/database/ts/mongoose.ts.ejs +28 -28
  131. package/templates/common/docker-compose.yml.ejs +159 -159
  132. package/templates/common/ecosystem.config.js.ejs +40 -40
  133. package/templates/common/eslint.config.mjs.ejs +77 -77
  134. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  135. package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
  136. package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
  137. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  138. package/templates/common/jest.config.js.ejs +32 -32
  139. package/templates/common/jest.e2e.config.js.ejs +8 -8
  140. package/templates/common/kafka/js/config/kafka.js +9 -9
  141. package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
  142. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  143. package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
  144. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  145. package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
  146. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  147. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  148. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  149. package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
  150. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  151. package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
  152. package/templates/common/kafka/ts/config/kafka.ts +7 -7
  153. package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
  154. package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
  155. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  156. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  157. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  158. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  159. package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
  160. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  161. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  162. package/templates/common/migrate-mongo-config.js.ejs +31 -31
  163. package/templates/common/migrations/init.js.ejs +23 -23
  164. package/templates/common/package.json.ejs +119 -118
  165. package/templates/common/prompts/add-feature.md.ejs +26 -26
  166. package/templates/common/prompts/project-context.md.ejs +43 -43
  167. package/templates/common/prompts/troubleshoot.md.ejs +28 -28
  168. package/templates/common/public/css/style.css +147 -147
  169. package/templates/common/scripts/run-e2e.js.ejs +63 -63
  170. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  171. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  172. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  173. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  174. package/templates/common/sonar-project.properties.ejs +27 -27
  175. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  176. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  177. package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
  178. package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
  179. package/templates/common/swagger.yml.ejs +118 -66
  180. package/templates/common/tsconfig.json +22 -22
  181. package/templates/common/views/ejs/index.ejs +55 -55
  182. package/templates/common/views/pug/index.pug +40 -40
  183. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  184. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  185. package/templates/mvc/js/src/config/env.js.ejs +46 -46
  186. package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
  187. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  188. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  189. package/templates/mvc/js/src/errors/ApiError.js +14 -14
  190. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  191. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  192. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  193. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  194. package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
  195. package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
  196. package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
  197. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
  198. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  199. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  200. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
  201. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  202. package/templates/mvc/js/src/index.js.ejs +136 -136
  203. package/templates/mvc/js/src/routes/api.js +10 -8
  204. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  205. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  206. package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
  207. package/templates/mvc/js/src/utils/httpCodes.js +9 -9
  208. package/templates/mvc/js/src/utils/logger.js +40 -40
  209. package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
  210. package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
  211. package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
  212. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  213. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  214. package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
  215. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  216. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  217. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  218. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  219. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
  220. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
  221. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
  222. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
  223. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  224. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  225. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
  226. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  227. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  228. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  229. package/templates/mvc/ts/src/routes/api.ts +12 -10
  230. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  231. package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  232. package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
  233. package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
  234. package/templates/mvc/ts/src/utils/logger.ts +36 -36
  235. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -1,157 +1,157 @@
1
- jest.mock('ioredis', () => {
2
- const mRedis = jest.fn(() => ({
3
- on: jest.fn(),
4
- get: jest.fn(),
5
- set: jest.fn(),
6
- del: jest.fn(),
7
- quit: jest.fn().mockResolvedValue('OK'),
8
- }));
9
- return mRedis;
10
- });
11
-
12
- jest.mock('dotenv', () => ({
13
- config: jest.fn()
14
- }));
15
-
16
- const mockLogger = {
17
- info: jest.fn(),
18
- error: jest.fn(),
19
- };
20
-
21
- jest.mock('<%- loggerPath %>', () => mockLogger);
22
-
23
- describe('Redis Client', () => {
24
- let RedisService: any;
25
- let logger: any;
26
-
27
- beforeEach(() => {
28
- jest.clearAllMocks();
29
- jest.resetModules();
30
-
31
- // Clean environment
32
- const envVars = ['REDIS_HOST', 'REDIS_PORT', 'REDIS_PASSWORD'];
33
- envVars.forEach(v => delete process.env[v]);
34
-
35
- logger = require('<%- loggerPath %>');
36
- RedisService = require('<% if (architecture === "MVC") { %>@/config/redisClient<% } else { %>@/infrastructure/caching/redisClient<% } %>').default;
37
- });
38
-
39
- it('should initialize with default values when env vars are missing', () => {
40
- delete process.env.REDIS_HOST;
41
- delete process.env.REDIS_PORT;
42
- delete process.env.REDIS_PASSWORD;
43
-
44
- jest.resetModules();
45
- const NewRedisService = require('<% if (architecture === "MVC") { %>@/config/redisClient<% } else { %>@/infrastructure/caching/redisClient<% } %>').default;
46
- expect(NewRedisService).toBeDefined();
47
- });
48
-
49
- it('should handle redis events', () => {
50
- // Find the event handlers
51
- const handlers: { [key: string]: (...args: any[]) => any } = {};
52
- (RedisService.client.on as jest.Mock).mock.calls.forEach(([event, handler]) => {
53
- handlers[event] = handler;
54
- });
55
-
56
- if (handlers['connect']) {
57
- handlers['connect']();
58
- expect(logger.info).toHaveBeenCalledWith('Redis connected');
59
- }
60
-
61
- if (handlers['error']) {
62
- handlers['error'](new Error('Test Error'));
63
- expect(logger.error).toHaveBeenCalledWith('Redis error:', expect.any(Error));
64
- }
65
- });
66
-
67
- it('should get data from redis', async () => {
68
- const mockData = { test: 'data' };
69
- RedisService.client.get.mockResolvedValue(JSON.stringify(mockData));
70
-
71
- const data = await RedisService.get('test-key');
72
- expect(data).toEqual(mockData);
73
- expect(RedisService.client.get).toHaveBeenCalledWith('test-key');
74
- });
75
-
76
- it('should return null when key not found in redis', async () => {
77
- RedisService.client.get.mockResolvedValue(null);
78
- const data = await RedisService.get('non-existent');
79
- expect(data).toBeNull();
80
- });
81
-
82
- it('should handle errors in get', async () => {
83
- RedisService.client.get.mockRejectedValue(new Error('Redis Error'));
84
- const result = await RedisService.get('test-key');
85
- expect(result).toBeNull();
86
- expect(logger.error).toHaveBeenCalled();
87
- });
88
-
89
- it('should set data to redis without TTL', async () => {
90
- const mockData = { test: 'data' };
91
- await RedisService.set('test-key', mockData);
92
- expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData));
93
- });
94
-
95
- it('should set data to redis with TTL', async () => {
96
- const mockData = { test: 'data' };
97
- await RedisService.set('test-key', mockData, 3600);
98
- expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData), 'EX', 3600);
99
- });
100
-
101
- it('should handle errors in set', async () => {
102
- RedisService.client.set.mockRejectedValue(new Error('Redis Error'));
103
- await RedisService.set('test-key', 'value');
104
- expect(logger.error).toHaveBeenCalled();
105
- });
106
-
107
- it('should delete data from redis', async () => {
108
- await RedisService.del('test-key');
109
- expect(RedisService.client.del).toHaveBeenCalledWith('test-key');
110
- });
111
-
112
- it('should handle errors in del', async () => {
113
- RedisService.client.del.mockRejectedValue(new Error('Redis Error'));
114
- await RedisService.del('test-key');
115
- expect(logger.error).toHaveBeenCalled();
116
- });
117
-
118
- it('should use getOrSet and call fetcher if not cached', async () => {
119
- RedisService.get = jest.fn().mockResolvedValue(null);
120
- RedisService.set = jest.fn();
121
- const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
122
-
123
- const result = await RedisService.getOrSet('new-key', fetcher);
124
-
125
- expect(result).toEqual({ new: 'data' });
126
- expect(fetcher).toHaveBeenCalled();
127
- expect(RedisService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
128
- });
129
-
130
- it('should use getOrSet and return cached data', async () => {
131
- const cachedData = { cached: 'data' };
132
- RedisService.get = jest.fn().mockResolvedValue(cachedData);
133
- const fetcher = jest.fn();
134
-
135
- const result = await RedisService.getOrSet('cached-key', fetcher);
136
-
137
- expect(result).toEqual(cachedData);
138
- expect(fetcher).not.toHaveBeenCalled();
139
- });
140
-
141
- it('should handle falsy data from fetcher in getOrSet', async () => {
142
- RedisService.get = jest.fn().mockResolvedValue(null);
143
- RedisService.set = jest.fn();
144
- const fetcher = jest.fn().mockResolvedValue(null);
145
-
146
- const result = await RedisService.getOrSet('empty-key', fetcher);
147
-
148
- expect(result).toBeNull();
149
- expect(RedisService.set).not.toHaveBeenCalled();
150
- });
151
-
152
- it('should quit the redis client', async () => {
153
- const result = await RedisService.quit();
154
- expect(result).toBe('OK');
155
- expect(RedisService.client.quit).toHaveBeenCalled();
156
- });
157
- });
1
+ jest.mock('ioredis', () => {
2
+ const mRedis = jest.fn(() => ({
3
+ on: jest.fn(),
4
+ get: jest.fn(),
5
+ set: jest.fn(),
6
+ del: jest.fn(),
7
+ quit: jest.fn().mockResolvedValue('OK'),
8
+ }));
9
+ return mRedis;
10
+ });
11
+
12
+ jest.mock('dotenv', () => ({
13
+ config: jest.fn()
14
+ }));
15
+
16
+ const mockLogger = {
17
+ info: jest.fn(),
18
+ error: jest.fn(),
19
+ };
20
+
21
+ jest.mock('<%- loggerPath %>', () => mockLogger);
22
+
23
+ describe('Redis Client', () => {
24
+ let RedisService: any;
25
+ let logger: any;
26
+
27
+ beforeEach(() => {
28
+ jest.clearAllMocks();
29
+ jest.resetModules();
30
+
31
+ // Clean environment
32
+ const envVars = ['REDIS_HOST', 'REDIS_PORT', 'REDIS_PASSWORD'];
33
+ envVars.forEach(v => delete process.env[v]);
34
+
35
+ logger = require('<%- loggerPath %>');
36
+ RedisService = require('<% if (architecture === "MVC") { %>@/config/redisClient<% } else { %>@/infrastructure/caching/redisClient<% } %>').default;
37
+ });
38
+
39
+ it('should initialize with default values when env vars are missing', () => {
40
+ delete process.env.REDIS_HOST;
41
+ delete process.env.REDIS_PORT;
42
+ delete process.env.REDIS_PASSWORD;
43
+
44
+ jest.resetModules();
45
+ const NewRedisService = require('<% if (architecture === "MVC") { %>@/config/redisClient<% } else { %>@/infrastructure/caching/redisClient<% } %>').default;
46
+ expect(NewRedisService).toBeDefined();
47
+ });
48
+
49
+ it('should handle redis events', () => {
50
+ // Find the event handlers
51
+ const handlers: { [key: string]: (...args: any[]) => any } = {};
52
+ (RedisService.client.on as jest.Mock).mock.calls.forEach(([event, handler]) => {
53
+ handlers[event] = handler;
54
+ });
55
+
56
+ if (handlers['connect']) {
57
+ handlers['connect']();
58
+ expect(logger.info).toHaveBeenCalledWith('Redis connected');
59
+ }
60
+
61
+ if (handlers['error']) {
62
+ handlers['error'](new Error('Test Error'));
63
+ expect(logger.error).toHaveBeenCalledWith('Redis error:', expect.any(Error));
64
+ }
65
+ });
66
+
67
+ it('should get data from redis', async () => {
68
+ const mockData = { test: 'data' };
69
+ RedisService.client.get.mockResolvedValue(JSON.stringify(mockData));
70
+
71
+ const data = await RedisService.get('test-key');
72
+ expect(data).toEqual(mockData);
73
+ expect(RedisService.client.get).toHaveBeenCalledWith('test-key');
74
+ });
75
+
76
+ it('should return null when key not found in redis', async () => {
77
+ RedisService.client.get.mockResolvedValue(null);
78
+ const data = await RedisService.get('non-existent');
79
+ expect(data).toBeNull();
80
+ });
81
+
82
+ it('should handle errors in get', async () => {
83
+ RedisService.client.get.mockRejectedValue(new Error('Redis Error'));
84
+ const result = await RedisService.get('test-key');
85
+ expect(result).toBeNull();
86
+ expect(logger.error).toHaveBeenCalled();
87
+ });
88
+
89
+ it('should set data to redis without TTL', async () => {
90
+ const mockData = { test: 'data' };
91
+ await RedisService.set('test-key', mockData);
92
+ expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData));
93
+ });
94
+
95
+ it('should set data to redis with TTL', async () => {
96
+ const mockData = { test: 'data' };
97
+ await RedisService.set('test-key', mockData, 3600);
98
+ expect(RedisService.client.set).toHaveBeenCalledWith('test-key', JSON.stringify(mockData), 'EX', 3600);
99
+ });
100
+
101
+ it('should handle errors in set', async () => {
102
+ RedisService.client.set.mockRejectedValue(new Error('Redis Error'));
103
+ await RedisService.set('test-key', 'value');
104
+ expect(logger.error).toHaveBeenCalled();
105
+ });
106
+
107
+ it('should delete data from redis', async () => {
108
+ await RedisService.del('test-key');
109
+ expect(RedisService.client.del).toHaveBeenCalledWith('test-key');
110
+ });
111
+
112
+ it('should handle errors in del', async () => {
113
+ RedisService.client.del.mockRejectedValue(new Error('Redis Error'));
114
+ await RedisService.del('test-key');
115
+ expect(logger.error).toHaveBeenCalled();
116
+ });
117
+
118
+ it('should use getOrSet and call fetcher if not cached', async () => {
119
+ RedisService.get = jest.fn().mockResolvedValue(null);
120
+ RedisService.set = jest.fn();
121
+ const fetcher = jest.fn().mockResolvedValue({ new: 'data' });
122
+
123
+ const result = await RedisService.getOrSet('new-key', fetcher);
124
+
125
+ expect(result).toEqual({ new: 'data' });
126
+ expect(fetcher).toHaveBeenCalled();
127
+ expect(RedisService.set).toHaveBeenCalledWith('new-key', { new: 'data' }, 3600);
128
+ });
129
+
130
+ it('should use getOrSet and return cached data', async () => {
131
+ const cachedData = { cached: 'data' };
132
+ RedisService.get = jest.fn().mockResolvedValue(cachedData);
133
+ const fetcher = jest.fn();
134
+
135
+ const result = await RedisService.getOrSet('cached-key', fetcher);
136
+
137
+ expect(result).toEqual(cachedData);
138
+ expect(fetcher).not.toHaveBeenCalled();
139
+ });
140
+
141
+ it('should handle falsy data from fetcher in getOrSet', async () => {
142
+ RedisService.get = jest.fn().mockResolvedValue(null);
143
+ RedisService.set = jest.fn();
144
+ const fetcher = jest.fn().mockResolvedValue(null);
145
+
146
+ const result = await RedisService.getOrSet('empty-key', fetcher);
147
+
148
+ expect(result).toBeNull();
149
+ expect(RedisService.set).not.toHaveBeenCalled();
150
+ });
151
+
152
+ it('should quit the redis client', async () => {
153
+ const result = await RedisService.quit();
154
+ expect(result).toBe('OK');
155
+ expect(RedisService.client.quit).toHaveBeenCalled();
156
+ });
157
+ });
@@ -1,80 +1,89 @@
1
- import Redis from 'ioredis';
2
- import dotenv from 'dotenv';
3
- import logger from '<%- loggerPath %>';
4
-
5
- dotenv.config();
6
-
7
- class RedisService {
8
- private client: Redis;
9
- private static instance: RedisService;
10
-
11
- private constructor() {
12
- this.client = new Redis({
13
- host: process.env.REDIS_HOST || 'localhost',
14
- port: Number(process.env.REDIS_PORT) || 6379,
15
- password: process.env.REDIS_PASSWORD || undefined,
16
- retryStrategy: (times) => Math.min(times * 50, 2000),
17
- });
18
-
19
- this.client.on('connect', () => {
20
- logger.info('Redis connected');
21
- });
22
-
23
- this.client.on('error', (err) => {
24
- logger.error('Redis error:', err);
25
- });
26
- }
27
-
28
- public static getInstance(): RedisService {
29
- if (!RedisService.instance) {
30
- RedisService.instance = new RedisService();
31
- }
32
- return RedisService.instance;
33
- }
34
-
35
- public async get<T>(key: string): Promise<T | null> {
36
- try {
37
- const data = await this.client.get(key);
38
- return data ? JSON.parse(data) : null;
39
- } catch (error) {
40
- logger.error(`Redis get error for key ${key}:`, error);
41
- return null;
42
- }
43
- }
44
-
45
- public async set(key: string, value: unknown, ttl?: number): Promise<void> {
46
- try {
47
- const data = JSON.stringify(value);
48
- if (ttl) {
49
- await this.client.set(key, data, 'EX', ttl);
50
- } else {
51
- await this.client.set(key, data);
52
- }
53
- } catch (error) {
54
- logger.error(`Redis set error for key ${key}:`, error);
55
- }
56
- }
57
-
58
- public async del(key: string): Promise<void> {
59
- try {
60
- await this.client.del(key);
61
- } catch (error) {
62
- logger.error(`Redis del error for key ${key}:`, error);
63
- }
64
- }
65
-
66
- public async getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl: number = 3600): Promise<T> {
67
- const cached = await this.get<T>(key);
68
- if (cached) return cached;
69
-
70
- const data = await fetcher();
71
- if (data) await this.set(key, data, ttl);
72
- return data;
73
- }
74
-
75
- public async quit(): Promise<'OK'> {
76
- return await this.client.quit();
77
- }
78
- }
79
-
80
- export default RedisService.getInstance();
1
+ import Redis from 'ioredis';
2
+ import dotenv from 'dotenv';
3
+ import logger from '<%- loggerPath %>';
4
+
5
+ dotenv.config();
6
+
7
+ class RedisService {
8
+ private client: Redis;
9
+ private static instance: RedisService;
10
+
11
+ private constructor() {
12
+ this.client = new Redis({
13
+ host: process.env.REDIS_HOST || 'localhost',
14
+ port: Number(process.env.REDIS_PORT) || 6379,
15
+ password: process.env.REDIS_PASSWORD || undefined,
16
+ retryStrategy: (times) => Math.min(times * 50, 2000),
17
+ });
18
+
19
+ this.client.on('connect', () => {
20
+ logger.info('Redis connected');
21
+ });
22
+
23
+ this.client.on('error', (err) => {
24
+ logger.error('Redis error:', err);
25
+ });
26
+ }
27
+
28
+ public static getInstance(): RedisService {
29
+ if (!RedisService.instance) {
30
+ RedisService.instance = new RedisService();
31
+ }
32
+ return RedisService.instance;
33
+ }
34
+
35
+ public async get<T>(key: string): Promise<T | null> {
36
+ try {
37
+ const data = await this.client.get(key);
38
+ return data ? JSON.parse(data) : null;
39
+ } catch (error) {
40
+ logger.error(`Redis get error for key ${key}:`, error);
41
+ return null;
42
+ }
43
+ }
44
+
45
+ public async set(key: string, value: unknown, ttl?: number): Promise<void> {
46
+ try {
47
+ const data = JSON.stringify(value);
48
+ if (ttl) {
49
+ await this.client.set(key, data, 'EX', ttl);
50
+ } else {
51
+ await this.client.set(key, data);
52
+ }
53
+ } catch (error) {
54
+ logger.error(`Redis set error for key ${key}:`, error);
55
+ }
56
+ }
57
+
58
+ public async del(key: string): Promise<void> {
59
+ try {
60
+ await this.client.del(key);
61
+ } catch (error) {
62
+ logger.error(`Redis del error for key ${key}:`, error);
63
+ }
64
+ }
65
+
66
+ public async flush(): Promise<void> {
67
+ try {
68
+ await this.client.flushall();
69
+ logger.info('Redis flushed');
70
+ } catch (error) {
71
+ logger.error('Redis flush error:', error);
72
+ }
73
+ }
74
+
75
+ public async getOrSet<T>(key: string, fetcher: () => Promise<T>, ttl: number = 3600): Promise<T> {
76
+ const cached = await this.get<T>(key);
77
+ if (cached) return cached;
78
+
79
+ const data = await fetcher();
80
+ if (data) await this.set(key, data, ttl);
81
+ return data;
82
+ }
83
+
84
+ public async quit(): Promise<'OK'> {
85
+ return await this.client.quit();
86
+ }
87
+ }
88
+
89
+ export default RedisService.getInstance();
@@ -1,19 +1,19 @@
1
- const { Sequelize } = require('sequelize');
2
- require('dotenv').config();
3
-
4
- <% if (database === 'MySQL') { %>const dialect = 'mysql';<% } -%>
5
- <% if (database === 'PostgreSQL') { %>const dialect = 'postgres';<% } -%>
6
-
7
- const sequelize = new Sequelize(
8
- process.env.DB_NAME || '<%= dbName %>',
9
- process.env.DB_USER || '<% if (database === 'MySQL') { %>root<% } else { %>postgres<% } %>',
10
- process.env.DB_PASSWORD || '<% if (database === 'MySQL') { %>root<% } else { %>root<% } %>',
11
- {
12
- host: process.env.DB_HOST || '127.0.0.1',
13
- dialect: dialect,
14
- logging: false,
15
- port: parseInt(process.env.DB_PORT || '<% if (database === 'MySQL') { %>3306<% } else { %>5432<% } %>')
16
- }
17
- );
18
-
19
- module.exports = sequelize;
1
+ const { Sequelize } = require('sequelize');
2
+ require('dotenv').config();
3
+
4
+ <% if (database === 'MySQL') { %>const dialect = 'mysql';<% } -%>
5
+ <% if (database === 'PostgreSQL') { %>const dialect = 'postgres';<% } -%>
6
+
7
+ const sequelize = new Sequelize(
8
+ process.env.DB_NAME || '<%= dbName %>',
9
+ process.env.DB_USER || '<% if (database === 'MySQL') { %>root<% } else { %>postgres<% } %>',
10
+ process.env.DB_PASSWORD || '<% if (database === 'MySQL') { %>root<% } else { %>root<% } %>',
11
+ {
12
+ host: process.env.DB_HOST || '127.0.0.1',
13
+ dialect: dialect,
14
+ logging: false,
15
+ port: parseInt(process.env.DB_PORT || '<% if (database === 'MySQL') { %>3306<% } else { %>5432<% } %>')
16
+ }
17
+ );
18
+
19
+ module.exports = sequelize;
@@ -1,56 +1,56 @@
1
- jest.mock('sequelize', () => {
2
- const mSequelize = jest.fn(() => ({
3
- authenticate: jest.fn().mockResolvedValue(true),
4
- define: jest.fn(),
5
- }));
6
- return { Sequelize: mSequelize };
7
- });
8
-
9
- jest.mock('dotenv', () => ({
10
- config: jest.fn()
11
- }));
12
-
13
- describe('Database Configuration', () => {
14
- beforeEach(() => {
15
- jest.clearAllMocks();
16
- jest.resetModules();
17
-
18
- // Clean environment
19
- const envVars = ['DB_NAME', 'DB_USER', 'DB_PASSWORD', 'DB_HOST', 'DB_PORT'];
20
- envVars.forEach(v => delete process.env[v]);
21
- });
22
-
23
- it('should initialize Sequelize with environment variables', () => {
24
- const { Sequelize: SequelizeMock } = require('sequelize');
25
- process.env.DB_NAME = 'testdb';
26
- process.env.DB_USER = 'testuser';
27
- process.env.DB_PASSWORD = 'testpassword';
28
- process.env.DB_HOST = 'localhost';
29
- process.env.DB_PORT = '5432';
30
-
31
- require('<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>');
32
-
33
- expect(SequelizeMock).toHaveBeenCalledWith(
34
- 'testdb',
35
- 'testuser',
36
- 'testpassword',
37
- expect.objectContaining({
38
- host: 'localhost',
39
- port: 5432
40
- })
41
- );
42
- });
43
-
44
- it('should initialize Sequelize with default values when env vars are missing', () => {
45
- const { Sequelize: SequelizeMock } = require('sequelize');
46
- delete process.env.DB_NAME;
47
- delete process.env.DB_USER;
48
- delete process.env.DB_PASSWORD;
49
- delete process.env.DB_HOST;
50
- delete process.env.DB_PORT;
51
-
52
- require('<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>');
53
-
54
- expect(SequelizeMock).toHaveBeenCalledTimes(1);
55
- });
56
- });
1
+ jest.mock('sequelize', () => {
2
+ const mSequelize = jest.fn(() => ({
3
+ authenticate: jest.fn().mockResolvedValue(true),
4
+ define: jest.fn(),
5
+ }));
6
+ return { Sequelize: mSequelize };
7
+ });
8
+
9
+ jest.mock('dotenv', () => ({
10
+ config: jest.fn()
11
+ }));
12
+
13
+ describe('Database Configuration', () => {
14
+ beforeEach(() => {
15
+ jest.clearAllMocks();
16
+ jest.resetModules();
17
+
18
+ // Clean environment
19
+ const envVars = ['DB_NAME', 'DB_USER', 'DB_PASSWORD', 'DB_HOST', 'DB_PORT'];
20
+ envVars.forEach(v => delete process.env[v]);
21
+ });
22
+
23
+ it('should initialize Sequelize with environment variables', () => {
24
+ const { Sequelize: SequelizeMock } = require('sequelize');
25
+ process.env.DB_NAME = 'testdb';
26
+ process.env.DB_USER = 'testuser';
27
+ process.env.DB_PASSWORD = 'testpassword';
28
+ process.env.DB_HOST = 'localhost';
29
+ process.env.DB_PORT = '5432';
30
+
31
+ require('<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>');
32
+
33
+ expect(SequelizeMock).toHaveBeenCalledWith(
34
+ 'testdb',
35
+ 'testuser',
36
+ 'testpassword',
37
+ expect.objectContaining({
38
+ host: 'localhost',
39
+ port: 5432
40
+ })
41
+ );
42
+ });
43
+
44
+ it('should initialize Sequelize with default values when env vars are missing', () => {
45
+ const { Sequelize: SequelizeMock } = require('sequelize');
46
+ delete process.env.DB_NAME;
47
+ delete process.env.DB_USER;
48
+ delete process.env.DB_PASSWORD;
49
+ delete process.env.DB_HOST;
50
+ delete process.env.DB_PORT;
51
+
52
+ require('<% if (architecture === "MVC") { %>@/config/database<% } else { %>@/infrastructure/database/database<% } %>');
53
+
54
+ expect(SequelizeMock).toHaveBeenCalledTimes(1);
55
+ });
56
+ });