@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.
- package/LICENSE.txt +204 -0
- package/README.md +243 -2
- package/build-info.json +3 -0
- package/cli/cli-customizations.cjs +9 -0
- package/cli/cli.cjs +40 -0
- package/cli/logo.js +31 -0
- package/cli/version.cjs +12 -0
- package/generators/ci-cd/USAGE +5 -0
- package/generators/ci-cd/command.js +5 -0
- package/generators/ci-cd/generator.js +158 -0
- package/generators/ci-cd/index.js +2 -0
- package/generators/ci-cd/templates/.gitlab-ci.yml.ejs +137 -0
- package/generators/ci-cd/templates/azure-pipelines.yml.ejs +68 -0
- package/generators/ci-cd/templates/circle.yml.ejs +59 -0
- package/generators/ci-cd/templates/docker-registry.yml.ejs +58 -0
- package/generators/ci-cd/templates/github-ci.yml.ejs +90 -0
- package/generators/ci-cd/templates/jenkins/Jenkinsfile.ejs +104 -0
- package/generators/ci-cd/templates/jenkins/idea.gdsl +90 -0
- package/generators/ci-cd/templates/jenkins/jenkins.yml.ejs +33 -0
- package/generators/ci-cd/templates/travis.yml.ejs +75 -0
- package/generators/client/command.js +5 -0
- package/generators/client/generator.js +21 -0
- package/generators/client/generators/bootstrap/command.js +5 -0
- package/generators/client/generators/bootstrap/generator.js +28 -0
- package/generators/client/generators/bootstrap/index.js +2 -0
- package/generators/client/index.js +2 -0
- package/generators/common/generators/bootstrap/command.js +5 -0
- package/generators/common/generators/bootstrap/generator.js +37 -0
- package/generators/common/generators/bootstrap/index.js +2 -0
- package/generators/docker/command.js +5 -0
- package/generators/docker/generator.js +16 -0
- package/generators/docker/generators/bootstrap/command.js +5 -0
- package/generators/docker/generators/bootstrap/generator.js +56 -0
- package/generators/docker/generators/bootstrap/index.js +2 -0
- package/generators/docker/index.js +2 -0
- package/generators/docker/templates/docker/app.yml.ejs +25 -0
- package/generators/generator-nodejs-constants.js +32 -0
- package/generators/languages/command.js +5 -0
- package/generators/languages/generator.js +22 -0
- package/generators/languages/index.js +2 -0
- package/generators/languages/templates/src/main/webapp/i18n/en/home.json +19 -0
- package/generators/languages/templates/src/main/webapp/i18n/es/home.json +19 -0
- package/generators/languages/templates/src/main/webapp/i18n/it/home.json +19 -0
- package/generators/node-server/command.js +96 -0
- package/generators/node-server/entity-files.js +26 -0
- package/generators/node-server/files.js +254 -0
- package/generators/node-server/generator.js +705 -0
- package/generators/node-server/generators/bootstrap/command.js +5 -0
- package/generators/node-server/generators/bootstrap/generator.js +84 -0
- package/generators/node-server/generators/bootstrap/index.js +2 -0
- package/generators/node-server/generators/migrations/command.js +5 -0
- package/generators/node-server/generators/migrations/files.js +42 -0
- package/generators/node-server/generators/migrations/generator.js +108 -0
- package/generators/node-server/generators/migrations/index.js +2 -0
- package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityConstraintsMigration_.ts.ejs +40 -0
- package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityMigration_.ts.ejs +26 -0
- package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityRemovedMigration_.ts.ejs +15 -0
- package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityUpdatedConstraintsMigration_.ts.ejs +60 -0
- package/generators/node-server/generators/migrations/templates/server/src/migrations/_entityUpdatedMigration_.ts.ejs +28 -0
- package/generators/node-server/index.js +2 -0
- package/generators/node-server/resources/package.json +76 -0
- package/generators/node-server/support/api-fake-data.js +54 -0
- package/generators/node-server/support/columns.js +73 -0
- package/generators/node-server/support/database.js +24 -0
- package/generators/node-server/support/entity-authorities.js +32 -0
- package/generators/node-server/support/entity-paths.js +13 -0
- package/generators/node-server/support/enums.js +11 -0
- package/generators/node-server/support/index.js +9 -0
- package/generators/node-server/support/mail-templates.js +82 -0
- package/generators/node-server/support/migrations.js +376 -0
- package/generators/node-server/support/validators.js +25 -0
- package/generators/node-server/templates/.dockerignore.ejs +16 -0
- package/generators/node-server/templates/.gitignore.jhi.nodejs.ejs +24 -0
- package/generators/node-server/templates/Dockerfile.ejs +54 -0
- package/generators/node-server/templates/README.md.jhi.nodejs.ejs +220 -0
- package/generators/node-server/templates/package.json.ejs +82 -0
- package/generators/node-server/templates/server/README.md.ejs +277 -0
- package/generators/node-server/templates/server/e2e/_entityFileName_.database.e2e-spec.ts.ejs +192 -0
- package/generators/node-server/templates/server/e2e/_entityFileName_.e2e-spec.ts.ejs +402 -0
- package/generators/node-server/templates/server/e2e/account.e2e-spec.ts.ejs +349 -0
- package/generators/node-server/templates/server/e2e/app.e2e-spec.ts.ejs +188 -0
- package/generators/node-server/templates/server/e2e/authority.e2e-spec.ts.ejs +50 -0
- package/generators/node-server/templates/server/e2e/cors.e2e-spec.ts.ejs +110 -0
- package/generators/node-server/templates/server/e2e/management.e2e-spec.ts.ejs +180 -0
- package/generators/node-server/templates/server/e2e/oauth2-bearer.e2e-spec.ts.ejs +71 -0
- package/generators/node-server/templates/server/e2e/session.e2e-spec.ts.ejs +234 -0
- package/generators/node-server/templates/server/e2e/setup.test.js.ejs +1 -0
- package/generators/node-server/templates/server/e2e/user.e2e-spec.ts.ejs +318 -0
- package/generators/node-server/templates/server/env.ejs +1 -0
- package/generators/node-server/templates/server/eslint.config.mjs.ejs +48 -0
- package/generators/node-server/templates/server/nest-cli.json.ejs +11 -0
- package/generators/node-server/templates/server/ormconfig.ts.ejs +35 -0
- package/generators/node-server/templates/server/package.json.ejs +143 -0
- package/generators/node-server/templates/server/sonar-project.properties.ejs +10 -0
- package/generators/node-server/templates/server/src/app.config.spec.ts.ejs +13 -0
- package/generators/node-server/templates/server/src/app.config.ts.ejs +179 -0
- package/generators/node-server/templates/server/src/app.module.ts.ejs +80 -0
- package/generators/node-server/templates/server/src/application-config.ts.ejs +153 -0
- package/generators/node-server/templates/server/src/auth/account.controller.ts.ejs +183 -0
- package/generators/node-server/templates/server/src/auth/auth.module.ts.ejs +104 -0
- package/generators/node-server/templates/server/src/auth/auth.service.ts.ejs +294 -0
- package/generators/node-server/templates/server/src/auth/csrf.middleware.spec.ts.ejs +76 -0
- package/generators/node-server/templates/server/src/auth/csrf.middleware.ts.ejs +85 -0
- package/generators/node-server/templates/server/src/auth/decorators/auth-user.decorator.ts.ejs +8 -0
- package/generators/node-server/templates/server/src/auth/decorators/roles.decorator.ts.ejs +4 -0
- package/generators/node-server/templates/server/src/auth/dto/key-and-password.dto.ts.ejs +17 -0
- package/generators/node-server/templates/server/src/auth/dto/password-change.dto.ts.ejs +17 -0
- package/generators/node-server/templates/server/src/auth/dto/user-login.dto.ts.ejs +21 -0
- package/generators/node-server/templates/server/src/auth/guards/auth.guard.ts.ejs +50 -0
- package/generators/node-server/templates/server/src/auth/guards/oauth2-login.guard.ts.ejs +6 -0
- package/generators/node-server/templates/server/src/auth/guards/roles.guard.ts.ejs +25 -0
- package/generators/node-server/templates/server/src/auth/index.ts.ejs +8 -0
- package/generators/node-server/templates/server/src/auth/jwt.config.spec.ts.ejs +22 -0
- package/generators/node-server/templates/server/src/auth/jwt.config.ts.ejs +29 -0
- package/generators/node-server/templates/server/src/auth/oauth2.authorities.spec.ts.ejs +24 -0
- package/generators/node-server/templates/server/src/auth/oauth2.authorities.ts.ejs +33 -0
- package/generators/node-server/templates/server/src/auth/oauth2.config.ts.ejs +51 -0
- package/generators/node-server/templates/server/src/auth/passport.jwt.strategy.ts.ejs +45 -0
- package/generators/node-server/templates/server/src/auth/passport.oauth2-bearer.strategy.ts.ejs +32 -0
- package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.spec.ts.ejs +27 -0
- package/generators/node-server/templates/server/src/auth/passport.oauth2.strategy.ts.ejs +44 -0
- package/generators/node-server/templates/server/src/auth/password-util.ts.ejs +10 -0
- package/generators/node-server/templates/server/src/auth/password.service.ts.ejs +34 -0
- package/generators/node-server/templates/server/src/auth/payload.interface.ts.ejs +14 -0
- package/generators/node-server/templates/server/src/auth/role-type.ts.ejs +7 -0
- package/generators/node-server/templates/server/src/auth/session-user.middleware.ts.ejs +33 -0
- package/generators/node-server/templates/server/src/auth/session.entity.ts.ejs +36 -0
- package/generators/node-server/templates/server/src/auth/session.store.spec.ts.ejs +99 -0
- package/generators/node-server/templates/server/src/auth/session.store.ts.ejs +116 -0
- package/generators/node-server/templates/server/src/auth/user.jwt.controller.ts.ejs +26 -0
- package/generators/node-server/templates/server/src/auth/user.oauth2.controller.ts.ejs +78 -0
- package/generators/node-server/templates/server/src/auth/user.session.controller.ts.ejs +103 -0
- package/generators/node-server/templates/server/src/common/common.module.ts.ejs +19 -0
- package/generators/node-server/templates/server/src/common/database/base.entity.ts.ejs +13 -0
- package/generators/node-server/templates/server/src/common/database/column-transformers.spec.ts.ejs +46 -0
- package/generators/node-server/templates/server/src/common/database/column-transformers.ts.ejs +69 -0
- package/generators/node-server/templates/server/src/common/database/column-types.spec.ts.ejs +21 -0
- package/generators/node-server/templates/server/src/common/database/column-types.ts.ejs +29 -0
- package/generators/node-server/templates/server/src/common/database/pagination.entity.spec.ts.ejs +66 -0
- package/generators/node-server/templates/server/src/common/database/pagination.entity.ts.ejs +108 -0
- package/generators/node-server/templates/server/src/common/dto/base.dto.ts.ejs +19 -0
- package/generators/node-server/templates/server/src/common/errors/error-constants.ts.ejs +10 -0
- package/generators/node-server/templates/server/src/common/errors/problem-details.filter.ts.ejs +63 -0
- package/generators/node-server/templates/server/src/common/errors/problem.exception.ts.ejs +92 -0
- package/generators/node-server/templates/server/src/common/field_validators.ejs +77 -0
- package/generators/node-server/templates/server/src/common/header-util.ts.ejs +105 -0
- package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.spec.ts.ejs +93 -0
- package/generators/node-server/templates/server/src/common/interceptors/logging.interceptor.ts.ejs +48 -0
- package/generators/node-server/templates/server/src/common/logging.spec.ts.ejs +83 -0
- package/generators/node-server/templates/server/src/common/logging.ts.ejs +129 -0
- package/generators/node-server/templates/server/src/common/metrics.spec.ts.ejs +43 -0
- package/generators/node-server/templates/server/src/common/metrics.ts.ejs +198 -0
- package/generators/node-server/templates/server/src/common/request.ts.ejs +8 -0
- package/generators/node-server/templates/server/src/common/sortable-properties.ts.ejs +43 -0
- package/generators/node-server/templates/server/src/common/updatable-properties.ts.ejs +14 -0
- package/generators/node-server/templates/server/src/config/application-dev.yml.ejs +118 -0
- package/generators/node-server/templates/server/src/config/application-prod.yml.ejs +97 -0
- package/generators/node-server/templates/server/src/config/application-secret-samples.yml.ejs +42 -0
- package/generators/node-server/templates/server/src/config/application-test.yml.ejs +68 -0
- package/generators/node-server/templates/server/src/config/application-tls-samples.yml.ejs +15 -0
- package/generators/node-server/templates/server/src/config/application-tls.yml.ejs +15 -0
- package/generators/node-server/templates/server/src/config/application.yml.ejs +149 -0
- package/generators/node-server/templates/server/src/config.spec.ts.ejs +81 -0
- package/generators/node-server/templates/server/src/config.ts.ejs +255 -0
- package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.controller.ts.ejs +178 -0
- package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.entity.ts.ejs +110 -0
- package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.mapper.ts.ejs +37 -0
- package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.module.ts.ejs +14 -0
- package/generators/node-server/templates/server/src/entities/_entityFileName_/_entityFileName_.service.ts.ejs +123 -0
- package/generators/node-server/templates/server/src/entities/_entityFileName_/dto/_entityFileName_.dto.ts.ejs +99 -0
- package/generators/node-server/templates/server/src/mail/mail.module.ts.ejs +49 -0
- package/generators/node-server/templates/server/src/mail/mail.service.spec.ts.ejs +105 -0
- package/generators/node-server/templates/server/src/mail/mail.service.ts.ejs +120 -0
- package/generators/node-server/templates/server/src/main.ts.ejs +114 -0
- package/generators/node-server/templates/server/src/management/api-docs.controller.ts.ejs +27 -0
- package/generators/node-server/templates/server/src/management/api-docs.service.ts.ejs +8 -0
- package/generators/node-server/templates/server/src/management/configuration.controller.ts.ejs +80 -0
- package/generators/node-server/templates/server/src/management/health.controller.spec.ts.ejs +79 -0
- package/generators/node-server/templates/server/src/management/health.controller.ts.ejs +87 -0
- package/generators/node-server/templates/server/src/management/health.module.ts.ejs +9 -0
- package/generators/node-server/templates/server/src/management/loggers.controller.ts.ejs +40 -0
- package/generators/node-server/templates/server/src/management/management.controller.spec.ts.ejs +26 -0
- package/generators/node-server/templates/server/src/management/management.controller.ts.ejs +34 -0
- package/generators/node-server/templates/server/src/management/management.module.ts.ejs +21 -0
- package/generators/node-server/templates/server/src/management/metrics.controller.ts.ejs +85 -0
- package/generators/node-server/templates/server/src/migrations/1570200270081-CreateTables.ts.ejs +64 -0
- package/generators/node-server/templates/server/src/migrations/1570200270082-CreateSessions.ts.ejs +26 -0
- package/generators/node-server/templates/server/src/migrations/1570200490072-SeedUsersRoles.ts.ejs +74 -0
- package/generators/node-server/templates/server/src/migrations/support/schema.ts.ejs +254 -0
- package/generators/node-server/templates/server/src/orm.config.ts.ejs +147 -0
- package/generators/node-server/templates/server/src/registry/consul.service.ts.ejs +70 -0
- package/generators/node-server/templates/server/src/registry/eureka.service.ts.ejs +129 -0
- package/generators/node-server/templates/server/src/swagger.ts.ejs +24 -0
- package/generators/node-server/templates/server/src/tls.ts.ejs +27 -0
- package/generators/node-server/templates/server/src/users/authority.controller.ts.ejs +85 -0
- package/generators/node-server/templates/server/src/users/authority.entity.ts.ejs +22 -0
- package/generators/node-server/templates/server/src/users/dto/authority.dto.ts.ejs +10 -0
- package/generators/node-server/templates/server/src/users/dto/user.dto.ts.ejs +116 -0
- package/generators/node-server/templates/server/src/users/public.user.controller.ts.ejs +51 -0
- package/generators/node-server/templates/server/src/users/user.controller.ts.ejs +191 -0
- package/generators/node-server/templates/server/src/users/user.entity.ts.ejs +63 -0
- package/generators/node-server/templates/server/src/users/user.mapper.ts.ejs +26 -0
- package/generators/node-server/templates/server/src/users/user.module.ts.ejs +19 -0
- package/generators/node-server/templates/server/src/users/user.service.ts.ejs +156 -0
- package/generators/node-server/templates/server/tsconfig.build.json.ejs +9 -0
- package/generators/node-server/templates/server/tsconfig.json.ejs +23 -0
- package/generators/node-server/templates/server/typeorm-migration.ts.ejs +18 -0
- package/generators/node-server/templates/server/vitest.config.e2e.ts.ejs +16 -0
- package/generators/node-server/templates/server/vitest.config.ts.ejs +16 -0
- package/generators/server/command.js +7 -0
- package/generators/server/generator.js +20 -0
- package/generators/server/generators/bootstrap/command.js +5 -0
- package/generators/server/generators/bootstrap/generator.js +15 -0
- package/generators/server/generators/bootstrap/index.js +2 -0
- package/generators/server/index.js +2 -0
- package/package.json +75 -4
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<%_
|
|
2
|
+
// The values of the fields as the API exchanges them, reproducible: the faker of the entity is seeded for this test.
|
|
3
|
+
resetFakerSeed('nodejs-database-e2e');
|
|
4
|
+
const created = nodejsApiFakeEntity();
|
|
5
|
+
const updated = nodejsApiFakeEntity();
|
|
6
|
+
const approximateFields = created.approximateFields;
|
|
7
|
+
// The relationships of the entity with a join column or a join table (the persistableRelationships of JHipster): stored
|
|
8
|
+
// by the id of the related record.
|
|
9
|
+
const storedRelationships = databaseTypeSql ? persistableRelationships : [];
|
|
10
|
+
const anyUserRelationship = storedRelationships.some(relationship => relationship.otherEntity.builtInUser);
|
|
11
|
+
// The relationships the other entity stores (nodejsMappedByRelationships), with another entity of the application.
|
|
12
|
+
const inverseRelationships = databaseTypeSql
|
|
13
|
+
? nodejsMappedByRelationships.filter(relationship => !relationship.otherEntity.builtIn && relationship.otherRelationship?.propertyName)
|
|
14
|
+
: [];
|
|
15
|
+
const literal = value => JSON.stringify(value);
|
|
16
|
+
_%>
|
|
17
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
18
|
+
import { INestApplication } from '@nestjs/common';
|
|
19
|
+
import { Test, TestingModule } from '@nestjs/testing';
|
|
20
|
+
import request from 'supertest';
|
|
21
|
+
<%_ if (anyUserRelationship) { _%>
|
|
22
|
+
import { DataSource } from 'typeorm';
|
|
23
|
+
<%_ } _%>
|
|
24
|
+
|
|
25
|
+
import { AppModule } from '../src/app.module.ts';
|
|
26
|
+
import { configureApp } from '../src/app.config.ts';
|
|
27
|
+
<%_ if (anyUserRelationship) { _%>
|
|
28
|
+
import { <%= user.persistClass %> } from '../src/users/user.entity.ts';
|
|
29
|
+
<%_ } _%>
|
|
30
|
+
import { AuthGuard } from '../src/auth/guards/auth.guard.ts';
|
|
31
|
+
import { RolesGuard } from '../src/auth/guards/roles.guard.ts';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* <%= entityClass %> stored in the database and read back through the REST API, like the resource tests of JHipster
|
|
35
|
+
* Spring Boot: the values of every field as the API exchanges them<% if (storedRelationships.length > 0) { %>, and the relationships stored by the id of the related
|
|
36
|
+
* record, without changing it<% } %>.
|
|
37
|
+
*/
|
|
38
|
+
describe('<%= entityClass %> on the database', () => {
|
|
39
|
+
let app: INestApplication;
|
|
40
|
+
|
|
41
|
+
// The values of the fields, of a creation then of an update.
|
|
42
|
+
const createdValues: Record<string, any> = {
|
|
43
|
+
<%_ for (const [name, value] of Object.entries(created.values)) { _%>
|
|
44
|
+
<%= name %>: <%- literal(value) %>,
|
|
45
|
+
<%_ } _%>
|
|
46
|
+
};
|
|
47
|
+
const updatedValues: Record<string, any> = {
|
|
48
|
+
<%_ for (const [name, value] of Object.entries(updated.values)) { _%>
|
|
49
|
+
<%= name %>: <%- literal(value) %>,
|
|
50
|
+
<%_ } _%>
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** The values read back: a Float is approximate on the databases keeping it in single precision. */
|
|
54
|
+
const expected = (values: Record<string, any>): Record<string, any> => ({
|
|
55
|
+
...values,
|
|
56
|
+
<%_ for (const name of approximateFields) { _%>
|
|
57
|
+
<%= name %>: expect.closeTo(values.<%= name %>, 1),
|
|
58
|
+
<%_ } _%>
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
beforeAll(async () => {
|
|
62
|
+
const moduleFixture: TestingModule = await Test.createTestingModule({
|
|
63
|
+
imports: [AppModule],
|
|
64
|
+
})
|
|
65
|
+
.overrideGuard(AuthGuard)
|
|
66
|
+
.useValue({ canActivate: () => true })
|
|
67
|
+
.overrideGuard(RolesGuard)
|
|
68
|
+
.useValue({ canActivate: () => true })
|
|
69
|
+
.compile();
|
|
70
|
+
|
|
71
|
+
app = moduleFixture.createNestApplication();
|
|
72
|
+
configureApp(app);
|
|
73
|
+
await app.init();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
afterAll(async () => {
|
|
77
|
+
await app?.close();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should store every field and read it back, then update and delete it', async () => {
|
|
81
|
+
const server = app.getHttpServer();
|
|
82
|
+
const { body: stored } = await request(server).post('/api/<%= entityApiUrl %>').send(createdValues).expect(201);
|
|
83
|
+
const { body: read } = await request(server).get(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(200);
|
|
84
|
+
expect(read).toMatchObject(expected(createdValues));
|
|
85
|
+
|
|
86
|
+
await request(server)
|
|
87
|
+
.put(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`)
|
|
88
|
+
.send({ ...updatedValues, <%= primaryKey.name %>: stored.<%= primaryKey.name %> })
|
|
89
|
+
.expect(200);
|
|
90
|
+
const { body: readUpdated } = await request(server).get(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(200);
|
|
91
|
+
expect(readUpdated).toMatchObject(expected(updatedValues));
|
|
92
|
+
|
|
93
|
+
await request(server).delete(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(204);
|
|
94
|
+
await request(server).get(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(404);
|
|
95
|
+
});
|
|
96
|
+
<%_ for (const relationship of storedRelationships) {
|
|
97
|
+
const otherEntity = relationship.otherEntity;
|
|
98
|
+
const otherId = otherEntity.primaryKey.name;
|
|
99
|
+
const collection = relationship.relationshipType === 'many-to-many';
|
|
100
|
+
const property = relationship.propertyName;
|
|
101
|
+
const otherValues = relationship.nodejsRelatedValues;
|
|
102
|
+
// A text field of the related record, sent changed with its id: the relationship does not store it (no cascade).
|
|
103
|
+
const otherTextField = otherValues && otherEntity.fields.find(field => !field.id && field.fieldType === 'String' && field.fieldName in otherValues);
|
|
104
|
+
_%>
|
|
105
|
+
|
|
106
|
+
it('should store the <%= property %> relationship by the id of the related record, without changing it', async () => {
|
|
107
|
+
const server = app.getHttpServer();
|
|
108
|
+
<%_ if (otherEntity.builtInUser) { _%>
|
|
109
|
+
// A user of this test: the applications without seed users (OAuth2) have none.
|
|
110
|
+
const users = app.get(DataSource).getRepository(<%= user.persistClass %>);
|
|
111
|
+
const related = await users.save(
|
|
112
|
+
users.create({
|
|
113
|
+
login: '<%= entityInstance.toLowerCase() %>-<%= property.toLowerCase() %>-e2e',
|
|
114
|
+
email: '<%= entityInstance.toLowerCase() %>-<%= property.toLowerCase() %>-e2e@localhost',
|
|
115
|
+
password: '',
|
|
116
|
+
activationKey: 'e2e-activation-key',
|
|
117
|
+
resetKey: 'e2e-reset-key',
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
<%_ } else { _%>
|
|
121
|
+
const relatedValues: Record<string, any> = <%- literal(otherValues) %>;
|
|
122
|
+
const { body: related } = await request(server).post('/api/<%= otherEntity.entityApiUrl %>').send(relatedValues).expect(201);
|
|
123
|
+
<%_ } _%>
|
|
124
|
+
<%_ if (otherTextField) { _%>
|
|
125
|
+
const reference = { <%= otherId %>: related.<%= otherId %>, <%= otherTextField.fieldName %>: 'not stored through the relationship' };
|
|
126
|
+
<%_ } else { _%>
|
|
127
|
+
const reference = { <%= otherId %>: related.<%= otherId %> };
|
|
128
|
+
<%_ } _%>
|
|
129
|
+
const { body: stored } = await request(server)
|
|
130
|
+
.post('/api/<%= entityApiUrl %>')
|
|
131
|
+
.send({ ...createdValues, <%= property %>: <%- collection ? '[reference]' : 'reference' %> })
|
|
132
|
+
.expect(201);
|
|
133
|
+
|
|
134
|
+
const { body: read } = await request(server).get(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(200);
|
|
135
|
+
<%_ if (collection) { _%>
|
|
136
|
+
expect(read.<%= property %>).toEqual([expect.objectContaining({ <%= otherId %>: related.<%= otherId %> })]);
|
|
137
|
+
<%_ } else { _%>
|
|
138
|
+
expect(read.<%= property %>).toMatchObject({ <%= otherId %>: related.<%= otherId %> });
|
|
139
|
+
<%_ } _%>
|
|
140
|
+
<%_ if (otherEntity.builtInUser) { _%>
|
|
141
|
+
// The keys of the user never in a response, like the @JsonIgnore keys of JHipster Spring Boot.
|
|
142
|
+
expect(JSON.stringify(read.<%= property %>)).not.toMatch(/e2e-(activation|reset)-key/);
|
|
143
|
+
<%_ } _%>
|
|
144
|
+
<%_ if (otherTextField) { _%>
|
|
145
|
+
const { body: relatedRead } = await request(server).get(`/api/<%= otherEntity.entityApiUrl %>/${related.<%= otherId %>}`).expect(200);
|
|
146
|
+
expect(relatedRead.<%= otherTextField.fieldName %>).toBe(relatedValues.<%= otherTextField.fieldName %>);
|
|
147
|
+
<%_ } _%>
|
|
148
|
+
|
|
149
|
+
await request(server).delete(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(204);
|
|
150
|
+
<%_ if (otherEntity.builtInUser) { _%>
|
|
151
|
+
await users.remove(related);
|
|
152
|
+
<%_ } else if (!otherEntity.builtIn) { _%>
|
|
153
|
+
await request(server).delete(`/api/<%= otherEntity.entityApiUrl %>/${related.<%= otherId %>}`).expect(204);
|
|
154
|
+
<%_ } _%>
|
|
155
|
+
});
|
|
156
|
+
<%_ } _%>
|
|
157
|
+
<%_ for (const relationship of inverseRelationships) {
|
|
158
|
+
const otherEntity = relationship.otherEntity;
|
|
159
|
+
const otherId = otherEntity.primaryKey.name;
|
|
160
|
+
const property = relationship.propertyName;
|
|
161
|
+
const collection = relationship.relationshipType !== 'one-to-one';
|
|
162
|
+
const otherProperty = relationship.otherRelationship.propertyName;
|
|
163
|
+
const otherCollection = relationship.relationshipType === 'many-to-many';
|
|
164
|
+
const otherValues = relationship.nodejsRelatedValues;
|
|
165
|
+
_%>
|
|
166
|
+
|
|
167
|
+
it('should not store the <%= property %> relationship from this side, like the mappedBy side of JHipster Spring Boot', async () => {
|
|
168
|
+
const server = app.getHttpServer();
|
|
169
|
+
const { body: stored } = await request(server).post('/api/<%= entityApiUrl %>').send(createdValues).expect(201);
|
|
170
|
+
const reference = { <%= primaryKey.name %>: stored.<%= primaryKey.name %> };
|
|
171
|
+
const { body: related } = await request(server)
|
|
172
|
+
.post('/api/<%= otherEntity.entityApiUrl %>')
|
|
173
|
+
.send({ ...<%- literal(otherValues) %>, <%= otherProperty %>: <%- otherCollection ? '[reference]' : 'reference' %> })
|
|
174
|
+
.expect(201);
|
|
175
|
+
|
|
176
|
+
await request(server)
|
|
177
|
+
.put(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`)
|
|
178
|
+
.send({ ...stored, <%= property %>: <%- collection ? '[]' : 'null' %> })
|
|
179
|
+
.expect(200);
|
|
180
|
+
|
|
181
|
+
const { body: relatedRead } = await request(server).get(`/api/<%= otherEntity.entityApiUrl %>/${related.<%= otherId %>}`).expect(200);
|
|
182
|
+
<%_ if (otherCollection) { _%>
|
|
183
|
+
expect(relatedRead.<%= otherProperty %>).toEqual([expect.objectContaining(reference)]);
|
|
184
|
+
<%_ } else { _%>
|
|
185
|
+
expect(relatedRead.<%= otherProperty %>).toMatchObject(reference);
|
|
186
|
+
<%_ } _%>
|
|
187
|
+
|
|
188
|
+
await request(server).delete(`/api/<%= otherEntity.entityApiUrl %>/${related.<%= otherId %>}`).expect(204);
|
|
189
|
+
await request(server).delete(`/api/<%= entityApiUrl %>/${stored.<%= primaryKey.name %>}`).expect(204);
|
|
190
|
+
});
|
|
191
|
+
<%_ } _%>
|
|
192
|
+
});
|
|
@@ -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
|
+
});
|