nodejs-quickstart-structure 2.0.0 → 2.1.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 (161) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +44 -40
  3. package/bin/index.js +6 -3
  4. package/lib/generator.js +10 -4
  5. package/lib/modules/app-setup.js +76 -6
  6. package/lib/modules/auth-setup.js +143 -0
  7. package/lib/modules/caching-setup.js +8 -1
  8. package/lib/modules/config-files.js +10 -0
  9. package/lib/modules/database-setup.js +2 -1
  10. package/lib/modules/project-setup.js +1 -0
  11. package/lib/prompts.js +40 -1
  12. package/package.json +5 -4
  13. package/templates/clean-architecture/js/src/domain/models/User.js +3 -1
  14. package/templates/clean-architecture/js/src/index.js.ejs +2 -0
  15. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +12 -3
  16. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +25 -2
  17. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +27 -0
  18. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +3 -0
  19. package/templates/clean-architecture/js/src/infrastructure/webserver/server.spec.js.ejs +49 -0
  20. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.spec.js.ejs +14 -0
  21. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +41 -4
  22. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +69 -4
  23. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -6
  24. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +38 -21
  25. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +10 -5
  26. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +32 -10
  27. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +1 -1
  28. package/templates/clean-architecture/js/src/interfaces/routes/api.js.ejs +15 -0
  29. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +4 -0
  30. package/templates/clean-architecture/js/src/usecases/CreateUser.js.ejs +34 -0
  31. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +3 -2
  32. package/templates/clean-architecture/js/src/usecases/DeleteUser.js.ejs +27 -0
  33. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js.ejs +36 -0
  34. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +14 -0
  35. package/templates/clean-architecture/js/src/usecases/GetUserById.js.ejs +36 -0
  36. package/templates/clean-architecture/js/src/usecases/GetUserById.spec.js.ejs +48 -0
  37. package/templates/clean-architecture/js/src/usecases/UpdateUser.js.ejs +28 -0
  38. package/templates/clean-architecture/js/src/utils/errorMessages.js +1 -0
  39. package/templates/clean-architecture/js/src/utils/httpCodes.js +2 -0
  40. package/templates/clean-architecture/ts/src/config/env.ts.ejs +12 -3
  41. package/templates/clean-architecture/ts/src/domain/user.ts +3 -1
  42. package/templates/clean-architecture/ts/src/index.ts.ejs +4 -0
  43. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +55 -9
  44. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +32 -3
  45. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +26 -6
  46. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +57 -15
  47. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +38 -23
  48. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +14 -8
  49. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +33 -10
  50. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +15 -5
  51. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +1 -1
  52. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +9 -1
  53. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts.ejs +16 -0
  54. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +3 -2
  55. package/templates/clean-architecture/ts/src/usecases/createUser.ts.ejs +35 -0
  56. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +1 -0
  57. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts.ejs +24 -0
  58. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts.ejs +21 -0
  59. package/templates/clean-architecture/ts/src/usecases/getUserById.spec.ts.ejs +47 -0
  60. package/templates/clean-architecture/ts/src/usecases/getUserById.ts.ejs +23 -0
  61. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +1 -0
  62. package/templates/clean-architecture/ts/src/usecases/updateUser.ts.ejs +25 -0
  63. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +1 -0
  64. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +1 -0
  65. package/templates/common/.cursorrules.ejs +9 -0
  66. package/templates/common/.env.example.ejs +17 -10
  67. package/templates/common/.gitlab-ci.yml.ejs +3 -1
  68. package/templates/common/Jenkinsfile.ejs +10 -1
  69. package/templates/common/README.md.ejs +64 -19
  70. package/templates/common/_circleci/config.yml.ejs +96 -0
  71. package/templates/common/_github/workflows/ci.yml.ejs +1 -1
  72. package/templates/common/auth/js/controllers/authController.js.ejs +168 -0
  73. package/templates/common/auth/js/controllers/authController.spec.js.ejs +148 -0
  74. package/templates/common/auth/js/middleware/authMiddleware.js.ejs +58 -0
  75. package/templates/common/auth/js/middleware/authMiddleware.spec.js.ejs +108 -0
  76. package/templates/common/auth/js/routes/authRoutes.js.ejs +16 -0
  77. package/templates/common/auth/js/services/jwtService.js.ejs +54 -0
  78. package/templates/common/auth/js/services/jwtService.spec.js.ejs +84 -0
  79. package/templates/common/auth/ts/controllers/authController.spec.ts.ejs +161 -0
  80. package/templates/common/auth/ts/controllers/authController.ts.ejs +165 -0
  81. package/templates/common/auth/ts/middleware/authMiddleware.spec.ts.ejs +128 -0
  82. package/templates/common/auth/ts/middleware/authMiddleware.ts.ejs +59 -0
  83. package/templates/common/auth/ts/routes/authRoutes.ts.ejs +20 -0
  84. package/templates/common/auth/ts/services/jwtService.spec.ts.ejs +89 -0
  85. package/templates/common/auth/ts/services/jwtService.ts.ejs +60 -0
  86. package/templates/common/bitbucket-pipelines.yml.ejs +60 -0
  87. package/templates/common/caching/clean/js/CreateUser.js.ejs +14 -5
  88. package/templates/common/caching/clean/js/DeleteUser.js.ejs +2 -1
  89. package/templates/common/caching/clean/js/GetUserById.js.ejs +39 -0
  90. package/templates/common/caching/clean/js/UpdateUser.js.ejs +2 -1
  91. package/templates/common/caching/clean/ts/createUser.ts.ejs +14 -6
  92. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +2 -1
  93. package/templates/common/caching/clean/ts/getUserById.ts.ejs +32 -0
  94. package/templates/common/caching/clean/ts/updateUser.ts.ejs +2 -2
  95. package/templates/common/database/js/models/User.js.ejs +14 -1
  96. package/templates/common/database/js/models/User.js.mongoose.ejs +7 -0
  97. package/templates/common/database/js/models/User.spec.js.ejs +12 -0
  98. package/templates/common/database/ts/models/User.spec.ts.ejs +10 -0
  99. package/templates/common/database/ts/models/User.ts.ejs +17 -0
  100. package/templates/common/database/ts/models/User.ts.mongoose.ejs +8 -0
  101. package/templates/common/docker-compose.yml.ejs +14 -0
  102. package/templates/common/ecosystem.config.js.ejs +9 -3
  103. package/templates/common/eslint.config.mjs.ejs +3 -0
  104. package/templates/common/jest.config.js.ejs +11 -9
  105. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +1 -1
  106. package/templates/common/kafka/js/services/kafkaService.js.ejs +1 -1
  107. package/templates/common/migrations/init.js.ejs +5 -4
  108. package/templates/common/package.json.ejs +10 -2
  109. package/templates/common/prompts/project-context.md.ejs +8 -1
  110. package/templates/common/scripts/run-e2e.js.ejs +26 -10
  111. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +149 -107
  112. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +88 -47
  113. package/templates/common/swagger.yml.ejs +148 -0
  114. package/templates/common/tsconfig.eslint.json +15 -0
  115. package/templates/common/tsconfig.json +2 -1
  116. package/templates/common/views/ejs/index.ejs +264 -30
  117. package/templates/common/views/ejs/login.ejs.ejs +244 -0
  118. package/templates/common/views/ejs/signup.ejs.ejs +282 -0
  119. package/templates/common/views/pug/index.pug +269 -38
  120. package/templates/common/views/pug/login.pug.ejs +195 -0
  121. package/templates/common/views/pug/signup.pug.ejs +241 -0
  122. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +6 -0
  123. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +6 -0
  124. package/templates/mvc/js/src/config/env.js.ejs +12 -3
  125. package/templates/mvc/js/src/controllers/userController.js.ejs +29 -5
  126. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +27 -12
  127. package/templates/mvc/js/src/graphql/context.js.ejs +14 -3
  128. package/templates/mvc/js/src/graphql/context.spec.js.ejs +36 -21
  129. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +10 -5
  130. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +32 -10
  131. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +1 -1
  132. package/templates/mvc/js/src/index.js.ejs +16 -3
  133. package/templates/mvc/js/src/routes/api.js.ejs +14 -0
  134. package/templates/mvc/js/src/routes/api.spec.js.ejs +3 -0
  135. package/templates/mvc/js/src/utils/errorMessages.js +1 -0
  136. package/templates/mvc/js/src/utils/httpCodes.js +1 -0
  137. package/templates/mvc/ts/src/config/env.ts.ejs +12 -3
  138. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +95 -7
  139. package/templates/mvc/ts/src/controllers/userController.ts.ejs +68 -11
  140. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +36 -23
  141. package/templates/mvc/ts/src/graphql/context.ts.ejs +15 -6
  142. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +32 -10
  143. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +15 -5
  144. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +1 -1
  145. package/templates/mvc/ts/src/index.ts.ejs +15 -3
  146. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +6 -0
  147. package/templates/mvc/ts/src/routes/api.ts.ejs +15 -0
  148. package/templates/mvc/ts/src/utils/errorMessages.ts +1 -0
  149. package/templates/mvc/ts/src/utils/httpCodes.ts +1 -0
  150. package/templates/clean-architecture/js/src/interfaces/routes/api.js +0 -12
  151. package/templates/clean-architecture/js/src/usecases/CreateUser.js +0 -14
  152. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +0 -11
  153. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +0 -12
  154. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +0 -11
  155. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +0 -13
  156. package/templates/clean-architecture/ts/src/usecases/createUser.ts +0 -13
  157. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +0 -9
  158. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +0 -10
  159. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +0 -9
  160. package/templates/mvc/js/src/routes/api.js +0 -10
  161. package/templates/mvc/ts/src/routes/api.ts +0 -12
@@ -3,118 +3,160 @@ const request = require('supertest');
3
3
  const SERVER_URL = process.env.TEST_URL || `http://127.0.0.1:${process.env.PORT || 3001}`;
4
4
 
5
5
  describe('E2E User Tests', () => {
6
- // Global setup and teardown hooks can be added here
7
- // typically for database seeding or external authentication checks prior to E2E.
8
- let userId;
9
- const uniqueEmail = `test_${Date.now()}@example.com`;
6
+ let userId;
7
+ <%_ if (auth.includes('JWT')) { _%>
8
+ let authToken;
9
+ <%_ } _%>
10
+ const uniqueEmail = `test_${Date.now()}@example.com`;
11
+ <%_ if (auth.includes('JWT')) { _%>
12
+ const testPassword = 'password123';
13
+ <%_ } _%>
14
+
15
+ <%_ if (auth.includes('JWT')) { _%>
16
+ it('should fail to fetch users without token (Protected)', async () => {
17
+ <%_ if (communication === 'GraphQL') { _%>
18
+ const query = `{ getAllUsers { id name } }`;
19
+ const response = await request(SERVER_URL).post('/graphql').send({ query });
20
+ // In GraphQL errors are usually in the body with 200/400 status
21
+ if (response.statusCode === 200 && response.body.errors) {
22
+ expect(response.body.errors[0].message.toLowerCase()).toContain('unauthorized');
23
+ } else {
24
+ expect([401, 400]).toContain(response.statusCode);
25
+ }
26
+ <%_ } else { _%>
27
+ const response = await request(SERVER_URL).get('/api/users');
28
+ expect(response.statusCode).toBe(401);
29
+ <%_ } _%>
30
+ });
31
+ <%_ } _%>
10
32
 
11
33
  <%_ if (communication === 'GraphQL') { -%>
12
- it('should create a user via GraphQL', async () => {
13
- const query = `
14
- mutation {
15
- createUser(name: "Test User", email: "${uniqueEmail}") {
16
- id
17
- name
18
- email
19
- }
20
- }
21
- `;
22
- const response = await request(SERVER_URL)
23
- .post('/graphql')
24
- .send({ query });
25
-
26
- expect(response.statusCode).toBe(200);
27
- userId = response.body.data.createUser.id;
28
- expect(userId).toBeDefined();
29
- });
30
-
31
- it('should update a user via GraphQL', async () => {
32
- const query = `
33
- mutation {
34
- updateUser(id: "${userId}", name: "Updated User") {
35
- id
36
- name
37
- }
38
- }
39
- `;
40
- const response = await request(SERVER_URL)
41
- .post('/graphql')
42
- .send({ query });
43
-
44
- expect(response.statusCode).toBe(200);
45
- expect(response.body.data.updateUser.name).toBe("Updated User");
46
- });
47
-
48
- it('should delete a user via GraphQL', async () => {
49
- const query = `
50
- mutation {
51
- deleteUser(id: "${userId}")
52
- }
53
- `;
54
- const response = await request(SERVER_URL)
55
- .post('/graphql')
56
- .send({ query });
57
-
58
- expect(response.statusCode).toBe(200);
59
- expect(response.body.data.deleteUser).toBe(true);
60
- });
61
- <%_ } else if (communication === 'Kafka') { -%>
62
- it('should trigger Kafka event for user creation', async () => {
63
- const response = await request(SERVER_URL)
64
- .post('/api/users')
65
- .send({ name: 'Test User', email: uniqueEmail });
66
-
67
- expect([201, 202]).toContain(response.statusCode);
68
- userId = response.body.id || response.body._id;
69
- expect(userId).toBeDefined();
70
-
71
- // Wait for Kafka to process...
72
- await new Promise(resolve => setTimeout(resolve, 500));
73
- });
74
-
75
- it('should trigger Kafka event for user update', async () => {
76
- const response = await request(SERVER_URL)
77
- .patch(`/api/users/${userId}`)
78
- .send({ name: 'Updated User' });
79
-
80
- expect([200, 202, 204]).toContain(response.statusCode);
81
-
82
- // Wait for Kafka to process...
83
- await new Promise(resolve => setTimeout(resolve, 500));
84
- });
85
-
86
- it('should trigger Kafka event for user deletion', async () => {
87
- const response = await request(SERVER_URL)
88
- .delete(`/api/users/${userId}`);
89
-
90
- expect([200, 202, 204]).toContain(response.statusCode);
91
-
92
- // Wait for Kafka to process...
93
- await new Promise(resolve => setTimeout(resolve, 500));
94
- });
34
+ it('should create a user via GraphQL', async () => {
35
+ const query = `
36
+ mutation {
37
+ createUser(name: "Test User", email: "${uniqueEmail}"<%_ if (auth.includes('JWT')) { _%>, password: "${testPassword}"<%_ } _%>) {
38
+ id
39
+ name
40
+ email
41
+ }
42
+ }
43
+ `;
44
+ const response = await request(SERVER_URL)
45
+ .post('/graphql')
46
+ .send({ query });
47
+
48
+ expect(response.statusCode).toBe(200);
49
+ expect(response.body.errors).toBeUndefined();
50
+ userId = response.body.data.createUser.id;
51
+ expect(userId).toBeDefined();
52
+ });
95
53
  <%_ } else { -%>
96
- it('should create a user successfully via REST', async () => {
97
- const response = await request(SERVER_URL)
98
- .post('/api/users')
99
- .send({ name: 'Test User', email: uniqueEmail });
100
-
101
- expect(response.statusCode).toBe(201);
102
- userId = response.body.id || response.body._id;
103
- });
104
-
105
- it('should update a user successfully via REST', async () => {
106
- const response = await request(SERVER_URL)
107
- .patch(`/api/users/${userId}`)
108
- .send({ name: 'Updated User' });
54
+ it('should create a user successfully (Signup)', async () => {
55
+ const response = await request(SERVER_URL)
56
+ .post('/api/users')
57
+ .send({ name: 'Test User', email: uniqueEmail<%_ if (auth.includes('JWT')) { _%>, password: testPassword <%_ } _%>});
58
+
59
+ expect([201, 202]).toContain(response.statusCode);
60
+ userId = response.body.id || response.body._id;
61
+ });
62
+ <%_ } -%>
109
63
 
110
- expect(response.statusCode).toBe(200);
111
- });
64
+ <%_ if (auth.includes('JWT')) { _%>
65
+ it('should login and obtain a JWT token', async () => {
66
+ const response = await request(SERVER_URL)
67
+ .post('/api/auth/login')
68
+ .send({ email: uniqueEmail, password: testPassword });
112
69
 
113
- it('should delete a user successfully via REST', async () => {
114
- const response = await request(SERVER_URL)
115
- .delete(`/api/users/${userId}`);
70
+ expect(response.statusCode).toBe(200);
71
+ expect(response.body.accessToken || response.body.token).toBeDefined();
72
+ authToken = response.body.accessToken || response.body.token;
73
+ });
74
+ <%_ } _%>
116
75
 
117
- expect(response.statusCode).toBe(200);
118
- });
76
+ <%_ if (communication === 'GraphQL') { -%>
77
+ it('should fetch all users via GraphQL', async () => {
78
+ const query = `{ getAllUsers { id name email } }`;
79
+ const response = await request(SERVER_URL)
80
+ .post('/graphql')
81
+ <%_ if (auth.includes('JWT')) { _%>
82
+ .set('Authorization', `Bearer ${authToken}`)
83
+ <%_ } _%>
84
+ .send({ query });
85
+
86
+ expect(response.statusCode).toBe(200);
87
+ expect(Array.isArray(response.body.data.getAllUsers)).toBe(true);
88
+ const user = response.body.data.getAllUsers.find(u => u.id === userId);
89
+ expect(user).toBeDefined();
90
+ });
91
+
92
+ it('should update a user via GraphQL', async () => {
93
+ const query = `
94
+ mutation {
95
+ updateUser(id: "${userId}", name: "Updated User") {
96
+ id
97
+ name
98
+ }
99
+ }
100
+ `;
101
+ const response = await request(SERVER_URL)
102
+ .post('/graphql')
103
+ <%_ if (auth.includes('JWT')) { _%>
104
+ .set('Authorization', `Bearer ${authToken}`)
105
+ <%_ } _%>
106
+ .set('Content-Type', 'application/json')
107
+ .send({ query });
108
+
109
+ expect(response.statusCode).toBe(200);
110
+ expect(response.body.data.updateUser.name).toBe("Updated User");
111
+ });
112
+
113
+ it('should delete a user via GraphQL', async () => {
114
+ const query = `
115
+ mutation {
116
+ deleteUser(id: "${userId}")
117
+ }
118
+ `;
119
+ const response = await request(SERVER_URL)
120
+ .post('/graphql')
121
+ <%_ if (auth.includes('JWT')) { _%>
122
+ .set('Authorization', `Bearer ${authToken}`)
123
+ <%_ } _%>
124
+ .set('Content-Type', 'application/json')
125
+ .send({ query });
126
+
127
+ expect(response.statusCode).toBe(200);
128
+ expect(response.body.data.deleteUser).toBe(true);
129
+ });
130
+ <%_ } else { -%>
131
+ it('should fetch users successfully', async () => {
132
+ const response = await request(SERVER_URL)
133
+ .get('/api/users')
134
+ <%_ if (auth.includes('JWT')) { _%>
135
+ .set('Authorization', `Bearer ${authToken}`);
136
+ <%_ } _%>
137
+ expect(response.statusCode).toBe(200);
138
+ expect(Array.isArray(response.body)).toBe(true);
139
+ });
140
+
141
+ it('should update a user successfully', async () => {
142
+ const response = await request(SERVER_URL)
143
+ .patch(`/api/users/${userId}`)
144
+ <%_ if (auth.includes('JWT')) { _%>
145
+ .set('Authorization', `Bearer ${authToken}`)
146
+ <%_ } _%>
147
+ .send({ name: 'Updated User' });
148
+
149
+ expect([200, 202, 204]).toContain(response.statusCode);
150
+ });
151
+
152
+ it('should delete a user successfully', async () => {
153
+ const response = await request(SERVER_URL)
154
+ .delete(`/api/users/${userId}`)
155
+ <%_ if (auth.includes('JWT')) { _%>
156
+ .set('Authorization', `Bearer ${authToken}`)
157
+ <%_ } _%>;
158
+
159
+ expect([200, 202, 204]).toContain(response.statusCode);
160
+ });
119
161
  <%_ } -%>
120
162
  });
@@ -3,16 +3,37 @@ import request from 'supertest';
3
3
  const SERVER_URL = process.env.TEST_URL || `http://127.0.0.1:${process.env.PORT || 3001}`;
4
4
 
5
5
  describe('E2E User Tests', () => {
6
- // Global setup and teardown hooks can be added here
7
- // typically for database seeding or external authentication checks prior to E2E.
8
6
  let userId: string;
7
+ <%_ if (auth.includes('JWT')) { _%>
8
+ let authToken: string;
9
+ <%_ } _%>
9
10
  const uniqueEmail = `test_${Date.now()}@example.com`;
11
+ <%_ if (auth.includes('JWT')) { _%>
12
+ const testPassword = 'password123';
13
+ <%_ } _%>
14
+
15
+ <%_ if (auth.includes('JWT')) { _%>
16
+ it('should fail to fetch users without token (Protected)', async () => {
17
+ <%_ if (communication === 'GraphQL') { _%>
18
+ const query = `{ getAllUsers { id name } }`;
19
+ const response = await request(SERVER_URL).post('/graphql').send({ query });
20
+ if (response.statusCode === 200 && response.body.errors) {
21
+ expect(response.body.errors[0].message.toLowerCase()).toContain('unauthorized');
22
+ } else {
23
+ expect([401, 400]).toContain(response.statusCode);
24
+ }
25
+ <%_ } else { _%>
26
+ const response = await request(SERVER_URL).get('/api/users');
27
+ expect(response.statusCode).toBe(401);
28
+ <%_ } _%>
29
+ });
30
+ <%_ } _%>
10
31
 
11
32
  <%_ if (communication === 'GraphQL') { -%>
12
33
  it('should create a user via GraphQL', async () => {
13
34
  const query = `
14
35
  mutation {
15
- createUser(name: "Test User", email: "${uniqueEmail}") {
36
+ createUser(name: "Test User", email: "${uniqueEmail}"<%_ if (auth.includes('JWT')) { _%>, password: "${testPassword}"<%_ } _%>) {
16
37
  id
17
38
  name
18
39
  email
@@ -24,9 +45,48 @@ describe('E2E User Tests', () => {
24
45
  .send({ query });
25
46
 
26
47
  expect(response.statusCode).toBe(200);
48
+ expect(response.body.errors).toBeUndefined();
27
49
  userId = response.body.data.createUser.id;
28
50
  expect(userId).toBeDefined();
29
51
  });
52
+ <%_ } else { -%>
53
+ it('should create a user successfully (Signup)', async () => {
54
+ const response = await request(SERVER_URL)
55
+ .post('/api/users')
56
+ .send({ name: 'Test User', email: uniqueEmail<%_ if (auth.includes('JWT')) { _%>, password: testPassword <%_ } _%>});
57
+
58
+ expect([201, 202]).toContain(response.statusCode);
59
+ userId = response.body.id || response.body._id;
60
+ });
61
+ <%_ } -%>
62
+
63
+ <%_ if (auth.includes('JWT')) { _%>
64
+ it('should login and obtain a JWT token', async () => {
65
+ const response = await request(SERVER_URL)
66
+ .post('/api/auth/login')
67
+ .send({ email: uniqueEmail, password: testPassword });
68
+
69
+ expect(response.statusCode).toBe(200);
70
+ expect(response.body.accessToken || response.body.token).toBeDefined();
71
+ authToken = response.body.accessToken || response.body.token;
72
+ });
73
+ <%_ } _%>
74
+
75
+ <%_ if (communication === 'GraphQL') { -%>
76
+ it('should fetch all users via GraphQL', async () => {
77
+ const query = `{ getAllUsers { id name email } }`;
78
+ const response = await request(SERVER_URL)
79
+ .post('/graphql')
80
+ <%_ if (auth.includes('JWT')) { _%>
81
+ .set('Authorization', `Bearer ${authToken}`)
82
+ <%_ } _%>
83
+ .send({ query });
84
+
85
+ expect(response.statusCode).toBe(200);
86
+ expect(Array.isArray(response.body.data.getAllUsers)).toBe(true);
87
+ const user = response.body.data.getAllUsers.find((u: any) => u.id === userId);
88
+ expect(user).toBeDefined();
89
+ });
30
90
 
31
91
  it('should update a user via GraphQL', async () => {
32
92
  const query = `
@@ -39,6 +99,10 @@ describe('E2E User Tests', () => {
39
99
  `;
40
100
  const response = await request(SERVER_URL)
41
101
  .post('/graphql')
102
+ <%_ if (auth.includes('JWT')) { _%>
103
+ .set('Authorization', `Bearer ${authToken}`)
104
+ <%_ } _%>
105
+ .set('Content-Type', 'application/json')
42
106
  .send({ query });
43
107
 
44
108
  expect(response.statusCode).toBe(200);
@@ -53,68 +117,45 @@ describe('E2E User Tests', () => {
53
117
  `;
54
118
  const response = await request(SERVER_URL)
55
119
  .post('/graphql')
120
+ <%_ if (auth.includes('JWT')) { _%>
121
+ .set('Authorization', `Bearer ${authToken}`)
122
+ <%_ } _%>
123
+ .set('Content-Type', 'application/json')
56
124
  .send({ query });
57
125
 
58
126
  expect(response.statusCode).toBe(200);
59
127
  expect(response.body.data.deleteUser).toBe(true);
60
128
  });
61
- <%_ } else if (communication === 'Kafka') { -%>
62
- it('should trigger Kafka event for user creation', async () => {
129
+ <%_ } else { -%>
130
+ it('should fetch users successfully', async () => {
63
131
  const response = await request(SERVER_URL)
64
- .post('/api/users')
65
- .send({ name: 'Test User', email: uniqueEmail });
66
-
67
- expect([201, 202]).toContain(response.statusCode);
68
- userId = response.body.id || response.body._id;
69
- expect(userId).toBeDefined();
70
-
71
- // Wait for Kafka to process...
72
- await new Promise(resolve => setTimeout(resolve, 500));
132
+ .get('/api/users')
133
+ <%_ if (auth.includes('JWT')) { _%>
134
+ .set('Authorization', `Bearer ${authToken}`)
135
+ <%_ } _%>;
136
+ expect(response.statusCode).toBe(200);
137
+ expect(Array.isArray(response.body)).toBe(true);
73
138
  });
74
139
 
75
- it('should trigger Kafka event for user update', async () => {
140
+ it('should update a user successfully', async () => {
76
141
  const response = await request(SERVER_URL)
77
142
  .patch(`/api/users/${userId}`)
143
+ <%_ if (auth.includes('JWT')) { _%>
144
+ .set('Authorization', `Bearer ${authToken}`)
145
+ <%_ } _%>
78
146
  .send({ name: 'Updated User' });
79
147
 
80
148
  expect([200, 202, 204]).toContain(response.statusCode);
81
-
82
- // Wait for Kafka to process...
83
- await new Promise(resolve => setTimeout(resolve, 500));
84
149
  });
85
150
 
86
- it('should trigger Kafka event for user deletion', async () => {
151
+ it('should delete a user successfully', async () => {
87
152
  const response = await request(SERVER_URL)
88
- .delete(`/api/users/${userId}`);
153
+ .delete(`/api/users/${userId}`)
154
+ <%_ if (auth.includes('JWT')) { _%>
155
+ .set('Authorization', `Bearer ${authToken}`)
156
+ <%_ } _%>;
89
157
 
90
158
  expect([200, 202, 204]).toContain(response.statusCode);
91
-
92
- // Wait for Kafka to process...
93
- await new Promise(resolve => setTimeout(resolve, 500));
94
- });
95
- <%_ } else { -%>
96
- it('should create a user successfully via REST', async () => {
97
- const response = await request(SERVER_URL)
98
- .post('/api/users')
99
- .send({ name: 'Test User', email: uniqueEmail });
100
-
101
- expect(response.statusCode).toBe(201);
102
- userId = response.body.id || response.body._id;
103
- });
104
-
105
- it('should update a user successfully via REST', async () => {
106
- const response = await request(SERVER_URL)
107
- .patch(`/api/users/${userId}`)
108
- .send({ name: 'Updated User' });
109
-
110
- expect(response.statusCode).toBe(200);
111
- });
112
-
113
- it('should delete a user successfully via REST', async () => {
114
- const response = await request(SERVER_URL)
115
- .delete(`/api/users/${userId}`);
116
-
117
- expect(response.statusCode).toBe(200);
118
159
  });
119
160
  <%_ } -%>
120
161
  });
@@ -7,12 +7,20 @@ servers:
7
7
  - url: http://localhost:3000
8
8
  description: Local Server
9
9
  components:
10
+ <%_ if (auth.includes('JWT')) { -%>
11
+ securitySchemes:
12
+ bearerAuth:
13
+ type: http
14
+ scheme: bearer
15
+ bearerFormat: JWT
16
+ <%_ } -%>
10
17
  schemas:
11
18
  User:
12
19
  type: object
13
20
  required:
14
21
  - name
15
22
  - email
23
+ <% if (auth.includes('JWT')) { %>- password<% } %>
16
24
  properties:
17
25
  id:
18
26
  type: integer
@@ -23,6 +31,12 @@ components:
23
31
  email:
24
32
  type: string
25
33
  description: The email of the user
34
+ <% if (auth.includes('JWT')) { %>
35
+ password:
36
+ type: string
37
+ writeOnly: true
38
+ description: The password of the user
39
+ <% } %>
26
40
  example:
27
41
  id: 1
28
42
  name: John Doe
@@ -30,7 +44,103 @@ components:
30
44
  tags:
31
45
  - name: Users
32
46
  description: The users managing API
47
+ <%_ if (auth.includes('JWT')) { -%>
48
+ - name: Auth
49
+ description: Authentication API
50
+ <%_ } -%>
33
51
  paths:
52
+ <%_ if (auth.includes('JWT')) { -%>
53
+ /api/auth/login:
54
+ post:
55
+ summary: Login and receive a JWT token
56
+ tags:
57
+ - Auth
58
+ requestBody:
59
+ required: true
60
+ content:
61
+ application/json:
62
+ schema:
63
+ type: object
64
+ required:
65
+ - email
66
+ - password
67
+ properties:
68
+ email:
69
+ type: string
70
+ password:
71
+ type: string
72
+ responses:
73
+ '200':
74
+ description: Login successful
75
+ content:
76
+ application/json:
77
+ schema:
78
+ type: object
79
+ properties:
80
+ token:
81
+ type: string
82
+ accessToken:
83
+ type: string
84
+ refreshToken:
85
+ type: string
86
+ '401':
87
+ description: Invalid credentials
88
+ /api/auth/refresh:
89
+ post:
90
+ summary: Refresh access token using a refresh token
91
+ tags:
92
+ - Auth
93
+ requestBody:
94
+ required: true
95
+ content:
96
+ application/json:
97
+ schema:
98
+ type: object
99
+ required:
100
+ - refreshToken
101
+ properties:
102
+ refreshToken:
103
+ type: string
104
+ responses:
105
+ '200':
106
+ description: Token refreshed successfully
107
+ content:
108
+ application/json:
109
+ schema:
110
+ type: object
111
+ properties:
112
+ accessToken:
113
+ type: string
114
+ refreshToken:
115
+ type: string
116
+ '401':
117
+ description: Invalid refresh token
118
+ /api/auth/logout:
119
+ post:
120
+ summary: Logout and revoke refresh token
121
+ tags:
122
+ - Auth
123
+ security:
124
+ - bearerAuth: []
125
+ requestBody:
126
+ content:
127
+ application/json:
128
+ schema:
129
+ type: object
130
+ properties:
131
+ refreshToken:
132
+ type: string
133
+ responses:
134
+ '200':
135
+ description: Logged out successfully
136
+ content:
137
+ application/json:
138
+ schema:
139
+ type: object
140
+ properties:
141
+ message:
142
+ type: string
143
+ <%_ } -%>
34
144
  /api/users:
35
145
  get:
36
146
  summary: Returns the list of all the users
@@ -45,6 +155,10 @@ paths:
45
155
  type: array
46
156
  items:
47
157
  $ref: '#/components/schemas/User'
158
+ <%_ if (auth.includes('JWT')) { -%>
159
+ security:
160
+ - bearerAuth: []
161
+ <%_ } -%>
48
162
  post:
49
163
  summary: Create a new user
50
164
  tags:
@@ -65,6 +179,32 @@ paths:
65
179
  '500':
66
180
  description: Some server error
67
181
  /api/users/{id}:
182
+ get:
183
+ summary: Get a user by ID
184
+ tags:
185
+ - Users
186
+ parameters:
187
+ - in: path
188
+ name: id
189
+ schema:
190
+ type: string
191
+ required: true
192
+ description: The user id
193
+ responses:
194
+ '200':
195
+ description: The user details
196
+ content:
197
+ application/json:
198
+ schema:
199
+ $ref: '#/components/schemas/User'
200
+ '404':
201
+ description: User not found
202
+ '500':
203
+ description: Some server error
204
+ <%_ if (auth.includes('JWT')) { -%>
205
+ security:
206
+ - bearerAuth: []
207
+ <%_ } -%>
68
208
  patch:
69
209
  summary: Update an existing user
70
210
  tags:
@@ -98,6 +238,10 @@ paths:
98
238
  description: User not found
99
239
  '500':
100
240
  description: Some server error
241
+ <%_ if (auth.includes('JWT')) { -%>
242
+ security:
243
+ - bearerAuth: []
244
+ <%_ } -%>
101
245
  delete:
102
246
  summary: Delete an existing user
103
247
  tags:
@@ -116,3 +260,7 @@ paths:
116
260
  description: User not found
117
261
  '500':
118
262
  description: Some server error
263
+ <%_ if (auth.includes('JWT')) { -%>
264
+ security:
265
+ - bearerAuth: []
266
+ <%_ } -%>
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "allowJs": true
6
+ },
7
+ "include": [
8
+ "src/**/*",
9
+ "tests/**/*",
10
+ "migrations/**/*.js",
11
+ "*.js",
12
+ "*.mjs",
13
+ "scripts/**/*.js"
14
+ ]
15
+ }
@@ -10,7 +10,8 @@
10
10
  "forceConsistentCasingInFileNames": true,
11
11
  "baseUrl": ".",
12
12
  "paths": {
13
- "@/*": ["src/*"]
13
+ "@/*": ["src/*"],
14
+ "@tests/*": ["tests/*"]
14
15
  }
15
16
  },
16
17
  "include": [