improve tests
This commit is contained in:
		
							parent
							
								
									075a856d09
								
							
						
					
					
						commit
						efea6fe13c
					
				| 
						 | 
				
			
			@ -29,7 +29,7 @@ export class RouteCompleter extends Completer {
 | 
			
		|||
            break;
 | 
			
		||||
          case RouteCompleterType.DETAILED:
 | 
			
		||||
            const detailedCandidateRoute =
 | 
			
		||||
              await this.query.routeProvider.getBasic(
 | 
			
		||||
              await this.query.routeProvider.getDetailed(
 | 
			
		||||
                (candidate.getProps().carpoolSteps as WayStep[]).map(
 | 
			
		||||
                  (wayStep: WayStep) => wayStep.point,
 | 
			
		||||
                ),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,10 @@
 | 
			
		|||
import { Inject, Injectable } from '@nestjs/common';
 | 
			
		||||
import { RouteProviderPort } from '../core/application/ports/route-provider.port';
 | 
			
		||||
import { GetRouteControllerPort } from '@modules/geography/core/application/ports/get-route-controller.port';
 | 
			
		||||
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '../ad.di-tokens';
 | 
			
		||||
import {
 | 
			
		||||
  AD_GET_BASIC_ROUTE_CONTROLLER,
 | 
			
		||||
  AD_GET_DETAILED_ROUTE_CONTROLLER,
 | 
			
		||||
} from '../ad.di-tokens';
 | 
			
		||||
import { Point, Route } from '@modules/geography/core/domain/route.types';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +12,8 @@ export class RouteProvider implements RouteProviderPort {
 | 
			
		|||
  constructor(
 | 
			
		||||
    @Inject(AD_GET_BASIC_ROUTE_CONTROLLER)
 | 
			
		||||
    private readonly getBasicRouteController: GetRouteControllerPort,
 | 
			
		||||
    @Inject(AD_GET_DETAILED_ROUTE_CONTROLLER)
 | 
			
		||||
    private readonly getDetailedRouteController: GetRouteControllerPort,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  getBasic = async (waypoints: Point[]): Promise<Route> =>
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +22,7 @@ export class RouteProvider implements RouteProviderPort {
 | 
			
		|||
    });
 | 
			
		||||
 | 
			
		||||
  getDetailed = async (waypoints: Point[]): Promise<Route> =>
 | 
			
		||||
    await this.getBasicRouteController.get({
 | 
			
		||||
    await this.getDetailedRouteController.get({
 | 
			
		||||
      waypoints,
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,117 @@
 | 
			
		|||
import { AdRepositoryPort } from '@modules/ad/core/application/ports/ad.repository.port';
 | 
			
		||||
import { RouteProviderPort } from '@modules/ad/core/application/ports/route-provider.port';
 | 
			
		||||
import {
 | 
			
		||||
  Algorithm,
 | 
			
		||||
  Selector,
 | 
			
		||||
} from '@modules/ad/core/application/queries/match/algorithm.abstract';
 | 
			
		||||
import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
 | 
			
		||||
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
 | 
			
		||||
import { Frequency, Role } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { CandidateEntity } from '@modules/ad/core/domain/candidate.entity';
 | 
			
		||||
import { MatchEntity } from '@modules/ad/core/domain/match.entity';
 | 
			
		||||
 | 
			
		||||
const originWaypoint: Waypoint = {
 | 
			
		||||
  position: 0,
 | 
			
		||||
  lat: 48.689445,
 | 
			
		||||
  lon: 6.17651,
 | 
			
		||||
  houseNumber: '5',
 | 
			
		||||
  street: 'Avenue Foch',
 | 
			
		||||
  locality: 'Nancy',
 | 
			
		||||
  postalCode: '54000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
const destinationWaypoint: Waypoint = {
 | 
			
		||||
  position: 1,
 | 
			
		||||
  lat: 48.8566,
 | 
			
		||||
  lon: 2.3522,
 | 
			
		||||
  locality: 'Paris',
 | 
			
		||||
  postalCode: '75000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockRouteProvider: RouteProviderPort = {
 | 
			
		||||
  getBasic: jest.fn(),
 | 
			
		||||
  getDetailed: jest.fn(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const matchQuery = new MatchQuery(
 | 
			
		||||
  {
 | 
			
		||||
    frequency: Frequency.PUNCTUAL,
 | 
			
		||||
    fromDate: '2023-08-28',
 | 
			
		||||
    toDate: '2023-08-28',
 | 
			
		||||
    schedule: [
 | 
			
		||||
      {
 | 
			
		||||
        time: '01:05',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    waypoints: [originWaypoint, destinationWaypoint],
 | 
			
		||||
  },
 | 
			
		||||
  mockRouteProvider,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const mockAdRepository: AdRepositoryPort = {
 | 
			
		||||
  insertExtra: jest.fn(),
 | 
			
		||||
  findOneById: jest.fn(),
 | 
			
		||||
  findOne: jest.fn(),
 | 
			
		||||
  insert: jest.fn(),
 | 
			
		||||
  update: jest.fn(),
 | 
			
		||||
  updateWhere: jest.fn(),
 | 
			
		||||
  delete: jest.fn(),
 | 
			
		||||
  count: jest.fn(),
 | 
			
		||||
  healthCheck: jest.fn(),
 | 
			
		||||
  getCandidateAds: jest.fn(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SomeSelector extends Selector {
 | 
			
		||||
  select = async (): Promise<CandidateEntity[]> => [
 | 
			
		||||
    CandidateEntity.create({
 | 
			
		||||
      id: 'cc260669-1c6d-441f-80a5-19cd59afb777',
 | 
			
		||||
      role: Role.DRIVER,
 | 
			
		||||
      driverWaypoints: [
 | 
			
		||||
        {
 | 
			
		||||
          lat: 48.678454,
 | 
			
		||||
          lon: 6.189745,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          lat: 48.84877,
 | 
			
		||||
          lon: 2.398457,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
      passengerWaypoints: [
 | 
			
		||||
        {
 | 
			
		||||
          lat: 48.849445,
 | 
			
		||||
          lon: 6.68651,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          lat: 47.18746,
 | 
			
		||||
          lon: 2.89742,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
      driverDistance: 350145,
 | 
			
		||||
      driverDuration: 13548,
 | 
			
		||||
      spacetimeDetourRatio: {
 | 
			
		||||
        maxDistanceDetourRatio: 0.3,
 | 
			
		||||
        maxDurationDetourRatio: 0.3,
 | 
			
		||||
      },
 | 
			
		||||
    }),
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SomeAlgorithm extends Algorithm {
 | 
			
		||||
  constructor(
 | 
			
		||||
    protected readonly query: MatchQuery,
 | 
			
		||||
    protected readonly repository: AdRepositoryPort,
 | 
			
		||||
  ) {
 | 
			
		||||
    super(query, repository);
 | 
			
		||||
    this.selector = new SomeSelector(query, repository);
 | 
			
		||||
    this.processors = [];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
describe('Abstract Algorithm', () => {
 | 
			
		||||
  it('should return matches', async () => {
 | 
			
		||||
    const someAlgorithm = new SomeAlgorithm(matchQuery, mockAdRepository);
 | 
			
		||||
    const matches: MatchEntity[] = await someAlgorithm.match();
 | 
			
		||||
    expect(matches).toHaveLength(1);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,154 @@
 | 
			
		|||
import {
 | 
			
		||||
  RouteCompleter,
 | 
			
		||||
  RouteCompleterType,
 | 
			
		||||
} from '@modules/ad/core/application/queries/match/completer/route.completer';
 | 
			
		||||
import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query';
 | 
			
		||||
import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types';
 | 
			
		||||
import { Waypoint } from '@modules/ad/core/application/types/waypoint.type';
 | 
			
		||||
import { Frequency, Role } from '@modules/ad/core/domain/ad.types';
 | 
			
		||||
import { CandidateEntity } from '@modules/ad/core/domain/candidate.entity';
 | 
			
		||||
import { Target } from '@modules/ad/core/domain/candidate.types';
 | 
			
		||||
import { Actor } from '@modules/ad/core/domain/value-objects/actor.value-object';
 | 
			
		||||
import { Point } from '@modules/ad/core/domain/value-objects/point.value-object';
 | 
			
		||||
 | 
			
		||||
const originWaypoint: Waypoint = {
 | 
			
		||||
  position: 0,
 | 
			
		||||
  lat: 48.689445,
 | 
			
		||||
  lon: 6.17651,
 | 
			
		||||
  houseNumber: '5',
 | 
			
		||||
  street: 'Avenue Foch',
 | 
			
		||||
  locality: 'Nancy',
 | 
			
		||||
  postalCode: '54000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
const destinationWaypoint: Waypoint = {
 | 
			
		||||
  position: 1,
 | 
			
		||||
  lat: 48.8566,
 | 
			
		||||
  lon: 2.3522,
 | 
			
		||||
  locality: 'Paris',
 | 
			
		||||
  postalCode: '75000',
 | 
			
		||||
  country: 'France',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const matchQuery = new MatchQuery(
 | 
			
		||||
  {
 | 
			
		||||
    algorithmType: AlgorithmType.PASSENGER_ORIENTED,
 | 
			
		||||
    driver: true,
 | 
			
		||||
    passenger: true,
 | 
			
		||||
    frequency: Frequency.PUNCTUAL,
 | 
			
		||||
    fromDate: '2023-08-28',
 | 
			
		||||
    toDate: '2023-08-28',
 | 
			
		||||
    schedule: [
 | 
			
		||||
      {
 | 
			
		||||
        time: '07:05',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    strict: false,
 | 
			
		||||
    waypoints: [originWaypoint, destinationWaypoint],
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    getBasic: jest.fn().mockImplementation(() => ({
 | 
			
		||||
      distance: 350101,
 | 
			
		||||
      duration: 14422,
 | 
			
		||||
      fwdAzimuth: 273,
 | 
			
		||||
      backAzimuth: 93,
 | 
			
		||||
      distanceAzimuth: 336544,
 | 
			
		||||
      points: [],
 | 
			
		||||
    })),
 | 
			
		||||
    getDetailed: jest.fn().mockImplementation(() => ({
 | 
			
		||||
      distance: 350102,
 | 
			
		||||
      duration: 14423,
 | 
			
		||||
      fwdAzimuth: 273,
 | 
			
		||||
      backAzimuth: 93,
 | 
			
		||||
      distanceAzimuth: 336544,
 | 
			
		||||
      points: [],
 | 
			
		||||
    })),
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const candidate: CandidateEntity = CandidateEntity.create({
 | 
			
		||||
  id: 'cc260669-1c6d-441f-80a5-19cd59afb777',
 | 
			
		||||
  role: Role.DRIVER,
 | 
			
		||||
  driverWaypoints: [
 | 
			
		||||
    {
 | 
			
		||||
      lat: 48.678454,
 | 
			
		||||
      lon: 6.189745,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      lat: 48.84877,
 | 
			
		||||
      lon: 2.398457,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
  passengerWaypoints: [
 | 
			
		||||
    {
 | 
			
		||||
      lat: 48.689445,
 | 
			
		||||
      lon: 6.17651,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      lat: 48.8566,
 | 
			
		||||
      lon: 2.3522,
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
  driverDistance: 350145,
 | 
			
		||||
  driverDuration: 13548,
 | 
			
		||||
  spacetimeDetourRatio: {
 | 
			
		||||
    maxDistanceDetourRatio: 0.3,
 | 
			
		||||
    maxDurationDetourRatio: 0.3,
 | 
			
		||||
  },
 | 
			
		||||
}).setCarpoolPath([
 | 
			
		||||
  {
 | 
			
		||||
    point: new Point({
 | 
			
		||||
      lat: 48.689445,
 | 
			
		||||
      lon: 6.17651,
 | 
			
		||||
    }),
 | 
			
		||||
    actors: [
 | 
			
		||||
      new Actor({
 | 
			
		||||
        role: Role.DRIVER,
 | 
			
		||||
        target: Target.START,
 | 
			
		||||
      }),
 | 
			
		||||
      new Actor({
 | 
			
		||||
        role: Role.PASSENGER,
 | 
			
		||||
        target: Target.START,
 | 
			
		||||
      }),
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    point: new Point({
 | 
			
		||||
      lat: 48.8566,
 | 
			
		||||
      lon: 2.3522,
 | 
			
		||||
    }),
 | 
			
		||||
    actors: [
 | 
			
		||||
      new Actor({
 | 
			
		||||
        role: Role.DRIVER,
 | 
			
		||||
        target: Target.FINISH,
 | 
			
		||||
      }),
 | 
			
		||||
      new Actor({
 | 
			
		||||
        role: Role.PASSENGER,
 | 
			
		||||
        target: Target.FINISH,
 | 
			
		||||
      }),
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
describe('Route completer', () => {
 | 
			
		||||
  it('should complete candidates with basic setting', async () => {
 | 
			
		||||
    const routeCompleter: RouteCompleter = new RouteCompleter(
 | 
			
		||||
      matchQuery,
 | 
			
		||||
      RouteCompleterType.BASIC,
 | 
			
		||||
    );
 | 
			
		||||
    const completedCandidates: CandidateEntity[] =
 | 
			
		||||
      await routeCompleter.complete([candidate]);
 | 
			
		||||
    expect(completedCandidates.length).toBe(1);
 | 
			
		||||
    expect(completedCandidates[0].getProps().distance).toBe(350101);
 | 
			
		||||
  });
 | 
			
		||||
  it('should complete candidates with detailed setting', async () => {
 | 
			
		||||
    const routeCompleter: RouteCompleter = new RouteCompleter(
 | 
			
		||||
      matchQuery,
 | 
			
		||||
      RouteCompleterType.DETAILED,
 | 
			
		||||
    );
 | 
			
		||||
    const completedCandidates: CandidateEntity[] =
 | 
			
		||||
      await routeCompleter.complete([candidate]);
 | 
			
		||||
    expect(completedCandidates.length).toBe(1);
 | 
			
		||||
    expect(completedCandidates[0].getProps().distance).toBe(350102);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,7 @@
 | 
			
		|||
import { AD_GET_BASIC_ROUTE_CONTROLLER } from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import {
 | 
			
		||||
  AD_GET_BASIC_ROUTE_CONTROLLER,
 | 
			
		||||
  AD_GET_DETAILED_ROUTE_CONTROLLER,
 | 
			
		||||
} from '@modules/ad/ad.di-tokens';
 | 
			
		||||
import { Point } from '@modules/ad/core/application/types/point.type';
 | 
			
		||||
import { RouteProvider } from '@modules/ad/infrastructure/route-provider';
 | 
			
		||||
import { GetRouteControllerPort } from '@modules/geography/core/application/ports/get-route-controller.port';
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +41,30 @@ const mockGetBasicRouteController: GetRouteControllerPort = {
 | 
			
		|||
  })),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockGetDetailedRouteController: GetRouteControllerPort = {
 | 
			
		||||
  get: jest.fn().mockImplementationOnce(() => ({
 | 
			
		||||
    distance: 350102,
 | 
			
		||||
    duration: 14423,
 | 
			
		||||
    fwdAzimuth: 273,
 | 
			
		||||
    backAzimuth: 93,
 | 
			
		||||
    distanceAzimuth: 336544,
 | 
			
		||||
    points: [
 | 
			
		||||
      {
 | 
			
		||||
        lon: 6.1765102,
 | 
			
		||||
        lat: 48.689445,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        lon: 4.984578,
 | 
			
		||||
        lat: 48.725687,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        lon: 2.3522,
 | 
			
		||||
        lat: 48.8566,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  })),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('Route provider', () => {
 | 
			
		||||
  let routeProvider: RouteProvider;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +76,10 @@ describe('Route provider', () => {
 | 
			
		|||
          provide: AD_GET_BASIC_ROUTE_CONTROLLER,
 | 
			
		||||
          useValue: mockGetBasicRouteController,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: AD_GET_DETAILED_ROUTE_CONTROLLER,
 | 
			
		||||
          useValue: mockGetDetailedRouteController,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,4 +98,13 @@ describe('Route provider', () => {
 | 
			
		|||
    expect(route.distance).toBe(350101);
 | 
			
		||||
    expect(route.duration).toBe(14422);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should provide a detailed route', async () => {
 | 
			
		||||
    const route: Route = await routeProvider.getDetailed([
 | 
			
		||||
      originPoint,
 | 
			
		||||
      destinationPoint,
 | 
			
		||||
    ]);
 | 
			
		||||
    expect(route.distance).toBe(350102);
 | 
			
		||||
    expect(route.duration).toBe(14423);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
import { GetDetailedRouteController } from '@modules/geography/interface/controllers/get-detailed-route.controller';
 | 
			
		||||
import { RouteMapper } from '@modules/geography/route.mapper';
 | 
			
		||||
import { QueryBus } from '@nestjs/cqrs';
 | 
			
		||||
import { Test, TestingModule } from '@nestjs/testing';
 | 
			
		||||
 | 
			
		||||
const mockQueryBus = {
 | 
			
		||||
  execute: jest.fn(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mockRouteMapper = {
 | 
			
		||||
  toPersistence: jest.fn(),
 | 
			
		||||
  toDomain: jest.fn(),
 | 
			
		||||
  toResponse: jest.fn(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
describe('Get Detailed Route Controller', () => {
 | 
			
		||||
  let getDetailedRouteController: GetDetailedRouteController;
 | 
			
		||||
 | 
			
		||||
  beforeAll(async () => {
 | 
			
		||||
    const module: TestingModule = await Test.createTestingModule({
 | 
			
		||||
      providers: [
 | 
			
		||||
        {
 | 
			
		||||
          provide: QueryBus,
 | 
			
		||||
          useValue: mockQueryBus,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: RouteMapper,
 | 
			
		||||
          useValue: mockRouteMapper,
 | 
			
		||||
        },
 | 
			
		||||
        GetDetailedRouteController,
 | 
			
		||||
      ],
 | 
			
		||||
    }).compile();
 | 
			
		||||
 | 
			
		||||
    getDetailedRouteController = module.get<GetDetailedRouteController>(
 | 
			
		||||
      GetDetailedRouteController,
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  afterEach(async () => {
 | 
			
		||||
    jest.clearAllMocks();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should be defined', () => {
 | 
			
		||||
    expect(getDetailedRouteController).toBeDefined();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should get a route', async () => {
 | 
			
		||||
    jest.spyOn(mockQueryBus, 'execute');
 | 
			
		||||
    await getDetailedRouteController.get({
 | 
			
		||||
      waypoints: [
 | 
			
		||||
        {
 | 
			
		||||
          lat: 48.689445,
 | 
			
		||||
          lon: 6.17651,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          lat: 48.8566,
 | 
			
		||||
          lon: 2.3522,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    });
 | 
			
		||||
    expect(mockQueryBus.execute).toHaveBeenCalledTimes(1);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Loading…
	
		Reference in New Issue