diff --git a/services/API-service/package-lock.json b/services/API-service/package-lock.json index d080474f95..4f43563d03 100644 --- a/services/API-service/package-lock.json +++ b/services/API-service/package-lock.json @@ -37,6 +37,8 @@ "typescript": "^4.9.5" }, "devDependencies": { + "@automock/adapters.nestjs": "^2.1.0", + "@automock/jest": "^2.1.0", "@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@types/express": "^5.0.0", "@types/jest": "^29.5.14", @@ -84,6 +86,74 @@ "node": ">=6.0.0" } }, + "node_modules/@automock/adapters.nestjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@automock/adapters.nestjs/-/adapters.nestjs-2.1.0.tgz", + "integrity": "sha512-cwolpTMF+frIm6idLC/zD0obgG/Wf5wP6I8FKJBcRy+Cuc9Pyy/E7200zafYlOVzUlZUP16VqchgGWpUyb1U3Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@automock/common": "^3.1.0", + "@automock/types": "^2.0.1", + "reflect-metadata": "^0.1.13" + }, + "engines": { + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + } + }, + "node_modules/@automock/common": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@automock/common/-/common-3.1.0.tgz", + "integrity": "sha512-Y7N4YnSZRuSIfGV4/PdG2JyURa9PK1maqGZBYUG2/sIW+H/Mlhc/3NpegnlUyQFRBexEJtgmUsvfzzI1/lm0JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@automock/types": "^2.0.1" + }, + "engines": { + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + } + }, + "node_modules/@automock/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@automock/core/-/core-2.1.0.tgz", + "integrity": "sha512-VIaY2woE7nWXhXKlNzk4+xzCuaVBXfGYwowrzdI+MmJBKqi2z0lUjNVix74hZRWhJpkOW+PR3UThFvThgyqIqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@automock/common": "^3.1.0", + "@automock/types": "^2.0.1", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + } + }, + "node_modules/@automock/jest": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@automock/jest/-/jest-2.1.0.tgz", + "integrity": "sha512-kJuTu/a5bbG8SICIfITgESpIrVbBfbMykDdICmPvJkeI51Ldq+tqiLS2Ded16vLWS9WeFKeTw/+2b/DO8QyV0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@automock/core": "^2.1.0", + "@automock/types": "^2.0.1" + }, + "engines": { + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + }, + "peerDependencies": { + "jest": "^26 || ^27 || ^28 || ^29" + } + }, + "node_modules/@automock/types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@automock/types/-/types-2.0.1.tgz", + "integrity": "sha512-ue35e4im3n7l+Eqq3kCA2nNs8jzJbjYLni+vlPdgJ+9KfsEykJjA1OpnNN/PG1tDaM0iyR2p/uZg27MOC/qiTg==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -8266,6 +8336,13 @@ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", @@ -11932,6 +12009,53 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "@automock/adapters.nestjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@automock/adapters.nestjs/-/adapters.nestjs-2.1.0.tgz", + "integrity": "sha512-cwolpTMF+frIm6idLC/zD0obgG/Wf5wP6I8FKJBcRy+Cuc9Pyy/E7200zafYlOVzUlZUP16VqchgGWpUyb1U3Q==", + "dev": true, + "requires": { + "@automock/common": "^3.1.0", + "@automock/types": "^2.0.1", + "reflect-metadata": "^0.1.13" + } + }, + "@automock/common": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@automock/common/-/common-3.1.0.tgz", + "integrity": "sha512-Y7N4YnSZRuSIfGV4/PdG2JyURa9PK1maqGZBYUG2/sIW+H/Mlhc/3NpegnlUyQFRBexEJtgmUsvfzzI1/lm0JA==", + "dev": true, + "requires": { + "@automock/types": "^2.0.1" + } + }, + "@automock/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@automock/core/-/core-2.1.0.tgz", + "integrity": "sha512-VIaY2woE7nWXhXKlNzk4+xzCuaVBXfGYwowrzdI+MmJBKqi2z0lUjNVix74hZRWhJpkOW+PR3UThFvThgyqIqQ==", + "dev": true, + "requires": { + "@automock/common": "^3.1.0", + "@automock/types": "^2.0.1", + "lodash.isequal": "^4.5.0" + } + }, + "@automock/jest": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@automock/jest/-/jest-2.1.0.tgz", + "integrity": "sha512-kJuTu/a5bbG8SICIfITgESpIrVbBfbMykDdICmPvJkeI51Ldq+tqiLS2Ded16vLWS9WeFKeTw/+2b/DO8QyV0Q==", + "dev": true, + "requires": { + "@automock/core": "^2.1.0", + "@automock/types": "^2.0.1" + } + }, + "@automock/types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@automock/types/-/types-2.0.1.tgz", + "integrity": "sha512-ue35e4im3n7l+Eqq3kCA2nNs8jzJbjYLni+vlPdgJ+9KfsEykJjA1OpnNN/PG1tDaM0iyR2p/uZg27MOC/qiTg==", + "dev": true + }, "@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -17890,6 +18014,12 @@ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true + }, "lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", diff --git a/services/API-service/package.json b/services/API-service/package.json index 177b9e313e..65bf5a265e 100644 --- a/services/API-service/package.json +++ b/services/API-service/package.json @@ -55,6 +55,8 @@ "typescript": "^4.9.5" }, "devDependencies": { + "@automock/adapters.nestjs": "^2.1.0", + "@automock/jest": "^2.1.0", "@ianvs/prettier-plugin-sort-imports": "^4.4.0", "@types/express": "^5.0.0", "@types/jest": "^29.5.14", diff --git a/services/API-service/src/api/typhoon-track/dto/trackpoint-details.ts b/services/API-service/src/api/typhoon-track/dto/trackpoint-details.ts index d1ea98640a..96df7ddc57 100644 --- a/services/API-service/src/api/typhoon-track/dto/trackpoint-details.ts +++ b/services/API-service/src/api/typhoon-track/dto/trackpoint-details.ts @@ -21,12 +21,12 @@ export class TrackpointDetailsDto { @ApiProperty({ example: 90.0 }) @IsNotEmpty() @IsNumber() - public lat: string; + public lat: number; @ApiProperty({ example: 90.0 }) @IsNotEmpty() @IsNumber() - public lon: string; + public lon: number; @ApiProperty({ example: new Date() }) @IsNotEmpty() diff --git a/services/API-service/src/api/typhoon-track/typhoon-track.controller.ts b/services/API-service/src/api/typhoon-track/typhoon-track.controller.ts index 93382493a5..39740417dd 100644 --- a/services/API-service/src/api/typhoon-track/typhoon-track.controller.ts +++ b/services/API-service/src/api/typhoon-track/typhoon-track.controller.ts @@ -57,7 +57,7 @@ export class TyphoonTrackController { summary: 'Get Typhoon track data for given country and leadtime', }) @ApiParam({ name: 'countryCodeISO3', required: true, type: 'string' }) - @ApiQuery({ name: 'eventName', required: false, type: 'string' }) + @ApiQuery({ name: 'eventName', required: true, type: 'string' }) @ApiResponse({ status: 200, description: diff --git a/services/API-service/src/api/typhoon-track/typhoon-track.service.spec.ts b/services/API-service/src/api/typhoon-track/typhoon-track.service.spec.ts new file mode 100644 index 0000000000..3c58cb6273 --- /dev/null +++ b/services/API-service/src/api/typhoon-track/typhoon-track.service.spec.ts @@ -0,0 +1,118 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +// import { beforeEach, describe, it } from 'node:test'; + +import { getRepositoryToken } from '@nestjs/typeorm'; + +import { TestBed } from '@automock/jest'; +import { Repository } from 'typeorm'; + +import { HelperService } from '../../shared/helper.service'; +import { LeadTime } from '../admin-area-dynamic-data/enum/lead-time.enum'; +import { TyphoonCategory } from './dto/trackpoint-details'; +import { TyphoonTrackEntity } from './typhoon-track.entity'; +import { TyphoonTrackService } from './typhoon-track.service'; + +const countryCodeISO3 = 'PHL'; +const eventName = 'Mock typhoon 1'; + +const timestamp = new Date(); +const date = timestamp.toISOString(); +const mockRecentDate = { date, timestamp }; + +const mockTyphoonTrack: TyphoonTrackEntity[] = [ + { + id: '123e4567-e89b-12d3-a456-426614174000', + countryCodeISO3, + leadTime: LeadTime.hour72, + date: timestamp, + timestamp, + timestampOfTrackpoint: timestamp, + windspeed: 120, + category: TyphoonCategory.STS, + firstLandfall: true, + closestToLand: false, + eventName, + geom: JSON.parse(JSON.stringify({})), + }, +]; + +describe('TyphoonTrackService', () => { + let typhoonTrackService: TyphoonTrackService; + let helperService: HelperService; + let typhoonTrackRepository: Repository; + + beforeEach(async () => { + const { unit, unitRef } = TestBed.create(TyphoonTrackService).compile(); + + typhoonTrackService = unit; + helperService = unitRef.get(HelperService); + typhoonTrackRepository = unitRef.get( + getRepositoryToken(TyphoonTrackEntity) as any, + ); + + jest + .spyOn(helperService, 'getRecentDate') + .mockResolvedValue(mockRecentDate); + + jest + .spyOn(typhoonTrackRepository, 'find') + .mockResolvedValue(mockTyphoonTrack); + }); + + it('should be defined', () => { + expect(typhoonTrackService).toBeDefined(); + expect(typhoonTrackRepository).toBeDefined(); + }); + + describe('getTyphoonSpecificProperties', () => { + it('should yield typhoonLandfall=true if track contains point with firstLandfall=true', async () => { + // Arrange + mockTyphoonTrack[0].firstLandfall = true; + + // Act + const result = await typhoonTrackService.getTyphoonSpecificProperties( + countryCodeISO3, + eventName, + ); + + // Assert + expect(result.typhoonLandfall).toBe(true); + expect(result.typhoonNoLandfallYet).toBe(false); + }); + + it('should yield typhoonLandfall=false for scenario NoLandfall', async () => { + // Arrange + mockTyphoonTrack[0].firstLandfall = false; + + // Act + const result = await typhoonTrackService.getTyphoonSpecificProperties( + countryCodeISO3, + eventName, + ); + + // Assert + expect(result.typhoonLandfall).toBe(false); + expect(result.typhoonNoLandfallYet).toBe(false); + }); + + it('should yield typhoonNoLandfallYet=true for scenario NoLandfallYet', async () => { + // Arrange + mockTyphoonTrack[0].firstLandfall = false; + mockTyphoonTrack.push(mockTyphoonTrack[0]); // Add a 2nd trackpoint, also no landfall + mockTyphoonTrack[1].timestampOfTrackpoint = new Date( + timestamp.getTime() + 3 * 60 * 60 * 1000, + ); // Add 3 hours, making this the "last" point in the track + mockTyphoonTrack[1].closestToLand = true; // Set last point to be closest to land + + // Act + const result = await typhoonTrackService.getTyphoonSpecificProperties( + countryCodeISO3, + eventName, + ); + + // Assert + expect(result.typhoonLandfall).toBe(false); + expect(result.typhoonNoLandfallYet).toBe(true); + }); + }); +}); diff --git a/services/API-service/src/api/typhoon-track/typhoon-track.service.ts b/services/API-service/src/api/typhoon-track/typhoon-track.service.ts index 425d6b9bec..3144b2e43b 100644 --- a/services/API-service/src/api/typhoon-track/typhoon-track.service.ts +++ b/services/API-service/src/api/typhoon-track/typhoon-track.service.ts @@ -113,7 +113,8 @@ export class TyphoonTrackService { DisasterType.Typhoon, ); const filters = { - countryCodeISO3: countryCodeISO3, + countryCodeISO3, + eventName, // eventName is required because National View is currently not supported for Typhoon timestamp: MoreThanOrEqual( this.helperService.getUploadCutoffMoment( DisasterType.Typhoon, @@ -121,9 +122,6 @@ export class TyphoonTrackService { ), ), }; - if (eventName) { - filters['eventName'] = eventName; - } return filters; } diff --git a/services/API-service/src/scripts/git-lfs/point-layers/glofas_stations_ZMB.csv b/services/API-service/src/scripts/git-lfs/point-layers/glofas_stations_ZMB.csv index 32543adee0..56253fb99b 100644 --- a/services/API-service/src/scripts/git-lfs/point-layers/glofas_stations_ZMB.csv +++ b/services/API-service/src/scripts/git-lfs/point-layers/glofas_stations_ZMB.csv @@ -1,7 +1,7 @@ stationCode,stationName,lat,lon,fid G1264,NearChibote,-9.9061,29.501,G1264 G1265,ChungaRanch,-9.930000305,32.13000107,G1265 -G1269,MbesumaPontoon60773245,-10,32.1667,G1269 +G1269,MbesumaPontoon60773245,-10,32.122,G1269 G1271,PumpHouse,-10.175,30.975,G1271 G1294,ChembeFerry,-11.975,28.725,G1294 G1312,Mpatamato,-13.25,28.1333,G1312 diff --git a/tests/integration/fixtures/users.const.ts b/tests/integration/fixtures/users.const.ts index 0ff38d558e..97a227e85d 100644 --- a/tests/integration/fixtures/users.const.ts +++ b/tests/integration/fixtures/users.const.ts @@ -1,7 +1,6 @@ -import { UserRole } from '../../../services/API-service/src/api/user/user-role.enum'; -import { UserStatus } from '../../../services/API-service/src/api/user/user-status.enum'; +import { UserRole } from '../helpers/API-service/enum/user-role.enum'; +import { UserStatus } from '../helpers/API-service/enum/user-status.enum'; -// REFACTOR: it will happen a lot throughout these integration tests to use DTO's from the API-service. Is it fine to import them like this? export const userData = { email: 'dunant@redcross.nl', username: 'dunant', diff --git a/tests/integration/helpers/API-service/dto/create-user.dto.ts b/tests/integration/helpers/API-service/dto/create-user.dto.ts new file mode 100644 index 0000000000..05b55ac6d3 --- /dev/null +++ b/tests/integration/helpers/API-service/dto/create-user.dto.ts @@ -0,0 +1,18 @@ +import { UserRole } from '../enum/user-role.enum'; +import { UserStatus } from '../enum/user-status.enum'; + +const userRoleArray = Object.values(UserRole).map((item) => String(item)); + +export class CreateUserDto { + public email: string; + public username: string; + public firstName: string; + public middleName?: string; + public lastName: string; + public role: UserRole; + public countryCodesISO3: string[]; + public disasterTypes: string[]; + public status: UserStatus; + public password: string; + public whatsappNumber: string; +} diff --git a/tests/integration/helpers/API-service/dto/upload-typhoon-track.dto.ts b/tests/integration/helpers/API-service/dto/upload-typhoon-track.dto.ts new file mode 100644 index 0000000000..356bb19ab1 --- /dev/null +++ b/tests/integration/helpers/API-service/dto/upload-typhoon-track.dto.ts @@ -0,0 +1,27 @@ +import { LeadTime } from '../enum/lead-time.enum'; + +export class UploadTyphoonTrackDto { + public countryCodeISO3: string; + public leadTime: LeadTime; + public eventName: string; + public trackpointDetails: TrackpointDetailsDto[]; + public readonly date: Date; +} + +export enum TyphoonCategory { + TD = 'TD', + TS = 'TS', + STS = 'STS', + TY = 'TY', + STY = 'STY', +} + +export class TrackpointDetailsDto { + public lat: number; + public lon: number; + public timestampOfTrackpoint: Date; + public windspeed: number; + public category: TyphoonCategory; + public firstLandfall: boolean; + public closestToLand: boolean; +} diff --git a/tests/integration/helpers/API-service/enum/disaster-type.enum.ts b/tests/integration/helpers/API-service/enum/disaster-type.enum.ts new file mode 100644 index 0000000000..a85dd9019e --- /dev/null +++ b/tests/integration/helpers/API-service/enum/disaster-type.enum.ts @@ -0,0 +1,8 @@ +export enum DisasterType { + Floods = 'floods', + HeavyRain = 'heavy-rain', + Malaria = 'malaria', + Drought = 'drought', + Typhoon = 'typhoon', + FlashFloods = 'flash-floods', +} diff --git a/tests/integration/helpers/API-service/enum/lead-time.enum.ts b/tests/integration/helpers/API-service/enum/lead-time.enum.ts new file mode 100644 index 0000000000..d8bf502b8c --- /dev/null +++ b/tests/integration/helpers/API-service/enum/lead-time.enum.ts @@ -0,0 +1,191 @@ +export enum LeadTime { + day0 = '0-day', + day1 = '1-day', + day2 = '2-day', + day3 = '3-day', + day4 = '4-day', + day5 = '5-day', + day6 = '6-day', + day7 = '7-day', + month0 = '0-month', + month1 = '1-month', + month2 = '2-month', + month3 = '3-month', + month4 = '4-month', + month5 = '5-month', + month6 = '6-month', + month7 = '7-month', + month8 = '8-month', + month9 = '9-month', + month10 = '10-month', + month11 = '11-month', + hour0 = '0-hour', + hour1 = '1-hour', + hour2 = '2-hour', + hour3 = '3-hour', + hour4 = '4-hour', + hour5 = '5-hour', + hour6 = '6-hour', + hour7 = '7-hour', + hour8 = '8-hour', + hour9 = '9-hour', + hour10 = '10-hour', + hour11 = '11-hour', + hour12 = '12-hour', + hour13 = '13-hour', + hour14 = '14-hour', + hour15 = '15-hour', + hour16 = '16-hour', + hour17 = '17-hour', + hour18 = '18-hour', + hour19 = '19-hour', + hour20 = '20-hour', + hour21 = '21-hour', + hour22 = '22-hour', + hour23 = '23-hour', + hour24 = '24-hour', + hour25 = '25-hour', + hour26 = '26-hour', + hour27 = '27-hour', + hour28 = '28-hour', + hour29 = '29-hour', + hour30 = '30-hour', + hour31 = '31-hour', + hour32 = '32-hour', + hour33 = '33-hour', + hour34 = '34-hour', + hour35 = '35-hour', + hour36 = '36-hour', + hour37 = '37-hour', + hour38 = '38-hour', + hour39 = '39-hour', + hour40 = '40-hour', + hour41 = '41-hour', + hour42 = '42-hour', + hour43 = '43-hour', + hour44 = '44-hour', + hour45 = '45-hour', + hour46 = '46-hour', + hour47 = '47-hour', + hour48 = '48-hour', + hour49 = '49-hour', + hour50 = '50-hour', + hour51 = '51-hour', + hour52 = '52-hour', + hour53 = '53-hour', + hour54 = '54-hour', + hour55 = '55-hour', + hour56 = '56-hour', + hour57 = '57-hour', + hour58 = '58-hour', + hour59 = '59-hour', + hour60 = '60-hour', + hour61 = '61-hour', + hour62 = '62-hour', + hour63 = '63-hour', + hour64 = '64-hour', + hour65 = '65-hour', + hour66 = '66-hour', + hour67 = '67-hour', + hour68 = '68-hour', + hour69 = '69-hour', + hour70 = '70-hour', + hour71 = '71-hour', + hour72 = '72-hour', + hour73 = '73-hour', + hour74 = '74-hour', + hour75 = '75-hour', + hour76 = '76-hour', + hour77 = '77-hour', + hour78 = '78-hour', + hour79 = '79-hour', + hour80 = '80-hour', + hour81 = '81-hour', + hour82 = '82-hour', + hour83 = '83-hour', + hour84 = '84-hour', + hour85 = '85-hour', + hour86 = '86-hour', + hour87 = '87-hour', + hour88 = '88-hour', + hour89 = '89-hour', + hour90 = '90-hour', + hour91 = '91-hour', + hour92 = '92-hour', + hour93 = '93-hour', + hour94 = '94-hour', + hour95 = '95-hour', + hour96 = '96-hour', + hour97 = '97-hour', + hour98 = '98-hour', + hour99 = '99-hour', + hour100 = '100-hour', + hour101 = '101-hour', + hour102 = '102-hour', + hour103 = '103-hour', + hour104 = '104-hour', + hour105 = '105-hour', + hour106 = '106-hour', + hour107 = '107-hour', + hour108 = '108-hour', + hour109 = '109-hour', + hour110 = '110-hour', + hour111 = '111-hour', + hour112 = '112-hour', + hour113 = '113-hour', + hour114 = '114-hour', + hour115 = '115-hour', + hour116 = '116-hour', + hour117 = '117-hour', + hour118 = '118-hour', + hour119 = '119-hour', + hour120 = '120-hour', + hour121 = '121-hour', + hour122 = '122-hour', + hour123 = '123-hour', + hour124 = '124-hour', + hour125 = '125-hour', + hour126 = '126-hour', + hour127 = '127-hour', + hour128 = '128-hour', + hour129 = '129-hour', + hour130 = '130-hour', + hour131 = '131-hour', + hour132 = '132-hour', + hour133 = '133-hour', + hour134 = '134-hour', + hour135 = '135-hour', + hour136 = '136-hour', + hour137 = '137-hour', + hour138 = '138-hour', + hour139 = '139-hour', + hour140 = '140-hour', + hour141 = '141-hour', + hour142 = '142-hour', + hour143 = '143-hour', + hour144 = '144-hour', + hour145 = '145-hour', + hour146 = '146-hour', + hour147 = '147-hour', + hour148 = '148-hour', + hour149 = '149-hour', + hour150 = '150-hour', + hour151 = '151-hour', + hour152 = '152-hour', + hour153 = '153-hour', + hour154 = '154-hour', + hour155 = '155-hour', + hour156 = '156-hour', + hour157 = '157-hour', + hour158 = '158-hour', + hour159 = '159-hour', + hour160 = '160-hour', + hour161 = '161-hour', + hour162 = '162-hour', + hour163 = '163-hour', + hour164 = '164-hour', + hour165 = '165-hour', + hour166 = '166-hour', + hour167 = '167-hour', + hour168 = '168-hour', +} diff --git a/tests/integration/helpers/API-service/enum/mock-scenario.enum.ts b/tests/integration/helpers/API-service/enum/mock-scenario.enum.ts new file mode 100644 index 0000000000..8a0401d614 --- /dev/null +++ b/tests/integration/helpers/API-service/enum/mock-scenario.enum.ts @@ -0,0 +1,28 @@ +export enum FloodsScenario { + Trigger = 'trigger', + Warning = 'warning', + WarningToTrigger = 'warning-to-trigger', + NoTrigger = 'no-trigger', +} + +export enum FlashFloodsScenario { + Trigger = 'trigger', + TriggerBlantyre = 'trigger-blantyre', + WarningKaronga = 'warning-karonga', + TriggerOngoingRumphi = 'trigger-ongoing-rumphi', + NoTrigger = 'no-trigger', +} + +export enum MalariaScenario { + Trigger = 'trigger', + NoTrigger = 'no-trigger', +} + +export enum TyphoonScenario { + NoEvent = 'noEvent', + EventNoLandfall = 'eventNoLandfall', + EventNoLandfallYet = 'eventNoLandfallYet', + EventNoTrigger = 'eventNoTrigger', + EventTrigger = 'eventTrigger', + EventAfterLandfall = 'eventAfterLandfall', +} diff --git a/tests/integration/helpers/API-service/enum/user-role.enum.ts b/tests/integration/helpers/API-service/enum/user-role.enum.ts new file mode 100644 index 0000000000..0be2ae812b --- /dev/null +++ b/tests/integration/helpers/API-service/enum/user-role.enum.ts @@ -0,0 +1,6 @@ +export enum UserRole { + Admin = 'admin', + DisasterManager = 'disaster-manager', + PipelineUser = 'pipeline-user', + Guest = 'guest', +} diff --git a/tests/integration/helpers/API-service/enum/user-status.enum.ts b/tests/integration/helpers/API-service/enum/user-status.enum.ts new file mode 100644 index 0000000000..6c70134c9b --- /dev/null +++ b/tests/integration/helpers/API-service/enum/user-status.enum.ts @@ -0,0 +1,4 @@ +export enum UserStatus { + Active = 'active', + Inactive = 'inactive', +} diff --git a/tests/integration/helpers/API-service/json/disasters.json b/tests/integration/helpers/API-service/json/disasters.json new file mode 100644 index 0000000000..e9d4582be3 --- /dev/null +++ b/tests/integration/helpers/API-service/json/disasters.json @@ -0,0 +1,62 @@ +[ + { + "disasterType": "floods", + "label": "flood", + "triggerUnit": "alert_threshold", + "actionsUnit": "population_affected", + "showOnlyTriggeredAreas": true, + "leadTimeUnit": "day", + "minLeadTime": "0-day", + "maxLeadTime": "7-day" + }, + { + "disasterType": "heavy-rain", + "label": "heavy rainfall", + "triggerUnit": "alert_threshold", + "actionsUnit": "population_affected", + "showOnlyTriggeredAreas": true, + "leadTimeUnit": "day", + "minLeadTime": "1-day", + "maxLeadTime": "7-day" + }, + { + "disasterType": "malaria", + "label": "malaria", + "triggerUnit": "alert_threshold", + "actionsUnit": "potential_cases", + "showOnlyTriggeredAreas": false, + "leadTimeUnit": "month", + "minLeadTime": "0-month", + "maxLeadTime": "2-month" + }, + { + "disasterType": "drought", + "label": "drought", + "triggerUnit": "alert_threshold", + "actionsUnit": "population_affected", + "showOnlyTriggeredAreas": true, + "leadTimeUnit": "month", + "minLeadTime": "0-month", + "maxLeadTime": "11-month" + }, + { + "disasterType": "typhoon", + "label": "typhoon", + "triggerUnit": "alert_threshold", + "actionsUnit": "houses_affected", + "showOnlyTriggeredAreas": false, + "leadTimeUnit": "hour", + "minLeadTime": "0-hour", + "maxLeadTime": "168-hour" + }, + { + "disasterType": "flash-floods", + "label": "flash flood", + "triggerUnit": "alert_threshold", + "actionsUnit": "population_affected", + "showOnlyTriggeredAreas": false, + "leadTimeUnit": "hour", + "minLeadTime": "0-hour", + "maxLeadTime": "48-hour" + } +] diff --git a/tests/integration/helpers/API-service/json/users.json b/tests/integration/helpers/API-service/json/users.json new file mode 100644 index 0000000000..42b33be1dd --- /dev/null +++ b/tests/integration/helpers/API-service/json/users.json @@ -0,0 +1,112 @@ +[ + { + "email": "dunant@redcross.nl", + "username": "dunant", + "firstName": "Henry", + "lastName": "Dunant", + "userRole": "admin", + "password": "password", + "userStatus": "active" + }, + { + "email": "uganda@redcross.nl", + "username": "uganda", + "firstName": "Uganda", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["UGA"] + }, + { + "email": "zambia@redcross.nl", + "username": "zambia", + "firstName": "Zambia", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["ZMB"] + }, + { + "email": "zimbabwe@redcross.nl", + "username": "zimbabwe", + "firstName": "Zimbabwe", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["ZWE"] + }, + { + "email": "kenya@redcross.nl", + "username": "kenya", + "firstName": "Kenya", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["KEN"] + }, + { + "email": "ethiopia@redcross.nl", + "username": "ethiopia", + "firstName": "Ethiopia", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["ETH"] + }, + { + "email": "philippines@redcross.nl", + "username": "philippines", + "firstName": "Philippines", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["PHL"] + }, + { + "email": "malawi@redcross.nl", + "username": "malawi", + "firstName": "Malawi", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["MWI"] + }, + { + "email": "malawi-flash-floods@redcross.nl", + "username": "malawi-flash-floods", + "firstName": "Malawi", + "middleName": "Flash Floods", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["MWI"], + "disasterTypes": ["flash-floods"] + }, + { + "email": "southsudan@redcross.nl", + "username": "southsudan", + "firstName": "South Sudan", + "lastName": "Manager", + "userRole": "disaster-manager", + "password": "password", + "userStatus": "active", + "countries": ["SSD"] + }, + { + "email": "demo-user@redcross.nl", + "username": "demo-user@redcross.nl", + "firstName": "Demo", + "lastName": "User", + "userRole": "disaster-manager", + "password": "ibf-portal", + "userStatus": "active" + } +] diff --git a/tests/integration/helpers/utility.helper.ts b/tests/integration/helpers/utility.helper.ts index 4ec6381616..163fe13c5d 100644 --- a/tests/integration/helpers/utility.helper.ts +++ b/tests/integration/helpers/utility.helper.ts @@ -1,15 +1,15 @@ import * as request from 'supertest'; import TestAgent from 'supertest/lib/agent'; - -import { DisasterType } from '../../../services/API-service/src/api/disaster/disaster-type.enum'; -import { CreateUserDto } from '../../../services/API-service/src/api/user/dto/create-user.dto'; +import { CreateUserDto } from './API-service/dto/create-user.dto'; +import { UploadTyphoonTrackDto } from './API-service/dto/upload-typhoon-track.dto'; +import { DisasterType } from './API-service/enum/disaster-type.enum'; import { - MalariaScenario, FlashFloodsScenario, FloodsScenario, + MalariaScenario, TyphoonScenario, -} from '../../../services/API-service/src/scripts/enum/mock-scenario.enum'; -import users from '../../../services/API-service/src/scripts/json/users.json'; +} from './API-service/enum/mock-scenario.enum'; +import users from './API-service/json/users.json'; export async function getAccessToken(): Promise { const admin = users.find((user) => user.userRole === 'admin'); @@ -179,3 +179,39 @@ export function changePassword( .set('Authorization', `Bearer ${accessToken}`) .send({ email, password }); } + +// Start splitting this up into multiple helper files +export function getTyphoonTrack( + countryCodeISO3: string, + eventName: string, + accessToken: string, +): Promise { + let query = {}; + if (eventName) { + query = { eventName: eventName }; + } + return getServer() + .get(`/typhoon-track/${countryCodeISO3}`) + .query(query) + .set('Authorization', `Bearer ${accessToken}`); +} + +export function postTyphoonTrack( + uploadTyphoonTrackDto: UploadTyphoonTrackDto, + accessToken: string, +): Promise { + return getServer() + .post(`/typhoon-track`) + .set('Authorization', `Bearer ${accessToken}`) + .send(uploadTyphoonTrackDto); +} + +export function getEventsSummary( + countryCodeISO3: string, + disasterType: DisasterType, + accessToken: string, +): Promise { + return getServer() + .get(`/event/${countryCodeISO3}/${disasterType}`) + .set('Authorization', `Bearer ${accessToken}`); +} diff --git a/tests/integration/email/drought/email-uga-drought.test.ts b/tests/integration/tests/email/drought/email-uga-drought.test.ts similarity index 94% rename from tests/integration/email/drought/email-uga-drought.test.ts rename to tests/integration/tests/email/drought/email-uga-drought.test.ts index efd4fd9f1b..f50259eaa1 100644 --- a/tests/integration/email/drought/email-uga-drought.test.ts +++ b/tests/integration/tests/email/drought/email-uga-drought.test.ts @@ -1,13 +1,12 @@ import { JSDOM } from 'jsdom'; - -import { DisasterType } from '../../../../services/API-service/src/api/disaster/disaster-type.enum'; +import { DisasterType } from '../../../helpers/API-service/enum/disaster-type.enum'; import { getAccessToken, getEventTitle, mockDynamicData, resetDB, sendNotification, -} from '../../helpers/utility.helper'; +} from '../../../helpers/utility.helper'; const countryCodeISO3 = 'UGA'; const disasterType = DisasterType.Drought; @@ -15,7 +14,7 @@ const disasterType = DisasterType.Drought; describe('Should send an email for uga drought', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); diff --git a/tests/integration/email/flash-flood/email-mwi-flash-flood.test.ts b/tests/integration/tests/email/flash-flood/email-mwi-flash-flood.test.ts similarity index 82% rename from tests/integration/email/flash-flood/email-mwi-flash-flood.test.ts rename to tests/integration/tests/email/flash-flood/email-mwi-flash-flood.test.ts index 3f20bfa858..89ec9821d8 100644 --- a/tests/integration/email/flash-flood/email-mwi-flash-flood.test.ts +++ b/tests/integration/tests/email/flash-flood/email-mwi-flash-flood.test.ts @@ -1,18 +1,18 @@ -import { FlashFloodsScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; -import { getAccessToken, resetDB } from '../../helpers/utility.helper'; +import { FlashFloodsScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; +import { getAccessToken, resetDB } from '../../../helpers/utility.helper'; import { testFlashFloodScenario } from './test-flash-flood-scenario.helper'; const countryCodeISO3 = 'MWI'; describe('Should send an email for mwi flash flood', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); it('trigger', async () => { - const eventNames = ['Blantyre City', 'Karonga']; // Scenario contains also 'Rumphi' but as ongoing, for which no email is sent + const eventNames = ['Blantyre City', 'Karonga']; // Scenario contains also 'Rumphi' but as ongoing, for which no email is sent const result = await testFlashFloodScenario( FlashFloodsScenario.Trigger, countryCodeISO3, diff --git a/tests/integration/email/flash-flood/test-flash-flood-scenario.helper.ts b/tests/integration/tests/email/flash-flood/test-flash-flood-scenario.helper.ts similarity index 89% rename from tests/integration/email/flash-flood/test-flash-flood-scenario.helper.ts rename to tests/integration/tests/email/flash-flood/test-flash-flood-scenario.helper.ts index 7e63ccb520..ea36f04bc7 100644 --- a/tests/integration/email/flash-flood/test-flash-flood-scenario.helper.ts +++ b/tests/integration/tests/email/flash-flood/test-flash-flood-scenario.helper.ts @@ -1,11 +1,11 @@ import { JSDOM } from 'jsdom'; -import { DisasterType } from '../../../../services/API-service/src/api/disaster/disaster-type.enum'; -import { FlashFloodsScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; +import { DisasterType } from '../../../helpers/API-service/enum/disaster-type.enum'; +import { FlashFloodsScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; import { getEventTitle, mockFlashFlood, sendNotification, -} from '../../helpers/utility.helper'; +} from '../../../helpers/utility.helper'; export async function testFlashFloodScenario( scenario: FlashFloodsScenario, diff --git a/tests/integration/email/floods/email-ssd-floods.test.ts b/tests/integration/tests/email/floods/email-ssd-floods.test.ts similarity index 80% rename from tests/integration/email/floods/email-ssd-floods.test.ts rename to tests/integration/tests/email/floods/email-ssd-floods.test.ts index af6d2b753f..86f10e99ac 100644 --- a/tests/integration/email/floods/email-ssd-floods.test.ts +++ b/tests/integration/tests/email/floods/email-ssd-floods.test.ts @@ -1,12 +1,12 @@ -import { FloodsScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; -import { getAccessToken, resetDB } from '../../helpers/utility.helper'; +import { FloodsScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; +import { getAccessToken, resetDB } from '../../../helpers/utility.helper'; import { testFloodScenario } from './test-flood-scenario.helper'; const countryCodeISO3 = 'SSD'; describe('Should send an email for ssd floods', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); diff --git a/tests/integration/email/floods/email-uga-floods.test.ts b/tests/integration/tests/email/floods/email-uga-floods.test.ts similarity index 87% rename from tests/integration/email/floods/email-uga-floods.test.ts rename to tests/integration/tests/email/floods/email-uga-floods.test.ts index cc4cadf1ff..aec22ae099 100644 --- a/tests/integration/email/floods/email-uga-floods.test.ts +++ b/tests/integration/tests/email/floods/email-uga-floods.test.ts @@ -1,12 +1,12 @@ -import { FloodsScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; -import { getAccessToken, resetDB } from '../../helpers/utility.helper'; +import { FloodsScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; +import { getAccessToken, resetDB } from '../../../helpers/utility.helper'; import { testFloodScenario } from './test-flood-scenario.helper'; const countryCodeISO3 = 'UGA'; describe('Should send an email for uga floods', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); diff --git a/tests/integration/email/floods/test-flood-scenario.helper.ts b/tests/integration/tests/email/floods/test-flood-scenario.helper.ts similarity index 85% rename from tests/integration/email/floods/test-flood-scenario.helper.ts rename to tests/integration/tests/email/floods/test-flood-scenario.helper.ts index 98433c8875..dc33c69ad6 100644 --- a/tests/integration/email/floods/test-flood-scenario.helper.ts +++ b/tests/integration/tests/email/floods/test-flood-scenario.helper.ts @@ -1,14 +1,13 @@ import { JSDOM } from 'jsdom'; -import { DisasterType } from '../../../../services/API-service/src/api/disaster/disaster-type.enum'; -import { FloodsScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; - -import disasters from '../../../../services/API-service/src/scripts/json/disasters.json'; +import disasters from '../../../helpers/API-service/json/disasters.json'; import { getEventTitle, mockFloods, sendNotification, -} from '../../helpers/utility.helper'; +} from '../../../helpers/utility.helper'; +import { FloodsScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; +import { DisasterType } from '../../../helpers/API-service/enum/disaster-type.enum'; interface Event { eventName: string; diff --git a/tests/integration/email/malaria/email-eth-malaria.test.ts b/tests/integration/tests/email/malaria/email-eth-malaria.test.ts similarity index 78% rename from tests/integration/email/malaria/email-eth-malaria.test.ts rename to tests/integration/tests/email/malaria/email-eth-malaria.test.ts index 21985383d3..e2a002a991 100644 --- a/tests/integration/email/malaria/email-eth-malaria.test.ts +++ b/tests/integration/tests/email/malaria/email-eth-malaria.test.ts @@ -1,12 +1,12 @@ -import { MalariaScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; -import { getAccessToken, resetDB } from '../../helpers/utility.helper'; +import { MalariaScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; +import { getAccessToken, resetDB } from '../../../helpers/utility.helper'; import { testMalariaScenario } from './test-malaria-scenario.helper'; const countryCodeISO3 = 'ETH'; describe('Should send an email for eth malaria', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); diff --git a/tests/integration/email/malaria/test-malaria-scenario.helper.ts b/tests/integration/tests/email/malaria/test-malaria-scenario.helper.ts similarity index 89% rename from tests/integration/email/malaria/test-malaria-scenario.helper.ts rename to tests/integration/tests/email/malaria/test-malaria-scenario.helper.ts index 9d7b42482d..c9574ff699 100644 --- a/tests/integration/email/malaria/test-malaria-scenario.helper.ts +++ b/tests/integration/tests/email/malaria/test-malaria-scenario.helper.ts @@ -1,12 +1,11 @@ import { JSDOM } from 'jsdom'; - -import { DisasterType } from '../../../../services/API-service/src/api/disaster/disaster-type.enum'; -import { MalariaScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; +import { DisasterType } from '../../../helpers/API-service/enum/disaster-type.enum'; +import { MalariaScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; import { getEventTitle, mockMalaria, sendNotification, -} from '../../helpers/utility.helper'; +} from '../../../helpers/utility.helper'; export async function testMalariaScenario( scenario: MalariaScenario, diff --git a/tests/integration/email/typhoon/email-phl-typhoon.test.ts b/tests/integration/tests/email/typhoon/email-phl-typhoon.test.ts similarity index 86% rename from tests/integration/email/typhoon/email-phl-typhoon.test.ts rename to tests/integration/tests/email/typhoon/email-phl-typhoon.test.ts index dbba8f3321..22bb39aba4 100644 --- a/tests/integration/email/typhoon/email-phl-typhoon.test.ts +++ b/tests/integration/tests/email/typhoon/email-phl-typhoon.test.ts @@ -1,12 +1,12 @@ -import { TyphoonScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; -import { getAccessToken, resetDB } from '../../helpers/utility.helper'; +import { TyphoonScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; +import { getAccessToken, resetDB } from '../../../helpers/utility.helper'; import { testTyphoonScenario } from './test-typhoon-scenario.helper'; const countryCodeISO3 = 'PHL'; describe('Should send an email for phl typhoon', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); diff --git a/tests/integration/email/typhoon/test-typhoon-scenario.helper.ts b/tests/integration/tests/email/typhoon/test-typhoon-scenario.helper.ts similarity index 90% rename from tests/integration/email/typhoon/test-typhoon-scenario.helper.ts rename to tests/integration/tests/email/typhoon/test-typhoon-scenario.helper.ts index db19cfb5c9..c95dd78c1b 100644 --- a/tests/integration/email/typhoon/test-typhoon-scenario.helper.ts +++ b/tests/integration/tests/email/typhoon/test-typhoon-scenario.helper.ts @@ -1,12 +1,11 @@ import { JSDOM } from 'jsdom'; - -import { DisasterType } from '../../../../services/API-service/src/api/disaster/disaster-type.enum'; -import { TyphoonScenario } from '../../../../services/API-service/src/scripts/enum/mock-scenario.enum'; +import { DisasterType } from '../../../helpers/API-service/enum/disaster-type.enum'; +import { TyphoonScenario } from '../../../helpers/API-service/enum/mock-scenario.enum'; import { getEventTitle, mockTyphoon, sendNotification, -} from '../../helpers/utility.helper'; +} from '../../../helpers/utility.helper'; export async function testTyphoonScenario( scenario: TyphoonScenario, diff --git a/tests/integration/tests/typhoon-track/get-typhoon-specific-properties.test.ts b/tests/integration/tests/typhoon-track/get-typhoon-specific-properties.test.ts new file mode 100644 index 0000000000..7bedf569e9 --- /dev/null +++ b/tests/integration/tests/typhoon-track/get-typhoon-specific-properties.test.ts @@ -0,0 +1,42 @@ +import { DisasterType } from '../../helpers/API-service/enum/disaster-type.enum'; +import { TyphoonScenario } from '../../helpers/API-service/enum/mock-scenario.enum'; +import { + getAccessToken, + getEventsSummary, + mockTyphoon, + resetDB, +} from '../../helpers/utility.helper'; + +describe('get typhoon-specific properties', () => { + let accessToken: string; + const countryCodeISO3 = 'PHL'; + + beforeAll(async () => { + accessToken = await getAccessToken(); + await resetDB(accessToken); + }); + + // Here just 1 happy path is tested. See typhoon-track.service.spec for various unit tests on specific scenarios. + it('should yield typhoonLandfall=true for scenario Trigger', async () => { + // Arrange + await mockTyphoon( + TyphoonScenario.EventTrigger, + countryCodeISO3, + accessToken, + ); + + // Act + const eventsResult = await getEventsSummary( + countryCodeISO3, + DisasterType.Typhoon, + accessToken, + ); + + // Assert + expect(eventsResult.status).toBe(200); + expect(eventsResult.body.length).toBe(1); + expect( + eventsResult.body[0].disasterSpecificProperties.typhoonLandfall, + ).toBe(true); + }); +}); diff --git a/tests/integration/tests/typhoon-track/get-typhoon-track.test.ts b/tests/integration/tests/typhoon-track/get-typhoon-track.test.ts new file mode 100644 index 0000000000..4fbc99bfaf --- /dev/null +++ b/tests/integration/tests/typhoon-track/get-typhoon-track.test.ts @@ -0,0 +1,42 @@ +import { TyphoonScenario } from '../../helpers/API-service/enum/mock-scenario.enum'; +import { + getAccessToken, + getTyphoonTrack, + mockTyphoon, + resetDB, +} from '../../helpers/utility.helper'; + +describe('get typhoon track', () => { + let accessToken: string; + const countryCodeISO3 = 'PHL'; + + beforeAll(async () => { + accessToken = await getAccessToken(); + await resetDB(accessToken); + }); + + it('successfully', async () => { + // Arrange + await mockTyphoon( + TyphoonScenario.EventTrigger, + countryCodeISO3, + accessToken, + ); + const eventName = 'Mock typhoon 1'; + + // Act + const getTrackResult = await getTyphoonTrack( + countryCodeISO3, + eventName, + accessToken, + ); + + // Assert + expect(getTrackResult.status).toBe(200); + expect(getTrackResult.body.type).toBe('FeatureCollection'); + expect(getTrackResult.body.features.length).toBeGreaterThan(0); + expect( + getTrackResult.body.features[0].properties.timestampOfTrackpoint, + ).toBeDefined(); + }); +}); diff --git a/tests/integration/tests/typhoon-track/post-typhoon-track.test.ts b/tests/integration/tests/typhoon-track/post-typhoon-track.test.ts new file mode 100644 index 0000000000..46b3b14ef8 --- /dev/null +++ b/tests/integration/tests/typhoon-track/post-typhoon-track.test.ts @@ -0,0 +1,78 @@ +import { LeadTime } from '../../helpers/API-service/enum/lead-time.enum'; +import { TyphoonScenario } from '../../helpers/API-service/enum/mock-scenario.enum'; +import { + getAccessToken, + getTyphoonTrack, + mockTyphoon, + postTyphoonTrack, + resetDB, +} from '../../helpers/utility.helper'; +import { + TyphoonCategory, + UploadTyphoonTrackDto, +} from '../../helpers/API-service/dto/upload-typhoon-track.dto'; + +const countryCodeISO3 = 'PHL'; +const eventName = 'Mock typhoon 1'; +const sampleTyphoonTrack: UploadTyphoonTrackDto = { + countryCodeISO3, + leadTime: LeadTime.hour72, + eventName, + trackpointDetails: [ + { + timestampOfTrackpoint: new Date('2024-12-09T06:00:00.000Z'), + windspeed: 120, + category: TyphoonCategory.STS, + firstLandfall: true, + closestToLand: false, + lat: 12.0, + lon: 123.0, + }, + { + timestampOfTrackpoint: new Date('2024-12-09T09:00:00.000Z'), // 3 hours later + windspeed: 110, + category: TyphoonCategory.STS, + firstLandfall: false, + closestToLand: true, + lat: 12.0, + lon: 123.0, + }, + ], + date: new Date(), +}; + +describe('upload typhoon track', () => { + let accessToken: string; + const countryCodeISO3 = 'PHL'; + + beforeAll(async () => { + accessToken = await getAccessToken(); + await resetDB(accessToken); + }); + + it('upload successfully and return expected result on GET', async () => { + // Arrange + await mockTyphoon( + TyphoonScenario.EventTrigger, + countryCodeISO3, + accessToken, + ); + + // Act + const postTrackResult = await postTyphoonTrack( + sampleTyphoonTrack, + accessToken, + ); + + const getTrackResult = await getTyphoonTrack( + countryCodeISO3, + eventName, + accessToken, + ); + + // Assert + expect(postTrackResult.status).toBe(201); + expect(getTrackResult.status).toBe(200); + expect(getTrackResult.body.features.length).toBe(2); + }); +}); diff --git a/tests/integration/users/change-password.test.ts b/tests/integration/tests/users/change-password.test.ts similarity index 92% rename from tests/integration/users/change-password.test.ts rename to tests/integration/tests/users/change-password.test.ts index 6c13731f25..576d10063d 100644 --- a/tests/integration/users/change-password.test.ts +++ b/tests/integration/tests/users/change-password.test.ts @@ -1,15 +1,15 @@ -import { userData } from '../fixtures/users.const'; +import { userData } from '../../fixtures/users.const'; import { changePassword, getAccessToken, loginUser, resetDB, -} from '../helpers/utility.helper'; +} from '../../helpers/utility.helper'; describe('change password of user ..', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); diff --git a/tests/integration/users/create-user.test.ts b/tests/integration/tests/users/create-user.test.ts similarity index 80% rename from tests/integration/users/create-user.test.ts rename to tests/integration/tests/users/create-user.test.ts index a7cd877796..00e3b6c1bb 100644 --- a/tests/integration/users/create-user.test.ts +++ b/tests/integration/tests/users/create-user.test.ts @@ -1,21 +1,21 @@ -import { UserRole } from '../../../services/API-service/src/api/user/user-role.enum'; -import { userData } from '../fixtures/users.const'; +import { userData } from '../../fixtures/users.const'; import { createUser, getAccessToken, loginUser, resetDB, -} from '../helpers/utility.helper'; +} from '../../helpers/utility.helper'; +import { UserRole } from '../../helpers/API-service/enum/user-role.enum'; describe('create user', () => { let accessToken: string; - beforeEach(async () => { + beforeAll(async () => { accessToken = await getAccessToken(); await resetDB(accessToken); }); - it('successfully and log-in with it', async () => { + it('successfully, and log-in with it', async () => { // Arrange let newUserData = structuredClone(userData); newUserData.email = 'new-user@redcross.nl';