Connecting the Swagger documentation generator to the backend.
Connection https://www.npmjs.com/package/prisma-class-generator to generate a DTO from a Prisma.
Creating an nx library for working with the backend.
Connection https://www.npmjs.com/package/@openapitools/openapi-generator-cli to generate an SDK for working with the backend.
1. Install all the necessary packages
Commands
# Install all need dependencies npm i --save @nestjs/swagger # Install all need dev-dependencies npm i --save-dev prisma-class-generator @openapitools/openapi-generator-cli # Install all need peer-dependencies npm i --save class-transformer class-validator
Console output
$ npm i --save @nestjs/swagger added 5 packages, removed 1 package, and audited 2512 packages in 14s 300 packages are looking for funding run `npm fund` for details 17 vulnerabilities (6 moderate, 11 high) To address issues that do not require attention, run: npm audit fix To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details. $ npm i --save-dev prisma-class-generator @openapitools/openapi-generator-cli added 50 packages, and audited 2562 packages in 15s 304 packages are looking for funding run `npm fund` for details 18 vulnerabilities (6 moderate, 12 high) To address issues that do not require attention, run: npm audit fix To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details. $ npm i --save class-transformer class-validator added 1 package, removed 1 package, and audited 2768 packages in 9s 331 packages are looking for funding run `npm fund` for details 18 vulnerabilities (6 moderate, 12 high) To address issues that do not require attention, run: npm audit fix To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details.
2. Creating an Angular library for working with the backend
This library will be used to work with the backend.
Commands
# Create Angular library ./node_modules/.bin/nx g @nx/angular:library app-angular-rest-sdk --buildable --publishable --directory=libs/sdk/app-angular-rest-sdk --simpleName=true --projectNameAndRootFormat=as-provided --strict=true --prefix=app-angular-rest-sdk --standalone=true --selector=app-angular-rest-sdk --changeDetection=OnPush --importPath=@nestjs-mod-fullstack/app-angular-rest-sdk # Change file with test options rm -rf libs/sdk/app-angular-rest-sdk/src/test-setup.ts cp apps/client/src/test-setup.ts libs/sdk/app-angular-rest-sdk/src/test-setup.ts
Console output
$ ./node_modules/.bin/nx g @nx/angular:library app-angular-rest-sdk --buildable --publishable --directory=libs/sdk/app-angular-rest-sdk --simpleName=true --projectNameAndRootFormat=as-provided --strict=true --prefix=app-angular-rest-sdk --standalone=true --selector=app-angular-rest-sdk --changeDetection=OnPush --importPath=@nestjs-mod-fullstack/app-angular-rest-sdk NX Generating @nx/angular:library UPDATE nx.json CREATE libs/sdk/app-angular-rest-sdk/project.json CREATE libs/sdk/app-angular-rest-sdk/README.md CREATE libs/sdk/app-angular-rest-sdk/ng-package.json CREATE libs/sdk/app-angular-rest-sdk/package.json CREATE libs/sdk/app-angular-rest-sdk/tsconfig.json CREATE libs/sdk/app-angular-rest-sdk/tsconfig.lib.json CREATE libs/sdk/app-angular-rest-sdk/tsconfig.lib.prod.json CREATE libs/sdk/app-angular-rest-sdk/src/index.ts CREATE libs/sdk/app-angular-rest-sdk/jest.config.ts CREATE libs/sdk/app-angular-rest-sdk/src/test-setup.ts CREATE libs/sdk/app-angular-rest-sdk/tsconfig.spec.json CREATE libs/sdk/app-angular-rest-sdk/src/lib/app-angular-rest-sdk/app-angular-rest-sdk.component.css CREATE libs/sdk/app-angular-rest-sdk/src/lib/app-angular-rest-sdk/app-angular-rest-sdk.component.html CREATE libs/sdk/app-angular-rest-sdk/src/lib/app-angular-rest-sdk/app-angular-rest-sdk.component.spec.ts CREATE libs/sdk/app-angular-rest-sdk/src/lib/app-angular-rest-sdk/app-angular-rest-sdk.component.ts CREATE libs/sdk/app-angular-rest-sdk/.eslintrc.json UPDATE package.json UPDATE tsconfig.base.json added 31 packages, removed 37 packages, and audited 2556 packages in 12s 304 packages are looking for funding run `npm fund` for details 16 vulnerabilities (4 moderate, 12 high) To address issues that do not require attention, run: npm audit fix To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details. NX 👀 View Details of app-angular-rest-sdk Run "nx show project app-angular-rest-sdk" to view details about this project.
3. Creating a NestJS library for working with the backend
This library will be used from the backend's E2E tests.
Commands
# Create NestJS library ./node_modules/.bin/nx g @nestjs-mod/schematics:library app-rest-sdk --buildable --publishable --directory=libs/sdk/app-rest-sdk --simpleName=true --projectNameAndRootFormat=as-provided --strict=true
Console output
$ ./node_modules/.bin/nx g @nestjs-mod/schematics:library app-rest-sdk --buildable --publishable --directory=libs/sdk/app-rest-sdk --simpleName=true --projectNameAndRootFormat=as-provided --strict=true NX Generating @nestjs-mod/schematics:library CREATE libs/sdk/app-rest-sdk/tsconfig.json CREATE libs/sdk/app-rest-sdk/src/index.ts CREATE libs/sdk/app-rest-sdk/tsconfig.lib.json CREATE libs/sdk/app-rest-sdk/README.md CREATE libs/sdk/app-rest-sdk/package.json CREATE libs/sdk/app-rest-sdk/project.json CREATE libs/sdk/app-rest-sdk/.eslintrc.json CREATE libs/sdk/app-rest-sdk/jest.config.ts CREATE libs/sdk/app-rest-sdk/tsconfig.spec.json UPDATE tsconfig.base.json CREATE libs/sdk/app-rest-sdk/src/lib/app-rest-sdk.configuration.ts CREATE libs/sdk/app-rest-sdk/src/lib/app-rest-sdk.environments.ts CREATE libs/sdk/app-rest-sdk/src/lib/app-rest-sdk.module.ts
4. Add an additional DTO generator to the Prisma
Updated file apps/server/src/prisma/app-schema.prisma
generator client { provider = "prisma-client-js" output = "../../../../node_modules/@prisma/app-client" engineType = "binary" } generator prismaClassGenerator { provider = "prisma-class-generator" output = "../app/generated/rest/dto" dryRun = "false" separateRelationFields = "false" makeIndexFile = "file" } datasource db { provider = "postgres" url = env("SERVER_APP_DATABASE_URL") } model AppDemo { id String @id(map: "PK_APP_DEMO") @default(dbgenerated("uuid_generate_v4()")) @db.Uuid name String @unique(map: "UQ_APP_DEMO") @db.VarChar(128) createdAt DateTime @default(now()) @db.Timestamp(6) updatedAt DateTime @default(now()) @db.Timestamp(6) } model migrations { installed_rank Int @id(map: "__migrations_pk") version String? @db.VarChar(50) description String @db.VarChar(200) type String @db.VarChar(20) script String @db.VarChar(1000) checksum Int? installed_by String @db.VarChar(100) installed_on DateTime @default(now()) @db.Timestamp(6) execution_time Int success Boolean @@index([success], map: "__migrations_s_idx") @@map("__migrations") }
5. Adding support for Swagger documentation generation in the backend code
Updated the apps/server/src/main.ts
file
import { DefaultNestApplicationInitializer, DefaultNestApplicationListener, InfrastructureMarkdownReportGenerator, PACKAGE_JSON_FILE, ProjectUtils, bootstrapNestApplication, isInfrastructureMode } from '@nestjs-mod/common'; import { DOCKER_COMPOSE_FILE, DockerCompose, DockerComposePostgreSQL } from '@nestjs-mod/docker-compose'; import { FLYWAY_JS_CONFIG_FILE, Flyway } from '@nestjs-mod/flyway'; import { NestjsPinoLoggerModule } from '@nestjs-mod/pino'; import { ECOSYSTEM_CONFIG_FILE, Pm2 } from '@nestjs-mod/pm2'; import { FakePrismaClient, PRISMA_SCHEMA_FILE, PrismaModule } from '@nestjs-mod/prisma'; import { TerminusHealthCheckModule } from '@nestjs-mod/terminus'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { MemoryHealthIndicator } from '@nestjs/terminus'; import { writeFileSync } from 'fs'; import { join, resolve } from 'path'; import { AppModule } from './app/app.module'; const appFeatureName = 'app'; const rootFolder = join(__dirname, '..', '..', '..'); const appFolder = join(rootFolder, 'apps', 'server'); bootstrapNestApplication({ modules: { system: [ ProjectUtils.forRoot({ staticConfiguration: { applicationPackageJsonFile: join(appFolder, PACKAGE_JSON_FILE), packageJsonFile: join(rootFolder, PACKAGE_JSON_FILE), envFile: join(rootFolder, '.env'), }, }), DefaultNestApplicationInitializer.forRoot({ staticConfiguration: { bufferLogs: true }, }), NestjsPinoLoggerModule.forRoot(), TerminusHealthCheckModule.forRootAsync({ configurationFactory: (memoryHealthIndicator: MemoryHealthIndicator) => ({ standardHealthIndicators: [ { name: 'memory_heap', check: () => memoryHealthIndicator.checkHeap('memory_heap', 150 * 1024 * 1024), }, ], }), inject: [MemoryHealthIndicator], }), DefaultNestApplicationListener.forRoot({ staticConfiguration: { // When running in infrastructure mode, the backend server does not start. mode: isInfrastructureMode() ? 'silent' : 'listen', async preListen(options) { if (options.app) { options.app.setGlobalPrefix('api'); const swaggerConf = new DocumentBuilder().addBearerAuth().build(); const document = SwaggerModule.createDocument(options.app, swaggerConf); SwaggerModule.setup('swagger', options.app, document); if (isInfrastructureMode()) { writeFileSync(resolve(__dirname, '..', '..', '..', 'app-swagger.json'), JSON.stringify(document)); } } }, }, }), ], core: [ PrismaModule.forRoot({ staticConfiguration: { schemaFile: join(appFolder, 'src', 'prisma', `${appFeatureName}-${PRISMA_SCHEMA_FILE}`), featureName: appFeatureName, prismaModule: isInfrastructureMode() ? { PrismaClient: FakePrismaClient } : import(`@prisma/app-client`), addMigrationScripts: false, }, }), ], feature: [AppModule.forRoot()], infrastructure: [ InfrastructureMarkdownReportGenerator.forRoot({ staticConfiguration: { markdownFile: join(appFolder, 'INFRASTRUCTURE.MD'), skipEmptySettings: true, }, }), Pm2.forRoot({ configuration: { ecosystemConfigFile: join(rootFolder, ECOSYSTEM_CONFIG_FILE), applicationScriptFile: join('dist/apps/server/main.js'), }, }), DockerCompose.forRoot({ configuration: { dockerComposeFileVersion: '3', dockerComposeFile: join(appFolder, DOCKER_COMPOSE_FILE), }, }), DockerComposePostgreSQL.forRoot(), DockerComposePostgreSQL.forFeature({ featureModuleName: appFeatureName, }), Flyway.forRoot({ staticConfiguration: { featureName: appFeatureName, migrationsFolder: join(appFolder, 'src', 'migrations'), configFile: join(rootFolder, FLYWAY_JS_CONFIG_FILE), }, }), ], }, });
6. Adding a command to generate an SDK for working with the backend
The updated part of the apps/server/project' file.json
{ "generate": { "executor": "nx:run-commands", "options": { "commands": ["./node_modules/.bin/prisma generate --schema=./apps/server/src/prisma/app-schema.prisma", "./node_modules/.bin/rucken make-ts-list", "export NESTJS_MODE=infrastructure && ./node_modules/.bin/nx serve server --host=0.0.0.0 --watch=false", "rm -rf ./libs/sdk/app-angular-rest-sdk/src/lib && mkdir ./libs/sdk/app-angular-rest-sdk/src/lib && ./node_modules/.bin/openapi-generator-cli generate -i ./app-swagger.json -g typescript-angular -o ./libs/sdk/app-angular-rest-sdk/src/lib --additional-properties=apiModulePrefix=RestClient,configurationPrefix=RestClient,fileNaming=kebab-case,modelFileSuffix=.interface,modelSuffix=Interface,enumNameSuffix=Type,enumPropertyNaming=original,serviceFileSuffix=-rest.service,serviceSuffix=RestService", "rm -rf ./libs/sdk/app-rest-sdk/src/lib && mkdir ./libs/sdk/app-rest-sdk/src/lib && ./node_modules/.bin/openapi-generator-cli generate -i ./app-swagger.json -g typescript-axios -o ./libs/sdk/app-rest-sdk/src/lib"], "parallel": false, "envFile": "./.env", "color": true } } }
7. For the Swagger generator to work, you need to install Java
Commands
sudo apt install default-jre
Console output
$ sudo apt install default-jre [sudo] password for endy: Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: default-jre-headless openjdk-11-jre openjdk-11-jre-headless Suggested packages: fonts-ipafont-gothic fonts-ipafont-mincho fonts-wqy-microhei | fonts-wqy-zenhei The following NEW packages will be installed: default-jre default-jre-headless openjdk-11-jre openjdk-11-jre-headless 0 upgraded, 4 newly installed, 0 to remove and 9 not upgraded. Need to get 38,5 MB of archives. After this operation, 177 MB of additional disk space will be used. Do you want to continue? [Y/n] Y Get:1 http://ru.archive.ubuntu.com/ubuntu focal-updates/main amd64 openjdk-11-jre-headless amd64 11.0.24+8-1ubuntu3~20.04 [38,3 MB] Get:2 http://ru.archive.ubuntu.com/ubuntu focal/main amd64 default-jre-headless amd64 2:1.11-72 [3 192 B] Get:3 http://ru.archive.ubuntu.com/ubuntu focal-updates/main amd64 openjdk-11-jre amd64 11.0.24+8-1ubuntu3~20.04 [195 kB] Get:4 http://ru.archive.ubuntu.com/ubuntu focal/main amd64 default-jre amd64 2:1.11-72 [1 084 B] Fetched 38,5 MB in 6s (6 643 kB/s) Selecting previously unselected package openjdk-11-jre-headless:amd64. (Reading database ... 224645 files and directories currently installed.) Preparing to unpack .../openjdk-11-jre-headless_11.0.24+8-1ubuntu3~20.04_amd64.deb ... Unpacking openjdk-11-jre-headless:amd64 (11.0.24+8-1ubuntu3~20.04) ... Selecting previously unselected package default-jre-headless. Preparing to unpack .../default-jre-headless_2%3a1.11-72_amd64.deb ... Unpacking default-jre-headless (2:1.11-72) ... Selecting previously unselected package openjdk-11-jre:amd64. Preparing to unpack .../openjdk-11-jre_11.0.24+8-1ubuntu3~20.04_amd64.deb ... Unpacking openjdk-11-jre:amd64 (11.0.24+8-1ubuntu3~20.04) ... Selecting previously unselected package default-jre. Preparing to unpack .../default-jre_2%3a1.11-72_amd64.deb ... Unpacking default-jre (2:1.11-72) ... Setting up openjdk-11-jre-headless:amd64 (11.0.24+8-1ubuntu3~20.04) ... update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/java to provide /usr/bin/java (java) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs to provide /usr/bin/jjs (jjs) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/keytool to provide /usr/bin/keytool (keytool) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/rmid to provide /usr/bin/rmid (rmid) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/rmiregistry to provide /usr/bin/rmiregistry (rmiregistry) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/pack200 to provide /usr/bin/pack200 (pack200) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/unpack200 to provide /usr/bin/unpack200 (unpack200) in auto mode update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/lib/jexec to provide /usr/bin/jexec (jexec) in auto mode Setting up openjdk-11-jre:amd64 (11.0.24+8-1ubuntu3~20.04) ... Setting up default-jre-headless (2:1.11-72) ... Setting up default-jre (2:1.11-72) ... Processing triggers for mime-support (3.64ubuntu1) ... Processing triggers for hicolor-icon-theme (0.17-2) ... Processing triggers for gnome-menus (3.36.0-1ubuntu1) ... Processing triggers for desktop-file-utils (0.24-1ubuntu3) ...
8. Since the eslint library rules with the SDK differ from the application rules, we add the SDK folders to .eslintignore
Updated .eslintignore
file
node_modules libs/sdk/app-rest-sdk/src/lib libs/sdk/app-angular-rest-sdk/src/lib
9. Since the generators create a configuration typescript for the tests, they automatically fall into the general index.ts, we need to add them to the exceptions of the index generator.ts files
Updated the rucken.json
{ "makeTsList": { "indexFileName": "index", "excludes": [ "test-setup.ts", // <-- updates "*node_modules*", "*public_api.ts*", "*.spec*", "environment*", "*e2e*", "*.stories.ts", "*.d.ts" ] } }
10. Starting all generators
Commands
npm run generate
Console output
$ npm run generate > @nestjs-mod-fullstack/source@0.0.0 generate > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=generate --skip-nx-cache=true && npm run make-ts-list && npm run lint:fix ✔ nx run server:generate (14s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target generate for project server (14s) > @nestjs-mod-fullstack/source@0.0.0 make-ts-list > ./node_modules/.bin/rucken make-ts-list > @nestjs-mod-fullstack/source@0.0.0 lint:fix > npm run tsc:lint && ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=lint --fix > @nestjs-mod-fullstack/source@0.0.0 tsc:lint > ./node_modules/.bin/tsc --noEmit -p tsconfig.base.json ✔ nx run client:lint [existing outputs match the cache, left as is] ✔ nx run app-angular-rest-sdk:lint [existing outputs match the cache, left as is] ✔ nx run server-e2e:lint (1s) ✔ nx run server:lint (1s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target lint for 4 projects (1s) With additional flags: --fix=true Nx read the output from the cache instead of running the command for 2 out of 4 tasks. NX Nx detected flaky tasks client:lint app-angular-rest-sdk:lint server-e2e:lint Flaky tasks can disrupt your CI pipeline. Automatically retry them with Nx Cloud. Learn more at https://nx.dev/ci/features/flaky-tasks
11. We register the created DTOs for the methods in the AppController controller and create all the missing DTOs
Updated the apps/server/src/app/app.controller.ts
file
import { Controller, Delete, Get, Param, Post } from '@nestjs/common'; import { InjectPrismaClient } from '@nestjs-mod/prisma'; import { ApiCreatedResponse, ApiProperty, ApiResponse } from '@nestjs/swagger'; import { PrismaClient as AppPrismaClient } from '@prisma/app-client'; import { randomUUID } from 'crypto'; import { AppService } from './app.service'; import { AppDemo } from './generated/rest/dto/app_demo'; export class AppData { // <- updates @ApiProperty({ type: String }) message: string; } @Controller() export class AppController { constructor( @InjectPrismaClient() private readonly appPrismaClient: AppPrismaClient, private readonly appService: AppService ) {} @Get() @ApiResponse({ type: AppData }) // <- updates getData() { return this.appService.getData(); } @Post('/demo') @ApiCreatedResponse({ type: AppDemo }) // <- updates async demoCreateOne() { return await this.appPrismaClient.appDemo.create({ data: { name: 'demo name' + randomUUID() } }); } @Get('/demo/:id') @ApiResponse({ type: AppDemo }) // <- updates async demoFindOne(@Param('id') id: string) { return await this.appPrismaClient.appDemo.findFirstOrThrow({ where: { id } }); } @Delete('/demo/:id') @ApiResponse({ type: AppDemo }) // <- updates async demoDeleteOne(@Param('id') id: string) { return await this.appPrismaClient.appDemo.delete({ where: { id } }); } @Get('/demo') @ApiResponse({ type: AppDemo, isArray: true }) // <- updates async demoFindMany() { return await this.appPrismaClient.appDemo.findMany(); } }
12. Connecting the SDK module to work with the backend in an Angular application
Updated file apps/client/src/app/app.config.ts
import { provideHttpClient } from '@angular/common/http'; import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core'; import { provideClientHydration } from '@angular/platform-browser'; import { provideRouter } from '@angular/router'; import { RestClientApiModule, RestClientConfiguration } from '@nestjs-mod-fullstack/app-angular-rest-sdk'; import { appRoutes } from './app.routes'; export const appConfig: ApplicationConfig = { providers: [ provideClientHydration(), provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(appRoutes), provideHttpClient(), importProvidersFrom( RestClientApiModule.forRoot( () => new RestClientConfiguration({ basePath: 'http://localhost:3000', }) ) ), ], };
13. Changing HttpClient to DefaultRestService in the Angular component of the application that works with the backend
Updated the apps/client/src/app/app.component.ts
file
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { RouterModule } from '@angular/router'; import { DefaultRestService } from '@nestjs-mod-fullstack/app-angular-rest-sdk'; import { NxWelcomeComponent } from './nx-welcome.component'; @Component({ standalone: true, imports: [NxWelcomeComponent, RouterModule], selector: 'app-root', templateUrl: './app.component.html', styleUrl: './app.component.scss', encapsulation: ViewEncapsulation.None, }) export class AppComponent implements OnInit { title = 'client'; serverMessage!: string; constructor(private readonly defaultRestService: DefaultRestService) {} ngOnInit() { this.defaultRestService.appControllerGetData().subscribe((result) => (this.serverMessage = result.message)); } }
14. Connecting the SDK to work with the backend in the Angular application unit test
Updated file apps/client/src/app/app.component.spec.ts
import { HttpClientModule } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { RouterModule } from '@angular/router'; import { RestClientApiModule, RestClientConfiguration } from '@nestjs-mod-fullstack/app-angular-rest-sdk'; import { AppComponent } from './app.component'; import { NxWelcomeComponent } from './nx-welcome.component'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ AppComponent, NxWelcomeComponent, RouterModule.forRoot([]), HttpClientModule, // <- updates RestClientApiModule.forRoot( // <- updates () => new RestClientConfiguration({ basePath: 'http://localhost:3000', }) ), ], }).compileComponents(); }); it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement as HTMLElement; expect(compiled.querySelector('h1')?.textContent).toContain('Welcome client'); }); it(`should have as title 'client'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app.title).toEqual('client'); }); });
15. Connecting the SDK to work with the backend in the E2E tests NestJS application
Updated file apps/server-e2e/src/server/server.spec.ts
import { Configuration, DefaultApi } from '@nestjs-mod-fullstack/app-rest-sdk'; describe('GET /api', () => { const defaultApi = new DefaultApi(new Configuration({ basePath: '/api' })); let newDemoObject: { id: string }; it('should return a message', async () => { const res = await defaultApi.appControllerGetData(); expect(res.status).toBe(200); expect(res.data).toEqual({ message: 'Hello API' }); }); it('should create and return a demo object', async () => { const res = await defaultApi.appControllerDemoCreateOne(); expect(res.status).toBe(201); expect(res.data.name).toContain('demo name'); newDemoObject = res.data; }); it('should get demo object by id', async () => { const res = await defaultApi.appControllerDemoFindOne(newDemoObject.id); expect(res.status).toBe(200); expect(res.data).toMatchObject(newDemoObject); }); it('should get all demo object', async () => { const res = await defaultApi.appControllerDemoFindMany(); expect(res.status).toBe(200); expect(res.data.filter((row) => row.id === newDemoObject.id)).toMatchObject([newDemoObject]); }); it('should delete demo object by id', async () => { const res = await defaultApi.appControllerDemoDeleteOne(newDemoObject.id); expect(res.status).toBe(200); expect(res.data).toMatchObject(newDemoObject); }); it('should get all demo object', async () => { const res = await defaultApi.appControllerDemoFindMany(); expect(res.status).toBe(200); expect(res.data.filter((row) => row.id === newDemoObject.id)).toMatchObject([]); }); });
16. Running unit tests for NestJS and Angular applications
Commands
npm run test
Console output
$ npm run test > @nestjs-mod-fullstack/source@0.0.0 test > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=test --skip-nx-cache=true --passWithNoTests --output-style=stream-without-prefixes > nx run app-angular-rest-sdk:test --passWithNoTests > nx run app-rest-sdk:test --passWithNoTests > nx run client:test --passWithNoTests NX Running target test for 4 projects ✔ nx run app-angular-rest-sdk:test (2s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ✔ nx run app-rest-sdk:test (2s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Running target test for 4 projects With additional flags: --passWithNoTests=true → Executing 2/2 remaining tasks in parallel... ✔ nx run client:test (5s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Running target test for 4 projects With additional flags: ✔ nx run server:test (5s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target test for 4 projects (7s) With additional flags: --passWithNoTests=true
17. Launching E2E tests for NestJS and Angular applications
Commands
./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes
Console output
$ ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes > nx run client-e2e:e2e > playwright test NX Running target e2e for 2 projects and 1 task they depend on NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/3 remaining tasks... ⠴ nx run client-e2e:e2e ✔ nx run client-e2e:e2e (7s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ✔ nx run server:build:production (3s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Running target e2e for 2 projects and 1 task they depend on → Executing 1/1 remaining tasks... ⠦ nx run server-e2e:e2e ✔ 2/2 succeeded [0 read from cache] PASS server-e2e apps/server-e2e/src/server/server.spec.ts GET /api ✓ should return a message (27 ms) ✔ nx run server-e2e:e2e (2s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Successfully ran target e2e for 2 projects and 1 task they depend on (12s) NX Nx detected a flaky task server-e2e:e2e Flaky tasks can disrupt your CI pipeline. Automatically retry them with Nx Cloud. Learn more at https://nx.dev/ci/features/flaky-tasks
There are no pictures in the post, the application operation is checked through tests, Swagger documentation is available at: http://localhost:3000/swagger .
In the next post, I will build applications on NestJS and Angular and run them in two versions: via PM2 and via Docker Compose...
Links
https://nestjs.com - the official website of the framework
https://nestjs-mod.com - the official website of additional utilities
https://github.com/nestjs-mod/nestjs-mod-fullstack - the project from the post
https://github.com/nestjs-mod/nestjs-mod-fullstack/commit/0353b23b1b65d1ff8e6e5f6185e235bbe05cf523 - commit to current changes
Top comments (0)