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.
- package/CHANGELOG.md +26 -0
- package/README.md +44 -40
- package/bin/index.js +6 -3
- package/lib/generator.js +10 -4
- package/lib/modules/app-setup.js +76 -6
- package/lib/modules/auth-setup.js +143 -0
- package/lib/modules/caching-setup.js +8 -1
- package/lib/modules/config-files.js +10 -0
- package/lib/modules/database-setup.js +2 -1
- package/lib/modules/project-setup.js +1 -0
- package/lib/prompts.js +40 -1
- package/package.json +5 -4
- package/templates/clean-architecture/js/src/domain/models/User.js +3 -1
- package/templates/clean-architecture/js/src/index.js.ejs +2 -0
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +12 -3
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +25 -2
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +27 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +3 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.spec.js.ejs +49 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.spec.js.ejs +14 -0
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +41 -4
- package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +69 -4
- package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +38 -21
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +10 -5
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +32 -10
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +1 -1
- package/templates/clean-architecture/js/src/interfaces/routes/api.js.ejs +15 -0
- package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +4 -0
- package/templates/clean-architecture/js/src/usecases/CreateUser.js.ejs +34 -0
- package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +3 -2
- package/templates/clean-architecture/js/src/usecases/DeleteUser.js.ejs +27 -0
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js.ejs +36 -0
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +14 -0
- package/templates/clean-architecture/js/src/usecases/GetUserById.js.ejs +36 -0
- package/templates/clean-architecture/js/src/usecases/GetUserById.spec.js.ejs +48 -0
- package/templates/clean-architecture/js/src/usecases/UpdateUser.js.ejs +28 -0
- package/templates/clean-architecture/js/src/utils/errorMessages.js +1 -0
- package/templates/clean-architecture/js/src/utils/httpCodes.js +2 -0
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +12 -3
- package/templates/clean-architecture/ts/src/domain/user.ts +3 -1
- package/templates/clean-architecture/ts/src/index.ts.ejs +4 -0
- package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +55 -9
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +32 -3
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +26 -6
- package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +57 -15
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +38 -23
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +14 -8
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +33 -10
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +15 -5
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +1 -1
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +9 -1
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts.ejs +16 -0
- package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +3 -2
- package/templates/clean-architecture/ts/src/usecases/createUser.ts.ejs +35 -0
- package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +1 -0
- package/templates/clean-architecture/ts/src/usecases/deleteUser.ts.ejs +24 -0
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts.ejs +21 -0
- package/templates/clean-architecture/ts/src/usecases/getUserById.spec.ts.ejs +47 -0
- package/templates/clean-architecture/ts/src/usecases/getUserById.ts.ejs +23 -0
- package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +1 -0
- package/templates/clean-architecture/ts/src/usecases/updateUser.ts.ejs +25 -0
- package/templates/clean-architecture/ts/src/utils/errorMessages.ts +1 -0
- package/templates/clean-architecture/ts/src/utils/httpCodes.ts +1 -0
- package/templates/common/.cursorrules.ejs +9 -0
- package/templates/common/.env.example.ejs +17 -10
- package/templates/common/.gitlab-ci.yml.ejs +3 -1
- package/templates/common/Jenkinsfile.ejs +10 -1
- package/templates/common/README.md.ejs +64 -19
- package/templates/common/_circleci/config.yml.ejs +96 -0
- package/templates/common/_github/workflows/ci.yml.ejs +1 -1
- package/templates/common/auth/js/controllers/authController.js.ejs +168 -0
- package/templates/common/auth/js/controllers/authController.spec.js.ejs +148 -0
- package/templates/common/auth/js/middleware/authMiddleware.js.ejs +58 -0
- package/templates/common/auth/js/middleware/authMiddleware.spec.js.ejs +108 -0
- package/templates/common/auth/js/routes/authRoutes.js.ejs +16 -0
- package/templates/common/auth/js/services/jwtService.js.ejs +54 -0
- package/templates/common/auth/js/services/jwtService.spec.js.ejs +84 -0
- package/templates/common/auth/ts/controllers/authController.spec.ts.ejs +161 -0
- package/templates/common/auth/ts/controllers/authController.ts.ejs +165 -0
- package/templates/common/auth/ts/middleware/authMiddleware.spec.ts.ejs +128 -0
- package/templates/common/auth/ts/middleware/authMiddleware.ts.ejs +59 -0
- package/templates/common/auth/ts/routes/authRoutes.ts.ejs +20 -0
- package/templates/common/auth/ts/services/jwtService.spec.ts.ejs +89 -0
- package/templates/common/auth/ts/services/jwtService.ts.ejs +60 -0
- package/templates/common/bitbucket-pipelines.yml.ejs +60 -0
- package/templates/common/caching/clean/js/CreateUser.js.ejs +14 -5
- package/templates/common/caching/clean/js/DeleteUser.js.ejs +2 -1
- package/templates/common/caching/clean/js/GetUserById.js.ejs +39 -0
- package/templates/common/caching/clean/js/UpdateUser.js.ejs +2 -1
- package/templates/common/caching/clean/ts/createUser.ts.ejs +14 -6
- package/templates/common/caching/clean/ts/deleteUser.ts.ejs +2 -1
- package/templates/common/caching/clean/ts/getUserById.ts.ejs +32 -0
- package/templates/common/caching/clean/ts/updateUser.ts.ejs +2 -2
- package/templates/common/database/js/models/User.js.ejs +14 -1
- package/templates/common/database/js/models/User.js.mongoose.ejs +7 -0
- package/templates/common/database/js/models/User.spec.js.ejs +12 -0
- package/templates/common/database/ts/models/User.spec.ts.ejs +10 -0
- package/templates/common/database/ts/models/User.ts.ejs +17 -0
- package/templates/common/database/ts/models/User.ts.mongoose.ejs +8 -0
- package/templates/common/docker-compose.yml.ejs +14 -0
- package/templates/common/ecosystem.config.js.ejs +9 -3
- package/templates/common/eslint.config.mjs.ejs +3 -0
- package/templates/common/jest.config.js.ejs +11 -9
- package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +1 -1
- package/templates/common/kafka/js/services/kafkaService.js.ejs +1 -1
- package/templates/common/migrations/init.js.ejs +5 -4
- package/templates/common/package.json.ejs +10 -2
- package/templates/common/prompts/project-context.md.ejs +8 -1
- package/templates/common/scripts/run-e2e.js.ejs +26 -10
- package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +149 -107
- package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +88 -47
- package/templates/common/swagger.yml.ejs +148 -0
- package/templates/common/tsconfig.eslint.json +15 -0
- package/templates/common/tsconfig.json +2 -1
- package/templates/common/views/ejs/index.ejs +264 -30
- package/templates/common/views/ejs/login.ejs.ejs +244 -0
- package/templates/common/views/ejs/signup.ejs.ejs +282 -0
- package/templates/common/views/pug/index.pug +269 -38
- package/templates/common/views/pug/login.pug.ejs +195 -0
- package/templates/common/views/pug/signup.pug.ejs +241 -0
- package/templates/db/mysql/V1__Initial_Setup.sql.ejs +6 -0
- package/templates/db/postgres/V1__Initial_Setup.sql.ejs +6 -0
- package/templates/mvc/js/src/config/env.js.ejs +12 -3
- package/templates/mvc/js/src/controllers/userController.js.ejs +29 -5
- package/templates/mvc/js/src/controllers/userController.spec.js.ejs +27 -12
- package/templates/mvc/js/src/graphql/context.js.ejs +14 -3
- package/templates/mvc/js/src/graphql/context.spec.js.ejs +36 -21
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +10 -5
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +32 -10
- package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +1 -1
- package/templates/mvc/js/src/index.js.ejs +16 -3
- package/templates/mvc/js/src/routes/api.js.ejs +14 -0
- package/templates/mvc/js/src/routes/api.spec.js.ejs +3 -0
- package/templates/mvc/js/src/utils/errorMessages.js +1 -0
- package/templates/mvc/js/src/utils/httpCodes.js +1 -0
- package/templates/mvc/ts/src/config/env.ts.ejs +12 -3
- package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +95 -7
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +68 -11
- package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +36 -23
- package/templates/mvc/ts/src/graphql/context.ts.ejs +15 -6
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +32 -10
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +15 -5
- package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +1 -1
- package/templates/mvc/ts/src/index.ts.ejs +15 -3
- package/templates/mvc/ts/src/routes/api.spec.ts.ejs +6 -0
- package/templates/mvc/ts/src/routes/api.ts.ejs +15 -0
- package/templates/mvc/ts/src/utils/errorMessages.ts +1 -0
- package/templates/mvc/ts/src/utils/httpCodes.ts +1 -0
- package/templates/clean-architecture/js/src/interfaces/routes/api.js +0 -12
- package/templates/clean-architecture/js/src/usecases/CreateUser.js +0 -14
- package/templates/clean-architecture/js/src/usecases/DeleteUser.js +0 -11
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +0 -12
- package/templates/clean-architecture/js/src/usecases/UpdateUser.js +0 -11
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +0 -13
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +0 -13
- package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +0 -9
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +0 -10
- package/templates/clean-architecture/ts/src/usecases/updateUser.ts +0 -9
- package/templates/mvc/js/src/routes/api.js +0 -10
- 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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
|
62
|
-
it('should
|
|
129
|
+
<%_ } else { -%>
|
|
130
|
+
it('should fetch users successfully', async () => {
|
|
63
131
|
const response = await request(SERVER_URL)
|
|
64
|
-
.
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
expect(
|
|
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
|
|
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
|
|
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
|
+
<%_ } -%>
|