Skip to content

Commit

Permalink
get countries for projects
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeh committed Oct 28, 2024
1 parent 74c6d98 commit 62e6bd4
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 10 deletions.
17 changes: 9 additions & 8 deletions api/src/modules/projects/projects.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ export class ProjectsController {
return { body: data, status: HttpStatus.OK };
});
}

@TsRestHandler(projectsContract.getProjectCountries)
async getProjectCountries(): ControllerResponse {
return tsRestHandler(projectsContract.getProjectCountries, async () => {
const data = await this.projectsService.getProjectCountries();
return { body: { data }, status: HttpStatus.OK };
});
}

@TsRestHandler(projectsContract.getProject)
async getProject(): ControllerResponse {
return tsRestHandler(
Expand All @@ -25,12 +34,4 @@ export class ProjectsController {
},
);
}

@TsRestHandler(projectsContract.getProjectCountries)
async getProjectCountries(): ControllerResponse {
return tsRestHandler(projectsContract.getProjectCountries, async () => {
const data = await this.projectsService.getProjectCountries();
return { body: { data }, status: HttpStatus.OK };
});
}
}
6 changes: 5 additions & 1 deletion api/src/modules/projects/projects.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ export class ProjectsService extends AppBaseService<

async getProjectCountries(): Promise<CountryWithNoGeometry[]> {
const projects = await this.projectRepository.find();

const countryCodes = projects.map((p) => p.countryCode);
const [countries] = await this.countryService.findAll({
filter: { code: In(projects.map((p) => p.countryCode)) },
filter: { code: countryCodes },
omitFields: ['geometry'],
disablePagination: true,
});

return countries as CountryWithNoGeometry[];
}
}
80 changes: 80 additions & 0 deletions api/test/integration/projects/projects.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { TestManager } from '../../utils/test-manager';
import { HttpStatus } from '@nestjs/common';
import { projectsContract } from '@shared/contracts/projects.contract';
import { Country } from '@shared/entities/country.entity';
import { Project } from '@shared/entities/projects.entity';

describe('Projects', () => {
let testManager: TestManager;

beforeAll(async () => {
testManager = await TestManager.createTestManager();
await testManager.ingestCountries();
});

afterEach(async () => {
await testManager.getDataSource().getRepository(Project).delete({});
});

afterAll(async () => {
await testManager.clearDatabase();
await testManager.close();
});

describe('Get Projects', () => {
test('Should return a list of Projects', async () => {
const countries = await testManager
.getDataSource()
.getRepository(Country)
.find();

const projects: Project[] = [];
for (const country of countries.slice(countries.length / 2)) {
projects.push(
await testManager
.mocks()
.createProject({ countryCode: country.code }),
);
}

const response = await testManager
.request()
.get(projectsContract.getProjects.path)
.query({ disablePagination: true });

expect(response.status).toBe(HttpStatus.OK);
expect(response.body.data.length).toBe(projects.length);
});
});

describe('Filters for Projects', () => {
test('Should get a list of countries there are projects in', async () => {
const fiveCountriesWithNoGeometry = await testManager
.getDataSource()
.getRepository(Country)
.find()
.then((countries) =>
countries.slice(0, 5).map((c) => {
const { geometry, ...rest } = c;
return rest;
}),
);

const projects: Project[] = [];
for (const country of fiveCountriesWithNoGeometry) {
projects.push(
await testManager
.mocks()
.createProject({ countryCode: country.code }),
);
}
const response = await testManager
.request()
.get(projectsContract.getProjectCountries.path);

expect(fiveCountriesWithNoGeometry).toEqual(
expect.arrayContaining(response.body.data),
);
});
});
});
9 changes: 8 additions & 1 deletion api/test/utils/test-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ import { User } from '@shared/entities/users/user.entity';
import { IEmailServiceToken } from '@api/modules/notifications/email/email-service.interface';
import { MockEmailService } from './mocks/mock-email.service';
import { ROLES } from '@shared/entities/users/roles.enum';
import { createBaseData, createUser } from '@shared/lib/entity-mocks';
import {
createBaseData,
createProject,
createUser,
} from '@shared/lib/entity-mocks';
import { clearTestDataFromDatabase } from '@shared/lib/db-helpers';
import * as path from 'path';
import * as fs from 'fs';
import { BaseData } from '@shared/entities/base-data.entity';
import { Project } from '@shared/entities/projects.entity';
/**
* @description: Abstraction for NestJS testing workflow. For now its a basic implementation to create a test app, but can be extended to encapsulate
* common testing utilities
Expand Down Expand Up @@ -105,6 +110,8 @@ export class TestManager {
createUser(this.getDataSource(), additionalData),
createBaseData: async (additionalData?: Partial<BaseData>) =>
createBaseData(this.getDataSource(), additionalData),
createProject: async (additionalData?: Partial<Project>) =>
createProject(this.getDataSource(), additionalData),
};
}
}
36 changes: 36 additions & 0 deletions shared/lib/entity-mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import {
BaseData,
ECOSYSTEM,
} from "@shared/entities/base-data.entity";
import {
Project,
PROJECT_PRICE_TYPE,
PROJECT_SIZE_FILTER,
} from "@shared/entities/projects.entity";
import { Country } from "@shared/entities/country.entity";

export const createUser = async (
dataSource: DataSource,
Expand Down Expand Up @@ -35,3 +41,33 @@ export const createBaseData = async (

return dataSource.getRepository(BaseData).save(baseData);
};

export const createProject = async (
dataSource: DataSource,
additionalData?: DeepPartial<Project>,
): Promise<Project> => {
const countries = await dataSource.getRepository(Country).find();
if (!countries.length) {
throw new Error("No countries in the database");
}
const defaultProjectData: Partial<Project> = {
projectName: "Test Project" + Math.random().toString(36).substring(7),
countryCode: countries[0].code,
activity: ACTIVITY.CONSERVATION,
ecosystem: ECOSYSTEM.MANGROVE,
activitySubtype: "Planting",
projectSize: 100,
projectSizeFilter: PROJECT_SIZE_FILTER.LARGE,
abatementPotential: 100,
totalCostNPV: 100,
totalCost: 100,
costPerTCO2eNPV: 100,
costPerTCO2e: 100,
initialPriceAssumption: "$100",
priceType: PROJECT_PRICE_TYPE.MARKET_PRICE,
};

return dataSource
.getRepository(Project)
.save({ ...defaultProjectData, ...additionalData });
};

0 comments on commit 62e6bd4

Please sign in to comment.