refactor to ddh, first commit

This commit is contained in:
sbriat
2023-08-16 12:28:20 +02:00
parent 0a6e4c0bf6
commit ce48890a66
208 changed files with 2596 additions and 2052 deletions

View File

@@ -0,0 +1,182 @@
import { CreateAdRequest } from '../../../domain/dtos/create-ad.request';
import { CreateAdUseCase } from '../../../domain/usecases/create-ad.usecase';
import { Test, TestingModule } from '@nestjs/testing';
import { AutomapperModule } from '@automapper/nestjs';
import { classes } from '@automapper/classes';
import { AdRepository } from '../../../adapters/secondaries/ad.repository';
import { CreateAdCommand } from '../../../commands/create-ad.command';
import { Ad } from '../../../domain/entities/ad';
import { AdProfile } from '../../../mappers/ad.profile';
import { Frequency } from '../../../domain/types/frequency.enum';
import { RouteType } from '../../../domain/entities/geography';
import { DatabaseException } from '../../../../database/exceptions/database.exception';
import { Route } from '../../../../geography/domain/entities/route';
import {
DIRECTION_ENCODER,
GEOROUTER_CREATOR,
PARAMS_PROVIDER,
TIMEZONE_FINDER,
} from '../../../ad.constants';
const mockAdRepository = {
createAd: jest.fn().mockImplementation((ad) => {
if (ad.uuid == '00000000-0000-0000-0000-000000000000')
throw new DatabaseException();
return new Ad();
}),
};
const mockGeorouterCreator = {
create: jest.fn().mockImplementation(() => ({
route: jest.fn().mockImplementation(() => [
{
key: RouteType.DRIVER,
route: <Route>{
points: [],
fwdAzimuth: 0,
backAzimuth: 180,
distance: 20000,
duration: 1800,
},
},
{
key: RouteType.PASSENGER,
route: <Route>{
points: [],
fwdAzimuth: 0,
backAzimuth: 180,
distance: 20000,
duration: 1800,
},
},
{
key: RouteType.COMMON,
route: <Route>{
points: [],
fwdAzimuth: 0,
backAzimuth: 180,
distance: 20000,
duration: 1800,
},
},
]),
})),
};
const mockParamsProvider = {
getParams: jest.fn().mockImplementation(() => ({
DEFAULT_TIMEZONE: 'Europe/Paris',
GEOROUTER_TYPE: 'graphhopper',
GEOROUTER_URL: 'localhost',
})),
};
const mockTimezoneFinder = {
timezones: jest.fn().mockImplementation(() => ['Europe/Paris']),
};
const mockDirectionEncoder = {
encode: jest.fn(),
};
const createAdRequest: CreateAdRequest = {
uuid: '77c55dfc-c28b-4026-942e-f94e95401fb1',
userUuid: 'dfd993f6-7889-4876-9570-5e1d7b6e3f42',
driver: true,
passenger: false,
frequency: Frequency.RECURRENT,
fromDate: new Date('2023-04-26'),
toDate: new Date('2024-04-25'),
monTime: '07:00',
tueTime: '07:00',
wedTime: '07:00',
thuTime: '07:00',
friTime: '07:00',
satTime: null,
sunTime: null,
monMargin: 900,
tueMargin: 900,
wedMargin: 900,
thuMargin: 900,
friMargin: 900,
satMargin: 900,
sunMargin: 900,
seatsDriver: 3,
seatsPassenger: 1,
strict: false,
addresses: [
{ lon: 6, lat: 45 },
{ lon: 6.5, lat: 45.5 },
],
};
const setUuid = async (uuid: string): Promise<void> => {
createAdRequest.uuid = uuid;
};
const setIsDriver = async (isDriver: boolean): Promise<void> => {
createAdRequest.driver = isDriver;
};
const setIsPassenger = async (isPassenger: boolean): Promise<void> => {
createAdRequest.passenger = isPassenger;
};
describe('CreateAdUseCase', () => {
let createAdUseCase: CreateAdUseCase;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })],
providers: [
{
provide: AdRepository,
useValue: mockAdRepository,
},
{
provide: GEOROUTER_CREATOR,
useValue: mockGeorouterCreator,
},
{
provide: PARAMS_PROVIDER,
useValue: mockParamsProvider,
},
{
provide: TIMEZONE_FINDER,
useValue: mockTimezoneFinder,
},
{
provide: DIRECTION_ENCODER,
useValue: mockDirectionEncoder,
},
AdProfile,
CreateAdUseCase,
],
}).compile();
createAdUseCase = module.get<CreateAdUseCase>(CreateAdUseCase);
});
it('should be defined', () => {
expect(createAdUseCase).toBeDefined();
});
describe('execute', () => {
it('should create an ad as driver', async () => {
const ad = await createAdUseCase.execute(
new CreateAdCommand(createAdRequest),
);
expect(ad).toBeInstanceOf(Ad);
});
it('should create an ad as passenger', async () => {
await setIsDriver(false);
await setIsPassenger(true);
const ad = await createAdUseCase.execute(
new CreateAdCommand(createAdRequest),
);
expect(ad).toBeInstanceOf(Ad);
});
it('should throw an exception if repository fails', async () => {
await setUuid('00000000-0000-0000-0000-000000000000');
await expect(
createAdUseCase.execute(new CreateAdCommand(createAdRequest)),
).rejects.toBeInstanceOf(DatabaseException);
});
});
});

View File

@@ -0,0 +1,138 @@
import { Role } from '../../../domain/types/role.enum';
import { Geography } from '../../../domain/entities/geography';
import { Coordinate } from '../../../../geography/domain/entities/coordinate';
import { IGeorouter } from '../../../../geography/domain/interfaces/georouter.interface';
import { GeorouterSettings } from '../../../../geography/domain/types/georouter-settings.type';
import { Route } from '../../../../geography/domain/entities/route';
import { IGeodesic } from '../../../../geography/domain/interfaces/geodesic.interface';
const simpleCoordinates: Coordinate[] = [
{
lon: 6,
lat: 47,
},
{
lon: 6.1,
lat: 47.1,
},
];
const complexCoordinates: Coordinate[] = [
{
lon: 6,
lat: 47,
},
{
lon: 6.1,
lat: 47.1,
},
{
lon: 6.2,
lat: 47.2,
},
];
const mockGeodesic: IGeodesic = {
inverse: jest.fn(),
};
const driverRoute: Route = new Route(mockGeodesic);
driverRoute.distance = 25000;
const commonRoute: Route = new Route(mockGeodesic);
commonRoute.distance = 20000;
const mockGeorouter: IGeorouter = {
route: jest
.fn()
.mockResolvedValueOnce([
{
key: 'driver',
route: driverRoute,
},
])
.mockResolvedValueOnce([
{
key: 'passenger',
route: commonRoute,
},
])
.mockResolvedValueOnce([
{
key: 'common',
route: commonRoute,
},
])
.mockResolvedValueOnce([
{
key: 'driver',
route: driverRoute,
},
{
key: 'passenger',
route: commonRoute,
},
]),
};
const georouterSettings: GeorouterSettings = {
withDistance: false,
withPoints: true,
withTime: false,
};
describe('Geography entity', () => {
it('should be defined', () => {
expect(new Geography(simpleCoordinates)).toBeDefined();
});
it('should create a route as driver', async () => {
const geography = new Geography(complexCoordinates);
await geography.createRoutes(
[Role.DRIVER],
mockGeorouter,
georouterSettings,
);
expect(geography.driverRoute).toBeDefined();
expect(geography.passengerRoute).toBeUndefined();
expect(geography.driverRoute.distance).toBe(25000);
});
it('should create a route as passenger', async () => {
const geography = new Geography(simpleCoordinates);
await geography.createRoutes(
[Role.PASSENGER],
mockGeorouter,
georouterSettings,
);
expect(geography.driverRoute).toBeUndefined();
expect(geography.passengerRoute).toBeDefined();
expect(geography.passengerRoute.distance).toBe(20000);
});
it('should create routes as driver and passenger with simple coordinates', async () => {
const geography = new Geography(simpleCoordinates);
await geography.createRoutes(
[Role.DRIVER, Role.PASSENGER],
mockGeorouter,
georouterSettings,
);
expect(geography.driverRoute).toBeDefined();
expect(geography.passengerRoute).toBeDefined();
expect(geography.driverRoute.distance).toBe(20000);
expect(geography.passengerRoute.distance).toBe(20000);
});
it('should create routes as driver and passenger with complex coordinates', async () => {
const geography = new Geography(complexCoordinates);
await geography.createRoutes(
[Role.DRIVER, Role.PASSENGER],
mockGeorouter,
georouterSettings,
);
expect(geography.driverRoute).toBeDefined();
expect(geography.passengerRoute).toBeDefined();
expect(geography.driverRoute.distance).toBe(25000);
expect(geography.passengerRoute.distance).toBe(20000);
});
});

View File

@@ -0,0 +1,53 @@
import { TimeConverter } from '../../../domain/entities/time-converter';
describe('TimeConverter', () => {
it('should be defined', () => {
expect(new TimeConverter()).toBeDefined();
});
it('should convert a Europe/Paris datetime to utc datetime', () => {
expect(
TimeConverter.toUtcDatetime(
new Date('2023-05-01'),
'07:00',
'Europe/Paris',
).getUTCHours(),
).toBe(6);
});
it('should return undefined when trying to convert a Europe/Paris datetime to utc datetime without a valid date', () => {
expect(
TimeConverter.toUtcDatetime(undefined, '07:00', 'Europe/Paris'),
).toBeUndefined();
expect(
TimeConverter.toUtcDatetime(
new Date('2023-13-01'),
'07:00',
'Europe/Paris',
),
).toBeUndefined();
});
it('should return undefined when trying to convert a Europe/Paris datetime to utc datetime without a valid time', () => {
expect(
TimeConverter.toUtcDatetime(
new Date('2023-05-01'),
undefined,
'Europe/Paris',
),
).toBeUndefined();
expect(
TimeConverter.toUtcDatetime(new Date('2023-05-01'), 'a', 'Europe/Paris'),
).toBeUndefined();
});
it('should return undefined when trying to convert a datetime to utc datetime without a valid timezone', () => {
expect(
TimeConverter.toUtcDatetime(
new Date('2023-12-01'),
'07:00',
'OlympusMons/Mars',
),
).toBeUndefined();
});
});