diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..bd695a5 --- /dev/null +++ b/.env.test @@ -0,0 +1,8 @@ +# SERVICE +SERVICE_URL=0.0.0.0 +SERVICE_PORT=5006 +SERVICE_CONFIGURATION_DOMAIN=AD + + +# PRISMA +DATABASE_URL="postgresql://mobicoop:mobicoop@localhost:5432/mobicoop-test?schema=ad" diff --git a/package-lock.json b/package-lock.json index 28256e6..67a5d8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "@prisma/client": "^4.13.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "dotenv-cli": "^7.2.1", "ioredis": "^5.3.2", "reflect-metadata": "^0.1.13", "rxjs": "^7.2.0" @@ -3841,7 +3842,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4003,6 +4003,20 @@ "node": ">=12" } }, + "node_modules/dotenv-cli": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.2.1.tgz", + "integrity": "sha512-ODHbGTskqRtXAzZapDPvgNuDVQApu4oKX8lZW7Y0+9hKA6le1ZJlyRS687oU9FXjOVEDU/VFV6zI125HzhM1UQ==", + "dependencies": { + "cross-spawn": "^7.0.3", + "dotenv": "^16.0.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, "node_modules/dotenv-expand": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", @@ -5354,8 +5368,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", @@ -6798,7 +6811,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -7657,7 +7669,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -7669,7 +7680,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -8626,7 +8636,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, diff --git a/package.json b/package.json index e4340e5..3a42808 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "test:unit": "jest --testPathPattern 'tests/unit/' --verbose", "test:unit:watch": "jest --testPathPattern 'tests/unit/' --verbose --watch", "test:unit:ci": "jest --testPathPattern 'tests/unit/' --coverage", - "test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose", + "test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose --watch", + "test:integration:watch": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose", "test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/'", "test:cov": "jest --testPathPattern 'tests/unit/' --coverage", "test:e2e": "jest --config ./test/jest-e2e.json", @@ -50,6 +51,7 @@ "@prisma/client": "^4.13.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "dotenv-cli": "^7.2.1", "ioredis": "^5.3.2", "reflect-metadata": "^0.1.13", "rxjs": "^7.2.0" diff --git a/src/modules/ad/tests/integration/ad.controler.integration.spec.ts b/src/modules/ad/tests/integration/ad.controler.integration.spec.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/ad/tests/integration/ad.repository.integration.spec.ts b/src/modules/ad/tests/integration/ad.repository.integration.spec.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/modules/ad/tests/integration/ad.repository.spec.ts b/src/modules/ad/tests/integration/ad.repository.spec.ts new file mode 100644 index 0000000..a7b6d01 --- /dev/null +++ b/src/modules/ad/tests/integration/ad.repository.spec.ts @@ -0,0 +1,399 @@ +import { Test } from '@nestjs/testing'; +import { PrismaService } from '../../../database/adapters/secondaries/prisma-service'; +import { AdsRepository } from '../../adapters/secondaries/ads.repository'; +import { DatabaseModule } from '../../../database/database.module'; + +describe('Ad Repository', () => { + let prismaService: PrismaService; + let adsRepository: AdsRepository; + + const executeInsertCommand = async (table: string, object: any) => { + const command = `INSERT INTO ${table} ("${Object.keys(object).join( + '","', + )}") VALUES (${Object.values(object).join(',')})`; + + await prismaService.$executeRawUnsafe(command); + }; + const getSeed = (index: number, uuid: string): string => { + return `'${uuid.slice(0, -2)}${index.toString(16).padStart(2, '0')}'`; + }; + const baseUuid = { + uuid: 'be459a29-7a41-4c0b-b371-abe90bfb6f00', + }; + const baseAdress0Uuid = { + uuid: 'bad5e786-3b15-4e51-a8fc-926fa9327ff1', + }; + const baseAdress1Uuid = { + uuid: '4d200eb6-7389-487f-a1ca-dbc0e40381c9', + }; + const baseUserUuid = { + userUuid: "'113e0000-0000-4000-a000-000000000000'", + }; + const driverAd = { + driver: 'true', + passenger: 'false', + seatsDriver: 3, + seatsPassenger: 0, + strict: 'false', + }; + const passengerAd = { + driver: 'false', + passenger: 'true', + seatsDriver: 0, + seatsPassenger: 1, + strict: 'false', + }; + const driverAndPassengerAd = { + driver: 'true', + passenger: 'true', + seatsDriver: 3, + seatsPassenger: 1, + strict: 'false', + }; + const punctualAd = { + frequency: `'PUNCTUAL'`, + fromDate: `'2023-01-01'`, + toDate: `'2023-01-01'`, + monTime: 'NULL', + tueTime: 'NULL', + wedTime: 'NULL', + thuTime: 'NULL', + friTime: 'NULL', + satTime: 'NULL', + sunTime: `'07:00'`, + monMargin: 900, + tueMargin: 900, + wedMargin: 900, + thuMargin: 900, + friMargin: 900, + satMargin: 900, + sunMargin: 900, + }; + const recurrentAd = { + frequency: `'RECURRENT'`, + fromDate: `'2023-01-01'`, + toDate: `'2023-12-31'`, + 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, + }; + + const address0 = { + position: 0, + lon: 43.7102, + lat: 7.262, + locality: "'Nice'", + postalCode: "'06000'", + country: "'France'", + }; + const address1 = { + position: 1, + lon: 43.2965, + lat: 5.3698, + locality: "'Marseille'", + postalCode: "'13000'", + country: "'France'", + }; + const createPunctualDriverAds = async (nbToCreate = 10) => { + const adToCreate = { + ...baseUuid, + ...baseUserUuid, + ...driverAd, + ...punctualAd, + }; + for (let i = 0; i < nbToCreate; i++) { + adToCreate.uuid = getSeed(i, baseUuid.uuid); + await executeInsertCommand('ad', adToCreate); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress0Uuid.uuid), + adUuid: adToCreate.uuid, + ...address0, + }); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress1Uuid.uuid), + adUuid: adToCreate.uuid, + ...address1, + }); + } + }; + const createRecurrentDriverAds = async (nbToCreate = 10) => { + const adToCreate = { + ...baseUuid, + ...baseUserUuid, + ...driverAd, + ...punctualAd, + }; + for (let i = 0; i < nbToCreate; i++) { + adToCreate.uuid = getSeed(i, baseUuid.uuid); + await executeInsertCommand('ad', adToCreate); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress0Uuid.uuid), + adUuid: adToCreate.uuid, + ...address0, + }); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress1Uuid.uuid), + adUuid: adToCreate.uuid, + ...address1, + }); + } + }; + + const createPunctualPassengerAds = async (nbToCreate = 10) => { + const adToCreate = { + ...baseUuid, + ...baseUserUuid, + ...passengerAd, + ...punctualAd, + }; + for (let i = 0; i < nbToCreate; i++) { + adToCreate.uuid = getSeed(i, baseUuid.uuid); + await executeInsertCommand('ad', adToCreate); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress0Uuid.uuid), + adUuid: adToCreate.uuid, + ...address0, + }); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress1Uuid.uuid), + adUuid: adToCreate.uuid, + ...address1, + }); + } + }; + + const createRecurrentPassengerAds = async (nbToCreate = 10) => { + const adToCreate = { + ...baseUuid, + ...baseUserUuid, + ...passengerAd, + ...recurrentAd, + }; + for (let i = 0; i < nbToCreate; i++) { + adToCreate.uuid = getSeed(i, baseUuid.uuid); + await executeInsertCommand('ad', adToCreate); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress0Uuid.uuid), + adUuid: adToCreate.uuid, + ...address0, + }); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress1Uuid.uuid), + adUuid: adToCreate.uuid, + ...address1, + }); + } + }; + + const createPunctualDriverPassengerAds = async (nbToCreate = 10) => { + const adToCreate = { + ...baseUuid, + ...baseUserUuid, + ...driverAndPassengerAd, + ...punctualAd, + }; + for (let i = 0; i < nbToCreate; i++) { + adToCreate.uuid = getSeed(i, baseUuid.uuid); + await executeInsertCommand('ad', adToCreate); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress0Uuid.uuid), + adUuid: adToCreate.uuid, + ...address0, + }); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress1Uuid.uuid), + adUuid: adToCreate.uuid, + ...address1, + }); + } + }; + + const createRecurrentDriverPassengerAds = async (nbToCreate = 10) => { + const adToCreate = { + ...baseUuid, + ...baseUserUuid, + ...driverAndPassengerAd, + ...recurrentAd, + }; + for (let i = 0; i < nbToCreate; i++) { + adToCreate.uuid = getSeed(i, baseUuid.uuid); + await executeInsertCommand('ad', adToCreate); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress0Uuid.uuid), + adUuid: adToCreate.uuid, + ...address0, + }); + await executeInsertCommand('address', { + uuid: getSeed(i, baseAdress1Uuid.uuid), + adUuid: adToCreate.uuid, + ...address1, + }); + } + }; + beforeAll(async () => { + const module = await Test.createTestingModule({ + imports: [DatabaseModule], + providers: [PrismaService, AdsRepository], + }).compile(); + prismaService = module.get(PrismaService); + adsRepository = module.get(AdsRepository); + }); + afterAll(async () => { + await prismaService.$disconnect(); + }); + + beforeEach(async () => { + await prismaService.ad.deleteMany(); + }); + describe('findAll', () => { + it('should return an empty data array', async () => { + const res = await adsRepository.findAll(); + expect(res).toEqual({ + data: [], + total: 0, + }); + }); + + describe('drivers', () => { + it('should return a data array with 8 punctual driver ads', async () => { + await createPunctualDriverAds(8); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(8); + expect(ads.total).toBe(8); + expect(ads.data[0].driver).toBeTruthy(); + expect(ads.data[0].passenger).toBeFalsy(); + }); + + it('should return a data array limited to 10 punctual driver ads', async () => { + await createPunctualDriverAds(20); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(10); + expect(ads.total).toBe(20); + expect(ads.data[1].driver).toBeTruthy(); + expect(ads.data[1].passenger).toBeFalsy(); + }); + + it('should return a data array with 8 recurrent driver ads', async () => { + await createRecurrentDriverAds(8); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(8); + expect(ads.total).toBe(8); + expect(ads.data[2].driver).toBeTruthy(); + expect(ads.data[2].passenger).toBeFalsy(); + }); + + it('should return a data array limited to 10 recurrent driver ads', async () => { + await createRecurrentDriverAds(20); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(10); + expect(ads.total).toBe(20); + expect(ads.data[3].driver).toBeTruthy(); + expect(ads.data[3].passenger).toBeFalsy(); + }); + }); + + describe('passengers', () => { + it('should return a data array with 7 punctual passenger ads', async () => { + await createPunctualPassengerAds(7); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(7); + expect(ads.total).toBe(7); + expect(ads.data[0].passenger).toBeTruthy(); + expect(ads.data[0].driver).toBeFalsy(); + }); + + it('should return a data array limited to 10 punctual passenger ads', async () => { + await createPunctualPassengerAds(15); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(10); + expect(ads.total).toBe(15); + expect(ads.data[1].passenger).toBeTruthy(); + expect(ads.data[1].driver).toBeFalsy(); + }); + + it('should return a data array with 7 recurrent passenger ads', async () => { + await createRecurrentPassengerAds(7); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(7); + expect(ads.total).toBe(7); + expect(ads.data[2].passenger).toBeTruthy(); + expect(ads.data[2].driver).toBeFalsy(); + }); + + it('should return a data array limited to 10 recurrent passenger ads', async () => { + await createRecurrentPassengerAds(15); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(10); + expect(ads.total).toBe(15); + expect(ads.data[3].passenger).toBeTruthy(); + expect(ads.data[3].driver).toBeFalsy(); + }); + }); + + describe('drivers and passengers', () => { + it('should return a data array with 6 punctual driver and passenger ads', async () => { + await createPunctualDriverPassengerAds(6); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(6); + expect(ads.total).toBe(6); + expect(ads.data[0].passenger).toBeTruthy(); + expect(ads.data[0].driver).toBeTruthy(); + }); + + it('should return a data array limited to 10 punctual driver and passenger ads', async () => { + await createPunctualDriverPassengerAds(16); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(10); + expect(ads.total).toBe(16); + expect(ads.data[1].passenger).toBeTruthy(); + expect(ads.data[1].driver).toBeTruthy(); + }); + + it('should return a data array with 6 recurrent driver and passenger ads', async () => { + await createRecurrentDriverPassengerAds(6); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(6); + expect(ads.total).toBe(6); + expect(ads.data[2].passenger).toBeTruthy(); + expect(ads.data[2].driver).toBeTruthy(); + }); + + it('should return a data array limited to 10 recurrent driver and passenger ads', async () => { + await createRecurrentDriverPassengerAds(16); + const ads = await adsRepository.findAll(); + expect(ads.data.length).toBe(10); + expect(ads.total).toBe(16); + expect(ads.data[3].passenger).toBeTruthy(); + expect(ads.data[3].driver).toBeTruthy(); + }); + }); + }); + describe('findOneByUuid', () => { + it('should return an ad', async () => { + await createPunctualDriverAds(1); + const ad = await adsRepository.findOneByUuid(baseUuid.uuid); + expect(ad.uuid).toBe(baseUuid.uuid); + }); + + it('should return null', async () => { + const ad = await adsRepository.findOneByUuid( + '544572be-11fb-4244-8235-587221fc9104', + ); + expect(ad).toBeNull(); + }); + }); + describe('Create Ad', () => { + it('should Create an ad ', async () => {}); + }); +}); diff --git a/src/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts b/src/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts index 490636e..ca82a54 100644 --- a/src/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts +++ b/src/modules/ad/tests/unit/domain/create-ad.usecase.spec.ts @@ -41,7 +41,7 @@ const mockAddressWithoutPos1: AddressRequestDTO = { const mockAddressWithoutPos2: AddressRequestDTO = { lon: 43.7102, lat: 7.262, - locality: 'Marseille', + locality: 'Nice', postalCode: '06000', country: 'France', };