From a2ceca14807e72283267f459d6990de1225ad078 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Fri, 27 May 2022 12:31:52 -0300 Subject: [PATCH 01/19] init filter exception --- package-lock.json | 53 +++++++++++++++++++ package.json | 2 + src/app.module.ts | 6 ++- .../exception/custom-error.exception.ts | 15 ++++++ .../exception/empty-data.exception.ts | 11 ++++ .../filter/abstract-exception.filter.ts | 31 +++++++++++ .../filter/custom-error-exception.filter.ts | 17 ++++++ .../filter/error-exception.filter.ts | 16 ++++++ .../filter/http-exception.filter.ts | 20 +++++++ src/error-handling/filters.module.ts | 25 +++++++++ .../custom-exception-response.interface.ts | 7 +++ src/main.ts | 6 +++ .../controller/neighborhoods.controller.ts | 0 .../helper/extensions/exensions.module.ts | 0 .../helper/extensions/string.extension.ts | 0 .../adapter/neighborhoods.module.ts | 2 +- .../neighborhoods/guia-mais.repository.ts | 6 +-- .../adapter/service/neighborhoods.service.ts | 3 +- .../interface}/puppeteer/page.interface.ts | 0 ...eteer-neighborhood-repository.interface.ts | 2 +- .../puppeteer-repository.interface.ts | 0 .../model/neighborhoods-by-city.model.ts | 0 .../search/search-neighborhoods.model.ts | 0 .../puppeteer-neighborhood.repository.ts | 20 +++---- .../puppeteer/puppeteer.repository.ts | 2 +- .../neighborhoods-service.interface.ts | 0 .../neighborhoods.controller.spec.ts | 6 +-- .../guia-mais.repository.spec.ts | 6 +-- .../service/neighborhoods.service.spec.ts | 4 +- .../model/neighborhoods-by-city.model.spec.ts | 2 +- .../search/search-neighborhoods.model.spec.ts | 2 +- .../puppeteer-neighborhood.repository.spec.ts | 6 +-- .../puppeteer/puppeteer.repository.spec.ts | 6 +-- 33 files changed, 239 insertions(+), 37 deletions(-) create mode 100644 src/error-handling/exception/custom-error.exception.ts create mode 100644 src/error-handling/exception/empty-data.exception.ts create mode 100644 src/error-handling/filter/abstract-exception.filter.ts create mode 100644 src/error-handling/filter/custom-error-exception.filter.ts create mode 100644 src/error-handling/filter/error-exception.filter.ts create mode 100644 src/error-handling/filter/http-exception.filter.ts create mode 100644 src/error-handling/filters.module.ts create mode 100644 src/error-handling/interface/custom-exception-response.interface.ts rename src/{ => places-interface}/adapter/controller/neighborhoods.controller.ts (100%) rename src/{ => places-interface}/adapter/helper/extensions/exensions.module.ts (100%) rename src/{ => places-interface}/adapter/helper/extensions/string.extension.ts (100%) rename src/{ => places-interface}/adapter/neighborhoods.module.ts (92%) rename src/{ => places-interface}/adapter/repository/neighborhoods/guia-mais.repository.ts (88%) rename src/{ => places-interface}/adapter/service/neighborhoods.service.ts (89%) rename src/{domain/interfaces => places-interface/domain/interface}/puppeteer/page.interface.ts (100%) rename src/{domain/interfaces => places-interface/domain/interface}/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts (79%) rename src/{domain/interfaces => places-interface/domain/interface}/puppeteer/repository/puppeteer-repository.interface.ts (100%) rename src/{ => places-interface}/domain/model/neighborhoods-by-city.model.ts (100%) rename src/{ => places-interface}/domain/model/search/search-neighborhoods.model.ts (100%) rename src/{ => places-interface}/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts (52%) rename src/{ => places-interface}/domain/repository/puppeteer/puppeteer.repository.ts (87%) rename src/{ => places-interface}/domain/service/neighborhoods-service.interface.ts (100%) diff --git a/package-lock.json b/package-lock.json index f41bd8e..c8c7082 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "@nestjs/platform-express": "^8.0.0", "chai": "^4.3.6", "cheerio": "^1.0.0-rc.10", + "class-transformer": "^0.5.1", + "class-validator": "^0.13.2", "dotenv": "^16.0.1", "fs": "^0.0.1-security", "js-yaml": "^4.1.0", @@ -3050,6 +3052,20 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "node_modules/class-validator": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", + "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", + "dependencies": { + "libphonenumber-js": "^1.9.43", + "validator": "^13.7.0" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -6386,6 +6402,11 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.6.tgz", + "integrity": "sha512-CIjT100/SmntsUjsLVs2t3ufeN4KdNXUxhD07tH153pdbaCWuAjv0jK/gPuywR3IImB/U/MQM+x9RfhMs5XZiA==" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -8868,6 +8889,14 @@ "node": ">=10.12.0" } }, + "node_modules/validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -11568,6 +11597,20 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "class-validator": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.2.tgz", + "integrity": "sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==", + "requires": { + "libphonenumber-js": "^1.9.43", + "validator": "^13.7.0" + } + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -14098,6 +14141,11 @@ "type-check": "~0.4.0" } }, + "libphonenumber-js": { + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.6.tgz", + "integrity": "sha512-CIjT100/SmntsUjsLVs2t3ufeN4KdNXUxhD07tH153pdbaCWuAjv0jK/gPuywR3IImB/U/MQM+x9RfhMs5XZiA==" + }, "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -15943,6 +15991,11 @@ "source-map": "^0.7.3" } }, + "validator": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", + "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 93d6690..b498a96 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "@nestjs/platform-express": "^8.0.0", "chai": "^4.3.6", "cheerio": "^1.0.0-rc.10", + "class-transformer": "^0.5.1", + "class-validator": "^0.13.2", "dotenv": "^16.0.1", "fs": "^0.0.1-security", "js-yaml": "^4.1.0", diff --git a/src/app.module.ts b/src/app.module.ts index 849f3e2..4a90b4f 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,10 +1,12 @@ import { Module } from '@nestjs/common'; import { PuppeteerModule } from 'nest-puppeteer'; -import { ExtensionsModule } from './adapter/helper/extensions/exensions.module'; -import { NeighborhoodsModule } from './adapter/neighborhoods.module'; +import { FiltersModule } from './error-handling/filters.module'; +import { ExtensionsModule } from './places-interface/adapter/helper/extensions/exensions.module'; +import { NeighborhoodsModule } from './places-interface/adapter/neighborhoods.module'; @Module({ imports: [ + FiltersModule, ExtensionsModule, PuppeteerModule.forRoot({ isGlobal: true diff --git a/src/error-handling/exception/custom-error.exception.ts b/src/error-handling/exception/custom-error.exception.ts new file mode 100644 index 0000000..9951cc1 --- /dev/null +++ b/src/error-handling/exception/custom-error.exception.ts @@ -0,0 +1,15 @@ +import { HttpException } from '@nestjs/common'; + +export class CustomErrorException extends HttpException { + constructor( + public message: string, + status: number, + public errCode: number = -1 + ) { + super(message, status); + } + + get type(): string { + return this.constructor.name; + } +} diff --git a/src/error-handling/exception/empty-data.exception.ts b/src/error-handling/exception/empty-data.exception.ts new file mode 100644 index 0000000..e60dd55 --- /dev/null +++ b/src/error-handling/exception/empty-data.exception.ts @@ -0,0 +1,11 @@ +import { HttpStatus } from '@nestjs/common'; +import { CustomErrorException } from './custom-error.exception'; + +export class EmptyDataException extends CustomErrorException { + constructor(element = '') { + super( + `The ${element} data cannot be empty`, + HttpStatus.INTERNAL_SERVER_ERROR + ); + } +} diff --git a/src/error-handling/filter/abstract-exception.filter.ts b/src/error-handling/filter/abstract-exception.filter.ts new file mode 100644 index 0000000..90cb25a --- /dev/null +++ b/src/error-handling/filter/abstract-exception.filter.ts @@ -0,0 +1,31 @@ +import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common'; +import { AbstractHttpAdapter, HttpAdapterHost } from '@nestjs/core'; +import { CustomExceptionReponse } from '../interface/custom-exception-response.interface'; + +@Catch() +export abstract class AbstractExceptionFilter + implements ExceptionFilter +{ + protected httpAdapter: AbstractHttpAdapter; + constructor(adapterHost: HttpAdapterHost) { + this.httpAdapter = adapterHost.httpAdapter; + } + + getResponse( + host: ArgumentsHost, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _exception: ExceptionType + ): Record { + return host.switchToHttp().getResponse(); + } + + catch(exception: ExceptionType, host: ArgumentsHost) { + const response = this.getResponse(host, exception); + + const customResponse = this.makeCustomResponse(exception); + + this.httpAdapter.reply(response, customResponse, customResponse.status); + } + + abstract makeCustomResponse(exception: ExceptionType): CustomExceptionReponse; +} diff --git a/src/error-handling/filter/custom-error-exception.filter.ts b/src/error-handling/filter/custom-error-exception.filter.ts new file mode 100644 index 0000000..13d1ae0 --- /dev/null +++ b/src/error-handling/filter/custom-error-exception.filter.ts @@ -0,0 +1,17 @@ +import { Catch } from '@nestjs/common'; +import { CustomErrorException } from '../exception/custom-error.exception'; +import { AbstractExceptionFilter } from './abstract-exception.filter'; +import { CustomExceptionReponse } from '../interface/custom-exception-response.interface'; + +@Catch(CustomErrorException) +export class CustomErrorExceptionFilter extends AbstractExceptionFilter { + makeCustomResponse(exception: CustomErrorException): CustomExceptionReponse { + return { + status: exception.getStatus(), + message: exception.message, + type: exception.type, + errorCode: exception.errCode, + err: exception + }; + } +} diff --git a/src/error-handling/filter/error-exception.filter.ts b/src/error-handling/filter/error-exception.filter.ts new file mode 100644 index 0000000..26f8496 --- /dev/null +++ b/src/error-handling/filter/error-exception.filter.ts @@ -0,0 +1,16 @@ +import { Catch, HttpStatus } from '@nestjs/common'; +import { AbstractExceptionFilter } from './abstract-exception.filter'; +import { CustomExceptionReponse } from '../interface/custom-exception-response.interface'; + +@Catch() +export class ErrorExceptionFilter extends AbstractExceptionFilter { + makeCustomResponse(exception: Error): CustomExceptionReponse { + return { + status: HttpStatus.INTERNAL_SERVER_ERROR, + message: exception.message, + type: exception.name, + errorCode: HttpStatus.INTERNAL_SERVER_ERROR, + err: exception + }; + } +} diff --git a/src/error-handling/filter/http-exception.filter.ts b/src/error-handling/filter/http-exception.filter.ts new file mode 100644 index 0000000..6ca7d7f --- /dev/null +++ b/src/error-handling/filter/http-exception.filter.ts @@ -0,0 +1,20 @@ +import { Catch, ArgumentsHost, HttpException } from '@nestjs/common'; +import { AbstractExceptionFilter } from './abstract-exception.filter'; +import { CustomExceptionReponse } from '../interface/custom-exception-response.interface'; + +@Catch(HttpException) +export class HttpExceptionFilter extends AbstractExceptionFilter { + getResponse(host: ArgumentsHost, exception: HttpException): any { + return exception.getResponse(); + } + + makeCustomResponse(exception: HttpException): CustomExceptionReponse { + return { + status: exception.getStatus(), + message: exception.message, + type: exception.name, + errorCode: exception.getStatus(), + err: exception + }; + } +} diff --git a/src/error-handling/filters.module.ts b/src/error-handling/filters.module.ts new file mode 100644 index 0000000..086560e --- /dev/null +++ b/src/error-handling/filters.module.ts @@ -0,0 +1,25 @@ +import { Module } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; +import { CustomErrorExceptionFilter } from './filter/custom-error-exception.filter'; +import { ErrorExceptionFilter } from './filter/error-exception.filter'; +import { HttpExceptionFilter } from './filter/http-exception.filter'; + +@Module({ + imports: [], + controllers: [], + providers: [ + { + provide: APP_FILTER, + useClass: HttpExceptionFilter + }, + { + provide: APP_FILTER, + useClass: CustomErrorExceptionFilter + }, + { + provide: APP_FILTER, + useClass: ErrorExceptionFilter + } + ] +}) +export class FiltersModule {} diff --git a/src/error-handling/interface/custom-exception-response.interface.ts b/src/error-handling/interface/custom-exception-response.interface.ts new file mode 100644 index 0000000..99f01d6 --- /dev/null +++ b/src/error-handling/interface/custom-exception-response.interface.ts @@ -0,0 +1,7 @@ +export interface CustomExceptionReponse { + status: number; + message: string; + type: string; + errorCode: number; + err: any; +} diff --git a/src/main.ts b/src/main.ts index 13cad38..3d7c7a0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,14 @@ +import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); + app.useGlobalPipes( + new ValidationPipe({ + transform: true + }) + ); await app.listen(3000); } bootstrap(); diff --git a/src/adapter/controller/neighborhoods.controller.ts b/src/places-interface/adapter/controller/neighborhoods.controller.ts similarity index 100% rename from src/adapter/controller/neighborhoods.controller.ts rename to src/places-interface/adapter/controller/neighborhoods.controller.ts diff --git a/src/adapter/helper/extensions/exensions.module.ts b/src/places-interface/adapter/helper/extensions/exensions.module.ts similarity index 100% rename from src/adapter/helper/extensions/exensions.module.ts rename to src/places-interface/adapter/helper/extensions/exensions.module.ts diff --git a/src/adapter/helper/extensions/string.extension.ts b/src/places-interface/adapter/helper/extensions/string.extension.ts similarity index 100% rename from src/adapter/helper/extensions/string.extension.ts rename to src/places-interface/adapter/helper/extensions/string.extension.ts diff --git a/src/adapter/neighborhoods.module.ts b/src/places-interface/adapter/neighborhoods.module.ts similarity index 92% rename from src/adapter/neighborhoods.module.ts rename to src/places-interface/adapter/neighborhoods.module.ts index 8125e9d..9875e43 100644 --- a/src/adapter/neighborhoods.module.ts +++ b/src/places-interface/adapter/neighborhoods.module.ts @@ -4,7 +4,7 @@ import { PuppeteerModule } from 'nest-puppeteer'; import { NeighborhoodsController } from './controller/neighborhoods.controller'; import { GuiaMaisRepository } from './repository/neighborhoods/guia-mais.repository'; import { NeighborhoodsService } from './service/neighborhoods.service'; -import configuration from '../config/configuration'; +import configuration from '../../config/configuration'; @Module({ imports: [ diff --git a/src/adapter/repository/neighborhoods/guia-mais.repository.ts b/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts similarity index 88% rename from src/adapter/repository/neighborhoods/guia-mais.repository.ts rename to src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts index fdcf050..ba48522 100644 --- a/src/adapter/repository/neighborhoods/guia-mais.repository.ts +++ b/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts @@ -2,11 +2,11 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { CheerioAPI } from 'cheerio'; import { InjectPage } from 'nest-puppeteer'; -import { IPuppeteerNeighborhoodRepository } from '../../../domain/interfaces/puppeteer/repository/puppeteer-neighborhood-repository.interface'; -import { PuppeteerNeighborhoodRepository } from '../../../domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository'; import { NeighborhoodsByCity } from '../../../domain/model/neighborhoods-by-city.model'; import { SearchNeighborhoods } from '../../../domain/model/search/search-neighborhoods.model'; -import { Page } from '../../../domain/interfaces/puppeteer/page.interface'; +import { IPuppeteerNeighborhoodRepository } from '../../../domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface'; +import { PuppeteerNeighborhoodRepository } from '../../../domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository'; +import { Page } from '../../../domain/interface/puppeteer/page.interface'; @Injectable() export class GuiaMaisRepository diff --git a/src/adapter/service/neighborhoods.service.ts b/src/places-interface/adapter/service/neighborhoods.service.ts similarity index 89% rename from src/adapter/service/neighborhoods.service.ts rename to src/places-interface/adapter/service/neighborhoods.service.ts index c0de949..04c365c 100644 --- a/src/adapter/service/neighborhoods.service.ts +++ b/src/places-interface/adapter/service/neighborhoods.service.ts @@ -1,7 +1,8 @@ import { Inject, Injectable } from '@nestjs/common'; -import { INeighborhoodsService } from 'src/domain/service/neighborhoods-service.interface'; import { NeighborhoodsByCity } from '../../domain/model/neighborhoods-by-city.model'; import { SearchNeighborhoods } from '../../domain/model/search/search-neighborhoods.model'; +import { INeighborhoodsService } from '../../domain/service/neighborhoods-service.interface'; + import { GuiaMaisRepository } from '../repository/neighborhoods/guia-mais.repository'; @Injectable() diff --git a/src/domain/interfaces/puppeteer/page.interface.ts b/src/places-interface/domain/interface/puppeteer/page.interface.ts similarity index 100% rename from src/domain/interfaces/puppeteer/page.interface.ts rename to src/places-interface/domain/interface/puppeteer/page.interface.ts diff --git a/src/domain/interfaces/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts b/src/places-interface/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts similarity index 79% rename from src/domain/interfaces/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts rename to src/places-interface/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts index f202f81..063ff0c 100644 --- a/src/domain/interfaces/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts +++ b/src/places-interface/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts @@ -1,4 +1,4 @@ -import { SearchNeighborhoods } from 'src/domain/model/search/search-neighborhoods.model'; +import { SearchNeighborhoods } from '../../../model/search/search-neighborhoods.model'; import { NeighborhoodsByCity } from '../../../model/neighborhoods-by-city.model'; import { IPuppeteerRepository } from './puppeteer-repository.interface'; diff --git a/src/domain/interfaces/puppeteer/repository/puppeteer-repository.interface.ts b/src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts similarity index 100% rename from src/domain/interfaces/puppeteer/repository/puppeteer-repository.interface.ts rename to src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts diff --git a/src/domain/model/neighborhoods-by-city.model.ts b/src/places-interface/domain/model/neighborhoods-by-city.model.ts similarity index 100% rename from src/domain/model/neighborhoods-by-city.model.ts rename to src/places-interface/domain/model/neighborhoods-by-city.model.ts diff --git a/src/domain/model/search/search-neighborhoods.model.ts b/src/places-interface/domain/model/search/search-neighborhoods.model.ts similarity index 100% rename from src/domain/model/search/search-neighborhoods.model.ts rename to src/places-interface/domain/model/search/search-neighborhoods.model.ts diff --git a/src/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts b/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts similarity index 52% rename from src/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts rename to src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts index f7b80cb..d0aedb6 100644 --- a/src/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts +++ b/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { CheerioAPI } from 'cheerio'; -import { NeighborhoodsByCity } from 'src/domain/model/neighborhoods-by-city.model'; -import { SearchNeighborhoods } from 'src/domain/model/search/search-neighborhoods.model'; +import { NeighborhoodsByCity } from '../../../model/neighborhoods-by-city.model'; +import { SearchNeighborhoods } from '../../../model/search/search-neighborhoods.model'; import { PuppeteerRepository } from '../puppeteer.repository'; -import { IPuppeteerNeighborhoodRepository } from '../../../interfaces/puppeteer/repository/puppeteer-neighborhood-repository.interface'; +import { IPuppeteerNeighborhoodRepository } from '../../../interface/puppeteer/repository/puppeteer-neighborhood-repository.interface'; export abstract class PuppeteerNeighborhoodRepository extends PuppeteerRepository @@ -16,16 +16,12 @@ export abstract class PuppeteerNeighborhoodRepository return this.buildElementFromDocument(searchParams, $); } - /* istanbul ignore next */ - buildElementFromDocument( + abstract buildElementFromDocument( _searchParams: SearchNeighborhoods, _$: CheerioAPI - ): NeighborhoodsByCity[] { - throw new Error('Method not implemented.'); - } + ); - /* istanbul ignore next */ - async callEndpoint(_searchParams: SearchNeighborhoods): Promise { - throw new Error('Method not implemented.'); - } + abstract callEndpoint( + _searchParams: SearchNeighborhoods + ): Promise; } diff --git a/src/domain/repository/puppeteer/puppeteer.repository.ts b/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts similarity index 87% rename from src/domain/repository/puppeteer/puppeteer.repository.ts rename to src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts index 9309625..cdb7feb 100644 --- a/src/domain/repository/puppeteer/puppeteer.repository.ts +++ b/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts @@ -1,6 +1,6 @@ import * as cheerio from 'cheerio'; import { CheerioAPI } from 'cheerio'; -import { Page } from '../../interfaces/puppeteer/page.interface'; +import { Page } from '../../interface/puppeteer/page.interface'; export abstract class PuppeteerRepository { constructor(protected url: string, protected readonly page: Page) {} diff --git a/src/domain/service/neighborhoods-service.interface.ts b/src/places-interface/domain/service/neighborhoods-service.interface.ts similarity index 100% rename from src/domain/service/neighborhoods-service.interface.ts rename to src/places-interface/domain/service/neighborhoods-service.interface.ts diff --git a/test/unit/adapter/controller/neighborhoods.controller.spec.ts b/test/unit/adapter/controller/neighborhoods.controller.spec.ts index e9c2f10..ae43214 100644 --- a/test/unit/adapter/controller/neighborhoods.controller.spec.ts +++ b/test/unit/adapter/controller/neighborhoods.controller.spec.ts @@ -1,11 +1,11 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { NeighborhoodsController } from '../../../../src/adapter/controller/neighborhoods.controller'; -import { NeighborhoodsService } from '../../../../src/adapter/service/neighborhoods.service'; +import { NeighborhoodsController } from '../../../../src/places-interface/adapter/controller/neighborhoods.controller'; +import { NeighborhoodsService } from '../../../../src/places-interface/adapter/service/neighborhoods.service'; import { ConfigModule } from '@nestjs/config'; import configuration from '../../../../src/config/configuration'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { NeighborhoodsByCity } from '../../../../src/domain/model/neighborhoods-by-city.model'; +import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; describe('NeighborhoodsController', () => { let neighborhoodsController: NeighborhoodsController; diff --git a/test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts b/test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts index 2d5ee21..788ad7f 100644 --- a/test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts +++ b/test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts @@ -2,11 +2,11 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ConfigService } from '@nestjs/config'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { GuiaMaisRepository } from '../../../../../src/adapter/repository/neighborhoods/guia-mais.repository'; +import { GuiaMaisRepository } from '../../../../../src/places-interface/adapter/repository/neighborhoods/guia-mais.repository'; import { PuppeteerModule } from 'nest-puppeteer'; -import { SearchNeighborhoods } from '../../../../../src/domain/model/search/search-neighborhoods.model'; +import { SearchNeighborhoods } from '../../../../../src/places-interface/domain/model/search/search-neighborhoods.model'; import * as fs from 'fs'; -import { ExtensionsModule } from '../../../../../src/adapter/helper/extensions/exensions.module'; +import { ExtensionsModule } from '../../../../../src/places-interface/adapter/helper/extensions/exensions.module'; import * as cheerio from 'cheerio'; jest.useFakeTimers(); diff --git a/test/unit/adapter/service/neighborhoods.service.spec.ts b/test/unit/adapter/service/neighborhoods.service.spec.ts index ede20db..d0a53a9 100644 --- a/test/unit/adapter/service/neighborhoods.service.spec.ts +++ b/test/unit/adapter/service/neighborhoods.service.spec.ts @@ -1,8 +1,8 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { NeighborhoodsService } from '../../../../src/adapter/service/neighborhoods.service'; +import { NeighborhoodsService } from '../../../../src/places-interface/adapter/service/neighborhoods.service'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { NeighborhoodsByCity } from '../../../../src/domain/model/neighborhoods-by-city.model'; +import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; describe('NeighborhoodsService', () => { let sut: NeighborhoodsService; diff --git a/test/unit/domain/model/neighborhoods-by-city.model.spec.ts b/test/unit/domain/model/neighborhoods-by-city.model.spec.ts index df084bb..44ca28c 100644 --- a/test/unit/domain/model/neighborhoods-by-city.model.spec.ts +++ b/test/unit/domain/model/neighborhoods-by-city.model.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { NeighborhoodsByCity } from '../../../../src/domain/model/neighborhoods-by-city.model'; +import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; describe('NeighborhoodsByCity', () => { it('should instance NeighborhoodsByCity and return the object with the correct properties', async () => { diff --git a/test/unit/domain/model/search/search-neighborhoods.model.spec.ts b/test/unit/domain/model/search/search-neighborhoods.model.spec.ts index e4e67ea..dbbb5a8 100644 --- a/test/unit/domain/model/search/search-neighborhoods.model.spec.ts +++ b/test/unit/domain/model/search/search-neighborhoods.model.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { SearchNeighborhoods } from '../../../../../src/domain/model/search/search-neighborhoods.model'; +import { SearchNeighborhoods } from '../../../../../src/places-interface/domain/model/search/search-neighborhoods.model'; describe('SearchNeighborhoods', () => { it('should instance SearchNeighborhoods and return the object with the correct properties', async () => { diff --git a/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts b/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts index 7dab464..b63f58d 100644 --- a/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts +++ b/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts @@ -1,8 +1,8 @@ import { Test, TestingModule } from '@nestjs/testing'; import { PuppeteerModule } from 'nest-puppeteer'; -import { SearchNeighborhoods } from '../../../../../../src/domain/model/search/search-neighborhoods.model'; -import { ExtensionsModule } from '../../../../../../src/adapter/helper/extensions/exensions.module'; -import { PuppeteerNeighborhoodRepository } from '../../../../../../src/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository'; +import { SearchNeighborhoods } from '../../../../../../src/places-interface/domain/model/search/search-neighborhoods.model'; +import { ExtensionsModule } from '../../../../../../src/places-interface/adapter/helper/extensions/exensions.module'; +import { PuppeteerNeighborhoodRepository } from '../../../../../../src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository'; import { expect } from 'chai'; import * as sinon from 'sinon'; diff --git a/test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts b/test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts index ec3f44b..2dffa64 100644 --- a/test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts +++ b/test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts @@ -5,10 +5,10 @@ import { EvaluateFn } from 'puppeteer'; import { OptionsPage, Page -} from '../../../../../src/domain/interfaces/puppeteer/page.interface'; -import { ExtensionsModule } from '../../../../../src/adapter/helper/extensions/exensions.module'; +} from '../../../../../src/places-interface/domain/interface/puppeteer/page.interface'; +import { ExtensionsModule } from '../../../../../src/places-interface/adapter/helper/extensions/exensions.module'; import { expect } from 'chai'; -import { PuppeteerRepository } from '../../../../../src/domain/repository/puppeteer/puppeteer.repository'; +import { PuppeteerRepository } from '../../../../../src/places-interface/domain/repository/puppeteer/puppeteer.repository'; jest.useFakeTimers(); jest.setTimeout(50000); From 7c485c8da94550c7fa4498e48b6a695b7ce0514d Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sat, 28 May 2022 10:45:51 -0300 Subject: [PATCH 02/19] errors filter --- package-lock.json | 608 +++++++++--------- .../exception/empty-prop.exception.ts | 11 + .../exception/not-found.exception.ts | 8 + .../filter/abstract-exception.filter.ts | 2 + .../filter/custom-error-exception.filter.ts | 2 +- .../filter/error-exception.filter.ts | 18 +- .../filter/http-exception.filter.ts | 2 +- .../custom-exception-response.interface.ts | 2 +- .../helper/extensions/exensions.module.ts | 1 + .../helper/extensions/object.extension.ts | 32 + .../neighborhoods/guia-mais.repository.ts | 5 +- .../puppeteer-repository.interface.ts | 6 +- .../puppeteer-neighborhood.repository.ts | 16 +- .../puppeteer/puppeteer.repository.ts | 5 + .../puppeteer-neighborhood.repository.spec.ts | 82 --- 15 files changed, 412 insertions(+), 388 deletions(-) create mode 100644 src/error-handling/exception/empty-prop.exception.ts create mode 100644 src/error-handling/exception/not-found.exception.ts create mode 100644 src/places-interface/adapter/helper/extensions/object.extension.ts delete mode 100644 test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts diff --git a/package-lock.json b/package-lock.json index c8c7082..2085c6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -232,21 +232,21 @@ } }, "node_modules/@babel/core": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz", - "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", + "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.0", - "@babel/helper-compilation-targets": "^7.17.10", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.0", + "@babel/helpers": "^7.18.2", "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -271,12 +271,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz", - "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.0", + "@babel/types": "^7.18.2", "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" }, @@ -299,9 +299,9 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", - "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.17.10", @@ -326,13 +326,10 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, "engines": { "node": ">=6.9.0" } @@ -403,12 +400,12 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", - "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", "dev": true, "dependencies": { - "@babel/types": "^7.17.0" + "@babel/types": "^7.18.2" }, "engines": { "node": ">=6.9.0" @@ -445,14 +442,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz", - "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", "dev": true, "dependencies": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0" + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" }, "engines": { "node": ">=6.9.0" @@ -510,7 +507,7 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { @@ -544,9 +541,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz", + "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -732,19 +729,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz", - "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", + "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.0", - "@babel/helper-environment-visitor": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/parser": "^7.18.0", - "@babel/types": "^7.18.0", + "@babel/types": "^7.18.2", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -762,9 +759,9 @@ } }, "node_modules/@babel/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz", - "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz", + "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", @@ -790,37 +787,38 @@ "node": ">=0.1.90" } }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" } }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz", - "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.3.2", - "globals": "^13.9.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1360,6 +1358,19 @@ "npm": ">= 6.11.0" } }, + "node_modules/@nestjs/cli/node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@nestjs/common": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.4.5.tgz", @@ -1923,14 +1934,14 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.25.0.tgz", - "integrity": "sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz", + "integrity": "sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.25.0", - "@typescript-eslint/type-utils": "5.25.0", - "@typescript-eslint/utils": "5.25.0", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/type-utils": "5.26.0", + "@typescript-eslint/utils": "5.26.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -1956,14 +1967,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.25.0.tgz", - "integrity": "sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz", + "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.25.0", - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/typescript-estree": "5.25.0", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", "debug": "^4.3.4" }, "engines": { @@ -1983,13 +1994,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.25.0.tgz", - "integrity": "sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz", + "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/visitor-keys": "5.25.0" + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2000,12 +2011,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.25.0.tgz", - "integrity": "sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz", + "integrity": "sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.25.0", + "@typescript-eslint/utils": "5.26.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -2026,9 +2037,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.25.0.tgz", - "integrity": "sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz", + "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2039,13 +2050,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.25.0.tgz", - "integrity": "sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz", + "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/visitor-keys": "5.25.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2066,15 +2077,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.25.0.tgz", - "integrity": "sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.26.0.tgz", + "integrity": "sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.25.0", - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/typescript-estree": "5.25.0", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -2090,12 +2101,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.25.0.tgz", - "integrity": "sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz", + "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.25.0", + "@typescript-eslint/types": "5.26.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2894,9 +2905,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001341", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", - "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", "dev": true, "funding": [ { @@ -3128,7 +3139,7 @@ "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, "engines": { "node": ">=0.8" @@ -3137,7 +3148,7 @@ "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "engines": { "iojs": ">= 1.0.0", @@ -3195,7 +3206,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concat-stream": { "version": "1.6.2", @@ -3293,7 +3304,7 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/cookiejar": { "version": "2.1.3", @@ -3551,10 +3562,9 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "engines": { "node": ">=0.3.1" } @@ -3686,9 +3696,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "version": "1.4.140", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.140.tgz", + "integrity": "sha512-NLz5va823QfJBYOO/hLV4AfU4Crmkl/6Hl2pH3qdJcmi0ySZ3YTWHxOlDm3uJOFBEPy3pIhu8gKQo6prQTWKKA==", "dev": true }, "node_modules/emittery": { @@ -3883,12 +3893,12 @@ } }, "node_modules/eslint": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz", - "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.2.3", + "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -3906,7 +3916,7 @@ "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -4526,9 +4536,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", - "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "funding": [ { "type": "individual", @@ -6842,9 +6852,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", "dev": true }, "node_modules/normalize-path": { @@ -6869,9 +6879,9 @@ } }, "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dependencies": { "boolbase": "^1.0.0" }, @@ -6902,9 +6912,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7926,14 +7936,6 @@ "@sinonjs/commons": "^1.7.0" } }, - "node_modules/sinon/node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8599,12 +8601,12 @@ } }, "node_modules/ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz", + "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==", "dev": true, "dependencies": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -8615,7 +8617,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { @@ -8650,6 +8652,15 @@ "node": ">=0.4.0" } }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -8795,9 +8806,9 @@ } }, "node_modules/typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", + "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -9181,9 +9192,9 @@ } }, "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", + "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", "dev": true, "engines": { "node": ">=8.3.0" @@ -9427,21 +9438,21 @@ "dev": true }, "@babel/core": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz", - "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.2.tgz", + "integrity": "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.0", - "@babel/helper-compilation-targets": "^7.17.10", + "@babel/generator": "^7.18.2", + "@babel/helper-compilation-targets": "^7.18.2", "@babel/helper-module-transforms": "^7.18.0", - "@babel/helpers": "^7.18.0", + "@babel/helpers": "^7.18.2", "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0", + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -9458,12 +9469,12 @@ } }, "@babel/generator": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz", - "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "requires": { - "@babel/types": "^7.18.0", + "@babel/types": "^7.18.2", "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" }, @@ -9482,9 +9493,9 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", - "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.2.tgz", + "integrity": "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ==", "dev": true, "requires": { "@babel/compat-data": "^7.17.10", @@ -9502,13 +9513,10 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", + "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "dev": true }, "@babel/helper-function-name": { "version": "7.17.9", @@ -9561,12 +9569,12 @@ "dev": true }, "@babel/helper-simple-access": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", - "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.2.tgz", + "integrity": "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ==", "dev": true, "requires": { - "@babel/types": "^7.17.0" + "@babel/types": "^7.18.2" } }, "@babel/helper-split-export-declaration": { @@ -9591,14 +9599,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz", - "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.2.tgz", + "integrity": "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg==", "dev": true, "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.18.0", - "@babel/types": "^7.18.0" + "@babel/traverse": "^7.18.2", + "@babel/types": "^7.18.2" } }, "@babel/highlight": { @@ -9644,7 +9652,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "escape-string-regexp": { @@ -9671,9 +9679,9 @@ } }, "@babel/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.3.tgz", + "integrity": "sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -9805,19 +9813,19 @@ } }, "@babel/traverse": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz", - "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", + "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.0", - "@babel/helper-environment-visitor": "^7.16.7", + "@babel/generator": "^7.18.2", + "@babel/helper-environment-visitor": "^7.18.2", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/parser": "^7.18.0", - "@babel/types": "^7.18.0", + "@babel/types": "^7.18.2", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -9831,9 +9839,9 @@ } }, "@babel/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz", - "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.2.tgz", + "integrity": "sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -9853,31 +9861,37 @@ "dev": true, "optional": true }, - "@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true - }, "@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "requires": { - "@cspotcode/source-map-consumer": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } } }, "@eslint/eslintrc": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz", - "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.3.2", - "globals": "^13.9.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -10305,6 +10319,14 @@ "typescript": "4.6.4", "webpack": "5.72.1", "webpack-node-externals": "3.0.0" + }, + "dependencies": { + "typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "dev": true + } } }, "@nestjs/common": { @@ -10767,14 +10789,14 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.25.0.tgz", - "integrity": "sha512-icYrFnUzvm+LhW0QeJNKkezBu6tJs9p/53dpPLFH8zoM9w1tfaKzVurkPotEpAqQ8Vf8uaFyL5jHd0Vs6Z0ZQg==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz", + "integrity": "sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.25.0", - "@typescript-eslint/type-utils": "5.25.0", - "@typescript-eslint/utils": "5.25.0", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/type-utils": "5.26.0", + "@typescript-eslint/utils": "5.26.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -10784,52 +10806,52 @@ } }, "@typescript-eslint/parser": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.25.0.tgz", - "integrity": "sha512-r3hwrOWYbNKP1nTcIw/aZoH+8bBnh/Lh1iDHoFpyG4DnCpvEdctrSl6LOo19fZbzypjQMHdajolxs6VpYoChgA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz", + "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.25.0", - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/typescript-estree": "5.25.0", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.25.0.tgz", - "integrity": "sha512-p4SKTFWj+2VpreUZ5xMQsBMDdQ9XdRvODKXN4EksyBjFp2YvQdLkyHqOffakYZPuWJUDNu3jVXtHALDyTv3cww==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz", + "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/visitor-keys": "5.25.0" + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0" } }, "@typescript-eslint/type-utils": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.25.0.tgz", - "integrity": "sha512-B6nb3GK3Gv1Rsb2pqalebe/RyQoyG/WDy9yhj8EE0Ikds4Xa8RR28nHz+wlt4tMZk5bnAr0f3oC8TuDAd5CPrw==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz", + "integrity": "sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.25.0", + "@typescript-eslint/utils": "5.26.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.25.0.tgz", - "integrity": "sha512-7fWqfxr0KNHj75PFqlGX24gWjdV/FDBABXL5dyvBOWHpACGyveok8Uj4ipPX/1fGU63fBkzSIycEje4XsOxUFA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz", + "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.25.0.tgz", - "integrity": "sha512-MrPODKDych/oWs/71LCnuO7NyR681HuBly2uLnX3r5i4ME7q/yBqC4hW33kmxtuauLTM0OuBOhhkFaxCCOjEEw==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz", + "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==", "dev": true, "requires": { - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/visitor-keys": "5.25.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -10838,26 +10860,26 @@ } }, "@typescript-eslint/utils": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.25.0.tgz", - "integrity": "sha512-qNC9bhnz/n9Kba3yI6HQgQdBLuxDoMgdjzdhSInZh6NaDnFpTUlwNGxplUFWfY260Ya0TRPvkg9dd57qxrJI9g==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.26.0.tgz", + "integrity": "sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.25.0", - "@typescript-eslint/types": "5.25.0", - "@typescript-eslint/typescript-estree": "5.25.0", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.25.0.tgz", - "integrity": "sha512-yd26vFgMsC4h2dgX4+LR+GeicSKIfUvZREFLf3DDjZPtqgLx5AJZr6TetMNwFP9hcKreTTeztQYBTNbNoOycwA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz", + "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==", "dev": true, "requires": { - "@typescript-eslint/types": "5.25.0", + "@typescript-eslint/types": "5.26.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -11484,9 +11506,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001341", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", - "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", "dev": true }, "chai": { @@ -11656,13 +11678,13 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "collect-v8-coverage": { @@ -11707,7 +11729,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -11797,7 +11819,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "cookiejar": { "version": "2.1.3", @@ -12003,10 +12025,9 @@ } }, "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==" }, "diff-sequences": { "version": "27.5.1", @@ -12098,9 +12119,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "version": "1.4.140", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.140.tgz", + "integrity": "sha512-NLz5va823QfJBYOO/hLV4AfU4Crmkl/6Hl2pH3qdJcmi0ySZ3YTWHxOlDm3uJOFBEPy3pIhu8gKQo6prQTWKKA==", "dev": true }, "emittery": { @@ -12243,12 +12264,12 @@ } }, "eslint": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz", - "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.2.3", + "@eslint/eslintrc": "^1.3.0", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -12266,7 +12287,7 @@ "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", - "globals": "^13.6.0", + "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -12746,9 +12767,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", - "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" }, "fork-ts-checker-webpack-plugin": { "version": "7.2.11", @@ -14492,9 +14513,9 @@ "dev": true }, "node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", "dev": true }, "normalize-path": { @@ -14513,9 +14534,9 @@ } }, "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "requires": { "boolbase": "^1.0.0" } @@ -14537,9 +14558,9 @@ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" }, "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "on-finished": { "version": "2.4.1", @@ -15271,11 +15292,6 @@ "requires": { "@sinonjs/commons": "^1.7.0" } - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" } } }, @@ -15773,12 +15789,12 @@ } }, "ts-node": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.7.0.tgz", - "integrity": "sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz", + "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==", "dev": true, "requires": { - "@cspotcode/source-map-support": "0.7.0", + "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", @@ -15789,7 +15805,7 @@ "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "dependencies": { @@ -15798,6 +15814,12 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true } } }, @@ -15919,9 +15941,9 @@ } }, "typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", + "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", "dev": true }, "unbzip2-stream": { @@ -16210,9 +16232,9 @@ } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz", + "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==", "dev": true, "requires": {} }, diff --git a/src/error-handling/exception/empty-prop.exception.ts b/src/error-handling/exception/empty-prop.exception.ts new file mode 100644 index 0000000..f1e666a --- /dev/null +++ b/src/error-handling/exception/empty-prop.exception.ts @@ -0,0 +1,11 @@ +import { HttpStatus } from '@nestjs/common'; +import { CustomErrorException } from './custom-error.exception'; + +export class EmptyPropException extends CustomErrorException { + constructor(element = '') { + super( + `The property '${element.capitalize()}' cannot be empty`, + HttpStatus.INTERNAL_SERVER_ERROR + ); + } +} diff --git a/src/error-handling/exception/not-found.exception.ts b/src/error-handling/exception/not-found.exception.ts new file mode 100644 index 0000000..83a1e33 --- /dev/null +++ b/src/error-handling/exception/not-found.exception.ts @@ -0,0 +1,8 @@ +import { HttpStatus } from '@nestjs/common'; +import { CustomErrorException } from './custom-error.exception'; + +export class NotFoundException extends CustomErrorException { + constructor(element = '') { + super(`${element.capitalize()} not found`, HttpStatus.NOT_FOUND); + } +} diff --git a/src/error-handling/filter/abstract-exception.filter.ts b/src/error-handling/filter/abstract-exception.filter.ts index 90cb25a..5243c24 100644 --- a/src/error-handling/filter/abstract-exception.filter.ts +++ b/src/error-handling/filter/abstract-exception.filter.ts @@ -24,6 +24,8 @@ export abstract class AbstractExceptionFilter const customResponse = this.makeCustomResponse(exception); + console.error(customResponse); + this.httpAdapter.reply(response, customResponse, customResponse.status); } diff --git a/src/error-handling/filter/custom-error-exception.filter.ts b/src/error-handling/filter/custom-error-exception.filter.ts index 13d1ae0..4ff43b1 100644 --- a/src/error-handling/filter/custom-error-exception.filter.ts +++ b/src/error-handling/filter/custom-error-exception.filter.ts @@ -11,7 +11,7 @@ export class CustomErrorExceptionFilter extends AbstractExceptionFilter { - makeCustomResponse(exception: Error): CustomExceptionReponse { + makeCustomResponse(exception: any): CustomExceptionReponse { return { - status: HttpStatus.INTERNAL_SERVER_ERROR, + status: this.getStatus(exception), message: exception.message, type: exception.name, - errorCode: HttpStatus.INTERNAL_SERVER_ERROR, - err: exception + errorCode: this.getStatus(exception), + errInstance: exception }; } + + getStatus(exception: any): number { + let status = HttpStatus.INTERNAL_SERVER_ERROR; + + if (exception instanceof HttpException) status = exception.getStatus(); + + return status; + } } diff --git a/src/error-handling/filter/http-exception.filter.ts b/src/error-handling/filter/http-exception.filter.ts index 6ca7d7f..076f11b 100644 --- a/src/error-handling/filter/http-exception.filter.ts +++ b/src/error-handling/filter/http-exception.filter.ts @@ -14,7 +14,7 @@ export class HttpExceptionFilter extends AbstractExceptionFilter message: exception.message, type: exception.name, errorCode: exception.getStatus(), - err: exception + errInstance: exception }; } } diff --git a/src/error-handling/interface/custom-exception-response.interface.ts b/src/error-handling/interface/custom-exception-response.interface.ts index 99f01d6..2a0c6aa 100644 --- a/src/error-handling/interface/custom-exception-response.interface.ts +++ b/src/error-handling/interface/custom-exception-response.interface.ts @@ -3,5 +3,5 @@ export interface CustomExceptionReponse { message: string; type: string; errorCode: number; - err: any; + errInstance: any; } diff --git a/src/places-interface/adapter/helper/extensions/exensions.module.ts b/src/places-interface/adapter/helper/extensions/exensions.module.ts index 0489ae4..acfc2c1 100644 --- a/src/places-interface/adapter/helper/extensions/exensions.module.ts +++ b/src/places-interface/adapter/helper/extensions/exensions.module.ts @@ -1,4 +1,5 @@ import './string.extension'; +import './object.extension'; import { Module } from '@nestjs/common'; @Module({ diff --git a/src/places-interface/adapter/helper/extensions/object.extension.ts b/src/places-interface/adapter/helper/extensions/object.extension.ts new file mode 100644 index 0000000..19627d3 --- /dev/null +++ b/src/places-interface/adapter/helper/extensions/object.extension.ts @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/no-this-alias */ +import { EmptyPropException } from '../../../../error-handling/exception/empty-prop.exception'; + +declare global { + interface Object { + validateIsAnyEmptyKey(): void; + + getMethods(): string[]; + } +} + +Object.prototype.validateIsAnyEmptyKey = function () { + const context = this; + Object.keys(this).forEach(function (key) { + if (context[key].length == 0) throw new EmptyPropException(key); + }); +}; + +Object.prototype.getMethods = (): any[] => { + const properties = new Set(); + let currentObj = this; + const obj = this; + do { + Object.getOwnPropertyNames(currentObj).map((item) => properties.add(item)); + } while ((currentObj = Object.getPrototypeOf(currentObj))); + return [...properties.keys()].filter( + (item: string) => + typeof obj !== 'undefined' && typeof obj[item] === 'function' + ); +}; + +export {}; diff --git a/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts b/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts index ba48522..6e5fb58 100644 --- a/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts +++ b/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts @@ -23,7 +23,10 @@ export class GuiaMaisRepository ); } - buildElementFromDocument(searchParams, $: CheerioAPI): NeighborhoodsByCity[] { + buildElementsFromDocument( + searchParams, + $: CheerioAPI + ): NeighborhoodsByCity[] { const arrNeighborhoods = []; $('.cities.centerContent') .find('a') diff --git a/src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts b/src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts index f93543d..49a40bd 100644 --- a/src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts +++ b/src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts @@ -9,8 +9,12 @@ export interface IPuppeteerRepository { goToUrl(url: string): Promise; - buildElementFromDocument( + buildElementsFromDocument( searchParams: SearchElement, $: CheerioAPI ): ElementPlace[]; + + validateInput(searchParams: SearchElement): void; + + validateOutput(output: ElementPlace[]): void; } diff --git a/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts b/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts index d0aedb6..0b9748b 100644 --- a/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts +++ b/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts @@ -1,9 +1,9 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ import { CheerioAPI } from 'cheerio'; import { NeighborhoodsByCity } from '../../../model/neighborhoods-by-city.model'; import { SearchNeighborhoods } from '../../../model/search/search-neighborhoods.model'; import { PuppeteerRepository } from '../puppeteer.repository'; import { IPuppeteerNeighborhoodRepository } from '../../../interface/puppeteer/repository/puppeteer-neighborhood-repository.interface'; +import { NotFoundException } from '../../../../../error-handling/exception/not-found.exception'; export abstract class PuppeteerNeighborhoodRepository extends PuppeteerRepository @@ -12,11 +12,21 @@ export abstract class PuppeteerNeighborhoodRepository async getNeighborhoodsByCity( searchParams: SearchNeighborhoods ): Promise { + await this.validateInput(searchParams); + const $ = await this.callEndpoint(searchParams); - return this.buildElementFromDocument(searchParams, $); + const elements = this.buildElementsFromDocument(searchParams, $); + + await this.validateOutput(elements); + + return elements; + } + + validateOutput(output: NeighborhoodsByCity[]): void { + if (output.length == 0) throw new NotFoundException('Neighborhoods'); } - abstract buildElementFromDocument( + abstract buildElementsFromDocument( _searchParams: SearchNeighborhoods, _$: CheerioAPI ); diff --git a/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts b/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts index cdb7feb..7408986 100644 --- a/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts +++ b/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts @@ -1,6 +1,7 @@ import * as cheerio from 'cheerio'; import { CheerioAPI } from 'cheerio'; import { Page } from '../../interface/puppeteer/page.interface'; +import { SearchNeighborhoods } from '../../model/search/search-neighborhoods.model'; export abstract class PuppeteerRepository { constructor(protected url: string, protected readonly page: Page) {} @@ -21,4 +22,8 @@ export abstract class PuppeteerRepository { /* istanbul ignore next */ return this.page.evaluate(() => document.querySelector('*').outerHTML); } + + validateInput(searchParams: SearchNeighborhoods) { + searchParams.validateIsAnyEmptyKey(); + } } diff --git a/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts b/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts deleted file mode 100644 index b63f58d..0000000 --- a/test/unit/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { PuppeteerModule } from 'nest-puppeteer'; -import { SearchNeighborhoods } from '../../../../../../src/places-interface/domain/model/search/search-neighborhoods.model'; -import { ExtensionsModule } from '../../../../../../src/places-interface/adapter/helper/extensions/exensions.module'; -import { PuppeteerNeighborhoodRepository } from '../../../../../../src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository'; -import { expect } from 'chai'; -import * as sinon from 'sinon'; - -jest.useFakeTimers(); -jest.setTimeout(50000); - -class mockExtendClass extends PuppeteerNeighborhoodRepository {} - -describe('PuppeteerNeighborhoodRepository', () => { - let sut: PuppeteerNeighborhoodRepository; - let app: TestingModule; - - beforeEach(async () => { - app = await Test.createTestingModule({ - imports: [ - ExtensionsModule, - PuppeteerModule.forRoot({ - isGlobal: true - }) - ], - controllers: [], - providers: [mockExtendClass] - }).compile(); - - sut = app.get(mockExtendClass); - }); - - afterEach(async () => { - await app.close(); - }); - - describe('buildElementFromDocument', () => { - it('should call getEndpoint and throws a error', async () => { - const mockSearch = new SearchNeighborhoods('brasil', 'se', 'aracaju'); - try { - await sut.callEndpoint(mockSearch); - } catch (err) { - expect(err.message).to.be.equal('Method not implemented.'); - } - }); - - it('should call buildElementFromDocument and throws a error', async () => { - const mockSearch = new SearchNeighborhoods('brasil', 'se', 'aracaju'); - try { - await sut.buildElementFromDocument(mockSearch, null); - } catch (err) { - expect(err.message).to.be.equal('Method not implemented.'); - } - }); - - it('should call buildElementFromDocument and throws a error Method not implemented.', async () => { - const mockSearch = new SearchNeighborhoods('brasil', 'se', 'aracaju'); - const callback = function () { - return sut.buildElementFromDocument(mockSearch, null); - }; - expect(callback).to.throws(Error); - }); - }); - - describe('getNeighborhoodsByCity', () => { - it('should call getNeighborhoodsByCity and call callEndpoint with the correct params', async () => { - const callEndpointStub = sinon.stub(sut, 'callEndpoint').returns(null); - const buildElementFromDocumentStub = sinon - .stub(sut, 'buildElementFromDocument') - .returns([]); - - const mockSearch = new SearchNeighborhoods('brasil', 'se', 'aracaju'); - - await sut.getNeighborhoodsByCity(mockSearch); - - sinon.assert.calledOnceWithExactly(callEndpointStub, mockSearch); - - callEndpointStub.restore(); - buildElementFromDocumentStub.restore(); - }); - }); -}); From a97f57dca63631383b2fdd6988259946f69ac434 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sat, 28 May 2022 11:10:00 -0300 Subject: [PATCH 03/19] nest response interceptor --- src/app.module.ts | 17 +++++-- .../exception/custom-error.exception.ts | 0 .../exception/empty-data.exception.ts | 0 .../exception/empty-prop.exception.ts | 0 .../exception/not-found.exception.ts | 0 .../filter/abstract-exception.filter.ts | 0 .../filter/custom-error-exception.filter.ts | 0 .../filter/error-exception.filter.ts | 0 .../filter/http-exception.filter.ts | 0 .../error-handling/filters.module.ts | 0 .../custom-exception-response.interface.ts | 0 src/core/helper/is-empty.helper.ts | 3 ++ src/core/helpers/object.helper.ts | 3 ++ src/core/http/nest-response.builder.ts | 34 +++++++++++++ src/core/http/nest-response.ts | 11 +++++ .../http/transform-response-interceptor.ts | 48 +++++++++++++++++++ .../interface/custom-response.interface.ts | 4 ++ src/main.ts | 2 + .../controller/neighborhoods.controller.ts | 19 ++++---- .../helper/extensions/object.extension.ts | 8 +++- .../domain/controller/abstract-controller.ts | 11 +++++ .../puppeteer-neighborhood.repository.ts | 2 +- 22 files changed, 148 insertions(+), 14 deletions(-) rename src/{ => core}/error-handling/exception/custom-error.exception.ts (100%) rename src/{ => core}/error-handling/exception/empty-data.exception.ts (100%) rename src/{ => core}/error-handling/exception/empty-prop.exception.ts (100%) rename src/{ => core}/error-handling/exception/not-found.exception.ts (100%) rename src/{ => core}/error-handling/filter/abstract-exception.filter.ts (100%) rename src/{ => core}/error-handling/filter/custom-error-exception.filter.ts (100%) rename src/{ => core}/error-handling/filter/error-exception.filter.ts (100%) rename src/{ => core}/error-handling/filter/http-exception.filter.ts (100%) rename src/{ => core}/error-handling/filters.module.ts (100%) rename src/{ => core}/error-handling/interface/custom-exception-response.interface.ts (100%) create mode 100644 src/core/helper/is-empty.helper.ts create mode 100644 src/core/helpers/object.helper.ts create mode 100644 src/core/http/nest-response.builder.ts create mode 100644 src/core/http/nest-response.ts create mode 100644 src/core/http/transform-response-interceptor.ts create mode 100644 src/core/interface/custom-response.interface.ts create mode 100644 src/places-interface/domain/controller/abstract-controller.ts diff --git a/src/app.module.ts b/src/app.module.ts index 4a90b4f..de89a8e 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,6 +1,8 @@ -import { Module } from '@nestjs/common'; +import { ClassSerializerInterceptor, Module } from '@nestjs/common'; +import { APP_INTERCEPTOR } from '@nestjs/core'; import { PuppeteerModule } from 'nest-puppeteer'; -import { FiltersModule } from './error-handling/filters.module'; +import { FiltersModule } from './core/error-handling/filters.module'; +import { TransformResponseInterceptor } from './core/http/transform-response-interceptor'; import { ExtensionsModule } from './places-interface/adapter/helper/extensions/exensions.module'; import { NeighborhoodsModule } from './places-interface/adapter/neighborhoods.module'; @@ -14,6 +16,15 @@ import { NeighborhoodsModule } from './places-interface/adapter/neighborhoods.mo NeighborhoodsModule ], controllers: [], - providers: [] + providers: [ + { + provide: APP_INTERCEPTOR, + useClass: ClassSerializerInterceptor + }, + { + provide: APP_INTERCEPTOR, + useClass: TransformResponseInterceptor + } + ] }) export class AppModule {} diff --git a/src/error-handling/exception/custom-error.exception.ts b/src/core/error-handling/exception/custom-error.exception.ts similarity index 100% rename from src/error-handling/exception/custom-error.exception.ts rename to src/core/error-handling/exception/custom-error.exception.ts diff --git a/src/error-handling/exception/empty-data.exception.ts b/src/core/error-handling/exception/empty-data.exception.ts similarity index 100% rename from src/error-handling/exception/empty-data.exception.ts rename to src/core/error-handling/exception/empty-data.exception.ts diff --git a/src/error-handling/exception/empty-prop.exception.ts b/src/core/error-handling/exception/empty-prop.exception.ts similarity index 100% rename from src/error-handling/exception/empty-prop.exception.ts rename to src/core/error-handling/exception/empty-prop.exception.ts diff --git a/src/error-handling/exception/not-found.exception.ts b/src/core/error-handling/exception/not-found.exception.ts similarity index 100% rename from src/error-handling/exception/not-found.exception.ts rename to src/core/error-handling/exception/not-found.exception.ts diff --git a/src/error-handling/filter/abstract-exception.filter.ts b/src/core/error-handling/filter/abstract-exception.filter.ts similarity index 100% rename from src/error-handling/filter/abstract-exception.filter.ts rename to src/core/error-handling/filter/abstract-exception.filter.ts diff --git a/src/error-handling/filter/custom-error-exception.filter.ts b/src/core/error-handling/filter/custom-error-exception.filter.ts similarity index 100% rename from src/error-handling/filter/custom-error-exception.filter.ts rename to src/core/error-handling/filter/custom-error-exception.filter.ts diff --git a/src/error-handling/filter/error-exception.filter.ts b/src/core/error-handling/filter/error-exception.filter.ts similarity index 100% rename from src/error-handling/filter/error-exception.filter.ts rename to src/core/error-handling/filter/error-exception.filter.ts diff --git a/src/error-handling/filter/http-exception.filter.ts b/src/core/error-handling/filter/http-exception.filter.ts similarity index 100% rename from src/error-handling/filter/http-exception.filter.ts rename to src/core/error-handling/filter/http-exception.filter.ts diff --git a/src/error-handling/filters.module.ts b/src/core/error-handling/filters.module.ts similarity index 100% rename from src/error-handling/filters.module.ts rename to src/core/error-handling/filters.module.ts diff --git a/src/error-handling/interface/custom-exception-response.interface.ts b/src/core/error-handling/interface/custom-exception-response.interface.ts similarity index 100% rename from src/error-handling/interface/custom-exception-response.interface.ts rename to src/core/error-handling/interface/custom-exception-response.interface.ts diff --git a/src/core/helper/is-empty.helper.ts b/src/core/helper/is-empty.helper.ts new file mode 100644 index 0000000..a953ab7 --- /dev/null +++ b/src/core/helper/is-empty.helper.ts @@ -0,0 +1,3 @@ +export function isEmpty(x) { + return typeof x === 'object' && Object.keys(x).length === 0; +} diff --git a/src/core/helpers/object.helper.ts b/src/core/helpers/object.helper.ts new file mode 100644 index 0000000..a953ab7 --- /dev/null +++ b/src/core/helpers/object.helper.ts @@ -0,0 +1,3 @@ +export function isEmpty(x) { + return typeof x === 'object' && Object.keys(x).length === 0; +} diff --git a/src/core/http/nest-response.builder.ts b/src/core/http/nest-response.builder.ts new file mode 100644 index 0000000..3a11532 --- /dev/null +++ b/src/core/http/nest-response.builder.ts @@ -0,0 +1,34 @@ +import { CustomResponse } from '../interface/custom-response.interface'; +import { NestResponse } from './nest-response'; + +export class NestResponseBuilder { + private resposta: NestResponse = { + status: 200, + headers: {}, + body: { + success: true, + response: '' + } + }; + + setStatus(status: number) { + this.resposta.status = status; + return this; + } + + setHeader(headers: object) { + if (headers.isEmpty()) return this; + + this.resposta.headers = headers; + return this; + } + + setBody(body: CustomResponse) { + this.resposta.body = body; + return this; + } + + build() { + return new NestResponse(this.resposta); + } +} diff --git a/src/core/http/nest-response.ts b/src/core/http/nest-response.ts new file mode 100644 index 0000000..47cfca0 --- /dev/null +++ b/src/core/http/nest-response.ts @@ -0,0 +1,11 @@ +import { CustomResponse } from '../interface/custom-response.interface'; + +export class NestResponse { + status: number; + headers: object; + body: CustomResponse; + + constructor(resposta: NestResponse) { + Object.assign(this, resposta); + } +} diff --git a/src/core/http/transform-response-interceptor.ts b/src/core/http/transform-response-interceptor.ts new file mode 100644 index 0000000..1950ba8 --- /dev/null +++ b/src/core/http/transform-response-interceptor.ts @@ -0,0 +1,48 @@ +import { + NestInterceptor, + Injectable, + ExecutionContext, + CallHandler +} from '@nestjs/common'; + +import { AbstractHttpAdapter, HttpAdapterHost } from '@nestjs/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { NestResponse } from './nest-response'; + +@Injectable() +export class TransformResponseInterceptor implements NestInterceptor { + private httpAdapter: AbstractHttpAdapter; + + constructor(adapterHost: HttpAdapterHost) { + this.httpAdapter = adapterHost.httpAdapter; + } + + intercept( + context: ExecutionContext, + next: CallHandler + ): Observable | Promise> { + return next.handle().pipe( + map((responseController: NestResponse) => { + if (responseController instanceof NestResponse) { + const ctx = context.switchToHttp(); + const response = ctx.getResponse(); + const { headers, status, body } = responseController; + + const headersName = Object.getOwnPropertyNames(headers); + + headersName.forEach((header) => { + const headerValue = headers[header]; + this.httpAdapter.setHeader(response, header, headerValue); + }); + + this.httpAdapter.status(response, status); + + return body; + } + + return responseController; + }) + ); + } +} diff --git a/src/core/interface/custom-response.interface.ts b/src/core/interface/custom-response.interface.ts new file mode 100644 index 0000000..f6118de --- /dev/null +++ b/src/core/interface/custom-response.interface.ts @@ -0,0 +1,4 @@ +export interface CustomResponse { + success: boolean; + response: object | string | number; +} diff --git a/src/main.ts b/src/main.ts index 3d7c7a0..8c2c4a0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; +import { useContainer } from 'class-validator'; import { AppModule } from './app.module'; async function bootstrap() { @@ -9,6 +10,7 @@ async function bootstrap() { transform: true }) ); + useContainer(app.select(AppModule), { fallbackOnErrors: true }); await app.listen(3000); } bootstrap(); diff --git a/src/places-interface/adapter/controller/neighborhoods.controller.ts b/src/places-interface/adapter/controller/neighborhoods.controller.ts index b1d30cf..dce0ad1 100644 --- a/src/places-interface/adapter/controller/neighborhoods.controller.ts +++ b/src/places-interface/adapter/controller/neighborhoods.controller.ts @@ -1,20 +1,23 @@ -import { Controller, Get, Param } from '@nestjs/common'; +import { Controller, Get, HttpStatus, Param } from '@nestjs/common'; +import { NestResponse } from 'src/core/http/nest-response'; +import { AbstractController } from 'src/places-interface/domain/controller/abstract-controller'; import { NeighborhoodsService } from '../service/neighborhoods.service'; @Controller('neighborhoods') -export class NeighborhoodsController { - constructor(private readonly neighborhoodsService: NeighborhoodsService) {} +export class NeighborhoodsController extends AbstractController { + constructor(private readonly neighborhoodsService: NeighborhoodsService) { + super(); + } @Get('/city/:country/:state/:city') getNeighborhoodsByCity( @Param('country') country, @Param('state') state, @Param('city') city - ): Promise { - return this.neighborhoodsService.getNeighborhoodsByCity( - country, - state, - city + ): NestResponse { + return this.buildResponse( + HttpStatus.ACCEPTED, + this.neighborhoodsService.getNeighborhoodsByCity(country, state, city) ); } } diff --git a/src/places-interface/adapter/helper/extensions/object.extension.ts b/src/places-interface/adapter/helper/extensions/object.extension.ts index 19627d3..4bce4e7 100644 --- a/src/places-interface/adapter/helper/extensions/object.extension.ts +++ b/src/places-interface/adapter/helper/extensions/object.extension.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-this-alias */ -import { EmptyPropException } from '../../../../error-handling/exception/empty-prop.exception'; +import { EmptyPropException } from '../../../../core/error-handling/exception/empty-prop.exception'; declare global { interface Object { validateIsAnyEmptyKey(): void; - getMethods(): string[]; + isEmpty(): boolean; } } @@ -29,4 +29,8 @@ Object.prototype.getMethods = (): any[] => { ); }; +Object.prototype.isEmpty = (): boolean => { + return Object.keys(this).length === 0; +}; + export {}; diff --git a/src/places-interface/domain/controller/abstract-controller.ts b/src/places-interface/domain/controller/abstract-controller.ts new file mode 100644 index 0000000..6e03086 --- /dev/null +++ b/src/places-interface/domain/controller/abstract-controller.ts @@ -0,0 +1,11 @@ +import { NestResponseBuilder } from 'src/core/http/nest-response.builder'; + +export abstract class AbstractController { + buildResponse(status, body, header = {}) { + return new NestResponseBuilder() + .setStatus(status) + .setHeader(header) + .setBody(body) + .build(); + } +} diff --git a/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts b/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts index 0b9748b..be6fd71 100644 --- a/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts +++ b/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts @@ -3,7 +3,7 @@ import { NeighborhoodsByCity } from '../../../model/neighborhoods-by-city.model' import { SearchNeighborhoods } from '../../../model/search/search-neighborhoods.model'; import { PuppeteerRepository } from '../puppeteer.repository'; import { IPuppeteerNeighborhoodRepository } from '../../../interface/puppeteer/repository/puppeteer-neighborhood-repository.interface'; -import { NotFoundException } from '../../../../../error-handling/exception/not-found.exception'; +import { NotFoundException } from '../../../../../core/error-handling/exception/not-found.exception'; export abstract class PuppeteerNeighborhoodRepository extends PuppeteerRepository From 8381c16eb5a5bd5ffb6721a0a38d7513691f8a2a Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sat, 28 May 2022 11:32:43 -0300 Subject: [PATCH 04/19] fix unit tests --- .../filter/abstract-exception.filter.ts | 2 +- .../controller/neighborhoods.controller.ts | 4 ++-- .../domain/controller/abstract-controller.ts | 2 +- .../neighborhoods.controller.spec.ts | 21 ++++++++++--------- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/core/error-handling/filter/abstract-exception.filter.ts b/src/core/error-handling/filter/abstract-exception.filter.ts index 5243c24..4d25074 100644 --- a/src/core/error-handling/filter/abstract-exception.filter.ts +++ b/src/core/error-handling/filter/abstract-exception.filter.ts @@ -24,7 +24,7 @@ export abstract class AbstractExceptionFilter const customResponse = this.makeCustomResponse(exception); - console.error(customResponse); + console.error(exception); this.httpAdapter.reply(response, customResponse, customResponse.status); } diff --git a/src/places-interface/adapter/controller/neighborhoods.controller.ts b/src/places-interface/adapter/controller/neighborhoods.controller.ts index dce0ad1..6e62341 100644 --- a/src/places-interface/adapter/controller/neighborhoods.controller.ts +++ b/src/places-interface/adapter/controller/neighborhoods.controller.ts @@ -1,6 +1,6 @@ import { Controller, Get, HttpStatus, Param } from '@nestjs/common'; -import { NestResponse } from 'src/core/http/nest-response'; -import { AbstractController } from 'src/places-interface/domain/controller/abstract-controller'; +import { NestResponse } from '../../../core/http/nest-response'; +import { AbstractController } from '../../../places-interface/domain/controller/abstract-controller'; import { NeighborhoodsService } from '../service/neighborhoods.service'; @Controller('neighborhoods') diff --git a/src/places-interface/domain/controller/abstract-controller.ts b/src/places-interface/domain/controller/abstract-controller.ts index 6e03086..d942f58 100644 --- a/src/places-interface/domain/controller/abstract-controller.ts +++ b/src/places-interface/domain/controller/abstract-controller.ts @@ -1,4 +1,4 @@ -import { NestResponseBuilder } from 'src/core/http/nest-response.builder'; +import { NestResponseBuilder } from '../../../core/http/nest-response.builder'; export abstract class AbstractController { buildResponse(status, body, header = {}) { diff --git a/test/unit/adapter/controller/neighborhoods.controller.spec.ts b/test/unit/adapter/controller/neighborhoods.controller.spec.ts index ae43214..0962557 100644 --- a/test/unit/adapter/controller/neighborhoods.controller.spec.ts +++ b/test/unit/adapter/controller/neighborhoods.controller.spec.ts @@ -1,16 +1,17 @@ import { Test, TestingModule } from '@nestjs/testing'; import { NeighborhoodsController } from '../../../../src/places-interface/adapter/controller/neighborhoods.controller'; -import { NeighborhoodsService } from '../../../../src/places-interface/adapter/service/neighborhoods.service'; import { ConfigModule } from '@nestjs/config'; import configuration from '../../../../src/config/configuration'; import { expect } from 'chai'; import * as sinon from 'sinon'; import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; +import { ExtensionsModule } from '../../../../src/places-interface/adapter/helper/extensions/exensions.module'; +import { NeighborhoodsService } from '../../../../src/places-interface/adapter/service/neighborhoods.service'; describe('NeighborhoodsController', () => { let neighborhoodsController: NeighborhoodsController; - const mockGuiaMaisRepository = { + const mockNeighborhoodsService = { getNeighborhoodsByCity: () => { return; } @@ -33,15 +34,15 @@ describe('NeighborhoodsController', () => { ConfigModule.forRoot({ isGlobal: true, load: [configuration] - }) + }), + ExtensionsModule ], controllers: [NeighborhoodsController], providers: [ { - provide: 'GuiaMaisRepository', - useValue: mockGuiaMaisRepository - }, - NeighborhoodsService + provide: NeighborhoodsService, + useFactory: () => mockNeighborhoodsService + } ] }).compile(); @@ -53,7 +54,7 @@ describe('NeighborhoodsController', () => { describe('NeighborhoodsController', () => { it('should call getNeighborhoodsByCity and return an array', async () => { const guiaMaisStub = sinon - .stub(mockGuiaMaisRepository, 'getNeighborhoodsByCity') + .stub(mockNeighborhoodsService, 'getNeighborhoodsByCity') .returns(mockNeighborhoods); const actual = await neighborhoodsController.getNeighborhoodsByCity( @@ -62,8 +63,8 @@ describe('NeighborhoodsController', () => { 'orleans' ); - expect(actual).to.be.an('array'); - expect(actual.length).to.be.equal(2); + expect(actual.body).to.be.an('array').that.contains; + expect(actual.body).to.have.lengthOf(2); guiaMaisStub.restore(); }); From 8c3138bc8899b689489b1ad31a69e205995e999b Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 13:03:31 -0300 Subject: [PATCH 05/19] interceptor and nest reponse --- src/app.module.ts | 6 +-- .../exception/empty-data.exception.ts | 3 +- .../exception/empty-prop.exception.ts | 3 +- .../exception/not-found.exception.ts | 6 ++- .../filter/custom-error-exception.filter.ts | 3 +- .../filter/error-exception.filter.ts | 3 +- .../filter/http-exception.filter.ts | 5 +- .../custom-exception-response.interface.ts | 1 - src/core/helper/is-empty.helper.ts | 3 -- src/core/helpers/object.helper.ts | 3 -- src/core/http/nest-response.builder.ts | 10 ++-- src/core/http/nest-response.ts | 4 +- ...r.ts => transform-response.interceptor.ts} | 24 ++++----- .../controller/neighborhoods.controller.ts | 2 +- .../helper/extensions/exensions.module.ts | 0 .../helper/extensions/object.extension.ts | 2 +- .../helper/extensions/string.extension.ts | 0 .../adapter/neighborhoods.module.ts | 0 .../neighborhoods/guia-mais.repository.ts | 0 .../adapter/service/neighborhoods.service.ts | 0 .../domain/controller/abstract-controller.ts | 0 .../interface/puppeteer/page.interface.ts | 0 ...eteer-neighborhood-repository.interface.ts | 0 .../puppeteer-repository.interface.ts | 0 .../model/neighborhoods-by-city.model.ts | 0 .../search/search-neighborhoods.model.ts | 0 .../puppeteer-neighborhood.repository.ts | 0 .../puppeteer/puppeteer.repository.ts | 0 .../neighborhoods-service.interface.ts | 0 .../exception/empty-data.exception.spec.ts | 13 +++++ .../custom-error-exception.filter.spec.ts | 40 ++++++++++++++ .../filter/http-exception.filter.spec.ts | 52 +++++++++++++++++++ .../neighborhoods.controller.spec.ts | 10 ++-- .../extensions/object.extension.spec.ts | 29 +++++++++++ .../adapter/neighborhoods.module.spec.ts | 2 +- .../guia-mais.repository.spec.ts | 16 ++++-- .../service/neighborhoods.service.spec.ts | 4 +- .../model/neighborhoods-by-city.model.spec.ts | 2 +- .../search/search-neighborhoods.model.spec.ts | 2 +- .../puppeteer/puppeteer.repository.spec.ts | 6 +-- 40 files changed, 195 insertions(+), 59 deletions(-) delete mode 100644 src/core/helper/is-empty.helper.ts delete mode 100644 src/core/helpers/object.helper.ts rename src/core/http/{transform-response-interceptor.ts => transform-response.interceptor.ts} (54%) rename src/{places-interface => microservice}/adapter/controller/neighborhoods.controller.ts (87%) rename src/{places-interface => microservice}/adapter/helper/extensions/exensions.module.ts (100%) rename src/{places-interface => microservice}/adapter/helper/extensions/object.extension.ts (92%) rename src/{places-interface => microservice}/adapter/helper/extensions/string.extension.ts (100%) rename src/{places-interface => microservice}/adapter/neighborhoods.module.ts (100%) rename src/{places-interface => microservice}/adapter/repository/neighborhoods/guia-mais.repository.ts (100%) rename src/{places-interface => microservice}/adapter/service/neighborhoods.service.ts (100%) rename src/{places-interface => microservice}/domain/controller/abstract-controller.ts (100%) rename src/{places-interface => microservice}/domain/interface/puppeteer/page.interface.ts (100%) rename src/{places-interface => microservice}/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts (100%) rename src/{places-interface => microservice}/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts (100%) rename src/{places-interface => microservice}/domain/model/neighborhoods-by-city.model.ts (100%) rename src/{places-interface => microservice}/domain/model/search/search-neighborhoods.model.ts (100%) rename src/{places-interface => microservice}/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts (100%) rename src/{places-interface => microservice}/domain/repository/puppeteer/puppeteer.repository.ts (100%) rename src/{places-interface => microservice}/domain/service/neighborhoods-service.interface.ts (100%) create mode 100644 test/unit/core/error-handling/exception/empty-data.exception.spec.ts create mode 100644 test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts create mode 100644 test/unit/core/error-handling/filter/http-exception.filter.spec.ts rename test/unit/{ => microservice}/adapter/controller/neighborhoods.controller.spec.ts (76%) create mode 100644 test/unit/microservice/adapter/helper/extensions/object.extension.spec.ts rename test/unit/{ => microservice}/adapter/neighborhoods.module.spec.ts (90%) rename test/unit/{ => microservice}/adapter/repository/neighborhoods/guia-mais.repository.spec.ts (78%) rename test/unit/{ => microservice}/adapter/service/neighborhoods.service.spec.ts (82%) rename test/unit/{ => microservice}/domain/model/neighborhoods-by-city.model.spec.ts (75%) rename test/unit/{ => microservice}/domain/model/search/search-neighborhoods.model.spec.ts (75%) rename test/unit/{ => microservice}/domain/repository/puppeteer/puppeteer.repository.spec.ts (83%) diff --git a/src/app.module.ts b/src/app.module.ts index de89a8e..19c8308 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,9 +2,9 @@ import { ClassSerializerInterceptor, Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { PuppeteerModule } from 'nest-puppeteer'; import { FiltersModule } from './core/error-handling/filters.module'; -import { TransformResponseInterceptor } from './core/http/transform-response-interceptor'; -import { ExtensionsModule } from './places-interface/adapter/helper/extensions/exensions.module'; -import { NeighborhoodsModule } from './places-interface/adapter/neighborhoods.module'; +import { TransformResponseInterceptor } from './core/http/transform-response.interceptor'; +import { ExtensionsModule } from './microservice/adapter/helper/extensions/exensions.module'; +import { NeighborhoodsModule } from './microservice/adapter/neighborhoods.module'; @Module({ imports: [ diff --git a/src/core/error-handling/exception/empty-data.exception.ts b/src/core/error-handling/exception/empty-data.exception.ts index e60dd55..0a6265f 100644 --- a/src/core/error-handling/exception/empty-data.exception.ts +++ b/src/core/error-handling/exception/empty-data.exception.ts @@ -5,7 +5,8 @@ export class EmptyDataException extends CustomErrorException { constructor(element = '') { super( `The ${element} data cannot be empty`, - HttpStatus.INTERNAL_SERVER_ERROR + HttpStatus.INTERNAL_SERVER_ERROR, + 1 ); } } diff --git a/src/core/error-handling/exception/empty-prop.exception.ts b/src/core/error-handling/exception/empty-prop.exception.ts index f1e666a..31f3076 100644 --- a/src/core/error-handling/exception/empty-prop.exception.ts +++ b/src/core/error-handling/exception/empty-prop.exception.ts @@ -5,7 +5,8 @@ export class EmptyPropException extends CustomErrorException { constructor(element = '') { super( `The property '${element.capitalize()}' cannot be empty`, - HttpStatus.INTERNAL_SERVER_ERROR + HttpStatus.NOT_ACCEPTABLE, + 2 ); } } diff --git a/src/core/error-handling/exception/not-found.exception.ts b/src/core/error-handling/exception/not-found.exception.ts index 83a1e33..4fdd0bd 100644 --- a/src/core/error-handling/exception/not-found.exception.ts +++ b/src/core/error-handling/exception/not-found.exception.ts @@ -3,6 +3,10 @@ import { CustomErrorException } from './custom-error.exception'; export class NotFoundException extends CustomErrorException { constructor(element = '') { - super(`${element.capitalize()} not found`, HttpStatus.NOT_FOUND); + super( + `${element.capitalize()} not found`, + HttpStatus.NOT_FOUND, + HttpStatus.NOT_FOUND + ); } } diff --git a/src/core/error-handling/filter/custom-error-exception.filter.ts b/src/core/error-handling/filter/custom-error-exception.filter.ts index 4ff43b1..d9fd4b6 100644 --- a/src/core/error-handling/filter/custom-error-exception.filter.ts +++ b/src/core/error-handling/filter/custom-error-exception.filter.ts @@ -10,8 +10,7 @@ export class CustomErrorExceptionFilter extends AbstractExceptionFilter { status: this.getStatus(exception), message: exception.message, type: exception.name, - errorCode: this.getStatus(exception), - errInstance: exception + errorCode: this.getStatus(exception) }; } diff --git a/src/core/error-handling/filter/http-exception.filter.ts b/src/core/error-handling/filter/http-exception.filter.ts index 076f11b..56b7e89 100644 --- a/src/core/error-handling/filter/http-exception.filter.ts +++ b/src/core/error-handling/filter/http-exception.filter.ts @@ -4,7 +4,7 @@ import { CustomExceptionReponse } from '../interface/custom-exception-response.i @Catch(HttpException) export class HttpExceptionFilter extends AbstractExceptionFilter { - getResponse(host: ArgumentsHost, exception: HttpException): any { + getResponse(_host: ArgumentsHost, exception: HttpException): any { return exception.getResponse(); } @@ -13,8 +13,7 @@ export class HttpExceptionFilter extends AbstractExceptionFilter status: exception.getStatus(), message: exception.message, type: exception.name, - errorCode: exception.getStatus(), - errInstance: exception + errorCode: exception.getStatus() }; } } diff --git a/src/core/error-handling/interface/custom-exception-response.interface.ts b/src/core/error-handling/interface/custom-exception-response.interface.ts index 2a0c6aa..b2d9e71 100644 --- a/src/core/error-handling/interface/custom-exception-response.interface.ts +++ b/src/core/error-handling/interface/custom-exception-response.interface.ts @@ -3,5 +3,4 @@ export interface CustomExceptionReponse { message: string; type: string; errorCode: number; - errInstance: any; } diff --git a/src/core/helper/is-empty.helper.ts b/src/core/helper/is-empty.helper.ts deleted file mode 100644 index a953ab7..0000000 --- a/src/core/helper/is-empty.helper.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isEmpty(x) { - return typeof x === 'object' && Object.keys(x).length === 0; -} diff --git a/src/core/helpers/object.helper.ts b/src/core/helpers/object.helper.ts deleted file mode 100644 index a953ab7..0000000 --- a/src/core/helpers/object.helper.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isEmpty(x) { - return typeof x === 'object' && Object.keys(x).length === 0; -} diff --git a/src/core/http/nest-response.builder.ts b/src/core/http/nest-response.builder.ts index 3a11532..326409e 100644 --- a/src/core/http/nest-response.builder.ts +++ b/src/core/http/nest-response.builder.ts @@ -2,7 +2,7 @@ import { CustomResponse } from '../interface/custom-response.interface'; import { NestResponse } from './nest-response'; export class NestResponseBuilder { - private resposta: NestResponse = { + protected response: NestResponse = { status: 200, headers: {}, body: { @@ -12,23 +12,23 @@ export class NestResponseBuilder { }; setStatus(status: number) { - this.resposta.status = status; + this.response.status = status; return this; } setHeader(headers: object) { if (headers.isEmpty()) return this; - this.resposta.headers = headers; + this.response.headers = headers; return this; } setBody(body: CustomResponse) { - this.resposta.body = body; + this.response.body = body; return this; } build() { - return new NestResponse(this.resposta); + return new NestResponse(this.response); } } diff --git a/src/core/http/nest-response.ts b/src/core/http/nest-response.ts index 47cfca0..9990009 100644 --- a/src/core/http/nest-response.ts +++ b/src/core/http/nest-response.ts @@ -5,7 +5,7 @@ export class NestResponse { headers: object; body: CustomResponse; - constructor(resposta: NestResponse) { - Object.assign(this, resposta); + constructor(response: NestResponse) { + Object.assign(this, response); } } diff --git a/src/core/http/transform-response-interceptor.ts b/src/core/http/transform-response.interceptor.ts similarity index 54% rename from src/core/http/transform-response-interceptor.ts rename to src/core/http/transform-response.interceptor.ts index 1950ba8..a7a2aeb 100644 --- a/src/core/http/transform-response-interceptor.ts +++ b/src/core/http/transform-response.interceptor.ts @@ -24,24 +24,20 @@ export class TransformResponseInterceptor implements NestInterceptor { ): Observable | Promise> { return next.handle().pipe( map((responseController: NestResponse) => { - if (responseController instanceof NestResponse) { - const ctx = context.switchToHttp(); - const response = ctx.getResponse(); - const { headers, status, body } = responseController; + const ctx = context.switchToHttp(); + const response = ctx.getResponse(); + const { headers, status, body } = responseController; - const headersName = Object.getOwnPropertyNames(headers); + const headersName = Object.getOwnPropertyNames(headers); - headersName.forEach((header) => { - const headerValue = headers[header]; - this.httpAdapter.setHeader(response, header, headerValue); - }); + headersName.forEach((header) => { + const headerValue = headers[header]; + this.httpAdapter.setHeader(response, header, headerValue); + }); - this.httpAdapter.status(response, status); + this.httpAdapter.status(response, status); - return body; - } - - return responseController; + return body; }) ); } diff --git a/src/places-interface/adapter/controller/neighborhoods.controller.ts b/src/microservice/adapter/controller/neighborhoods.controller.ts similarity index 87% rename from src/places-interface/adapter/controller/neighborhoods.controller.ts rename to src/microservice/adapter/controller/neighborhoods.controller.ts index 6e62341..6fe5dde 100644 --- a/src/places-interface/adapter/controller/neighborhoods.controller.ts +++ b/src/microservice/adapter/controller/neighborhoods.controller.ts @@ -1,6 +1,6 @@ import { Controller, Get, HttpStatus, Param } from '@nestjs/common'; import { NestResponse } from '../../../core/http/nest-response'; -import { AbstractController } from '../../../places-interface/domain/controller/abstract-controller'; +import { AbstractController } from '../../domain/controller/abstract-controller'; import { NeighborhoodsService } from '../service/neighborhoods.service'; @Controller('neighborhoods') diff --git a/src/places-interface/adapter/helper/extensions/exensions.module.ts b/src/microservice/adapter/helper/extensions/exensions.module.ts similarity index 100% rename from src/places-interface/adapter/helper/extensions/exensions.module.ts rename to src/microservice/adapter/helper/extensions/exensions.module.ts diff --git a/src/places-interface/adapter/helper/extensions/object.extension.ts b/src/microservice/adapter/helper/extensions/object.extension.ts similarity index 92% rename from src/places-interface/adapter/helper/extensions/object.extension.ts rename to src/microservice/adapter/helper/extensions/object.extension.ts index 4bce4e7..f31f5eb 100644 --- a/src/places-interface/adapter/helper/extensions/object.extension.ts +++ b/src/microservice/adapter/helper/extensions/object.extension.ts @@ -30,7 +30,7 @@ Object.prototype.getMethods = (): any[] => { }; Object.prototype.isEmpty = (): boolean => { - return Object.keys(this).length === 0; + return Object.keys(this).length == 0; }; export {}; diff --git a/src/places-interface/adapter/helper/extensions/string.extension.ts b/src/microservice/adapter/helper/extensions/string.extension.ts similarity index 100% rename from src/places-interface/adapter/helper/extensions/string.extension.ts rename to src/microservice/adapter/helper/extensions/string.extension.ts diff --git a/src/places-interface/adapter/neighborhoods.module.ts b/src/microservice/adapter/neighborhoods.module.ts similarity index 100% rename from src/places-interface/adapter/neighborhoods.module.ts rename to src/microservice/adapter/neighborhoods.module.ts diff --git a/src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts b/src/microservice/adapter/repository/neighborhoods/guia-mais.repository.ts similarity index 100% rename from src/places-interface/adapter/repository/neighborhoods/guia-mais.repository.ts rename to src/microservice/adapter/repository/neighborhoods/guia-mais.repository.ts diff --git a/src/places-interface/adapter/service/neighborhoods.service.ts b/src/microservice/adapter/service/neighborhoods.service.ts similarity index 100% rename from src/places-interface/adapter/service/neighborhoods.service.ts rename to src/microservice/adapter/service/neighborhoods.service.ts diff --git a/src/places-interface/domain/controller/abstract-controller.ts b/src/microservice/domain/controller/abstract-controller.ts similarity index 100% rename from src/places-interface/domain/controller/abstract-controller.ts rename to src/microservice/domain/controller/abstract-controller.ts diff --git a/src/places-interface/domain/interface/puppeteer/page.interface.ts b/src/microservice/domain/interface/puppeteer/page.interface.ts similarity index 100% rename from src/places-interface/domain/interface/puppeteer/page.interface.ts rename to src/microservice/domain/interface/puppeteer/page.interface.ts diff --git a/src/places-interface/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts b/src/microservice/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts similarity index 100% rename from src/places-interface/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts rename to src/microservice/domain/interface/puppeteer/repository/puppeteer-neighborhood-repository.interface.ts diff --git a/src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts b/src/microservice/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts similarity index 100% rename from src/places-interface/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts rename to src/microservice/domain/interface/puppeteer/repository/puppeteer-repository.interface.ts diff --git a/src/places-interface/domain/model/neighborhoods-by-city.model.ts b/src/microservice/domain/model/neighborhoods-by-city.model.ts similarity index 100% rename from src/places-interface/domain/model/neighborhoods-by-city.model.ts rename to src/microservice/domain/model/neighborhoods-by-city.model.ts diff --git a/src/places-interface/domain/model/search/search-neighborhoods.model.ts b/src/microservice/domain/model/search/search-neighborhoods.model.ts similarity index 100% rename from src/places-interface/domain/model/search/search-neighborhoods.model.ts rename to src/microservice/domain/model/search/search-neighborhoods.model.ts diff --git a/src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts b/src/microservice/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts similarity index 100% rename from src/places-interface/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts rename to src/microservice/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts diff --git a/src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts b/src/microservice/domain/repository/puppeteer/puppeteer.repository.ts similarity index 100% rename from src/places-interface/domain/repository/puppeteer/puppeteer.repository.ts rename to src/microservice/domain/repository/puppeteer/puppeteer.repository.ts diff --git a/src/places-interface/domain/service/neighborhoods-service.interface.ts b/src/microservice/domain/service/neighborhoods-service.interface.ts similarity index 100% rename from src/places-interface/domain/service/neighborhoods-service.interface.ts rename to src/microservice/domain/service/neighborhoods-service.interface.ts diff --git a/test/unit/core/error-handling/exception/empty-data.exception.spec.ts b/test/unit/core/error-handling/exception/empty-data.exception.spec.ts new file mode 100644 index 0000000..01895df --- /dev/null +++ b/test/unit/core/error-handling/exception/empty-data.exception.spec.ts @@ -0,0 +1,13 @@ +import '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { EmptyDataException } from '../../../../../src/core/error-handling/exception/empty-data.exception'; +import { HttpStatus } from '@nestjs/common'; + +describe('EmptyDataException ', () => { + it('Should call instanciate EmptyDataException correctly', function () { + const exception = new EmptyDataException('any'); + expect(exception.message).to.be.equal('The any data cannot be empty'); + expect(exception.getStatus()).to.be.equal(HttpStatus.INTERNAL_SERVER_ERROR); + expect(exception.errCode).to.be.equal(1); + }); +}); diff --git a/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts b/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts new file mode 100644 index 0000000..df85281 --- /dev/null +++ b/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts @@ -0,0 +1,40 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ExtensionsModule } from '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { FiltersModule } from '../../../../../src/core/error-handling/filters.module'; +import { HttpStatus } from '@nestjs/common'; +import { CustomErrorExceptionFilter } from '../../../../../src/core/error-handling/filter/custom-error-exception.filter'; +import { EmptyPropException } from '../../../../../src/core/error-handling/exception/empty-prop.exception'; + +describe('CustomErrorExceptionFilter', () => { + let sut: CustomErrorExceptionFilter; + let app: TestingModule; + + beforeEach(async () => { + app = await Test.createTestingModule({ + imports: [ExtensionsModule, FiltersModule], + controllers: [], + providers: [CustomErrorExceptionFilter] + }).compile(); + + sut = app.get(CustomErrorExceptionFilter); + }); + + afterEach(async () => { + await app.close(); + }); + + describe('makeCustomResponse', () => { + it('should call makeCustomResponse and return the correct response', async () => { + const mockException = new EmptyPropException('any_prop'); + const mockResponse = { + status: HttpStatus.NOT_ACCEPTABLE, + message: `The property 'Any_prop' cannot be empty`, + type: 'EmptyPropException', + errorCode: 2 + }; + const actual = await sut.makeCustomResponse(mockException); + expect(JSON.stringify(actual)).to.be.equal(JSON.stringify(mockResponse)); + }); + }); +}); diff --git a/test/unit/core/error-handling/filter/http-exception.filter.spec.ts b/test/unit/core/error-handling/filter/http-exception.filter.spec.ts new file mode 100644 index 0000000..1ef26eb --- /dev/null +++ b/test/unit/core/error-handling/filter/http-exception.filter.spec.ts @@ -0,0 +1,52 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ExtensionsModule } from '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { FiltersModule } from '../../../../../src/core/error-handling/filters.module'; +import { HttpExceptionFilter } from '../../../../../src/core/error-handling/filter/http-exception.filter'; +import { HttpStatus, NotFoundException } from '@nestjs/common'; + +describe('HttpExceptionFilter', () => { + let sut: HttpExceptionFilter; + let app: TestingModule; + + beforeEach(async () => { + app = await Test.createTestingModule({ + imports: [ExtensionsModule, FiltersModule], + controllers: [], + providers: [HttpExceptionFilter] + }).compile(); + + sut = app.get(HttpExceptionFilter); + }); + + afterEach(async () => { + await app.close(); + }); + + describe('getResponse', () => { + it('should call getResponse and return the correct response', async () => { + const mockException = new NotFoundException('http'); + const mockResponse = { + statusCode: HttpStatus.NOT_FOUND, + message: 'http', + error: 'Not Found' + }; + const actual = await sut.getResponse(null, mockException); + expect(JSON.stringify(actual)).to.be.equal(JSON.stringify(mockResponse)); + }); + }); + + describe('makeCustomResponse', () => { + it('should call makeCustomResponse and return the correct response', async () => { + const mockException = new NotFoundException('http'); + const mockResponse = { + status: HttpStatus.NOT_FOUND, + message: 'http', + type: 'NotFoundException', + errorCode: HttpStatus.NOT_FOUND + }; + const actual = await sut.makeCustomResponse(mockException); + expect(JSON.stringify(actual)).to.be.equal(JSON.stringify(mockResponse)); + }); + }); +}); diff --git a/test/unit/adapter/controller/neighborhoods.controller.spec.ts b/test/unit/microservice/adapter/controller/neighborhoods.controller.spec.ts similarity index 76% rename from test/unit/adapter/controller/neighborhoods.controller.spec.ts rename to test/unit/microservice/adapter/controller/neighborhoods.controller.spec.ts index 0962557..c7e3ccd 100644 --- a/test/unit/adapter/controller/neighborhoods.controller.spec.ts +++ b/test/unit/microservice/adapter/controller/neighborhoods.controller.spec.ts @@ -1,12 +1,12 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { NeighborhoodsController } from '../../../../src/places-interface/adapter/controller/neighborhoods.controller'; +import { NeighborhoodsController } from '../../../../../src/microservice/adapter/controller/neighborhoods.controller'; import { ConfigModule } from '@nestjs/config'; -import configuration from '../../../../src/config/configuration'; +import configuration from '../../../../../src/config/configuration'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; -import { ExtensionsModule } from '../../../../src/places-interface/adapter/helper/extensions/exensions.module'; -import { NeighborhoodsService } from '../../../../src/places-interface/adapter/service/neighborhoods.service'; +import { NeighborhoodsByCity } from '../../../../../src/microservice/domain/model/neighborhoods-by-city.model'; +import { ExtensionsModule } from '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { NeighborhoodsService } from '../../../../../src/microservice/adapter/service/neighborhoods.service'; describe('NeighborhoodsController', () => { let neighborhoodsController: NeighborhoodsController; diff --git a/test/unit/microservice/adapter/helper/extensions/object.extension.spec.ts b/test/unit/microservice/adapter/helper/extensions/object.extension.spec.ts new file mode 100644 index 0000000..f7a0854 --- /dev/null +++ b/test/unit/microservice/adapter/helper/extensions/object.extension.spec.ts @@ -0,0 +1,29 @@ +import '../../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { SearchNeighborhoods } from '../../../../../../src/microservice/domain/model/search/search-neighborhoods.model'; +import { EmptyPropException } from '../../../../../../src/core/error-handling/exception/empty-prop.exception'; + +describe('object.extension', () => { + describe('getMethods', function () { + it('Should call getMethods and contain toString', function () { + const obj = new Object(); + expect(obj.getMethods()).to.include.members(['toString']); + }); + }); + + describe('validateIsAnyEmptyKey', function () { + it('Should call validateIsAnyEmptyKey and throw exccption', function () { + const validation = () => { + const obj = new SearchNeighborhoods('brasil', 'sc', 'orleans'); + obj.city = ''; + obj.validateIsAnyEmptyKey(); + }; + + try { + validation(); + } catch (err) { + expect(err.message).to.be.equal("The property 'City' cannot be empty"); + } + }); + }); +}); diff --git a/test/unit/adapter/neighborhoods.module.spec.ts b/test/unit/microservice/adapter/neighborhoods.module.spec.ts similarity index 90% rename from test/unit/adapter/neighborhoods.module.spec.ts rename to test/unit/microservice/adapter/neighborhoods.module.spec.ts index df80519..56442d8 100644 --- a/test/unit/adapter/neighborhoods.module.spec.ts +++ b/test/unit/microservice/adapter/neighborhoods.module.spec.ts @@ -1,5 +1,5 @@ import { NestFactory } from '@nestjs/core'; -import { AppModule } from '../../../src/app.module'; +import { AppModule } from '../../../../src/app.module'; import { INestApplication } from '@nestjs/common/interfaces/nest-application.interface'; import { expect } from 'chai'; import * as request from 'supertest'; diff --git a/test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts b/test/unit/microservice/adapter/repository/neighborhoods/guia-mais.repository.spec.ts similarity index 78% rename from test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts rename to test/unit/microservice/adapter/repository/neighborhoods/guia-mais.repository.spec.ts index 788ad7f..3dbebae 100644 --- a/test/unit/adapter/repository/neighborhoods/guia-mais.repository.spec.ts +++ b/test/unit/microservice/adapter/repository/neighborhoods/guia-mais.repository.spec.ts @@ -2,11 +2,11 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ConfigService } from '@nestjs/config'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { GuiaMaisRepository } from '../../../../../src/places-interface/adapter/repository/neighborhoods/guia-mais.repository'; +import { GuiaMaisRepository } from '../../../../../../src/microservice/adapter/repository/neighborhoods/guia-mais.repository'; import { PuppeteerModule } from 'nest-puppeteer'; -import { SearchNeighborhoods } from '../../../../../src/places-interface/domain/model/search/search-neighborhoods.model'; +import { SearchNeighborhoods } from '../../../../../../src/microservice/domain/model/search/search-neighborhoods.model'; import * as fs from 'fs'; -import { ExtensionsModule } from '../../../../../src/places-interface/adapter/helper/extensions/exensions.module'; +import { ExtensionsModule } from '../../../../../../src/microservice/adapter/helper/extensions/exensions.module'; import * as cheerio from 'cheerio'; jest.useFakeTimers(); @@ -102,4 +102,14 @@ describe('GuiaMaisRepository', () => { goToUrlStub.restore(); }); }); + + describe('callEndpoint', () => { + it('should call callEndpoint and call getDocumentHtml with the correct params', async () => { + try { + sut.validateOutput([]); + } catch (err) { + expect(err.message).to.be.equal('Neighborhoods not found'); + } + }); + }); }); diff --git a/test/unit/adapter/service/neighborhoods.service.spec.ts b/test/unit/microservice/adapter/service/neighborhoods.service.spec.ts similarity index 82% rename from test/unit/adapter/service/neighborhoods.service.spec.ts rename to test/unit/microservice/adapter/service/neighborhoods.service.spec.ts index d0a53a9..5b5afb0 100644 --- a/test/unit/adapter/service/neighborhoods.service.spec.ts +++ b/test/unit/microservice/adapter/service/neighborhoods.service.spec.ts @@ -1,8 +1,8 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { NeighborhoodsService } from '../../../../src/places-interface/adapter/service/neighborhoods.service'; +import { NeighborhoodsService } from '../../../../../src/microservice/adapter/service/neighborhoods.service'; import { expect } from 'chai'; import * as sinon from 'sinon'; -import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; +import { NeighborhoodsByCity } from '../../../../../src/microservice/domain/model/neighborhoods-by-city.model'; describe('NeighborhoodsService', () => { let sut: NeighborhoodsService; diff --git a/test/unit/domain/model/neighborhoods-by-city.model.spec.ts b/test/unit/microservice/domain/model/neighborhoods-by-city.model.spec.ts similarity index 75% rename from test/unit/domain/model/neighborhoods-by-city.model.spec.ts rename to test/unit/microservice/domain/model/neighborhoods-by-city.model.spec.ts index 44ca28c..9c6d8cf 100644 --- a/test/unit/domain/model/neighborhoods-by-city.model.spec.ts +++ b/test/unit/microservice/domain/model/neighborhoods-by-city.model.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { NeighborhoodsByCity } from '../../../../src/places-interface/domain/model/neighborhoods-by-city.model'; +import { NeighborhoodsByCity } from '../../../../../src/microservice/domain/model/neighborhoods-by-city.model'; describe('NeighborhoodsByCity', () => { it('should instance NeighborhoodsByCity and return the object with the correct properties', async () => { diff --git a/test/unit/domain/model/search/search-neighborhoods.model.spec.ts b/test/unit/microservice/domain/model/search/search-neighborhoods.model.spec.ts similarity index 75% rename from test/unit/domain/model/search/search-neighborhoods.model.spec.ts rename to test/unit/microservice/domain/model/search/search-neighborhoods.model.spec.ts index dbbb5a8..815a4b6 100644 --- a/test/unit/domain/model/search/search-neighborhoods.model.spec.ts +++ b/test/unit/microservice/domain/model/search/search-neighborhoods.model.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { SearchNeighborhoods } from '../../../../../src/places-interface/domain/model/search/search-neighborhoods.model'; +import { SearchNeighborhoods } from '../../../../../../src/microservice/domain/model/search/search-neighborhoods.model'; describe('SearchNeighborhoods', () => { it('should instance SearchNeighborhoods and return the object with the correct properties', async () => { diff --git a/test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts b/test/unit/microservice/domain/repository/puppeteer/puppeteer.repository.spec.ts similarity index 83% rename from test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts rename to test/unit/microservice/domain/repository/puppeteer/puppeteer.repository.spec.ts index 2dffa64..c3806bc 100644 --- a/test/unit/domain/repository/puppeteer/puppeteer.repository.spec.ts +++ b/test/unit/microservice/domain/repository/puppeteer/puppeteer.repository.spec.ts @@ -5,10 +5,10 @@ import { EvaluateFn } from 'puppeteer'; import { OptionsPage, Page -} from '../../../../../src/places-interface/domain/interface/puppeteer/page.interface'; -import { ExtensionsModule } from '../../../../../src/places-interface/adapter/helper/extensions/exensions.module'; +} from '../../../../../../src/microservice/domain/interface/puppeteer/page.interface'; +import { ExtensionsModule } from '../../../../../../src/microservice/adapter/helper/extensions/exensions.module'; import { expect } from 'chai'; -import { PuppeteerRepository } from '../../../../../src/places-interface/domain/repository/puppeteer/puppeteer.repository'; +import { PuppeteerRepository } from '../../../../../../src/microservice/domain/repository/puppeteer/puppeteer.repository'; jest.useFakeTimers(); jest.setTimeout(50000); From 23cb714869f24075e5cd8fcfaafb9d3887e53b40 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 14:28:49 -0300 Subject: [PATCH 06/19] improve cov --- .../error-handling/exception/empty-prop.exception.ts | 2 +- .../error-handling/exception/not-found.exception.ts | 2 +- .../exception/custom-error.exception.spec.ts | 12 ++++++++++++ .../exception/empty-data.exception.spec.ts | 7 +++++++ 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/unit/core/error-handling/exception/custom-error.exception.spec.ts diff --git a/src/core/error-handling/exception/empty-prop.exception.ts b/src/core/error-handling/exception/empty-prop.exception.ts index 31f3076..163d20d 100644 --- a/src/core/error-handling/exception/empty-prop.exception.ts +++ b/src/core/error-handling/exception/empty-prop.exception.ts @@ -2,7 +2,7 @@ import { HttpStatus } from '@nestjs/common'; import { CustomErrorException } from './custom-error.exception'; export class EmptyPropException extends CustomErrorException { - constructor(element = '') { + constructor(element: string) { super( `The property '${element.capitalize()}' cannot be empty`, HttpStatus.NOT_ACCEPTABLE, diff --git a/src/core/error-handling/exception/not-found.exception.ts b/src/core/error-handling/exception/not-found.exception.ts index 4fdd0bd..72ad3f6 100644 --- a/src/core/error-handling/exception/not-found.exception.ts +++ b/src/core/error-handling/exception/not-found.exception.ts @@ -2,7 +2,7 @@ import { HttpStatus } from '@nestjs/common'; import { CustomErrorException } from './custom-error.exception'; export class NotFoundException extends CustomErrorException { - constructor(element = '') { + constructor(element: string) { super( `${element.capitalize()} not found`, HttpStatus.NOT_FOUND, diff --git a/test/unit/core/error-handling/exception/custom-error.exception.spec.ts b/test/unit/core/error-handling/exception/custom-error.exception.spec.ts new file mode 100644 index 0000000..28593a8 --- /dev/null +++ b/test/unit/core/error-handling/exception/custom-error.exception.spec.ts @@ -0,0 +1,12 @@ +import '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { CustomErrorException } from '../../../../../src/core/error-handling/exception/custom-error.exception'; + +describe('EmptyDataException ', () => { + it('Should call instanciate EmptyDataException correctly', function () { + const exception = new CustomErrorException('any', 500); + expect(exception.message).to.be.equal('any'); + expect(exception.getStatus()).to.be.equal(500); + expect(exception.errCode).to.be.equal(-1); + }); +}); diff --git a/test/unit/core/error-handling/exception/empty-data.exception.spec.ts b/test/unit/core/error-handling/exception/empty-data.exception.spec.ts index 01895df..e755fc9 100644 --- a/test/unit/core/error-handling/exception/empty-data.exception.spec.ts +++ b/test/unit/core/error-handling/exception/empty-data.exception.spec.ts @@ -10,4 +10,11 @@ describe('EmptyDataException ', () => { expect(exception.getStatus()).to.be.equal(HttpStatus.INTERNAL_SERVER_ERROR); expect(exception.errCode).to.be.equal(1); }); + + it('Should call instanciate EmptyDataException correctly with default param', function () { + const exception = new EmptyDataException(); + expect(exception.message).to.be.equal('The data cannot be empty'); + expect(exception.getStatus()).to.be.equal(HttpStatus.INTERNAL_SERVER_ERROR); + expect(exception.errCode).to.be.equal(1); + }); }); From 5aac1baec2b3dbbc961be3827159958b8b272a98 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 14:58:01 -0300 Subject: [PATCH 07/19] resolve code smells --- .scannerwork/report-task.txt | 4 ++-- src/core/http/transform-response.interceptor.ts | 4 ++-- .../adapter/helper/extensions/object.extension.ts | 8 +++++--- .../neighborhood/puppeteer-neighborhood.repository.ts | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt index dacbcf7..41290c8 100644 --- a/.scannerwork/report-task.txt +++ b/.scannerwork/report-task.txt @@ -3,5 +3,5 @@ projectKey=maick05_places serverUrl=https://sonarcloud.io serverVersion=8.0.0.29264 dashboardUrl=https://sonarcloud.io/dashboard?id=maick05_places -ceTaskId=AYD9UWJG_z939kpPOwHR -ceTaskUrl=https://sonarcloud.io/api/ce/task?id=AYD9UWJG_z939kpPOwHR +ceTaskId=AYEQ9njQ_z939kpPPWqA +ceTaskUrl=https://sonarcloud.io/api/ce/task?id=AYEQ9njQ_z939kpPPWqA diff --git a/src/core/http/transform-response.interceptor.ts b/src/core/http/transform-response.interceptor.ts index a7a2aeb..25ceeda 100644 --- a/src/core/http/transform-response.interceptor.ts +++ b/src/core/http/transform-response.interceptor.ts @@ -12,7 +12,7 @@ import { NestResponse } from './nest-response'; @Injectable() export class TransformResponseInterceptor implements NestInterceptor { - private httpAdapter: AbstractHttpAdapter; + private readonly httpAdapter: AbstractHttpAdapter; constructor(adapterHost: HttpAdapterHost) { this.httpAdapter = adapterHost.httpAdapter; @@ -20,7 +20,7 @@ export class TransformResponseInterceptor implements NestInterceptor { intercept( context: ExecutionContext, - next: CallHandler + next: CallHandler ): Observable | Promise> { return next.handle().pipe( map((responseController: NestResponse) => { diff --git a/src/microservice/adapter/helper/extensions/object.extension.ts b/src/microservice/adapter/helper/extensions/object.extension.ts index f31f5eb..e6b9f4d 100644 --- a/src/microservice/adapter/helper/extensions/object.extension.ts +++ b/src/microservice/adapter/helper/extensions/object.extension.ts @@ -12,7 +12,7 @@ declare global { Object.prototype.validateIsAnyEmptyKey = function () { const context = this; Object.keys(this).forEach(function (key) { - if (context[key].length == 0) throw new EmptyPropException(key); + if (context[key].length === 0) throw new EmptyPropException(key); }); }; @@ -21,7 +21,9 @@ Object.prototype.getMethods = (): any[] => { let currentObj = this; const obj = this; do { - Object.getOwnPropertyNames(currentObj).map((item) => properties.add(item)); + Object.getOwnPropertyNames(currentObj).forEach((item) => + properties.add(item) + ); } while ((currentObj = Object.getPrototypeOf(currentObj))); return [...properties.keys()].filter( (item: string) => @@ -30,7 +32,7 @@ Object.prototype.getMethods = (): any[] => { }; Object.prototype.isEmpty = (): boolean => { - return Object.keys(this).length == 0; + return Object.keys(this).length === 0; }; export {}; diff --git a/src/microservice/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts b/src/microservice/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts index be6fd71..75faf7b 100644 --- a/src/microservice/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts +++ b/src/microservice/domain/repository/puppeteer/neighborhood/puppeteer-neighborhood.repository.ts @@ -12,18 +12,18 @@ export abstract class PuppeteerNeighborhoodRepository async getNeighborhoodsByCity( searchParams: SearchNeighborhoods ): Promise { - await this.validateInput(searchParams); + this.validateInput(searchParams); const $ = await this.callEndpoint(searchParams); const elements = this.buildElementsFromDocument(searchParams, $); - await this.validateOutput(elements); + this.validateOutput(elements); return elements; } validateOutput(output: NeighborhoodsByCity[]): void { - if (output.length == 0) throw new NotFoundException('Neighborhoods'); + if (output.length === 0) throw new NotFoundException('Neighborhoods'); } abstract buildElementsFromDocument( From b603f8a00dbcee13f46f0c17e49060829b32ad3c Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 17:42:53 -0300 Subject: [PATCH 08/19] ignore ws --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f62c03f..626b825 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ lerna-debug.log* !.vscode/launch.json !.vscode/extensions.json node_modules +*.code-workspace # Sonar .scannerwork/.sonar_lock From 98c563219d33fa7586b5b8ff2e368b729b9eceb9 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 18:13:03 -0300 Subject: [PATCH 09/19] readme --- README.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9fe8812..09970cb 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 [circleci-url]: https://circleci.com/gh/nestjs/nest -

A progressive Node.js framework for building efficient and scalable server-side applications.

+

This project use [Nest](https://github.com/nestjs/nest), a progressive Node.js framework for building efficient and scalable server-side applications.

NPM Version Package License @@ -24,7 +24,7 @@ ## Description -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. +API to get neighborhoods by City. ## Installation @@ -58,7 +58,7 @@ $ npm run test:e2e $ npm run test:cov ``` -## Support + + +## Contact + +maicksantos05@hotmail.com + +## Example + +After run the server, call a post method in postman or similar + +```bash +## Url example +http://localhost:3000/neighborhoods/city/brazil/sc/orleans +``` + +[Swagger](https://app.swaggerhub.com/apis/dev-seeder/Places/1.0.0) + +At the moment, it's working only for Brazil cities. From 74f7e40f865ac7709f79cfbe16479453f495e493 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 18:17:10 -0300 Subject: [PATCH 10/19] update readme --- README.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 09970cb..64efaf1 100644 --- a/README.md +++ b/README.md @@ -5,26 +5,15 @@ [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 [circleci-url]: https://circleci.com/gh/nestjs/nest -

This project use [Nest](https://github.com/nestjs/nest), a progressive Node.js framework for building efficient and scalable server-side applications.

-

-NPM Version -Package License -NPM Downloads -CircleCI -Coverage -Discord -Backers on Open Collective -Sponsors on Open Collective - - Support us - -

- +

This project use NestJS

+ +

[Nest](https://github.com/nestjs/nest), a progressive Node.js framework for building efficient and scalable server-side applications.

## Description -API to get neighborhoods by City. +API to get Places by Local Names. + +- Only Nighborhoods for now ## Installation @@ -78,7 +67,7 @@ maicksantos05@hotmail.com ## Example -After run the server, call a post method in postman or similar +After run the server, make a get in browser, postman or similar ```bash ## Url example From 1385633dae05b55009aec97b1ef64818e38a2af8 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 18:19:14 -0300 Subject: [PATCH 11/19] readme nest link --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 64efaf1..b7dfded 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,7 @@ [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 [circleci-url]: https://circleci.com/gh/nestjs/nest -

This project use NestJS

- -

[Nest](https://github.com/nestjs/nest), a progressive Node.js framework for building efficient and scalable server-side applications.

+

This project use Nest, a progressive Node.js framework for building efficient and scalable server-side applications.

## Description From 2ee393ac657db45c16962aa1fe5a4f5cfcaacef0 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 18:20:45 -0300 Subject: [PATCH 12/19] fix word --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b7dfded..69c3423 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 [circleci-url]: https://circleci.com/gh/nestjs/nest -

This project use Nest, a progressive Node.js framework for building efficient and scalable server-side applications.

+

This project use NestJS, a progressive Node.js framework for building efficient and scalable server-side applications.

## Description API to get Places by Local Names. -- Only Nighborhoods for now +- Only Neighborhoods for now ## Installation From cd6dd5bcd2b3e0d1b9c56ebb736700266c9036b8 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 21:45:33 -0300 Subject: [PATCH 13/19] fix e2e test --- package-lock.json | 55 +++++-------------- package.json | 5 +- src/main.ts | 5 +- .../controller/neighborhoods.controller.ts | 2 +- test/e2e/app.e2e-spec.ts | 24 +++----- 5 files changed, 30 insertions(+), 61 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2085c6a..7e4943c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,8 @@ "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", - "sinon": "^14.0.0" + "sinon": "^14.0.0", + "superagent": "^7.1.3" }, "devDependencies": { "@nestjs/cli": "^8.0.0", @@ -45,7 +46,7 @@ "jest": "^27.2.5", "prettier": "^2.3.2", "source-map-support": "^0.5.20", - "supertest": "^6.1.3", + "supertest": "^6.2.3", "ts-jest": "^27.0.3", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", @@ -2503,8 +2504,7 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/assertion-error": { "version": "1.1.0", @@ -3200,8 +3200,7 @@ "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -3309,8 +3308,7 @@ "node_modules/cookiejar": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", - "dev": true + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" }, "node_modules/core-util-is": { "version": "1.0.3", @@ -3543,7 +3541,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, "dependencies": { "asap": "^2.0.0", "wrappy": "1" @@ -4620,7 +4617,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", - "dev": true, "dependencies": { "dezalgo": "1.0.3", "hexoid": "1.0.0", @@ -4635,7 +4631,6 @@ "version": "6.9.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "dev": true, "engines": { "node": ">=0.6" }, @@ -4891,7 +4886,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "dev": true, "engines": { "node": ">=8" } @@ -6515,7 +6509,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -7774,7 +7767,6 @@ "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -8106,7 +8098,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/superagent/-/superagent-7.1.3.tgz", "integrity": "sha512-WA6et4nAvgBCS73lJvv1D0ssI5uk5Gh+TGN/kNe+B608EtcVs/yzfl+OLXTzDs7tOBDIpvgh/WUs1K2OK1zTeQ==", - "dev": true, "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.3", @@ -8128,7 +8119,6 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, "bin": { "mime": "cli.js" }, @@ -8140,7 +8130,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -8154,7 +8143,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -9244,8 +9232,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "1.10.2", @@ -11206,8 +11193,7 @@ "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "assertion-error": { "version": "1.1.0", @@ -11723,8 +11709,7 @@ "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "concat-map": { "version": "0.0.1", @@ -11824,8 +11809,7 @@ "cookiejar": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", - "dev": true + "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" }, "core-util-is": { "version": "1.0.3", @@ -12009,7 +11993,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -12816,7 +12799,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", - "dev": true, "requires": { "dezalgo": "1.0.3", "hexoid": "1.0.0", @@ -12827,8 +12809,7 @@ "qs": { "version": "6.9.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "dev": true + "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==" } } }, @@ -13009,8 +12990,7 @@ "hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", - "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", - "dev": true + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==" }, "html-encoding-sniffer": { "version": "2.0.1", @@ -14249,7 +14229,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -15158,7 +15137,6 @@ "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -15427,7 +15405,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/superagent/-/superagent-7.1.3.tgz", "integrity": "sha512-WA6et4nAvgBCS73lJvv1D0ssI5uk5Gh+TGN/kNe+B608EtcVs/yzfl+OLXTzDs7tOBDIpvgh/WUs1K2OK1zTeQ==", - "dev": true, "requires": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.3", @@ -15445,14 +15422,12 @@ "mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -15463,7 +15438,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -16264,8 +16238,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index b498a96..9bfdb85 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", - "sinon": "^14.0.0" + "sinon": "^14.0.0", + "superagent": "^7.1.3" }, "devDependencies": { "@nestjs/cli": "^8.0.0", @@ -57,7 +58,7 @@ "jest": "^27.2.5", "prettier": "^2.3.2", "source-map-support": "^0.5.20", - "supertest": "^6.1.3", + "supertest": "^6.2.3", "ts-jest": "^27.0.3", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", diff --git a/src/main.ts b/src/main.ts index 8c2c4a0..e952449 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,6 +11,7 @@ async function bootstrap() { }) ); useContainer(app.select(AppModule), { fallbackOnErrors: true }); - await app.listen(3000); + return await app.listen(3000); } -bootstrap(); + +module.exports = bootstrap(); diff --git a/src/microservice/adapter/controller/neighborhoods.controller.ts b/src/microservice/adapter/controller/neighborhoods.controller.ts index 6fe5dde..7f52f7b 100644 --- a/src/microservice/adapter/controller/neighborhoods.controller.ts +++ b/src/microservice/adapter/controller/neighborhoods.controller.ts @@ -16,7 +16,7 @@ export class NeighborhoodsController extends AbstractController { @Param('city') city ): NestResponse { return this.buildResponse( - HttpStatus.ACCEPTED, + HttpStatus.OK, this.neighborhoodsService.getNeighborhoodsByCity(country, state, city) ); } diff --git a/test/e2e/app.e2e-spec.ts b/test/e2e/app.e2e-spec.ts index ff9319b..531e271 100644 --- a/test/e2e/app.e2e-spec.ts +++ b/test/e2e/app.e2e-spec.ts @@ -1,8 +1,8 @@ -import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import * as request from 'supertest'; -// import expect from 'chai'; +import { expect } from 'chai'; import { AppModule } from '../../src/app.module'; +import { NestFactory } from '@nestjs/core'; jest.useFakeTimers(); jest.setTimeout(50000); @@ -11,12 +11,8 @@ describe('AppController (e2e)', () => { let app: INestApplication; beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule] - }).compile(); - - app = moduleFixture.createNestApplication(); - await app.init(); + app = await NestFactory.create(AppModule); + app.init(); }); afterEach(async () => { @@ -24,12 +20,10 @@ describe('AppController (e2e)', () => { }); it('/neighborhoods/city/brasil/sc/orleans (GET)', async () => { - try { - await request(app.getHttpServer()) - .get('/neighborhoods/city/brasil/sc/orleans') - .expect(200); - } catch (error) { - console.error(error); - } + const actual = await request(app.getHttpServer()) + .get('/neighborhoods/city/brasil/sc/orleans') + .expect(200); + + expect(actual.body).to.be.an('array').that.is.not.empty; }); }); From 7d67643f20b0aabe5f7a622900db7220469cd00e Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Sun, 29 May 2022 22:05:20 -0300 Subject: [PATCH 14/19] fix neighborhood module --- .../adapter/neighborhoods.module.spec.ts | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/test/unit/microservice/adapter/neighborhoods.module.spec.ts b/test/unit/microservice/adapter/neighborhoods.module.spec.ts index 56442d8..8d71f6a 100644 --- a/test/unit/microservice/adapter/neighborhoods.module.spec.ts +++ b/test/unit/microservice/adapter/neighborhoods.module.spec.ts @@ -1,31 +1,35 @@ -import { NestFactory } from '@nestjs/core'; -import { AppModule } from '../../../../src/app.module'; -import { INestApplication } from '@nestjs/common/interfaces/nest-application.interface'; -import { expect } from 'chai'; -import * as request from 'supertest'; +import { HttpStatus } from '@nestjs/common'; +import { NeighborhoodsModule } from '../../../../src/microservice/adapter/neighborhoods.module'; +import { Test, TestingModule } from '@nestjs/testing'; +import { NeighborhoodsController } from '../../../../src/microservice/adapter/controller/neighborhoods.controller'; +import { ExtensionsModule } from '../../../../src/microservice/adapter/helper/extensions/exensions.module'; -describe('NewStageForEmptyMovesInterfaceModule', () => { - let application: INestApplication; +describe('NeighborhoodsModule', () => { + let sut: NeighborhoodsController; + let app: TestingModule; + + const mockGuiaMaisRepository = { + getNeighborhoodsByCity() { + return; + } + }; beforeEach(async function () { - application = await NestFactory.create(AppModule); - application.init(); - }); + app = await Test.createTestingModule({ + imports: [NeighborhoodsModule, ExtensionsModule], + providers: [] + }) + .overrideProvider('GuiaMaisRepository') + .useValue(mockGuiaMaisRepository) + .compile(); - afterEach(async function () { - application.close(); + sut = app.get(NeighborhoodsController); }); - describe('#endpoint /', function () { - describe('GET /', function () { - it('should verify if default service returns 404', function (done) { - request(application.getHttpServer()) - .get('/') - .end(function (err, res) { - expect(res.status).to.be.equal(404); - done(err); - }); - }); + describe('NeighborhoodsController', function () { + it('should call buildResponse for status 200', async function () { + const actual = await sut.buildResponse(HttpStatus.OK, {}); + expect(actual.status).toBe(HttpStatus.OK); }); }); }); From 1c1891e9736e01d9a045f1fadc63bb61786cc87a Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Mon, 30 May 2022 13:05:33 -0300 Subject: [PATCH 15/19] improve cov --- .scannerwork/report-task.txt | 4 +- package-lock.json | 11 +++ package.json | 4 +- sonar-project.properties | 2 +- .../filter/error-exception.filter.ts | 13 +++- .../custom-error-exception.filter.spec.ts | 77 +++++++++++++++++- .../filter/error-exception.filter.spec.ts | 78 +++++++++++++++++++ 7 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 test/unit/core/error-handling/filter/error-exception.filter.spec.ts diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt index 41290c8..af55345 100644 --- a/.scannerwork/report-task.txt +++ b/.scannerwork/report-task.txt @@ -3,5 +3,5 @@ projectKey=maick05_places serverUrl=https://sonarcloud.io serverVersion=8.0.0.29264 dashboardUrl=https://sonarcloud.io/dashboard?id=maick05_places -ceTaskId=AYEQ9njQ_z939kpPPWqA -ceTaskUrl=https://sonarcloud.io/api/ce/task?id=AYEQ9njQ_z939kpPPWqA +ceTaskId=AYEShHKEx7rM3OF9_Y2O +ceTaskUrl=https://sonarcloud.io/api/ce/task?id=AYEShHKEx7rM3OF9_Y2O diff --git a/package-lock.json b/package-lock.json index 7e4943c..dd62aeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "UNLICENSED", "dependencies": { + "@golevelup/ts-jest": "^0.3.3", "@nestjs/common": "^8.0.0", "@nestjs/config": "^2.0.1", "@nestjs/core": "^8.0.0", @@ -852,6 +853,11 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/@golevelup/ts-jest": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@golevelup/ts-jest/-/ts-jest-0.3.3.tgz", + "integrity": "sha512-gut5EhD2S7W1p+C/IsUS1o0P5SHgxsN9TqHyRTjG+rfycniLNBfvIWZPEizpsTev/lR10/XOTpE0YicxPme2+Q==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", @@ -9906,6 +9912,11 @@ } } }, + "@golevelup/ts-jest": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@golevelup/ts-jest/-/ts-jest-0.3.3.tgz", + "integrity": "sha512-gut5EhD2S7W1p+C/IsUS1o0P5SHgxsN9TqHyRTjG+rfycniLNBfvIWZPEizpsTev/lR10/XOTpE0YicxPme2+Q==" + }, "@humanwhocodes/config-array": { "version": "0.9.5", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", diff --git a/package.json b/package.json index 9bfdb85..c75fb57 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "test:e2e": "jest --config ./test/e2e/jest-e2e.json" }, "dependencies": { + "@golevelup/ts-jest": "^0.3.3", "@nestjs/common": "^8.0.0", "@nestjs/config": "^2.0.1", "@nestjs/core": "^8.0.0", @@ -81,7 +82,8 @@ "coverageDirectory": "coverage", "coveragePathIgnorePatterns": [ "/node_modules/", - "/src/main.ts" + "/src/main.ts", + "/src/app.module.ts" ], "testEnvironment": "node" } diff --git a/sonar-project.properties b/sonar-project.properties index 566714d..6b0da3c 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -23,7 +23,7 @@ sonar.test.inclusions=test/**/*.spec.ts sonar.tests=./test -sonar.exclusions= .eslintrc.js, src/main.ts, src/test/*, test/app.e2e-spec.ts +sonar.exclusions= .eslintrc.js, src/main.ts, src/test/*, test/app.e2e-spec.ts, src/app.module.ts sonar.typescript.tsconfigPath=tsconfig.json diff --git a/src/core/error-handling/filter/error-exception.filter.ts b/src/core/error-handling/filter/error-exception.filter.ts index a02d8d7..c2f6d6f 100644 --- a/src/core/error-handling/filter/error-exception.filter.ts +++ b/src/core/error-handling/filter/error-exception.filter.ts @@ -1,6 +1,7 @@ import { Catch, HttpException, HttpStatus } from '@nestjs/common'; import { AbstractExceptionFilter } from './abstract-exception.filter'; import { CustomExceptionReponse } from '../interface/custom-exception-response.interface'; +import { CustomErrorException } from '../exception/custom-error.exception'; @Catch() export class ErrorExceptionFilter extends AbstractExceptionFilter { @@ -9,7 +10,7 @@ export class ErrorExceptionFilter extends AbstractExceptionFilter { status: this.getStatus(exception), message: exception.message, type: exception.name, - errorCode: this.getStatus(exception) + errorCode: this.getErrCode(exception) }; } @@ -20,4 +21,14 @@ export class ErrorExceptionFilter extends AbstractExceptionFilter { return status; } + + getErrCode(exception: any): number { + let errCode = -1; + + if (exception instanceof HttpException) errCode = exception.getStatus(); + + if (exception instanceof CustomErrorException) errCode = exception.errCode; + + return errCode; + } } diff --git a/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts b/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts index df85281..6123510 100644 --- a/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts +++ b/test/unit/core/error-handling/filter/custom-error-exception.filter.spec.ts @@ -2,13 +2,19 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ExtensionsModule } from '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; import { expect } from 'chai'; import { FiltersModule } from '../../../../../src/core/error-handling/filters.module'; -import { HttpStatus } from '@nestjs/common'; +import { HttpStatus, INestApplication } from '@nestjs/common'; import { CustomErrorExceptionFilter } from '../../../../../src/core/error-handling/filter/custom-error-exception.filter'; import { EmptyPropException } from '../../../../../src/core/error-handling/exception/empty-prop.exception'; +import { createMock } from '@golevelup/ts-jest'; +import { ExecutionContext } from '@nestjs/common'; +import * as sinon from 'sinon'; +import { NestFactory } from '@nestjs/core'; +import { AppModule } from '../../../../../src/app.module'; describe('CustomErrorExceptionFilter', () => { let sut: CustomErrorExceptionFilter; let app: TestingModule; + let server: INestApplication; beforeEach(async () => { app = await Test.createTestingModule({ @@ -18,10 +24,13 @@ describe('CustomErrorExceptionFilter', () => { }).compile(); sut = app.get(CustomErrorExceptionFilter); + server = await NestFactory.create(AppModule); + await server.init(); }); afterEach(async () => { await app.close(); + await server.close(); }); describe('makeCustomResponse', () => { @@ -37,4 +46,70 @@ describe('CustomErrorExceptionFilter', () => { expect(JSON.stringify(actual)).to.be.equal(JSON.stringify(mockResponse)); }); }); + + describe('getResponse', () => { + it('should call getResponse and call the functions correctly', async () => { + const mockResponse = { + status: HttpStatus.NOT_ACCEPTABLE, + message: `The property 'Any_prop' cannot be empty`, + type: 'EmptyPropException', + errorCode: 2 + }; + + const mockArgHostResponse = createMock({ + switchToHttp: () => ({ + getResponse: () => mockResponse + }) + }); + + const mockException = new EmptyPropException('any_prop'); + + const actual = await sut.getResponse(mockArgHostResponse, mockException); + expect(JSON.stringify(actual)).to.be.equal(JSON.stringify(mockResponse)); + }); + }); + + describe('catch', () => { + it('should call catch and call the functions correctly', async () => { + const mockException = new EmptyPropException('any_prop'); + + const mockResponse = { + status: HttpStatus.NOT_ACCEPTABLE, + message: `The property 'Any_prop' cannot be empty`, + type: 'EmptyPropException', + errorCode: 2 + }; + + const mockAdapterResponse = { + status: () => HttpStatus.NOT_ACCEPTABLE, + message: `The property 'Any_prop' cannot be empty`, + type: 'EmptyPropException', + errorCode: 2, + json: () => mockResponse + }; + + const mockArgHostResponse = createMock({ + switchToHttp: () => ({ + getResponse: () => mockAdapterResponse + }) + }); + + const getResponseSpy = sinon.spy(sut, 'getResponse'); + const makeCustomResponseSpy = sinon.spy(sut, 'makeCustomResponse'); + sinon.stub(sut, 'httpAdapter').value(server.getHttpAdapter()); + + await sut.catch(mockException, mockArgHostResponse); + + sinon.assert.calledOnceWithExactly( + getResponseSpy, + mockArgHostResponse, + mockException + ); + + sinon.assert.calledOnceWithExactly(makeCustomResponseSpy, mockException); + + getResponseSpy.restore(); + makeCustomResponseSpy.restore(); + }); + }); }); diff --git a/test/unit/core/error-handling/filter/error-exception.filter.spec.ts b/test/unit/core/error-handling/filter/error-exception.filter.spec.ts new file mode 100644 index 0000000..96d1e85 --- /dev/null +++ b/test/unit/core/error-handling/filter/error-exception.filter.spec.ts @@ -0,0 +1,78 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ExtensionsModule } from '../../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { FiltersModule } from '../../../../../src/core/error-handling/filters.module'; +import { HttpStatus, NotFoundException } from '@nestjs/common'; +import { ErrorExceptionFilter } from '../../../../../src/core/error-handling/filter/error-exception.filter'; +import { CustomErrorException } from '../../../../../src/core/error-handling/exception/custom-error.exception'; + +describe('ErrorExceptionFilter', () => { + let sut: ErrorExceptionFilter; + let app: TestingModule; + + beforeEach(async () => { + app = await Test.createTestingModule({ + imports: [ExtensionsModule, FiltersModule], + controllers: [], + providers: [ErrorExceptionFilter] + }).compile(); + + sut = app.get(ErrorExceptionFilter); + }); + + afterEach(async () => { + await app.close(); + }); + + describe('makeCustomResponse', () => { + it('should call makeCustomResponse and return the correct response', async () => { + const mockException = new Error('any_error'); + const mockResponse = { + status: HttpStatus.INTERNAL_SERVER_ERROR, + message: `any_error`, + type: mockException.name, + errorCode: -1 + }; + const actual = await sut.makeCustomResponse(mockException); + expect(JSON.stringify(actual)).to.be.equal(JSON.stringify(mockResponse)); + }); + }); + + describe('getStatus', () => { + it('should call getStatus and return the correct value for error instance', async () => { + const mockException = new Error('any_error'); + const actual = await sut.getStatus(mockException); + expect(actual).to.be.equal(HttpStatus.INTERNAL_SERVER_ERROR); + }); + + it('should call getStatus and return the correct value for HttpException instance', async () => { + const mockException = new NotFoundException(); + const actual = await sut.getStatus(mockException); + expect(actual).to.be.equal(HttpStatus.NOT_FOUND); + }); + }); + + describe('getErrCode', () => { + it('should call getErrCode and return the correct value for error instance', async () => { + const mockException = new Error('any_error'); + const actual = await sut.getErrCode(mockException); + expect(actual).to.be.equal(-1); + }); + + it('should call getErrCode and return the correct value for CustomErrorException instance', async () => { + const mockException = new CustomErrorException( + 'any', + HttpStatus.INTERNAL_SERVER_ERROR, + 10 + ); + const actual = await sut.getErrCode(mockException); + expect(actual).to.be.equal(10); + }); + + it('should call getErrCode and return the correct value for HttpException instance', async () => { + const mockException = new NotFoundException(); + const actual = await sut.getErrCode(mockException); + expect(actual).to.be.equal(HttpStatus.NOT_FOUND); + }); + }); +}); From 18cb1127e74f5ddda77b61aa5419817b6414cadc Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Mon, 30 May 2022 14:04:04 -0300 Subject: [PATCH 16/19] nest response and interceptor test --- src/core/http/nest-response.builder.ts | 5 +- .../helper/extensions/object.extension.ts | 5 -- .../core/http/nest-response.builder.spec.ts | 12 +++++ .../transform-response.interceptor.spec.ts | 52 +++++++++++++++++++ 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 test/unit/core/http/nest-response.builder.spec.ts create mode 100644 test/unit/core/http/transform-response.interceptor.spec.ts diff --git a/src/core/http/nest-response.builder.ts b/src/core/http/nest-response.builder.ts index 326409e..2cefe62 100644 --- a/src/core/http/nest-response.builder.ts +++ b/src/core/http/nest-response.builder.ts @@ -16,9 +16,8 @@ export class NestResponseBuilder { return this; } - setHeader(headers: object) { - if (headers.isEmpty()) return this; - + setHeader(headers: any) { + if (Object.keys(headers).length === 0) return this; this.response.headers = headers; return this; } diff --git a/src/microservice/adapter/helper/extensions/object.extension.ts b/src/microservice/adapter/helper/extensions/object.extension.ts index e6b9f4d..3662288 100644 --- a/src/microservice/adapter/helper/extensions/object.extension.ts +++ b/src/microservice/adapter/helper/extensions/object.extension.ts @@ -5,7 +5,6 @@ declare global { interface Object { validateIsAnyEmptyKey(): void; getMethods(): string[]; - isEmpty(): boolean; } } @@ -31,8 +30,4 @@ Object.prototype.getMethods = (): any[] => { ); }; -Object.prototype.isEmpty = (): boolean => { - return Object.keys(this).length === 0; -}; - export {}; diff --git a/test/unit/core/http/nest-response.builder.spec.ts b/test/unit/core/http/nest-response.builder.spec.ts new file mode 100644 index 0000000..b19cdda --- /dev/null +++ b/test/unit/core/http/nest-response.builder.spec.ts @@ -0,0 +1,12 @@ +import '../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { NestResponseBuilder } from '../../../../src/core/http/nest-response.builder'; + +describe('NestResponseBuilder ', () => { + it('Should call instanciate NestResponseBuilder and set header correctly', function () { + const mockHeaders = new Object({ anyKey: 'anyHeader' }); + const nestBuilder = new NestResponseBuilder(); + const actual = nestBuilder.setHeader(mockHeaders).build(); + expect(actual.headers).to.be.equal(mockHeaders); + }); +}); diff --git a/test/unit/core/http/transform-response.interceptor.spec.ts b/test/unit/core/http/transform-response.interceptor.spec.ts new file mode 100644 index 0000000..9ece991 --- /dev/null +++ b/test/unit/core/http/transform-response.interceptor.spec.ts @@ -0,0 +1,52 @@ +import '../../../../src/microservice/adapter/helper/extensions/exensions.module'; +import { expect } from 'chai'; +import { TransformResponseInterceptor } from '../../../../src/core/http/transform-response.interceptor'; +import { ExecutionContext, HttpStatus, INestApplication } from '@nestjs/common'; +import { NestFactory } from '@nestjs/core'; +import { AppModule } from '../../../../src/app.module'; +import { createMock } from '@golevelup/ts-jest'; +import { NestResponse } from '../../../../src/core/http/nest-response'; +import { NestResponseBuilder } from '../../../../src/core/http/nest-response.builder'; +import { CustomResponse } from '../../../../src/core/interface/custom-response.interface'; +import { of } from 'rxjs'; + +describe('TransformResponseInterceptor ', () => { + let app: INestApplication; + let mockAdapter; + + const callHandler = { + handle: jest.fn(() => of([mockNestResponse()])) + }; + + beforeEach(async function () { + app = await NestFactory.create(AppModule); + app.init(); + mockAdapter = { + httpAdapter: await app.getHttpAdapter() + }; + }); + + afterEach(async function () { + await app.close(); + }); + + const mockCustomResponse: CustomResponse = { + success: true, + response: 'any_data' + }; + + const mockNestResponse = (): NestResponse => { + const builder = new NestResponseBuilder(); + builder.setStatus(HttpStatus.OK); + builder.setBody(mockCustomResponse); + builder.setHeader({}); + return builder.build(); + }; + + it('Should call instanciate TransformResponseInterceptor correctly', async function () { + const mockExecutionContext = createMock(); + const sut = new TransformResponseInterceptor(mockAdapter); + const actual = await sut.intercept(mockExecutionContext, callHandler); + expect(typeof actual).to.be.equal('object'); + }); +}); From f4958679c7946a6eeba9af0d6e8e6d66c350fab9 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Mon, 30 May 2022 20:50:39 -0300 Subject: [PATCH 17/19] intercept response test --- .../http/transform-response.interceptor.ts | 32 ++++++----- .../transform-response.interceptor.spec.ts | 54 ++++++++++++++++--- 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/core/http/transform-response.interceptor.ts b/src/core/http/transform-response.interceptor.ts index 25ceeda..8b089dc 100644 --- a/src/core/http/transform-response.interceptor.ts +++ b/src/core/http/transform-response.interceptor.ts @@ -23,22 +23,30 @@ export class TransformResponseInterceptor implements NestInterceptor { next: CallHandler ): Observable | Promise> { return next.handle().pipe( + /* istanbul ignore next */ map((responseController: NestResponse) => { - const ctx = context.switchToHttp(); - const response = ctx.getResponse(); - const { headers, status, body } = responseController; + return this.interceptResponse(responseController, context); + }) + ); + } - const headersName = Object.getOwnPropertyNames(headers); + interceptResponse( + responseController: NestResponse, + context: ExecutionContext + ) { + const ctx = context.switchToHttp(); + const response = ctx.getResponse(); + const { headers, status, body } = responseController; - headersName.forEach((header) => { - const headerValue = headers[header]; - this.httpAdapter.setHeader(response, header, headerValue); - }); + const headersName = Object.getOwnPropertyNames(headers); - this.httpAdapter.status(response, status); + headersName.forEach((header) => { + const headerValue = headers[header]; + this.httpAdapter.setHeader(response, header, headerValue); + }); - return body; - }) - ); + this.httpAdapter.status(response, status); + + return body; } } diff --git a/test/unit/core/http/transform-response.interceptor.spec.ts b/test/unit/core/http/transform-response.interceptor.spec.ts index 9ece991..19a5d9b 100644 --- a/test/unit/core/http/transform-response.interceptor.spec.ts +++ b/test/unit/core/http/transform-response.interceptor.spec.ts @@ -1,7 +1,12 @@ import '../../../../src/microservice/adapter/helper/extensions/exensions.module'; import { expect } from 'chai'; import { TransformResponseInterceptor } from '../../../../src/core/http/transform-response.interceptor'; -import { ExecutionContext, HttpStatus, INestApplication } from '@nestjs/common'; +import { + ExecutionContext, + HttpStatus, + INestApplication, + ValidationPipe +} from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from '../../../../src/app.module'; import { createMock } from '@golevelup/ts-jest'; @@ -9,6 +14,7 @@ import { NestResponse } from '../../../../src/core/http/nest-response'; import { NestResponseBuilder } from '../../../../src/core/http/nest-response.builder'; import { CustomResponse } from '../../../../src/core/interface/custom-response.interface'; import { of } from 'rxjs'; +import * as sinon from 'sinon'; describe('TransformResponseInterceptor ', () => { let app: INestApplication; @@ -20,6 +26,11 @@ describe('TransformResponseInterceptor ', () => { beforeEach(async function () { app = await NestFactory.create(AppModule); + app.useGlobalPipes( + new ValidationPipe({ + transform: true + }) + ); app.init(); mockAdapter = { httpAdapter: await app.getHttpAdapter() @@ -39,14 +50,43 @@ describe('TransformResponseInterceptor ', () => { const builder = new NestResponseBuilder(); builder.setStatus(HttpStatus.OK); builder.setBody(mockCustomResponse); - builder.setHeader({}); + builder.setHeader({ + accept: 'application/json' + }); return builder.build(); }; - it('Should call instanciate TransformResponseInterceptor correctly', async function () { - const mockExecutionContext = createMock(); - const sut = new TransformResponseInterceptor(mockAdapter); - const actual = await sut.intercept(mockExecutionContext, callHandler); - expect(typeof actual).to.be.equal('object'); + describe('intercept', function () { + it('Should call instanciate TransformResponseInterceptor correctly', async function () { + const mockExecutionContext = createMock(); + + const sut = new TransformResponseInterceptor(mockAdapter); + + const actual = await sut.intercept(mockExecutionContext, callHandler); + + expect(typeof actual).to.be.equal('object'); + }); + }); + + describe('interceptResponse', function () { + it('Should call instanciate TransformResponseInterceptor correctly', async function () { + const mockExecutionContext = createMock(); + const sut = new TransformResponseInterceptor(mockAdapter); + const adapterStatusSpy = sinon.spy(mockAdapter.httpAdapter, 'status'); + const adapterHeaderSpy = sinon.spy(mockAdapter.httpAdapter, 'setHeader'); + + const actual = await sut.interceptResponse( + mockNestResponse(), + mockExecutionContext + ); + + sinon.assert.calledOnce(adapterStatusSpy); + sinon.assert.calledOnce(adapterHeaderSpy); + + expect(actual).to.be.equal(mockNestResponse().body); + + adapterHeaderSpy.restore(); + adapterStatusSpy.restore(); + }); }); }); From ac102ee7271e6fc027d2fda2806322056a0051e4 Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Mon, 30 May 2022 20:53:27 -0300 Subject: [PATCH 18/19] actions yml --- .github/workflows/e2e-tests.yml | 21 +++++++++++++++++++ .../{main.yml => sonar-unit-tests.yml} | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/e2e-tests.yml rename .github/workflows/{main.yml => sonar-unit-tests.yml} (95%) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 0000000..99e63a6 --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,21 @@ +name: e2e +on: + push: + branches: + - main + - development +jobs: + e2eTests: + name: e2e-Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: install + run: npm install + - name: e2e test + run: npm run test:e2e + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + diff --git a/.github/workflows/main.yml b/.github/workflows/sonar-unit-tests.yml similarity index 95% rename from .github/workflows/main.yml rename to .github/workflows/sonar-unit-tests.yml index f8489f0..03e3ffc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/sonar-unit-tests.yml @@ -1,4 +1,4 @@ -name: Build Sonar +name: Build Sonar Unit Tests on: push: branches: From b67f8595b51d46288de43b6a952d4d620fb9ac9d Mon Sep 17 00:00:00 2001 From: Maick Speck Date: Mon, 30 May 2022 21:01:29 -0300 Subject: [PATCH 19/19] config api port --- config/yaml/values.yaml | 2 ++ src/main.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config/yaml/values.yaml b/config/yaml/values.yaml index b66cb4e..02fb75f 100644 --- a/config/yaml/values.yaml +++ b/config/yaml/values.yaml @@ -2,3 +2,5 @@ repository: neighborhoods: guia-mais: url: 'https://www.guiamais.com.br/bairros' +api: + port: 3000 diff --git a/src/main.ts b/src/main.ts index e952449..7e3f12a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,5 @@ import { ValidationPipe } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; import { useContainer } from 'class-validator'; import { AppModule } from './app.module'; @@ -11,7 +12,8 @@ async function bootstrap() { }) ); useContainer(app.select(AppModule), { fallbackOnErrors: true }); - return await app.listen(3000); + const configService = app.get(ConfigService); + return await app.listen(configService.get('api.port')); } module.exports = bootstrap();