@mshima/generator-jhipster-nodejs 0.0.0-stage → 0.0.2

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 (216) hide show
  1. package/LICENSE.txt +204 -0
  2. package/README.md +243 -2
  3. package/build-info.json +3 -0
  4. package/cli/cli-customizations.cjs +9 -0
  5. package/cli/cli.cjs +40 -0
  6. package/cli/logo.js +31 -0
  7. package/cli/version.cjs +12 -0
  8. package/generators/ci-cd/USAGE +5 -0
  9. package/generators/ci-cd/command.js +5 -0
  10. package/generators/ci-cd/generator.js +158 -0
  11. package/generators/ci-cd/index.js +2 -0
  12. package/generators/ci-cd/templates/.gitlab-ci.yml.ejs +137 -0
  13. package/generators/ci-cd/templates/azure-pipelines.yml.ejs +68 -0
  14. package/generators/ci-cd/templates/circle.yml.ejs +59 -0
  15. package/generators/ci-cd/templates/docker-registry.yml.ejs +58 -0
  16. package/generators/ci-cd/templates/github-ci.yml.ejs +90 -0
  17. package/generators/ci-cd/templates/jenkins/Jenkinsfile.ejs +104 -0
  18. package/generators/ci-cd/templates/jenkins/idea.gdsl +90 -0
  19. package/generators/ci-cd/templates/jenkins/jenkins.yml.ejs +33 -0
  20. package/generators/ci-cd/templates/travis.yml.ejs +75 -0
  21. package/generators/client/command.js +5 -0
  22. package/generators/client/generator.js +21 -0
  23. package/generators/client/generators/bootstrap/command.js +5 -0
  24. package/generators/client/generators/bootstrap/generator.js +28 -0
  25. package/generators/client/generators/bootstrap/index.js +2 -0
  26. package/generators/client/index.js +2 -0
  27. package/generators/common/generators/bootstrap/command.js +5 -0
  28. package/generators/common/generators/bootstrap/generator.js +37 -0
  29. package/generators/common/generators/bootstrap/index.js +2 -0
  30. package/generators/docker/command.js +5 -0
  31. package/generators/docker/generator.js +16 -0
  32. package/generators/docker/generators/bootstrap/command.js +5 -0
  33. package/generators/docker/generators/bootstrap/generator.js +56 -0
  34. package/generators/docker/generators/bootstrap/index.js +2 -0
  35. package/generators/docker/index.js +2 -0
  36. package/generators/docker/templates/docker/app.yml.ejs +25 -0
  37. package/generators/generator-nodejs-constants.js +32 -0
  38. package/generators/languages/command.js +5 -0
  39. package/generators/languages/generator.js +22 -0
  40. package/generators/languages/index.js +2 -0
  41. package/generators/languages/templates/src/main/webapp/i18n/en/home.json +19 -0
  42. package/generators/languages/templates/src/main/webapp/i18n/es/home.json +19 -0
  43. package/generators/languages/templates/src/main/webapp/i18n/it/home.json +19 -0
  44. package/generators/node-server/command.js +96 -0
  45. package/generators/node-server/entity-files.js +26 -0
  46. package/generators/node-server/files.js +254 -0
  47. package/generators/node-server/generator.js +705 -0
  48. package/generators/node-server/generators/bootstrap/command.js +5 -0
  49. package/generators/node-server/generators/bootstrap/generator.js +84 -0
  50. package/generators/node-server/generators/bootstrap/index.js +2 -0
  51. package/generators/node-server/generators/migrations/command.js +5 -0
  52. package/generators/node-server/generators/migrations/files.js +42 -0
  53. package/generators/node-server/generators/migrations/generator.js +108 -0
  54. package/generators/node-server/generators/migrations/index.js +2 -0
  55. package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityConstraintsMigration_.ts.ejs +40 -0
  56. package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityMigration_.ts.ejs +26 -0
  57. package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityRemovedMigration_.ts.ejs +15 -0
  58. package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityUpdatedConstraintsMigration_.ts.ejs +60 -0
  59. package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityUpdatedMigration_.ts.ejs +28 -0
  60. package/generators/node-server/index.js +2 -0
  61. package/generators/node-server/resources/package.json +76 -0
  62. package/generators/node-server/support/api-fake-data.js +54 -0
  63. package/generators/node-server/support/columns.js +73 -0
  64. package/generators/node-server/support/database.js +24 -0
  65. package/generators/node-server/support/entity-authorities.js +32 -0
  66. package/generators/node-server/support/entity-paths.js +13 -0
  67. package/generators/node-server/support/enums.js +11 -0
  68. package/generators/node-server/support/index.js +9 -0
  69. package/generators/node-server/support/mail-templates.js +82 -0
  70. package/generators/node-server/support/migrations.js +376 -0
  71. package/generators/node-server/support/validators.js +25 -0
  72. package/generators/node-server/templates/.dockerignore.ejs +16 -0
  73. package/generators/node-server/templates/.gitignore.jhi.nodejs.ejs +24 -0
  74. package/generators/node-server/templates/Dockerfile.ejs +54 -0
  75. package/generators/node-server/templates/README.md.jhi.nodejs.ejs +220 -0
  76. package/generators/node-server/templates/package.json.ejs +82 -0
  77. package/generators/node-server/templates/server/README.md.ejs +277 -0
  78. package/generators/node-server/templates/server/e2e/_entityFileName_.database.e2e-spec.ts.ejs +192 -0
  79. package/generators/node-server/templates/server/e2e/_entityFileName_.e2e-spec.ts.ejs +402 -0
  80. package/generators/node-server/templates/server/e2e/account.e2e-spec.ts.ejs +349 -0
  81. package/generators/node-server/templates/server/e2e/app.e2e-spec.ts.ejs +188 -0
  82. package/generators/node-server/templates/server/e2e/authority.e2e-spec.ts.ejs +50 -0
  83. package/generators/node-server/templates/server/e2e/cors.e2e-spec.ts.ejs +110 -0
  84. package/generators/node-server/templates/server/e2e/management.e2e-spec.ts.ejs +180 -0
  85. package/generators/node-server/templates/server/e2e/oauth2-bearer.e2e-spec.ts.ejs +71 -0
  86. package/generators/node-server/templates/server/e2e/session.e2e-spec.ts.ejs +234 -0
  87. package/generators/node-server/templates/server/e2e/setup.test.js.ejs +1 -0
  88. package/generators/node-server/templates/server/e2e/user.e2e-spec.ts.ejs +318 -0
  89. package/generators/node-server/templates/server/env.ejs +1 -0
  90. package/generators/node-server/templates/server/eslint.config.mjs.ejs +48 -0
  91. package/generators/node-server/templates/server/nest-cli.json.ejs +11 -0
  92. package/generators/node-server/templates/server/ormconfig.ts.ejs +35 -0
  93. package/generators/node-server/templates/server/package.json.ejs +143 -0
  94. package/generators/node-server/templates/server/sonar-project.properties.ejs +10 -0
  95. package/generators/node-server/templates/server/src/app.config.spec.ts.ejs +13 -0
  96. package/generators/node-server/templates/server/src/app.config.ts.ejs +179 -0
  97. package/generators/node-server/templates/server/src/app.module.ts.ejs +80 -0
  98. package/generators/node-server/templates/server/src/application-config.ts.ejs +153 -0
  99. package/generators/node-server/templates/server/src/auth/account.controller.ts.ejs +183 -0
  100. package/generators/node-server/templates/server/src/auth/auth.module.ts.ejs +104 -0
  101. package/generators/node-server/templates/server/src/auth/auth.service.ts.ejs +294 -0
  102. package/generators/node-server/templates/server/src/auth/csrf.middleware.spec.ts.ejs +76 -0
  103. package/generators/node-server/templates/server/src/auth/csrf.middleware.ts.ejs +85 -0
  104. package/generators/node-server/templates/server/src/auth/decorators/auth-user.decorator.ts.ejs +8 -0
  105. package/generators/node-server/templates/server/src/auth/decorators/roles.decorator.ts.ejs +4 -0
  106. package/generators/node-server/templates/server/src/auth/dto/key-and-password.dto.ts.ejs +17 -0
  107. package/generators/node-server/templates/server/src/auth/dto/password-change.dto.ts.ejs +17 -0
  108. package/generators/node-server/templates/server/src/auth/dto/user-login.dto.ts.ejs +21 -0
  109. package/generators/node-server/templates/server/src/auth/guards/auth.guard.ts.ejs +50 -0
  110. package/generators/node-server/templates/server/src/auth/guards/oauth2-login.guard.ts.ejs +6 -0
  111. package/generators/node-server/templates/server/src/auth/guards/roles.guard.ts.ejs +25 -0
  112. package/generators/node-server/templates/server/src/auth/index.ts.ejs +8 -0
  113. package/generators/node-server/templates/server/src/auth/jwt.config.spec.ts.ejs +22 -0
  114. package/generators/node-server/templates/server/src/auth/jwt.config.ts.ejs +29 -0
  115. package/generators/node-server/templates/server/src/auth/oauth2.authorities.spec.ts.ejs +24 -0
  116. package/generators/node-server/templates/server/src/auth/oauth2.authorities.ts.ejs +33 -0
  117. package/generators/node-server/templates/server/src/auth/oauth2.config.ts.ejs +51 -0
  118. package/generators/node-server/templates/server/src/auth/passport.jwt.strategy.ts.ejs +45 -0
  119. package/generators/node-server/templates/server/src/auth/passport.oauth2-bearer.strategy.ts.ejs +32 -0
  120. package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.spec.ts.ejs +27 -0
  121. package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.ts.ejs +44 -0
  122. package/generators/node-server/templates/server/src/auth/password-util.ts.ejs +10 -0
  123. package/generators/node-server/templates/server/src/auth/password.service.ts.ejs +34 -0
  124. package/generators/node-server/templates/server/src/auth/payload.interface.ts.ejs +14 -0
  125. package/generators/node-server/templates/server/src/auth/role-type.ts.ejs +7 -0
  126. package/generators/node-server/templates/server/src/auth/session-user.middleware.ts.ejs +33 -0
  127. package/generators/node-server/templates/server/src/auth/session.entity.ts.ejs +36 -0
  128. package/generators/node-server/templates/server/src/auth/session.store.spec.ts.ejs +99 -0
  129. package/generators/node-server/templates/server/src/auth/session.store.ts.ejs +116 -0
  130. package/generators/node-server/templates/server/src/auth/user.jwt.controller.ts.ejs +26 -0
  131. package/generators/node-server/templates/server/src/auth/user.oauth2.controller.ts.ejs +78 -0
  132. package/generators/node-server/templates/server/src/auth/user.session.controller.ts.ejs +103 -0
  133. package/generators/node-server/templates/server/src/common/common.module.ts.ejs +19 -0
  134. package/generators/node-server/templates/server/src/common/database/base.entity.ts.ejs +13 -0
  135. package/generators/node-server/templates/server/src/common/database/column-transformers.spec.ts.ejs +46 -0
  136. package/generators/node-server/templates/server/src/common/database/column-transformers.ts.ejs +69 -0
  137. package/generators/node-server/templates/server/src/common/database/column-types.spec.ts.ejs +21 -0
  138. package/generators/node-server/templates/server/src/common/database/column-types.ts.ejs +29 -0
  139. package/generators/node-server/templates/server/src/common/database/pagination.entity.spec.ts.ejs +66 -0
  140. package/generators/node-server/templates/server/src/common/database/pagination.entity.ts.ejs +108 -0
  141. package/generators/node-server/templates/server/src/common/dto/base.dto.ts.ejs +19 -0
  142. package/generators/node-server/templates/server/src/common/errors/error-constants.ts.ejs +10 -0
  143. package/generators/node-server/templates/server/src/common/errors/problem-details.filter.ts.ejs +63 -0
  144. package/generators/node-server/templates/server/src/common/errors/problem.exception.ts.ejs +92 -0
  145. package/generators/node-server/templates/server/src/common/field_validators.ejs +77 -0
  146. package/generators/node-server/templates/server/src/common/header-util.ts.ejs +105 -0
  147. package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.spec.ts.ejs +93 -0
  148. package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.ts.ejs +48 -0
  149. package/generators/node-server/templates/server/src/common/logging.spec.ts.ejs +83 -0
  150. package/generators/node-server/templates/server/src/common/logging.ts.ejs +129 -0
  151. package/generators/node-server/templates/server/src/common/metrics.spec.ts.ejs +43 -0
  152. package/generators/node-server/templates/server/src/common/metrics.ts.ejs +198 -0
  153. package/generators/node-server/templates/server/src/common/request.ts.ejs +8 -0
  154. package/generators/node-server/templates/server/src/common/sortable-properties.ts.ejs +43 -0
  155. package/generators/node-server/templates/server/src/common/updatable-properties.ts.ejs +14 -0
  156. package/generators/node-server/templates/server/src/config/application-dev.yml.ejs +118 -0
  157. package/generators/node-server/templates/server/src/config/application-prod.yml.ejs +97 -0
  158. package/generators/node-server/templates/server/src/config/application-secret-samples.yml.ejs +42 -0
  159. package/generators/node-server/templates/server/src/config/application-test.yml.ejs +68 -0
  160. package/generators/node-server/templates/server/src/config/application-tls-samples.yml.ejs +15 -0
  161. package/generators/node-server/templates/server/src/config/application-tls.yml.ejs +15 -0
  162. package/generators/node-server/templates/server/src/config/application.yml.ejs +149 -0
  163. package/generators/node-server/templates/server/src/config.spec.ts.ejs +81 -0
  164. package/generators/node-server/templates/server/src/config.ts.ejs +255 -0
  165. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.controller.ts.ejs +178 -0
  166. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.entity.ts.ejs +110 -0
  167. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.mapper.ts.ejs +37 -0
  168. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.module.ts.ejs +14 -0
  169. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.service.ts.ejs +123 -0
  170. package/generators/node-server/templates/server/src/entities/_entityFileName_/dto/_entityFileName_.dto.ts.ejs +99 -0
  171. package/generators/node-server/templates/server/src/mail/mail.module.ts.ejs +49 -0
  172. package/generators/node-server/templates/server/src/mail/mail.service.spec.ts.ejs +105 -0
  173. package/generators/node-server/templates/server/src/mail/mail.service.ts.ejs +120 -0
  174. package/generators/node-server/templates/server/src/main.ts.ejs +114 -0
  175. package/generators/node-server/templates/server/src/management/api-docs.controller.ts.ejs +27 -0
  176. package/generators/node-server/templates/server/src/management/api-docs.service.ts.ejs +8 -0
  177. package/generators/node-server/templates/server/src/management/configuration.controller.ts.ejs +80 -0
  178. package/generators/node-server/templates/server/src/management/health.controller.spec.ts.ejs +79 -0
  179. package/generators/node-server/templates/server/src/management/health.controller.ts.ejs +87 -0
  180. package/generators/node-server/templates/server/src/management/health.module.ts.ejs +9 -0
  181. package/generators/node-server/templates/server/src/management/loggers.controller.ts.ejs +40 -0
  182. package/generators/node-server/templates/server/src/management/management.controller.spec.ts.ejs +26 -0
  183. package/generators/node-server/templates/server/src/management/management.controller.ts.ejs +34 -0
  184. package/generators/node-server/templates/server/src/management/management.module.ts.ejs +21 -0
  185. package/generators/node-server/templates/server/src/management/metrics.controller.ts.ejs +85 -0
  186. package/generators/node-server/templates/server/src/migrations/1570200270081-CreateTables.ts.ejs +64 -0
  187. package/generators/node-server/templates/server/src/migrations/1570200270082-CreateSessions.ts.ejs +26 -0
  188. package/generators/node-server/templates/server/src/migrations/1570200490072-SeedUsersRoles.ts.ejs +74 -0
  189. package/generators/node-server/templates/server/src/migrations/support/schema.ts.ejs +254 -0
  190. package/generators/node-server/templates/server/src/orm.config.ts.ejs +147 -0
  191. package/generators/node-server/templates/server/src/registry/consul.service.ts.ejs +70 -0
  192. package/generators/node-server/templates/server/src/registry/eureka.service.ts.ejs +129 -0
  193. package/generators/node-server/templates/server/src/swagger.ts.ejs +24 -0
  194. package/generators/node-server/templates/server/src/tls.ts.ejs +27 -0
  195. package/generators/node-server/templates/server/src/users/authority.controller.ts.ejs +85 -0
  196. package/generators/node-server/templates/server/src/users/authority.entity.ts.ejs +22 -0
  197. package/generators/node-server/templates/server/src/users/dto/authority.dto.ts.ejs +10 -0
  198. package/generators/node-server/templates/server/src/users/dto/user.dto.ts.ejs +116 -0
  199. package/generators/node-server/templates/server/src/users/public.user.controller.ts.ejs +51 -0
  200. package/generators/node-server/templates/server/src/users/user.controller.ts.ejs +191 -0
  201. package/generators/node-server/templates/server/src/users/user.entity.ts.ejs +63 -0
  202. package/generators/node-server/templates/server/src/users/user.mapper.ts.ejs +26 -0
  203. package/generators/node-server/templates/server/src/users/user.module.ts.ejs +19 -0
  204. package/generators/node-server/templates/server/src/users/user.service.ts.ejs +156 -0
  205. package/generators/node-server/templates/server/tsconfig.build.json.ejs +9 -0
  206. package/generators/node-server/templates/server/tsconfig.json.ejs +23 -0
  207. package/generators/node-server/templates/server/typeorm-migration.ts.ejs +18 -0
  208. package/generators/node-server/templates/server/vitest.config.e2e.ts.ejs +16 -0
  209. package/generators/node-server/templates/server/vitest.config.ts.ejs +16 -0
  210. package/generators/server/command.js +7 -0
  211. package/generators/server/generator.js +20 -0
  212. package/generators/server/generators/bootstrap/command.js +5 -0
  213. package/generators/server/generators/bootstrap/generator.js +15 -0
  214. package/generators/server/generators/bootstrap/index.js +2 -0
  215. package/generators/server/index.js +2 -0
  216. package/package.json +75 -4
@@ -0,0 +1,349 @@
1
+ import { afterEach, beforeEach, describe, expect, it, type MockInstance, vi } from 'vitest';
2
+ import { Test, TestingModule } from '@nestjs/testing';
3
+ import request from 'supertest';
4
+ import { AppModule } from '../src/app.module.ts';
5
+ import { configureApp } from '../src/app.config.ts';
6
+ import { ExecutionContext, INestApplication } from '@nestjs/common';
7
+ import { AuthGuard } from '../src/auth/guards/auth.guard.ts';
8
+ import { RolesGuard } from '../src/auth/guards/roles.guard.ts';
9
+ import { <%= user.dtoClass%> } from '../src/users/dto/user.dto.ts';
10
+ import { UserService } from '../src/users/user.service.ts';
11
+ import { PasswordChangeDTO } from '../src/auth/dto/password-change.dto.ts';
12
+ import { AuthService } from '../src/auth/auth.service.ts';
13
+ import { MailService } from '../src/mail/mail.service.ts';
14
+
15
+ describe('Account', () => {
16
+ let app: INestApplication;
17
+ let service: UserService;
18
+ let authService: AuthService;
19
+ let sendActivationEmail: MockInstance<MailService['sendActivationEmail']>;
20
+ let sendPasswordResetMail: MockInstance<MailService['sendPasswordResetMail']>;
21
+
22
+ const testUserDTO: <%= user.dtoClass%> = {
23
+ login: 'userTestLogin',
24
+ email: 'usertest@localhost.it',
25
+ password: 'testPassword',
26
+ };
27
+
28
+ // Saved before each test, with the id the database gives it: the authenticated user of the requests.
29
+ const testUserAuthenticated: any = {
30
+ login: 'userlogged',
31
+ email: 'userlogged@localhost.it',
32
+ password: 'userloggedPassword',
33
+ activated: true
34
+ };
35
+
36
+ const testPasswordChange: PasswordChangeDTO = {
37
+ currentPassword: testUserAuthenticated.password,
38
+ newPassword: 'newPassword',
39
+ };
40
+
41
+ let userAuthenticated: <%= user.dtoClass%>;
42
+
43
+ const authGuardMock = { canActivate: (context: ExecutionContext): any => {
44
+ const req = context.switchToHttp().getRequest();
45
+ req.user = userAuthenticated;
46
+ return true;
47
+ },
48
+ };
49
+
50
+ const rolesGuardMock = { canActivate: (): any => true };
51
+
52
+
53
+ beforeEach(async () => {
54
+ const moduleFixture: TestingModule = await Test.createTestingModule({
55
+ imports: [AppModule],
56
+ })
57
+ .overrideGuard(AuthGuard)
58
+ .useValue(authGuardMock)
59
+ .overrideGuard(RolesGuard)
60
+ .useValue(rolesGuardMock)
61
+ .compile();
62
+
63
+ app = moduleFixture.createNestApplication();
64
+ configureApp(app);
65
+ await app.init();
66
+ service = moduleFixture.get<UserService>(UserService);
67
+ authService = moduleFixture.get<AuthService>(AuthService);
68
+ // The mails are not sent, the tests check the users they are for.
69
+ const mailService = moduleFixture.get<MailService>(MailService);
70
+ sendActivationEmail = vi.spyOn(mailService, 'sendActivationEmail').mockResolvedValue();
71
+ sendPasswordResetMail = vi.spyOn(mailService, 'sendPasswordResetMail').mockResolvedValue();
72
+ userAuthenticated = await service.save(testUserAuthenticated, testUserAuthenticated.login, true);
73
+ });
74
+
75
+ it('/POST register new user', async () => {
76
+ const createdUser: <%= user.dtoClass%> = (
77
+ await request(app.getHttpServer())
78
+ .post('/api/register')
79
+ .send({ ...testUserDTO, activated: true })
80
+ .expect(201)
81
+ ).body;
82
+
83
+ // Like JHipster Spring Boot, the login in lower case, and a user not activated whatever the request.
84
+ expect(createdUser.login).toEqual(testUserDTO.login.toLowerCase());
85
+ // The activation key goes by mail only.
86
+ expect(createdUser.activationKey).toBeUndefined();
87
+ const registeredUser = (await service.findByFields({ where: { login: testUserDTO.login.toLowerCase() } }))!;
88
+ expect(registeredUser.activated).toBe(false);
89
+ expect(registeredUser.activationKey).toBeTruthy();
90
+ expect(sendActivationEmail).toHaveBeenCalledWith(expect.objectContaining({ login: registeredUser.login, activationKey: registeredUser.activationKey }));
91
+ await service.delete(registeredUser);
92
+ });
93
+
94
+ it('/POST register with the login of a not activated user replaces it', async () => {
95
+ await request(app.getHttpServer()).post('/api/register').send(testUserDTO).expect(201);
96
+ await request(app.getHttpServer())
97
+ .post('/api/register')
98
+ .send({ ...testUserDTO, email: 'usertest2@localhost.it' })
99
+ .expect(201);
100
+
101
+ const registeredUser = (await service.findByFields({ where: { login: testUserDTO.login.toLowerCase() } }))!;
102
+ expect(registeredUser.email).toEqual('usertest2@localhost.it');
103
+ await service.delete(registeredUser);
104
+ });
105
+
106
+ it('/POST register with a too short password is a validation error, like the ManagedUserVM of JHipster Spring Boot', async () => {
107
+ const problem = (
108
+ await request(app.getHttpServer())
109
+ .post('/api/register')
110
+ .send({ ...testUserDTO, password: 'abc' })
111
+ .expect(400)
112
+ ).body;
113
+
114
+ expect(problem).toMatchObject({
115
+ type: 'https://www.jhipster.tech/problem/constraint-violation',
116
+ fieldErrors: [expect.objectContaining({ field: 'password' })],
117
+ });
118
+ expect(await service.findByFields({ where: { login: testUserDTO.login.toLowerCase() } })).toBeFalsy();
119
+ });
120
+
121
+ it('/POST register with a mail of a domain without a top level domain, like the seed users', async () => {
122
+ await request(app.getHttpServer())
123
+ .post('/api/register')
124
+ .send({ ...testUserDTO, email: 'usertest@localhost' })
125
+ .expect(201);
126
+ const registeredUser = (await service.findByFields({ where: { login: testUserDTO.login.toLowerCase() } }))!;
127
+ expect(registeredUser.email).toBe('usertest@localhost');
128
+ await service.delete(registeredUser);
129
+ });
130
+
131
+ it('/POST register with an invalid login or email is a validation error', async () => {
132
+ const problem = (
133
+ await request(app.getHttpServer())
134
+ .post('/api/register')
135
+ .send({ ...testUserDTO, login: 'user name!', email: 'not an email' })
136
+ .expect(400)
137
+ ).body;
138
+
139
+ expect(problem).toMatchObject({ type: 'https://www.jhipster.tech/problem/constraint-violation' });
140
+ expect(problem.fieldErrors.map(({ field }: { field: string }) => field).sort()).toEqual(['email', 'login']);
141
+ });
142
+
143
+ it('/POST register with the login of another user is a login already used problem', async () => {
144
+ const problem = (
145
+ await request(app.getHttpServer())
146
+ .post('/api/register')
147
+ .send({ ...testUserDTO, login: testUserAuthenticated.login })
148
+ .expect(400)
149
+ ).body;
150
+
151
+ // The type the registration page of the JHipster clients reads.
152
+ expect(problem).toMatchObject({ type: 'https://www.jhipster.tech/problem/login-already-used', message: 'error.userexists' });
153
+ });
154
+
155
+ it('/POST register with the email of another user is an email already used problem', async () => {
156
+ const problem = (
157
+ await request(app.getHttpServer())
158
+ .post('/api/register')
159
+ .send({ ...testUserDTO, email: testUserAuthenticated.email })
160
+ .expect(400)
161
+ ).body;
162
+
163
+ expect(problem).toMatchObject({ type: 'https://www.jhipster.tech/problem/email-already-used', message: 'error.emailexists' });
164
+ });
165
+
166
+ it('/GET activate account', async () => {
167
+ await request(app.getHttpServer()).post('/api/register').send(testUserDTO).expect(201);
168
+ const { activationKey } = (await service.findByFields({ where: { login: testUserDTO.login.toLowerCase() } }))!;
169
+
170
+ await request(app.getHttpServer())
171
+ .get('/api/activate')
172
+ .query({ key: activationKey })
173
+ .expect(200);
174
+
175
+ const activatedUser = (await service.findByFields({ where: { login: testUserDTO.login.toLowerCase() } }))!;
176
+ expect(activatedUser.activated).toBe(true);
177
+ expect(activatedUser.activationKey).toBeFalsy();
178
+ await service.delete(activatedUser);
179
+ });
180
+
181
+ it('/GET activate account with an unknown key', async () => {
182
+ await request(app.getHttpServer())
183
+ .get('/api/activate')
184
+ .query({ key: 'unknownKey' })
185
+ .expect(500);
186
+ });
187
+
188
+ it('/GET activate account without key', async () => {
189
+ await request(app.getHttpServer())
190
+ .get('/api/activate')
191
+ .expect(500);
192
+ });
193
+
194
+
195
+ it('/GET authenticate', async () => {
196
+ const loginValue: any = (await request(app.getHttpServer())
197
+ .get('/api/authenticate')
198
+ .expect(200)).text;
199
+
200
+ expect(loginValue).toEqual(testUserAuthenticated.login);
201
+ });
202
+
203
+ it('/GET account', async () => {
204
+
205
+ const loggedUser: any = JSON.parse(( await request(app.getHttpServer())
206
+ .get('/api/account')
207
+ .expect(200)).text);
208
+
209
+ expect(String(loggedUser.id)).toEqual(String(userAuthenticated.id));
210
+ expect(loggedUser.login).toEqual(userAuthenticated.login);
211
+ expect(loggedUser.email).toEqual(userAuthenticated.email);
212
+
213
+ });
214
+
215
+ it('/POST account update settings', async () => {
216
+
217
+ const savedTestUser: <%= user.dtoClass%> = {
218
+ firstName: 'updateFirstName',
219
+ lastName: 'updateLastName',
220
+ ...testUserAuthenticated,
221
+ };
222
+ await request(app.getHttpServer())
223
+ .post('/api/account')
224
+ .send(savedTestUser)
225
+ .expect(200);
226
+
227
+ const updatedUserSettings = await service.findByFields({ where: { login: testUserAuthenticated.login } });
228
+ expect(updatedUserSettings?.firstName).toEqual(savedTestUser.firstName);
229
+ expect(updatedUserSettings?.lastName).toEqual(savedTestUser.lastName);
230
+
231
+ });
232
+
233
+ it('/POST account update settings keeps the mail in lower case, like JHipster Spring Boot', async () => {
234
+ await request(app.getHttpServer())
235
+ .post('/api/account')
236
+ .send({ ...testUserAuthenticated, email: 'UserLogged@LocalHost.it' })
237
+ .expect(200);
238
+
239
+ const updatedUserSettings = await service.findByFields({ where: { login: testUserAuthenticated.login } });
240
+ expect(updatedUserSettings?.email).toEqual('userlogged@localhost.it');
241
+ });
242
+
243
+ it('/POST account update settings with the mail of another user in another case is an email already used problem', async () => {
244
+ const otherUser = await service.save({ login: 'otheruser', email: 'otheruser@localhost.it', password: 'otherPassword' });
245
+ const problem = (
246
+ await request(app.getHttpServer())
247
+ .post('/api/account')
248
+ .send({ ...testUserAuthenticated, email: 'OtherUser@localhost.it' })
249
+ .expect(400)
250
+ ).body;
251
+
252
+ expect(problem).toMatchObject({ type: 'https://www.jhipster.tech/problem/email-already-used' });
253
+ await service.delete(otherUser);
254
+ });
255
+
256
+ it('/POST change password with a too short new password is an invalid password problem, like JHipster Spring Boot', async () => {
257
+ const problem = (
258
+ await request(app.getHttpServer())
259
+ .post('/api/account/change-password')
260
+ .send({ currentPassword: testUserAuthenticated.password, newPassword: 'abc' })
261
+ .expect(400)
262
+ ).body;
263
+
264
+ expect(problem).toMatchObject({ type: 'https://www.jhipster.tech/problem/invalid-password' });
265
+ });
266
+
267
+ it<%- databaseTypeMongodb ? '.skip' : ''%>('/POST change password', async () => {
268
+ await request(app.getHttpServer())
269
+ .post('/api/account/change-password')
270
+ .send(testPasswordChange)
271
+ .expect(200);
272
+
273
+ const successFullyLoggedInWithNewPassword = await authService
274
+ .authenticate(testUserAuthenticated.login, testPasswordChange.newPassword)
275
+ .then(() => true, () => false);
276
+
277
+ expect(successFullyLoggedInWithNewPassword).toEqual(true);
278
+ });
279
+
280
+ it<%- databaseTypeMongodb ? '.skip' : ''%>('logs in with the login in another case', async () => {
281
+ const loggedIn = await authService
282
+ .authenticate(testUserAuthenticated.login.toUpperCase(), testUserAuthenticated.password)
283
+ .then(() => true, () => false);
284
+ expect(loggedIn).toEqual(true);
285
+ });
286
+
287
+ it<%- databaseTypeMongodb ? '.skip' : ''%>('/POST change password with a wrong current password is an invalid password problem', async () => {
288
+ const problem = (
289
+ await request(app.getHttpServer())
290
+ .post('/api/account/change-password')
291
+ .send({ ...testPasswordChange, currentPassword: 'wrongPassword' })
292
+ .expect(400)
293
+ ).body;
294
+
295
+ expect(problem).toMatchObject({ type: 'https://www.jhipster.tech/problem/invalid-password', title: 'Incorrect password' });
296
+ });
297
+
298
+ it('/POST reset password init and finish', async () => {
299
+ // The mail is a text/plain body, as the JHipster clients send it.
300
+ await request(app.getHttpServer())
301
+ .post('/api/account/reset-password/init')
302
+ .set('Content-Type', 'text/plain')
303
+ .send(testUserAuthenticated.email)
304
+ .expect(200);
305
+
306
+ const { resetKey } = (await service.findByFields({ where: { login: testUserAuthenticated.login } }))!;
307
+ expect(resetKey).toBeTruthy();
308
+ expect(sendPasswordResetMail).toHaveBeenCalledWith(expect.objectContaining({ login: testUserAuthenticated.login, resetKey }));
309
+
310
+ await request(app.getHttpServer())
311
+ .post('/api/account/reset-password/finish')
312
+ .send({ key: resetKey, newPassword: 'resetPassword' })
313
+ .expect(200);
314
+
315
+ expect((await service.findByFields({ where: { login: testUserAuthenticated.login } }))?.resetKey).toBeFalsy();
316
+ const loggedInWithNewPassword = await authService
317
+ .authenticate(testUserAuthenticated.login, 'resetPassword')
318
+ .then(() => true, () => false);
319
+ expect(loggedInWithNewPassword).toEqual(true);
320
+ });
321
+
322
+ it('/POST reset password init of an unknown mail answers 200 too', async () => {
323
+ await request(app.getHttpServer())
324
+ .post('/api/account/reset-password/init')
325
+ .set('Content-Type', 'text/plain')
326
+ .send('unknown@localhost.it')
327
+ .expect(200);
328
+ expect(sendPasswordResetMail).not.toHaveBeenCalled();
329
+ });
330
+
331
+ it('/POST reset password finish with an unknown key', async () => {
332
+ await request(app.getHttpServer())
333
+ .post('/api/account/reset-password/finish')
334
+ .send({ key: 'unknownKey', newPassword: 'resetPassword' })
335
+ .expect(500);
336
+ });
337
+
338
+ it('/POST reset password finish with a too short password is a validation error', async () => {
339
+ await request(app.getHttpServer())
340
+ .post('/api/account/reset-password/finish')
341
+ .send({ key: 'unknownKey', newPassword: 'a' })
342
+ .expect(400);
343
+ });
344
+
345
+ afterEach(async () => {
346
+ await service.delete(userAuthenticated);
347
+ await app?.close();
348
+ });
349
+ });
@@ -0,0 +1,188 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
+ import { Test, TestingModule } from '@nestjs/testing';
3
+ import request from 'supertest';
4
+ import { AppModule } from '../src/app.module.ts';
5
+ import { configureApp } from '../src/app.config.ts';
6
+ import { INestApplication } from '@nestjs/common';
7
+ <%_ if (authenticationType === 'jwt') { _%>
8
+ import { JwtService } from '@nestjs/jwt';
9
+ <%_ } _%>
10
+ <%_ if (authenticationType === 'jwt' && generateUserManagement) { _%>
11
+ import { UserLoginDTO } from '../src/auth/dto/user-login.dto.ts';
12
+ <%_ } else if (authenticationType === 'jwt') { _%>
13
+ import { ConfigService } from '@nestjs/config';
14
+ import { JWT_ALGORITHM, jwtSecretKey } from '../src/auth/jwt.config.ts';
15
+ <%_ } else if (authenticationType === 'oauth2' && generateBuiltInUserEntity) { _%>
16
+ import { oidcUserOfClaims } from '../src/auth/oauth2.authorities.ts';
17
+ import { AuthService } from '../src/auth/auth.service.ts';
18
+ import { UserService } from '../src/users/user.service.ts';
19
+ <%_ } _%>
20
+
21
+ describe('App', () => {
22
+ let app: INestApplication;
23
+
24
+ // The test profile and the profiles of its group (application.yml).
25
+ const infoService = {
26
+ activeProfiles: ['test', 'secret-samples'],
27
+ 'display-ribbon-on-profiles': 'dev',
28
+ };
29
+ <%_ if (authenticationType === 'jwt' && generateUserManagement) { _%>
30
+ const testUserLogin: UserLoginDTO = {
31
+ username: 'admin',
32
+ password: 'admin',
33
+ rememberMe: true
34
+ };
35
+ <%_ } else if (authenticationType === 'oauth2') { _%>
36
+
37
+ const testRequest: any = {};
38
+ <%_ }_%>
39
+
40
+ beforeEach(async () => {
41
+ const moduleFixture: TestingModule = await Test.createTestingModule({
42
+ imports: [AppModule],
43
+ }).compile();
44
+
45
+ app = moduleFixture.createNestApplication();
46
+ configureApp(app);
47
+ await app.init();
48
+ });
49
+
50
+ it('/GET up running info OK', () => request(app.getHttpServer())
51
+ .get('/management/info')
52
+ .expect(200)
53
+ .expect(infoService));
54
+
55
+ it('/GET the headers of the responses, like JHipster Spring Boot', async () => {
56
+ const response = await request(app.getHttpServer())
57
+ .get('/management/info')
58
+ .expect(200)
59
+ .expect('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
60
+ .expect('Pragma', 'no-cache')
61
+ .expect('Expires', '0')
62
+ .expect('X-Content-Type-Options', 'nosniff')
63
+ .expect('X-XSS-Protection', '0')
64
+ <%_ if (skipClient) { _%>
65
+ .expect('X-Frame-Options', 'DENY');
66
+ <%_ } else { _%>
67
+ .expect('X-Frame-Options', 'SAMEORIGIN')
68
+ .expect('Referrer-Policy', 'strict-origin-when-cross-origin')
69
+ .expect('Content-Security-Policy', /^default-src 'self';/)
70
+ .expect('Permissions-Policy', /camera=\(\)/);
71
+ <%_ } _%>
72
+ expect(response.headers['x-powered-by']).toBeUndefined();
73
+ // Only on HTTPS requests.
74
+ expect(response.headers['strict-transport-security']).toBeUndefined();
75
+ });
76
+
77
+ it('/GET the API is not cached whatever the case of its path, like Express routes it', () => request(app.getHttpServer())
78
+ .get('/MANAGEMENT/info')
79
+ .expect(200)
80
+ .expect('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate'));
81
+
82
+ it('/GET an unknown path of the API is not found, not the client', () => request(app.getHttpServer())
83
+ .get('/api/unknown-resource')
84
+ .expect(404));
85
+
86
+ it('/GET health is UP without authentication', () => request(app.getHttpServer())
87
+ .get('/management/health')
88
+ .expect(200)
89
+ .expect({ status: 'UP', components: { db: { status: 'UP' } } }));
90
+
91
+ it('/GET the liveness and readiness probes are UP without authentication', async () => {
92
+ await request(app.getHttpServer()).get('/management/health/liveness').expect(200).expect({ status: 'UP' });
93
+ await request(app.getHttpServer()).get('/management/health/readiness').expect(200).expect({ status: 'UP' });
94
+ });
95
+
96
+ <%_ if (generateUserManagement) { _%>
97
+ it('/GET the authorities without authentication is unauthorized, like JHipster Spring Boot', () => request(app.getHttpServer())
98
+ .get('/api/authorities')
99
+ .expect(401));
100
+
101
+ it('/GET public users without authentication is unauthorized, like JHipster Spring Boot', () => request(app.getHttpServer())
102
+ .get('/api/users')
103
+ .expect(401));
104
+ <%_ } _%>
105
+
106
+ <%_ if (authenticationType === 'jwt' && generateUserManagement) { _%>
107
+ it<%- databaseTypeMongodb ? '.skip' : ''%>('/POST authenticate get jwt authenticate OK', () => request(app.getHttpServer())
108
+ .post('/api/authenticate')
109
+ .send(testUserLogin)
110
+ .expect(200));
111
+
112
+ it('/POST authenticate without credentials is a validation error', () => request(app.getHttpServer())
113
+ .post('/api/authenticate')
114
+ .send({})
115
+ .expect(400)
116
+ .expect(response => expect(response.body).toMatchObject({ message: 'error.validation', fieldErrors: expect.arrayContaining([expect.objectContaining({ field: 'username' })]) })));
117
+
118
+ it('/GET account with an expired jwt is unauthorized', () => {
119
+ const expiredToken = app.get(JwtService).sign({ sub: 'admin', auth: '' }, { expiresIn: -10 });
120
+ return request(app.getHttpServer())
121
+ .get('/api/account')
122
+ .set('Authorization', `Bearer ${expiredToken}`)
123
+ .expect(401);
124
+ });
125
+ <%_ } else if (authenticationType === 'jwt') { _%>
126
+ describe('with a token of the gateway', () => {
127
+ // Signed like a JHipster Spring Boot gateway: HS512 with the base64 decoded secret, login as subject, authorities in auth.
128
+ const gatewayJwtService = (): JwtService =>
129
+ new JwtService({ secret: jwtSecretKey(app.get(ConfigService)), signOptions: { algorithm: JWT_ALGORITHM } });
130
+
131
+ it('/GET account is the user of the token', () => {
132
+ const token = gatewayJwtService().sign({ sub: 'gateway-user', auth: 'ROLE_USER ROLE_ADMIN', userId: 1 });
133
+ return request(app.getHttpServer())
134
+ .get('/api/account')
135
+ .set('Authorization', `Bearer ${token}`)
136
+ .expect(200)
137
+ .expect(res => expect(res.body).toMatchObject({ login: 'gateway-user', authorities: ['ROLE_USER', 'ROLE_ADMIN'] }));
138
+ });
139
+
140
+ it('/GET account without a token is unauthorized', () => request(app.getHttpServer())
141
+ .get('/api/account')
142
+ .expect(401));
143
+
144
+ it('/GET account with an expired token is unauthorized', () => {
145
+ const expiredToken = gatewayJwtService().sign({ sub: 'gateway-user', auth: '' }, { expiresIn: -10 });
146
+ return request(app.getHttpServer())
147
+ .get('/api/account')
148
+ .set('Authorization', `Bearer ${expiredToken}`)
149
+ .expect(401);
150
+ });
151
+
152
+ it('/GET account with a token signed with the encoded secret is unauthorized', () => {
153
+ const encodedSecret = app.get(ConfigService).getOrThrow<string>('jhipster.security.authentication.jwt.base64-secret');
154
+ const token = new JwtService({ secret: encodedSecret }).sign({ sub: 'gateway-user', auth: 'ROLE_USER' });
155
+ return request(app.getHttpServer())
156
+ .get('/api/account')
157
+ .set('Authorization', `Bearer ${token}`)
158
+ .expect(401);
159
+ });
160
+ });
161
+ <%_ } else if (authenticationType === 'oauth2') { _%>
162
+ it('/POST security oauth2 does not perform logout', () => request(app.getHttpServer())
163
+ .post('/api/logout')
164
+ .send(testRequest)
165
+ .expect({})
166
+ .expect(201));
167
+
168
+ it('/GET account not logged', () => request(app.getHttpServer())
169
+ .get('/api/account')
170
+ // Like JHipster Spring Boot, the clients take a 401 for not logged.
171
+ .expect(401));
172
+ <%_ if (generateBuiltInUserEntity) { _%>
173
+
174
+ it('saves the user of the identity provider at its logins, without a password, like JHipster Spring Boot', async () => {
175
+ const authService = app.get(AuthService);
176
+ await authService.findUserOrSave(oidcUserOfClaims({ sub: 'idp-user', preferred_username: 'IdP-User', groups: ['ROLE_USER'] }));
177
+ await authService.findUserOrSave(oidcUserOfClaims({ sub: 'idp-user', preferred_username: 'idp-user', given_name: 'Updated', groups: ['ROLE_USER'] }));
178
+
179
+ const saved = await app.get(UserService).findByFields({ where: { login: 'idp-user' } });
180
+ expect(saved).toMatchObject({ login: 'idp-user', firstName: 'Updated', email: 'idp-user@localhost', activated: true });
181
+ });
182
+ <%_ } _%>
183
+ <%_ } _%>
184
+
185
+ afterEach(async () => {
186
+ await app?.close();
187
+ });
188
+ });
@@ -0,0 +1,50 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
2
+ import { INestApplication } from '@nestjs/common';
3
+ import { Test, TestingModule } from '@nestjs/testing';
4
+ import request from 'supertest';
5
+
6
+ import { configureApp } from '../src/app.config.ts';
7
+ import { AppModule } from '../src/app.module.ts';
8
+ import { AuthGuard } from '../src/auth/guards/auth.guard.ts';
9
+ import { RolesGuard } from '../src/auth/guards/roles.guard.ts';
10
+
11
+ describe('Authority Controller', () => {
12
+ let app: INestApplication;
13
+
14
+ beforeAll(async () => {
15
+ const moduleFixture: TestingModule = await Test.createTestingModule({
16
+ imports: [AppModule],
17
+ })
18
+ .overrideGuard(AuthGuard)
19
+ .useValue({ canActivate: (): any => true })
20
+ .overrideGuard(RolesGuard)
21
+ .useValue({ canActivate: (): any => true })
22
+ .compile();
23
+
24
+ app = moduleFixture.createNestApplication();
25
+ configureApp(app);
26
+ await app.init();
27
+ });
28
+
29
+ afterAll(async () => {
30
+ await app?.close();
31
+ });
32
+
33
+ it('/GET the authorities the user management assigns, like JHipster Spring Boot', async () => {
34
+ const authorities = (await request(app.getHttpServer()).get('/api/authorities').expect(200)).body;
35
+ expect(authorities).toEqual(expect.arrayContaining([{ name: 'ROLE_ADMIN' }, { name: 'ROLE_USER' }]));
36
+ });
37
+
38
+ it('/POST, /GET and /DELETE an authority, like JHipster Spring Boot', async () => {
39
+ const created = await request(app.getHttpServer()).post('/api/authorities').send({ name: 'ROLE_E2E' }).expect(201);
40
+ expect(created.body).toEqual({ name: 'ROLE_E2E' });
41
+ expect(created.headers.location).toBe('/api/authorities/ROLE_E2E');
42
+
43
+ const problem = (await request(app.getHttpServer()).post('/api/authorities').send({ name: 'ROLE_E2E' }).expect(400)).body;
44
+ expect(problem).toMatchObject({ message: 'error.idexists' });
45
+
46
+ await request(app.getHttpServer()).get('/api/authorities/ROLE_E2E').expect(200).expect({ name: 'ROLE_E2E' });
47
+ await request(app.getHttpServer()).delete('/api/authorities/ROLE_E2E').expect(204);
48
+ await request(app.getHttpServer()).get('/api/authorities/ROLE_E2E').expect(404);
49
+ });
50
+ });