matcher/src/modules/ad/tests/unit/interface/match.grpc.controller.spec.ts

338 lines
11 KiB
TypeScript

import { RpcExceptionCode } from '@mobicoop/ddd-library';
import { AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens';
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
import { MatchingResult } from '@modules/ad/core/application/queries/match/match.query-handler';
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
import { Frequency, Role } from '@modules/ad/core/domain/ad.types';
import { Target } from '@modules/ad/core/domain/candidate.types';
import { MatchEntity } from '@modules/ad/core/domain/match.entity';
import { ActorTime } from '@modules/ad/core/domain/value-objects/actor-time.value-object';
import { JourneyItem } from '@modules/ad/core/domain/value-objects/journey-item.value-object';
import { MatchingPaginatedResponseDto } from '@modules/ad/interface/dtos/matching.paginated.response.dto';
import { MatchRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/match.request.dto';
import { WaypointDto } from '@modules/ad/interface/grpc-controllers/dtos/waypoint.dto';
import { MatchGrpcController } from '@modules/ad/interface/grpc-controllers/match.grpc-controller';
import { MatchMapper } from '@modules/ad/match.mapper';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { QueryBus } from '@nestjs/cqrs';
import { RpcException } from '@nestjs/microservices';
import { Test, TestingModule } from '@nestjs/testing';
const originWaypoint: WaypointDto = {
position: 0,
lat: 48.689445,
lon: 6.17651,
houseNumber: '5',
street: 'Avenue Foch',
locality: 'Nancy',
postalCode: '54000',
country: 'France',
};
const destinationWaypoint: WaypointDto = {
position: 1,
lat: 48.8566,
lon: 2.3522,
locality: 'Paris',
postalCode: '75000',
country: 'France',
};
const recurrentMatchRequestDto: MatchRequestDto = {
driver: false,
passenger: true,
frequency: Frequency.RECURRENT,
fromDate: '2023-08-15',
toDate: '2024-09-30',
schedule: [
{
time: '07:00',
day: 5,
margin: 900,
},
],
waypoints: [originWaypoint, destinationWaypoint],
strict: false,
algorithmType: AlgorithmType.PASSENGER_ORIENTED,
};
const mockQueryBus = {
execute: jest
.fn()
.mockImplementationOnce(
() =>
<MatchingResult>{
id: '43c83ae2-f4b0-4ac6-b8bf-8071801924d4',
page: 1,
perPage: 10,
matches: [
MatchEntity.create({
adId: '53a0bf71-4132-4f7b-a4cc-88c796b6bdf1',
role: Role.DRIVER,
frequency: Frequency.RECURRENT,
distance: 356041,
duration: 12647,
initialDistance: 349251,
initialDuration: 12103,
journeys: [
{
firstDate: new Date('2023-09-01'),
lastDate: new Date('2024-08-30'),
journeyItems: [
new JourneyItem({
lat: 48.689445,
lon: 6.17651,
duration: 0,
distance: 0,
actorTimes: [
new ActorTime({
role: Role.DRIVER,
target: Target.START,
firstDatetime: new Date('2023-09-01 07:00'),
firstMinDatetime: new Date('2023-09-01 06:45'),
firstMaxDatetime: new Date('2023-09-01 07:15'),
lastDatetime: new Date('2024-08-30 07:00'),
lastMinDatetime: new Date('2024-08-30 06:45'),
lastMaxDatetime: new Date('2024-08-30 07:15'),
}),
],
}),
new JourneyItem({
lat: 48.369445,
lon: 6.67487,
duration: 2100,
distance: 56878,
actorTimes: [
new ActorTime({
role: Role.DRIVER,
target: Target.NEUTRAL,
firstDatetime: new Date('2023-09-01 07:35'),
firstMinDatetime: new Date('2023-09-01 07:20'),
firstMaxDatetime: new Date('2023-09-01 07:50'),
lastDatetime: new Date('2024-08-30 07:35'),
lastMinDatetime: new Date('2024-08-30 07:20'),
lastMaxDatetime: new Date('2024-08-30 07:50'),
}),
new ActorTime({
role: Role.PASSENGER,
target: Target.START,
firstDatetime: new Date('2023-09-01 07:32'),
firstMinDatetime: new Date('2023-09-01 07:17'),
firstMaxDatetime: new Date('2023-09-01 07:47'),
lastDatetime: new Date('2024-08-30 07:32'),
lastMinDatetime: new Date('2024-08-30 07:17'),
lastMaxDatetime: new Date('2024-08-30 07:47'),
}),
],
}),
new JourneyItem({
lat: 47.98487,
lon: 6.9427,
duration: 3840,
distance: 76491,
actorTimes: [
new ActorTime({
role: Role.DRIVER,
target: Target.NEUTRAL,
firstDatetime: new Date('2023-09-01 08:04'),
firstMinDatetime: new Date('2023-09-01 07:51'),
firstMaxDatetime: new Date('2023-09-01 08:19'),
lastDatetime: new Date('2024-08-30 08:04'),
lastMinDatetime: new Date('2024-08-30 07:51'),
lastMaxDatetime: new Date('2024-08-30 08:19'),
}),
new ActorTime({
role: Role.PASSENGER,
target: Target.FINISH,
firstDatetime: new Date('2023-09-01 08:01'),
firstMinDatetime: new Date('2023-09-01 07:46'),
firstMaxDatetime: new Date('2023-09-01 08:16'),
lastDatetime: new Date('2024-08-30 08:01'),
lastMinDatetime: new Date('2024-08-30 07:46'),
lastMaxDatetime: new Date('2024-08-30 08:16'),
}),
],
}),
new JourneyItem({
lat: 47.365987,
lon: 7.02154,
duration: 4980,
distance: 96475,
actorTimes: [
new ActorTime({
role: Role.DRIVER,
target: Target.FINISH,
firstDatetime: new Date('2023-09-01 08:23'),
firstMinDatetime: new Date('2023-09-01 08:08'),
firstMaxDatetime: new Date('2023-09-01 08:38'),
lastDatetime: new Date('2024-08-30 08:23'),
lastMinDatetime: new Date('2024-08-30 08:08'),
lastMaxDatetime: new Date('2024-08-30 08:38'),
}),
],
}),
],
},
],
}),
],
total: 1,
},
)
.mockImplementationOnce(() => {
throw new Error();
}),
};
const mockRouteProvider: RouteProviderPort = {
getBasic: jest.fn(),
getDetailed: jest.fn(),
};
const mockMatchMapper = {
toResponse: jest.fn().mockImplementation(() => ({
adId: '53a0bf71-4132-4f7b-a4cc-88c796b6bdf1',
role: 'DRIVER',
frequency: 'RECURRENT',
distance: 356041,
duration: 12647,
initialDistance: 349251,
initialDuration: 12103,
distanceDetour: 6790,
durationDetour: 544,
distanceDetourPercentage: 4.1,
durationDetourPercentage: 3.8,
journeys: [
{
day: 5,
firstDate: '2023-09-01',
lastDate: '2024-08-30',
journeyItems: [
{
lat: 48.689445,
lon: 6.17651,
duration: 0,
distance: 0,
time: '07:00',
actorTimes: [
{
role: 'DRIVER',
target: 'START',
},
],
},
{
lat: 48.369445,
lon: 6.67487,
duration: 2100,
distance: 56878,
time: '07:35',
actorTimes: [
{
role: 'DRIVER',
target: 'NEUTRAL',
},
{
role: 'PASSENGER',
target: 'START',
},
],
},
{
lat: 47.98487,
lon: 6.9427,
duration: 3840,
distance: 76491,
time: '08:04',
actorTimes: [
{
role: 'DRIVER',
target: 'NEUTRAL',
},
{
role: 'PASSENGER',
target: 'FINISH',
},
],
},
{
lat: 47.365987,
lon: 7.02154,
duration: 4980,
distance: 96475,
time: '08:23',
actorTimes: [
{
role: 'DRIVER',
target: 'FINISH',
},
],
},
],
},
],
})),
};
describe('Match Grpc Controller', () => {
let matchGrpcController: MatchGrpcController;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
MatchGrpcController,
{
provide: QueryBus,
useValue: mockQueryBus,
},
{
provide: AD_ROUTE_PROVIDER,
useValue: mockRouteProvider,
},
{
provide: MatchMapper,
useValue: mockMatchMapper,
},
{
provide: CACHE_MANAGER,
useValue: {},
},
],
}).compile();
matchGrpcController = module.get<MatchGrpcController>(MatchGrpcController);
});
afterEach(async () => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(matchGrpcController).toBeDefined();
});
it('should return a matching', async () => {
jest.spyOn(mockQueryBus, 'execute');
const matchingPaginatedResponseDto: MatchingPaginatedResponseDto =
await matchGrpcController.match(recurrentMatchRequestDto);
expect(matchingPaginatedResponseDto.id).toBe(
'43c83ae2-f4b0-4ac6-b8bf-8071801924d4',
);
expect(matchingPaginatedResponseDto.data).toHaveLength(1);
expect(matchingPaginatedResponseDto.page).toBe(1);
expect(matchingPaginatedResponseDto.perPage).toBe(10);
expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
});
it('should throw a generic RpcException', async () => {
jest.spyOn(mockQueryBus, 'execute');
expect.assertions(3);
try {
await matchGrpcController.match(recurrentMatchRequestDto);
} catch (e: any) {
expect(e).toBeInstanceOf(RpcException);
expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN);
}
expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
});
});