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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) 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 +41 -0
  46. package/generators/node-server/files.js +254 -0
  47. package/generators/node-server/generator.js +702 -0
  48. package/generators/node-server/generators/bootstrap/command.js +5 -0
  49. package/generators/node-server/generators/bootstrap/generator.js +83 -0
  50. package/generators/node-server/generators/bootstrap/index.js +2 -0
  51. package/generators/node-server/index.js +2 -0
  52. package/generators/node-server/resources/package.json +76 -0
  53. package/generators/node-server/support/api-fake-data.js +54 -0
  54. package/generators/node-server/support/columns.js +73 -0
  55. package/generators/node-server/support/database.js +24 -0
  56. package/generators/node-server/support/entity-authorities.js +32 -0
  57. package/generators/node-server/support/entity-paths.js +13 -0
  58. package/generators/node-server/support/enums.js +11 -0
  59. package/generators/node-server/support/index.js +9 -0
  60. package/generators/node-server/support/mail-templates.js +82 -0
  61. package/generators/node-server/support/migrations.js +197 -0
  62. package/generators/node-server/support/validators.js +25 -0
  63. package/generators/node-server/templates/.dockerignore.ejs +16 -0
  64. package/generators/node-server/templates/.gitignore.jhi.nodejs.ejs +24 -0
  65. package/generators/node-server/templates/Dockerfile.ejs +54 -0
  66. package/generators/node-server/templates/README.md.jhi.nodejs.ejs +220 -0
  67. package/generators/node-server/templates/package.json.ejs +84 -0
  68. package/generators/node-server/templates/server/README.md.ejs +269 -0
  69. package/generators/node-server/templates/server/e2e/_entityFileName_.database.e2e-spec.ts.ejs +192 -0
  70. package/generators/node-server/templates/server/e2e/_entityFileName_.e2e-spec.ts.ejs +402 -0
  71. package/generators/node-server/templates/server/e2e/account.e2e-spec.ts.ejs +349 -0
  72. package/generators/node-server/templates/server/e2e/app.e2e-spec.ts.ejs +188 -0
  73. package/generators/node-server/templates/server/e2e/authority.e2e-spec.ts.ejs +50 -0
  74. package/generators/node-server/templates/server/e2e/cors.e2e-spec.ts.ejs +110 -0
  75. package/generators/node-server/templates/server/e2e/management.e2e-spec.ts.ejs +180 -0
  76. package/generators/node-server/templates/server/e2e/oauth2-bearer.e2e-spec.ts.ejs +71 -0
  77. package/generators/node-server/templates/server/e2e/session.e2e-spec.ts.ejs +219 -0
  78. package/generators/node-server/templates/server/e2e/setup.test.js.ejs +1 -0
  79. package/generators/node-server/templates/server/e2e/user.e2e-spec.ts.ejs +318 -0
  80. package/generators/node-server/templates/server/env.ejs +1 -0
  81. package/generators/node-server/templates/server/eslint.config.mjs.ejs +48 -0
  82. package/generators/node-server/templates/server/nest-cli.json.ejs +11 -0
  83. package/generators/node-server/templates/server/ormconfig.ts.ejs +35 -0
  84. package/generators/node-server/templates/server/package.json.ejs +143 -0
  85. package/generators/node-server/templates/server/sonar-project.properties.ejs +10 -0
  86. package/generators/node-server/templates/server/src/app.config.spec.ts.ejs +13 -0
  87. package/generators/node-server/templates/server/src/app.config.ts.ejs +179 -0
  88. package/generators/node-server/templates/server/src/app.module.ts.ejs +80 -0
  89. package/generators/node-server/templates/server/src/application-config.ts.ejs +153 -0
  90. package/generators/node-server/templates/server/src/auth/account.controller.ts.ejs +183 -0
  91. package/generators/node-server/templates/server/src/auth/auth.module.ts.ejs +104 -0
  92. package/generators/node-server/templates/server/src/auth/auth.service.ts.ejs +294 -0
  93. package/generators/node-server/templates/server/src/auth/csrf.middleware.spec.ts.ejs +65 -0
  94. package/generators/node-server/templates/server/src/auth/csrf.middleware.ts.ejs +76 -0
  95. package/generators/node-server/templates/server/src/auth/decorators/auth-user.decorator.ts.ejs +8 -0
  96. package/generators/node-server/templates/server/src/auth/decorators/roles.decorator.ts.ejs +4 -0
  97. package/generators/node-server/templates/server/src/auth/dto/key-and-password.dto.ts.ejs +17 -0
  98. package/generators/node-server/templates/server/src/auth/dto/password-change.dto.ts.ejs +17 -0
  99. package/generators/node-server/templates/server/src/auth/dto/user-login.dto.ts.ejs +21 -0
  100. package/generators/node-server/templates/server/src/auth/guards/auth.guard.ts.ejs +50 -0
  101. package/generators/node-server/templates/server/src/auth/guards/oauth2-login.guard.ts.ejs +6 -0
  102. package/generators/node-server/templates/server/src/auth/guards/roles.guard.ts.ejs +25 -0
  103. package/generators/node-server/templates/server/src/auth/index.ts.ejs +8 -0
  104. package/generators/node-server/templates/server/src/auth/jwt.config.spec.ts.ejs +22 -0
  105. package/generators/node-server/templates/server/src/auth/jwt.config.ts.ejs +29 -0
  106. package/generators/node-server/templates/server/src/auth/oauth2.authorities.spec.ts.ejs +24 -0
  107. package/generators/node-server/templates/server/src/auth/oauth2.authorities.ts.ejs +33 -0
  108. package/generators/node-server/templates/server/src/auth/oauth2.config.ts.ejs +51 -0
  109. package/generators/node-server/templates/server/src/auth/passport.jwt.strategy.ts.ejs +45 -0
  110. package/generators/node-server/templates/server/src/auth/passport.oauth2-bearer.strategy.ts.ejs +32 -0
  111. package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.spec.ts.ejs +27 -0
  112. package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.ts.ejs +44 -0
  113. package/generators/node-server/templates/server/src/auth/password-util.ts.ejs +10 -0
  114. package/generators/node-server/templates/server/src/auth/password.service.ts.ejs +34 -0
  115. package/generators/node-server/templates/server/src/auth/payload.interface.ts.ejs +14 -0
  116. package/generators/node-server/templates/server/src/auth/role-type.ts.ejs +7 -0
  117. package/generators/node-server/templates/server/src/auth/session-user.middleware.ts.ejs +33 -0
  118. package/generators/node-server/templates/server/src/auth/session.entity.ts.ejs +36 -0
  119. package/generators/node-server/templates/server/src/auth/session.store.spec.ts.ejs +99 -0
  120. package/generators/node-server/templates/server/src/auth/session.store.ts.ejs +116 -0
  121. package/generators/node-server/templates/server/src/auth/user.jwt.controller.ts.ejs +26 -0
  122. package/generators/node-server/templates/server/src/auth/user.oauth2.controller.ts.ejs +78 -0
  123. package/generators/node-server/templates/server/src/auth/user.session.controller.ts.ejs +103 -0
  124. package/generators/node-server/templates/server/src/common/common.module.ts.ejs +19 -0
  125. package/generators/node-server/templates/server/src/common/database/base.entity.ts.ejs +13 -0
  126. package/generators/node-server/templates/server/src/common/database/column-transformers.spec.ts.ejs +46 -0
  127. package/generators/node-server/templates/server/src/common/database/column-transformers.ts.ejs +69 -0
  128. package/generators/node-server/templates/server/src/common/database/column-types.spec.ts.ejs +21 -0
  129. package/generators/node-server/templates/server/src/common/database/column-types.ts.ejs +29 -0
  130. package/generators/node-server/templates/server/src/common/database/pagination.entity.spec.ts.ejs +66 -0
  131. package/generators/node-server/templates/server/src/common/database/pagination.entity.ts.ejs +108 -0
  132. package/generators/node-server/templates/server/src/common/dto/base.dto.ts.ejs +19 -0
  133. package/generators/node-server/templates/server/src/common/errors/error-constants.ts.ejs +10 -0
  134. package/generators/node-server/templates/server/src/common/errors/problem-details.filter.ts.ejs +63 -0
  135. package/generators/node-server/templates/server/src/common/errors/problem.exception.ts.ejs +92 -0
  136. package/generators/node-server/templates/server/src/common/field_validators.ejs +77 -0
  137. package/generators/node-server/templates/server/src/common/header-util.ts.ejs +105 -0
  138. package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.spec.ts.ejs +93 -0
  139. package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.ts.ejs +48 -0
  140. package/generators/node-server/templates/server/src/common/logging.spec.ts.ejs +83 -0
  141. package/generators/node-server/templates/server/src/common/logging.ts.ejs +129 -0
  142. package/generators/node-server/templates/server/src/common/metrics.spec.ts.ejs +43 -0
  143. package/generators/node-server/templates/server/src/common/metrics.ts.ejs +198 -0
  144. package/generators/node-server/templates/server/src/common/request.ts.ejs +8 -0
  145. package/generators/node-server/templates/server/src/common/sortable-properties.ts.ejs +43 -0
  146. package/generators/node-server/templates/server/src/common/updatable-properties.ts.ejs +14 -0
  147. package/generators/node-server/templates/server/src/config/application-dev.yml.ejs +118 -0
  148. package/generators/node-server/templates/server/src/config/application-prod.yml.ejs +97 -0
  149. package/generators/node-server/templates/server/src/config/application-secret-samples.yml.ejs +42 -0
  150. package/generators/node-server/templates/server/src/config/application-test.yml.ejs +68 -0
  151. package/generators/node-server/templates/server/src/config/application-tls-samples.yml.ejs +15 -0
  152. package/generators/node-server/templates/server/src/config/application-tls.yml.ejs +15 -0
  153. package/generators/node-server/templates/server/src/config/application.yml.ejs +149 -0
  154. package/generators/node-server/templates/server/src/config.spec.ts.ejs +81 -0
  155. package/generators/node-server/templates/server/src/config.ts.ejs +255 -0
  156. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.controller.ts.ejs +178 -0
  157. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.entity.ts.ejs +110 -0
  158. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.mapper.ts.ejs +37 -0
  159. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.module.ts.ejs +14 -0
  160. package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.service.ts.ejs +123 -0
  161. package/generators/node-server/templates/server/src/entities/_entityFileName_/dto/_entityFileName_.dto.ts.ejs +99 -0
  162. package/generators/node-server/templates/server/src/mail/mail.module.ts.ejs +49 -0
  163. package/generators/node-server/templates/server/src/mail/mail.service.spec.ts.ejs +105 -0
  164. package/generators/node-server/templates/server/src/mail/mail.service.ts.ejs +120 -0
  165. package/generators/node-server/templates/server/src/main.ts.ejs +114 -0
  166. package/generators/node-server/templates/server/src/management/api-docs.controller.ts.ejs +27 -0
  167. package/generators/node-server/templates/server/src/management/api-docs.service.ts.ejs +8 -0
  168. package/generators/node-server/templates/server/src/management/configuration.controller.ts.ejs +80 -0
  169. package/generators/node-server/templates/server/src/management/health.controller.spec.ts.ejs +79 -0
  170. package/generators/node-server/templates/server/src/management/health.controller.ts.ejs +87 -0
  171. package/generators/node-server/templates/server/src/management/health.module.ts.ejs +9 -0
  172. package/generators/node-server/templates/server/src/management/loggers.controller.ts.ejs +40 -0
  173. package/generators/node-server/templates/server/src/management/management.controller.spec.ts.ejs +26 -0
  174. package/generators/node-server/templates/server/src/management/management.controller.ts.ejs +34 -0
  175. package/generators/node-server/templates/server/src/management/management.module.ts.ejs +21 -0
  176. package/generators/node-server/templates/server/src/management/metrics.controller.ts.ejs +85 -0
  177. package/generators/node-server/templates/server/src/migrations/1570200270081-CreateTables.ts.ejs +64 -0
  178. package/generators/node-server/templates/server/src/migrations/1570200270082-CreateSessions.ts.ejs +26 -0
  179. package/generators/node-server/templates/server/src/migrations/1570200490072-SeedUsersRoles.ts.ejs +74 -0
  180. package/generators/node-server/templates/server/src/migrations/_entityConstraintsMigration_.ts.ejs +40 -0
  181. package/generators/node-server/templates/server/src/migrations/_entityMigration_.ts.ejs +26 -0
  182. package/generators/node-server/templates/server/src/migrations/support/schema.ts.ejs +202 -0
  183. package/generators/node-server/templates/server/src/orm.config.ts.ejs +147 -0
  184. package/generators/node-server/templates/server/src/registry/consul.service.ts.ejs +70 -0
  185. package/generators/node-server/templates/server/src/registry/eureka.service.ts.ejs +129 -0
  186. package/generators/node-server/templates/server/src/swagger.ts.ejs +24 -0
  187. package/generators/node-server/templates/server/src/tls.ts.ejs +27 -0
  188. package/generators/node-server/templates/server/src/users/authority.controller.ts.ejs +85 -0
  189. package/generators/node-server/templates/server/src/users/authority.entity.ts.ejs +22 -0
  190. package/generators/node-server/templates/server/src/users/dto/authority.dto.ts.ejs +10 -0
  191. package/generators/node-server/templates/server/src/users/dto/user.dto.ts.ejs +116 -0
  192. package/generators/node-server/templates/server/src/users/public.user.controller.ts.ejs +51 -0
  193. package/generators/node-server/templates/server/src/users/user.controller.ts.ejs +191 -0
  194. package/generators/node-server/templates/server/src/users/user.entity.ts.ejs +63 -0
  195. package/generators/node-server/templates/server/src/users/user.mapper.ts.ejs +26 -0
  196. package/generators/node-server/templates/server/src/users/user.module.ts.ejs +19 -0
  197. package/generators/node-server/templates/server/src/users/user.service.ts.ejs +156 -0
  198. package/generators/node-server/templates/server/tsconfig.build.json.ejs +9 -0
  199. package/generators/node-server/templates/server/tsconfig.json.ejs +23 -0
  200. package/generators/node-server/templates/server/typeorm-migration.ts.ejs +18 -0
  201. package/generators/node-server/templates/server/vitest.config.e2e.ts.ejs +16 -0
  202. package/generators/node-server/templates/server/vitest.config.ts.ejs +16 -0
  203. package/generators/server/command.js +7 -0
  204. package/generators/server/generator.js +20 -0
  205. package/generators/server/generators/bootstrap/command.js +5 -0
  206. package/generators/server/generators/bootstrap/generator.js +15 -0
  207. package/generators/server/generators/bootstrap/index.js +2 -0
  208. package/generators/server/index.js +2 -0
  209. package/package.json +75 -4
@@ -0,0 +1,402 @@
1
+ <%_
2
+ // The fake data of this test, whatever the templates rendered before: the faker of the entity is seeded for it.
3
+ resetFakerSeed('nodejs-e2e-mock');
4
+ const numericId = primaryKey.tsType === 'number';
5
+ // The fake data of the fields, reproducible (the faker of the entity is seeded): distinct ids of the type of the primary
6
+ // key, as TypeScript literals, and a value for each field of the entity, as the API exchanges it.
7
+ const idField = primaryKey.fields[0];
8
+ const [entityId, unknownId, anotherId] = [idField.generateFakeData('ts'), idField.generateFakeData('ts'), idField.generateFakeData('ts')];
9
+ const fakeFields = fields
10
+ .filter(field => !field.id && !field.transient && !field.collection)
11
+ .map(field => [field.propertyName, field.nodejsApiFakeValue()])
12
+ .filter(([, value]) => value !== undefined && value !== null);
13
+ // An id the pipe of the path rejects: neither a number nor a UUID.
14
+ const invalidId = faker.lorem.word({ length: { min: 5, max: 10 } });
15
+ _%>
16
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
17
+ import { Test, TestingModule } from '@nestjs/testing';
18
+ import request from 'supertest';
19
+ import { AppModule } from '../src/app.module.ts';
20
+ import { configureApp } from '../src/app.config.ts';
21
+ import { INestApplication } from '@nestjs/common';
22
+ import { AuthGuard } from '../src/auth/guards/auth.guard.ts';
23
+ import { RolesGuard } from '../src/auth/guards/roles.guard.ts';
24
+ import { <%= dtoClass %> } from '../src/entities/<%= entityFileName %>/dto/<%= entityFileName %>.dto.ts';
25
+ import { <%= entityClass %>Service } from '../src/entities/<%= entityFileName %>/<%= entityFileName %>.service.ts';
26
+ import { DataSource, EntityMetadata } from 'typeorm';
27
+ import { <%= entityClass %> } from '../src/entities/<%= entityFileName %>/<%= entityFileName %>.entity.ts';
28
+
29
+ // The alert headers the JHipster clients read, named after jhipster.clientApp.name.
30
+ const alertHeader = (headers: Record<string, unknown>, suffix: string): unknown => headers[`x-<%= frontendAppName.toLowerCase() %>${suffix}`];
31
+
32
+ describe('<%= entityClass %> Controller', () => {
33
+ let app: INestApplication;
34
+
35
+ const authGuardMock = { canActivate: (): any => true };
36
+ const rolesGuardMock = { canActivate: (): any => true };
37
+ const entityMock: any = {
38
+ id: <%- entityId %>,
39
+ <%_ for (const [propertyName, value] of fakeFields) { _%>
40
+ <%- propertyName %>: <%- JSON.stringify(value) %>,
41
+ <%_ } _%>
42
+ }
43
+ const unknownId = <%- unknownId %>;
44
+ const anotherId = <%- anotherId %>;
45
+ <%_
46
+ // The global ValidationPipe of configureApp validates the requests: a body with valid values of the validated fields.
47
+ resetFakerSeed('nodejs-e2e');
48
+ const validatedFields = fields.filter(field => !field.id && field.fieldValidate && field.fieldType !== 'byte[]');
49
+ const validValues = Object.fromEntries(
50
+ validatedFields
51
+ .map(field => [field.fieldName, field.nodejsApiFakeValue()])
52
+ .filter(([, value]) => value !== undefined && value !== null),
53
+ );
54
+ const requiredField = validatedFields.find(field => field.fieldValidationRequired);
55
+ const enumField = fields.find(field => !field.id && field.fieldIsEnum);
56
+ _%>
57
+ const validEntity: any = {
58
+ ...entityMock,
59
+ <%_ for (const [fieldName, value] of Object.entries(validValues)) { _%>
60
+ <%= fieldName %>: <%- JSON.stringify(value) %>,
61
+ <%_ } _%>
62
+ };
63
+
64
+ const serviceMock: { metadata?: EntityMetadata, [method: string]: unknown } = {
65
+ findById: (id: any): any => (id === entityMock.id ? { ...entityMock } : undefined),
66
+ findAndCount: (): any => [entityMock, 0],
67
+ save: (): any => entityMock,
68
+ update: (dto: any): any => dto,
69
+ deleteById: (): any => entityMock
70
+ };
71
+
72
+
73
+ beforeEach(async () => {
74
+ const moduleFixture: TestingModule = await Test.createTestingModule({
75
+ imports: [AppModule],
76
+ }).overrideGuard(AuthGuard)
77
+ .useValue(authGuardMock)
78
+ .overrideGuard(RolesGuard)
79
+ .useValue(rolesGuardMock)
80
+ .overrideProvider(<%= entityClass %>Service)
81
+ .useValue(serviceMock)
82
+ .compile();
83
+ // The sort is validated with the TypeORM metadata of the entity.
84
+ serviceMock.metadata = moduleFixture.get(DataSource).getMetadata(<%= entityClass %>);
85
+
86
+ app = moduleFixture.createNestApplication();
87
+ configureApp(app);
88
+ await app.init();
89
+ });
90
+
91
+ it('/GET all <%= entityApiUrl %> ', async () => {
92
+
93
+ const getEntities: <%= dtoClass %>[] = (await request(app.getHttpServer())
94
+ .get('/api/<%= entityApiUrl %>')
95
+ .expect(200)).body;
96
+
97
+ expect(getEntities).toEqual(entityMock);
98
+
99
+ }
100
+ );
101
+
102
+ <%_
103
+ const sortField = fields.find(field => !field.id && !field.transient);
104
+ const sortRelationship = relationships.find(relationship => relationship.ownerSide && !relationship.collection);
105
+ _%>
106
+
107
+ it('/GET all <%= entityApiUrl %> sorted on a property of the entity', async () => {
108
+ await request(app.getHttpServer())
109
+ .get('/api/<%= entityApiUrl %>?sort=<%= sortField ? sortField.fieldName : primaryKey.name %>,desc')
110
+ .expect(200);
111
+ });
112
+ <%_ if (sortRelationship) { _%>
113
+
114
+ it('/GET all <%= entityApiUrl %> sorted on the id and the label of a relationship', async () => {
115
+ await request(app.getHttpServer())
116
+ .get('/api/<%= entityApiUrl %>?sort=<%= sortRelationship.propertyName %>.id,asc')
117
+ .expect(200);
118
+ await request(app.getHttpServer())
119
+ .get('/api/<%= entityApiUrl %>?sort=<%= sortRelationship.propertyName %>.<%= sortRelationship.otherEntityField %>,desc')
120
+ .expect(200);
121
+ });
122
+
123
+ it('/GET all <%= entityApiUrl %> sorted on a deeper property of a relationship', async () => {
124
+ await request(app.getHttpServer())
125
+ .get('/api/<%= entityApiUrl %>?sort=<%= sortRelationship.propertyName %>.id.unknown,asc')
126
+ .expect(400);
127
+ });
128
+ <%_ } _%>
129
+
130
+ it('/GET all <%= entityApiUrl %> sorted on an unknown property', async () => {
131
+ const response = await request(app.getHttpServer())
132
+ .get('/api/<%= entityApiUrl %>?sort=unknownProperty,asc')
133
+ .expect(400);
134
+
135
+ expect(response.body.detail).toBe('Invalid sort property: unknownProperty');
136
+ });
137
+
138
+ <%_ if (pagination === 'no') { _%>
139
+ it('/GET all <%= entityApiUrl %> without pagination, like JHipster Spring Boot', async () => {
140
+ const { findAndCount } = serviceMock;
141
+ const options: any[] = [];
142
+ (serviceMock as any).findAndCount = (findOptions: any): any => {
143
+ options.push(findOptions);
144
+ return [[entityMock], 45];
145
+ };
146
+ try {
147
+ const response = await request(app.getHttpServer())
148
+ .get('/api/<%= entityApiUrl %>')
149
+ .expect(200);
150
+
151
+ expect(options[0].take).toBeUndefined();
152
+ expect(response.headers['x-total-count']).toBeUndefined();
153
+ expect(response.headers.link).toBeUndefined();
154
+ } finally {
155
+ serviceMock.findAndCount = findAndCount;
156
+ }
157
+ });
158
+
159
+ <%_ } else { _%>
160
+ it('/GET all <%= entityApiUrl %> with the links of the pages', async () => {
161
+ const { findAndCount } = serviceMock;
162
+ // 45 records, 3 pages of 20.
163
+ serviceMock.findAndCount = (): any => [[entityMock], 45];
164
+ try {
165
+ const response = await request(app.getHttpServer())
166
+ .get('/api/<%= entityApiUrl %>?page=1&size=20')
167
+ .expect(200);
168
+
169
+ expect(response.headers['x-total-count']).toBe('45');
170
+ expect(response.headers.link.split(',')).toEqual([
171
+ '</api/<%= entityApiUrl %>?page=2&size=20>; rel="next"',
172
+ '</api/<%= entityApiUrl %>?page=0&size=20>; rel="prev"',
173
+ '</api/<%= entityApiUrl %>?page=2&size=20>; rel="last"',
174
+ '</api/<%= entityApiUrl %>?page=0&size=20>; rel="first"',
175
+ ]);
176
+ } finally {
177
+ serviceMock.findAndCount = findAndCount;
178
+ }
179
+ });
180
+
181
+ it('/GET all <%= entityApiUrl %> without records links the first page as the last one', async () => {
182
+ const response = await request(app.getHttpServer())
183
+ .get('/api/<%= entityApiUrl %>')
184
+ .expect(200);
185
+
186
+ expect(response.headers.link).toContain('page=0&size=20>; rel="last"');
187
+ expect(response.headers.link).not.toContain('rel="next"');
188
+ });
189
+
190
+ <%_ } _%>
191
+ it('/GET <%= entityApiUrl %> by id', async () => {
192
+
193
+
194
+ const getEntity: <%= dtoClass %> = (await request(app.getHttpServer())
195
+ .get(`/api/<%= entityApiUrl %>/${entityMock.id}`)
196
+ .expect(200)).body;
197
+
198
+ expect(getEntity).toEqual(entityMock);
199
+
200
+ }
201
+ );
202
+
203
+ it('/GET <%= entityApiUrl %> by an unknown id', async () => {
204
+ await request(app.getHttpServer())
205
+ .get(`/api/<%= entityApiUrl %>/${unknownId}`)
206
+ .expect(404);
207
+ });
208
+ <%_ if (numericId || primaryKey.typeUUID) { _%>
209
+
210
+ it('/GET <%= entityApiUrl %> by an invalid id', async () => {
211
+ await request(app.getHttpServer())
212
+ .get('/api/<%= entityApiUrl %>/<%= invalidId %>')
213
+ .expect(400);
214
+ });
215
+ <%_ } _%>
216
+
217
+ it('/POST create <%= entityApiUrl %>', async () => {
218
+ const { id: _id, ...newEntity } = validEntity;
219
+ const response = await request(app.getHttpServer())
220
+ .post('/api/<%= entityApiUrl %>')
221
+ .send(newEntity)
222
+ .expect(201);
223
+
224
+ expect(response.body).toEqual(entityMock);
225
+ expect(response.headers.location).toBe(`/api/<%= entityApiUrl %>/${entityMock.id}`);
226
+ expect(alertHeader(response.headers, '-alert')).toMatch(<%- enableTranslation ? `/^${frontendAppName}\\.${entityAlertName}\\.created$/` : `/^A new ${entityAlertName} is created with identifier /` %>);
227
+ });
228
+
229
+ it('/POST create <%= entityApiUrl %> ignores the properties its DTO does not declare', async () => {
230
+ // Like JHipster Spring Boot, which ignores the unknown properties of a request: the service gets the declared ones.
231
+ const { id: _id, ...newEntity } = validEntity;
232
+ const save = vi.spyOn(serviceMock as any, 'save');
233
+ try {
234
+ await request(app.getHttpServer())
235
+ .post('/api/<%= entityApiUrl %>')
236
+ .send({ ...newEntity, unknownProperty: 'unknown' })
237
+ .expect(201);
238
+
239
+ const [dto] = save.mock.calls[0];
240
+ expect(dto).not.toHaveProperty('unknownProperty');
241
+ expect(Object.keys(dto as object)).toEqual(expect.arrayContaining(Object.keys(JSON.parse(JSON.stringify(newEntity)))));
242
+ } finally {
243
+ save.mockRestore();
244
+ }
245
+ });
246
+
247
+ it('/POST create <%= entityApiUrl %> with an id', async () => {
248
+ const response = await request(app.getHttpServer())
249
+ .post('/api/<%= entityApiUrl %>')
250
+ .send(validEntity)
251
+ .expect(400);
252
+
253
+ expect(alertHeader(response.headers, '-error')).toBe('error.idexists');
254
+ expect(response.body).toMatchObject({ message: 'error.idexists', params: '<%= entityAlertName %>' });
255
+ expect(alertHeader(response.headers, '-params')).toBe('<%= entityAlertName %>');
256
+ });
257
+
258
+ <%_ if (requiredField) { _%>
259
+ it('/POST create <%= entityApiUrl %> without <%= requiredField.fieldName %> is a validation error', async () => {
260
+ const { <%= requiredField.fieldName %>: _<%= requiredField.fieldName %>, ...invalidEntity } = validEntity;
261
+
262
+ const error = (await request(app.getHttpServer())
263
+ .post('/api/<%= entityApiUrl %>')
264
+ .send(invalidEntity)
265
+ .expect(400)).body;
266
+
267
+ expect(error).toMatchObject({
268
+ type: 'https://www.jhipster.tech/problem/constraint-violation',
269
+ message: 'error.validation',
270
+ fieldErrors: [{ objectName: '<%= entityInstance %>', field: '<%= requiredField.fieldName %>', message: expect.any(String) }],
271
+ });
272
+ });
273
+
274
+ <%_ } _%>
275
+ <%_ if (enumField) { _%>
276
+ it('/POST create <%= entityApiUrl %> with a <%= enumField.fieldName %> out of its enum is a validation error', async () => {
277
+ const error = (await request(app.getHttpServer())
278
+ .post('/api/<%= entityApiUrl %>')
279
+ .send({ ...validEntity, <%= enumField.fieldName %>: 'NOT_A_<%= enumField.fieldType.toUpperCase() %>' })
280
+ .expect(400)).body;
281
+
282
+ expect(error).toMatchObject({ message: 'error.validation', fieldErrors: [expect.objectContaining({ field: '<%= enumField.fieldName %>' })] });
283
+ });
284
+
285
+ <%_ } _%>
286
+ it('/PUT update <%= entityApiUrl %> from id', async () => {
287
+ const response = await request(app.getHttpServer())
288
+ .put(`/api/<%= entityApiUrl %>/${entityMock.id}`)
289
+ .send(validEntity)
290
+ .expect(200);
291
+
292
+ expect(response.body).toEqual(validEntity);
293
+ expect(alertHeader(response.headers, '-alert')).toMatch(<%- enableTranslation ? `/^${frontendAppName}\\.${entityAlertName}\\.updated$/` : `/^A ${entityAlertName} is updated with identifier /` %>);
294
+ expect(alertHeader(response.headers, '-params')).toBe(String(entityMock.id));
295
+ }
296
+ );
297
+
298
+ it('/PUT update <%= entityApiUrl %> from another id', async () => {
299
+ const response = await request(app.getHttpServer())
300
+ .put(`/api/<%= entityApiUrl %>/${anotherId}`)
301
+ .send(validEntity)
302
+ .expect(400);
303
+
304
+ expect(alertHeader(response.headers, '-error')).toBe('error.idinvalid');
305
+ expect(response.body).toMatchObject({ message: 'error.idinvalid', params: '<%= entityAlertName %>' });
306
+ });
307
+
308
+ it('/PUT update <%= entityApiUrl %> without id', async () => {
309
+ const response = await request(app.getHttpServer())
310
+ .put(`/api/<%= entityApiUrl %>/${entityMock.id}`)
311
+ .send({ ...validEntity, id: undefined })
312
+ .expect(400);
313
+
314
+ expect(alertHeader(response.headers, '-error')).toBe('error.idnull');
315
+ expect(response.body).toMatchObject({ message: 'error.idnull', params: '<%= entityAlertName %>' });
316
+ });
317
+
318
+ it('/PUT update an unknown <%= entityApiUrl %>', async () => {
319
+ const response = await request(app.getHttpServer())
320
+ .put(`/api/<%= entityApiUrl %>/${unknownId}`)
321
+ .send({ ...validEntity, id: unknownId })
322
+ .expect(400);
323
+
324
+ expect(alertHeader(response.headers, '-error')).toBe('error.idnotfound');
325
+ expect(response.body).toMatchObject({ message: 'error.idnotfound', params: '<%= entityAlertName %>' });
326
+ });
327
+
328
+ it('/DELETE <%= entityApiUrl %>', async () => {
329
+
330
+
331
+ const deletedEntity: <%= dtoClass %> = (await request(app.getHttpServer())
332
+ .delete(`/api/<%= entityApiUrl %>/${entityMock.id}`)
333
+ .expect(204)).body;
334
+
335
+ expect(deletedEntity).toEqual({});
336
+ }
337
+ );
338
+
339
+ afterEach(async () => {
340
+ await app?.close();
341
+ });
342
+ <%_ if (nodejsReadRoles) { _%>
343
+
344
+ describe('with the roles of <%= entityClass %>, like the @PreAuthorize of JHipster Spring Boot', () => {
345
+ let rolesApp: INestApplication;
346
+
347
+ /** The application with its RolesGuard, for a user of these roles. */
348
+ const appOfUser = async (authorities: string[]): Promise<INestApplication> => {
349
+ const moduleFixture: TestingModule = await Test.createTestingModule({
350
+ imports: [AppModule],
351
+ }).overrideGuard(AuthGuard)
352
+ .useValue({ canActivate: (context: any): boolean => {
353
+ context.switchToHttp().getRequest().user = { login: 'user', authorities };
354
+ return true;
355
+ } })
356
+ .overrideProvider(<%= entityClass %>Service)
357
+ .useValue(serviceMock)
358
+ .compile();
359
+ serviceMock.metadata = moduleFixture.get(DataSource).getMetadata(<%= entityClass %>);
360
+ const rolesNestApp = moduleFixture.createNestApplication();
361
+ configureApp(rolesNestApp);
362
+ await rolesNestApp.init();
363
+ return rolesNestApp;
364
+ };
365
+
366
+ afterEach(async () => {
367
+ await rolesApp?.close();
368
+ });
369
+
370
+ it('refuses a user without its roles with 403', async () => {
371
+ rolesApp = await appOfUser(['ROLE_OTHER']);
372
+ await request(rolesApp.getHttpServer()).get('/api/<%= entityApiUrl %>').expect(403);
373
+ await request(rolesApp.getHttpServer()).get(`/api/<%= entityApiUrl %>/${entityMock.id}`).expect(403);
374
+ <%_ if (nodejsWriteRoles) { _%>
375
+ const { id: _id, ...newEntity } = validEntity;
376
+ await request(rolesApp.getHttpServer()).post('/api/<%= entityApiUrl %>').send(newEntity).expect(403);
377
+ await request(rolesApp.getHttpServer()).delete(`/api/<%= entityApiUrl %>/${entityMock.id}`).expect(403);
378
+ <%_ } _%>
379
+ });
380
+ <%_ if (nodejsWriteRoles) { _%>
381
+
382
+ it('allows a user of its roles to read and to write', async () => {
383
+ rolesApp = await appOfUser([<%- nodejsWriteRoles %>]);
384
+ await request(rolesApp.getHttpServer()).get('/api/<%= entityApiUrl %>').expect(200);
385
+ const { id: _id, ...newEntity } = validEntity;
386
+ await request(rolesApp.getHttpServer()).post('/api/<%= entityApiUrl %>').send(newEntity).expect(201);
387
+ });
388
+ <%_ } _%>
389
+ <%_ if (nodejsReadOnlyRoles) { _%>
390
+
391
+ it('allows a user of its read roles to read only', async () => {
392
+ rolesApp = await appOfUser([<%- nodejsReadOnlyRoles %>]);
393
+ await request(rolesApp.getHttpServer()).get('/api/<%= entityApiUrl %>').expect(200);
394
+ <%_ if (nodejsWriteRoles) { _%>
395
+ const { id: _id, ...newEntity } = validEntity;
396
+ await request(rolesApp.getHttpServer()).post('/api/<%= entityApiUrl %>').send(newEntity).expect(403);
397
+ <%_ } _%>
398
+ });
399
+ <%_ } _%>
400
+ });
401
+ <%_ } _%>
402
+ });