From d294049a284f58c9e1995bb4167cb5e3fbfb2013 Mon Sep 17 00:00:00 2001 From: sbriat Date: Tue, 27 Jun 2023 11:57:01 +0200 Subject: [PATCH] improve tests, added findAdById grpc controller test --- package.json | 3 +- .../create-ad.grpc.controller.ts | 7 +- .../find-ad-by-id.grpc.controller.ts | 10 +- .../create-ad.grpc.controller.spec.ts | 18 ++- .../find-ad-by-id.grpc.controller.spec.ts | 140 ++++++++++++++++++ 5 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 src/modules/ad/tests/unit/interface/find-ad-by-id.grpc.controller.spec.ts diff --git a/package.json b/package.json index bd1ef20..26bd1fb 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,8 @@ "moduleNameMapper": { "^@libs(.*)": "/libs/$1", "^@modules(.*)": "/modules/$1", - "^@src(.*)": "$1" + "^@src(.*)": "$1", + "^@utils(.*)": "utils/$1" }, "testEnvironment": "node" } diff --git a/src/modules/ad/interface/grpc-controllers/create-ad.grpc.controller.ts b/src/modules/ad/interface/grpc-controllers/create-ad.grpc.controller.ts index 65a7112..91158b7 100644 --- a/src/modules/ad/interface/grpc-controllers/create-ad.grpc.controller.ts +++ b/src/modules/ad/interface/grpc-controllers/create-ad.grpc.controller.ts @@ -1,13 +1,13 @@ import { Controller, UsePipes } from '@nestjs/common'; import { CommandBus } from '@nestjs/cqrs'; import { GrpcMethod, RpcException } from '@nestjs/microservices'; -import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe'; import { CreateAdRequestDto } from './dtos/create-ad.request.dto'; import { CreateAdCommand } from '../../core/commands/create-ad/create-ad.command'; import { AggregateID } from '@libs/ddd'; import { AdAlreadyExistsException } from '../../core/ad.errors'; import { IdResponse } from '@libs/api/id.response.dto'; import { RpcExceptionCode } from '@libs/exceptions/rpc-exception.codes.enum'; +import { RpcValidationPipe } from '@utils/pipes/rpc.validation-pipe'; @UsePipes( new RpcValidationPipe({ @@ -32,7 +32,10 @@ export class CreateAdGrpcController { code: RpcExceptionCode.ALREADY_EXISTS, message: error.message, }); - throw new RpcException({}); + throw new RpcException({ + code: RpcExceptionCode.UNKNOWN, + message: error.message, + }); } } } diff --git a/src/modules/ad/interface/grpc-controllers/find-ad-by-id.grpc.controller.ts b/src/modules/ad/interface/grpc-controllers/find-ad-by-id.grpc.controller.ts index b60008f..f7d5be3 100644 --- a/src/modules/ad/interface/grpc-controllers/find-ad-by-id.grpc.controller.ts +++ b/src/modules/ad/interface/grpc-controllers/find-ad-by-id.grpc.controller.ts @@ -7,6 +7,8 @@ import { FindAdByIdQuery } from '@modules/ad/core/queries/find-ad-by-id/find-ad- import { AdResponseDto } from '../dtos/ad.response.dto'; import { AdEntity } from '@modules/ad/core/ad.entity'; import { AdMapper } from '@modules/ad/ad.mapper'; +import { NotFoundException } from '@libs/exceptions'; +import { RpcExceptionCode } from '@libs/exceptions/rpc-exception.codes.enum'; @UsePipes( new RpcValidationPipe({ @@ -29,8 +31,14 @@ export class FindAdByIdGrpcController { ); return this.mapper.toResponse(ad); } catch (e) { + if (e instanceof NotFoundException) { + throw new RpcException({ + code: RpcExceptionCode.NOT_FOUND, + message: e.message, + }); + } throw new RpcException({ - code: e.code, + code: RpcExceptionCode.UNKNOWN, message: e.message, }); } diff --git a/src/modules/ad/tests/unit/interface/create-ad.grpc.controller.spec.ts b/src/modules/ad/tests/unit/interface/create-ad.grpc.controller.spec.ts index 49c4f8e..e0bc8e3 100644 --- a/src/modules/ad/tests/unit/interface/create-ad.grpc.controller.spec.ts +++ b/src/modules/ad/tests/unit/interface/create-ad.grpc.controller.spec.ts @@ -72,35 +72,45 @@ describe('Create Ad Grpc Controller', () => { ); }); + afterEach(async () => { + jest.clearAllMocks(); + }); + it('should be defined', () => { expect(createAdGrpcController).toBeDefined(); }); it('should create a new ad', async () => { + jest.spyOn(mockCommandBus, 'execute'); const result: IdResponse = await createAdGrpcController.create( punctualCreateAdRequest, ); expect(result).toBeInstanceOf(IdResponse); expect(result.id).toBe('200d61a8-d878-4378-a609-c19ea71633d2'); + expect(mockCommandBus.execute).toHaveBeenCalledTimes(1); }); - it('should throw an dedicated RpcException if ad already exists', async () => { - expect.assertions(2); + it('should throw a dedicated RpcException if ad already exists', async () => { + jest.spyOn(mockCommandBus, 'execute'); + expect.assertions(3); try { await createAdGrpcController.create(punctualCreateAdRequest); } catch (e: any) { expect(e).toBeInstanceOf(RpcException); expect(e.error.code).toBe(RpcExceptionCode.ALREADY_EXISTS); } + expect(mockCommandBus.execute).toHaveBeenCalledTimes(1); }); it('should throw a generic RpcException', async () => { - expect.assertions(2); + jest.spyOn(mockCommandBus, 'execute'); + expect.assertions(3); try { await createAdGrpcController.create(punctualCreateAdRequest); } catch (e: any) { expect(e).toBeInstanceOf(RpcException); - expect(e.error.code).toBeUndefined(); + expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN); } + expect(mockCommandBus.execute).toHaveBeenCalledTimes(1); }); }); diff --git a/src/modules/ad/tests/unit/interface/find-ad-by-id.grpc.controller.spec.ts b/src/modules/ad/tests/unit/interface/find-ad-by-id.grpc.controller.spec.ts new file mode 100644 index 0000000..b86dd3e --- /dev/null +++ b/src/modules/ad/tests/unit/interface/find-ad-by-id.grpc.controller.spec.ts @@ -0,0 +1,140 @@ +import { NotFoundException } from '@libs/exceptions'; +import { RpcExceptionCode } from '@libs/exceptions/rpc-exception.codes.enum'; +import { AdMapper } from '@modules/ad/ad.mapper'; +import { Frequency } from '@modules/ad/core/ad.types'; +import { FindAdByIdGrpcController } from '@modules/ad/interface/grpc-controllers/find-ad-by-id.grpc.controller'; +import { QueryBus } from '@nestjs/cqrs'; +import { RpcException } from '@nestjs/microservices'; +import { Test, TestingModule } from '@nestjs/testing'; + +const mockQueryBus = { + execute: jest + .fn() + .mockImplementationOnce(() => '200d61a8-d878-4378-a609-c19ea71633d2') + .mockImplementationOnce(() => { + throw new NotFoundException(); + }) + .mockImplementationOnce(() => { + throw new Error(); + }), +}; + +const mockAdMapper = { + toResponse: jest.fn().mockImplementationOnce(() => ({ + userId: '8cc90d1a-4a59-4289-a7d8-078f9db7857f', + driver: true, + passenger: true, + frequency: Frequency.PUNCTUAL, + fromDate: '2023-06-27', + toDate: '2023-06-27', + schedule: { + tue: '07:15', + }, + marginDurations: { + mon: 900, + tue: 900, + wed: 900, + thu: 900, + fri: 900, + sat: 900, + sun: 900, + }, + seatsProposed: 3, + seatsRequested: 1, + waypoints: [ + { + position: 0, + lon: 48.689445, + lat: 6.17651, + houseNumber: '5', + street: 'Avenue Foch', + locality: 'Nancy', + postalCode: '54000', + country: 'France', + }, + { + position: 1, + lon: 48.8566, + lat: 2.3522, + locality: 'Paris', + postalCode: '75000', + country: 'France', + }, + ], + })), +}; + +describe('Find Ad By Id Grpc Controller', () => { + let findAdbyIdGrpcController: FindAdByIdGrpcController; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + { + provide: QueryBus, + useValue: mockQueryBus, + }, + { + provide: AdMapper, + useValue: mockAdMapper, + }, + FindAdByIdGrpcController, + ], + }).compile(); + + findAdbyIdGrpcController = module.get( + FindAdByIdGrpcController, + ); + }); + + afterEach(async () => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(findAdbyIdGrpcController).toBeDefined(); + }); + + it('should return an ad', async () => { + jest.spyOn(mockQueryBus, 'execute'); + jest.spyOn(mockAdMapper, 'toResponse'); + const response = await findAdbyIdGrpcController.findOnebyId({ + id: '6dcf093c-c7db-4dae-8e9c-c715cebf83c7', + }); + expect(response.userId).toBe('8cc90d1a-4a59-4289-a7d8-078f9db7857f'); + expect(mockQueryBus.execute).toHaveBeenCalledTimes(1); + expect(mockAdMapper.toResponse).toHaveBeenCalledTimes(1); + }); + + it('should throw a dedicated RpcException if ad is not found', async () => { + jest.spyOn(mockQueryBus, 'execute'); + jest.spyOn(mockAdMapper, 'toResponse'); + expect.assertions(4); + try { + await findAdbyIdGrpcController.findOnebyId({ + id: 'ac85f5f4-41cd-4c5d-9aee-0a1acb176fb8', + }); + } catch (e: any) { + expect(e).toBeInstanceOf(RpcException); + expect(e.error.code).toBe(RpcExceptionCode.NOT_FOUND); + } + expect(mockQueryBus.execute).toHaveBeenCalledTimes(1); + expect(mockAdMapper.toResponse).toHaveBeenCalledTimes(0); + }); + + it('should throw a generic RpcException', async () => { + jest.spyOn(mockQueryBus, 'execute'); + jest.spyOn(mockAdMapper, 'toResponse'); + expect.assertions(4); + try { + await findAdbyIdGrpcController.findOnebyId({ + id: '53c8e7ec-ef68-42bc-ba4c-5ef3effa60a6', + }); + } catch (e: any) { + expect(e).toBeInstanceOf(RpcException); + expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN); + } + expect(mockQueryBus.execute).toHaveBeenCalledTimes(1); + expect(mockAdMapper.toResponse).toHaveBeenCalledTimes(0); + }); +});