Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: typhoon-track back-end unit and integration tests #1831

Merged
merged 11 commits into from
Dec 23, 2024
130 changes: 130 additions & 0 deletions services/API-service/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions services/API-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -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<TyphoonTrackEntity>;

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);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,15 @@ 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,
lastTriggeredDate.timestamp,
),
),
};
if (eventName) {
filters['eventName'] = eventName;
}
return filters;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 2 additions & 3 deletions tests/integration/fixtures/users.const.ts
Original file line number Diff line number Diff line change
@@ -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: '[email protected]',
username: 'dunant',
Expand Down
18 changes: 18 additions & 0 deletions tests/integration/helpers/API-service/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Loading
Loading