From aa7ec07ac3ebcaa88f9b2e239b689e2e79e69e22 Mon Sep 17 00:00:00 2001 From: Dyostiq <15174395+Dyostiq@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:47:46 +0200 Subject: [PATCH] test(api): add e2e test for setting and getting marxan input --- .../api/test/scenarios/input-file.e2e-spec.ts | 241 ++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 api/apps/api/test/scenarios/input-file.e2e-spec.ts diff --git a/api/apps/api/test/scenarios/input-file.e2e-spec.ts b/api/apps/api/test/scenarios/input-file.e2e-spec.ts new file mode 100644 index 0000000000..5be61abbb4 --- /dev/null +++ b/api/apps/api/test/scenarios/input-file.e2e-spec.ts @@ -0,0 +1,241 @@ +import { PromiseType } from 'utility-types'; +import { Repository } from 'typeorm'; +import * as request from 'supertest'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { + ClumpType, + HeuristicType, + IterativeImprovementType, + MarxanParameters, + RunMode, +} from '@marxan/marxan-input'; +import { Scenario } from '@marxan-api/modules/scenarios/scenario.api.entity'; +import { bootstrapApplication } from '../utils/api-application'; +import { GivenUserIsLoggedIn } from '../steps/given-user-is-logged-in'; +import { GivenProjectExists } from '../steps/given-project'; +import { ScenariosTestUtils } from '../utils/scenarios.test.utils'; +import { E2E_CONFIG } from '../e2e.config'; + +let fixtures: PromiseType>; + +beforeEach(async () => { + fixtures = await getFixtures(); +}); + +afterEach(async () => { + await fixtures.cleanup(); +}); + +describe(`when a user updates scenario with input data`, () => { + let scenarioId: string; + beforeEach(async () => { + // given + scenarioId = await fixtures.GivenScenarioExists(); + + // when + await fixtures.WhenUpdatesScenarioWithInput( + scenarioId, + fixtures.scenarioMetadata, + ); + }); + + // then + it(`should return the same metadata to user`, async () => { + await fixtures.ThenScenarioHasMetadata( + scenarioId, + fixtures.scenarioMetadata, + ); + }); +}); + +describe(`when a user updates scenario with input data with verbosity`, () => { + let scenarioId: string; + beforeEach(async () => { + // given + scenarioId = await fixtures.GivenScenarioExists(); + + // when + await fixtures.WhenUpdatesScenarioWithInput( + scenarioId, + fixtures.scenarioMetadataWithVerbosity, + ); + }); + + // then + it(`should return set metdata but without verbosity`, async () => { + await fixtures.ThenScenarioHasMetadata( + scenarioId, + fixtures.scenarioMetadata, + ); + }); +}); + +describe(`when a user updates scenario with input data with input keys`, () => { + let scenarioId: string; + beforeEach(async () => { + // given + scenarioId = await fixtures.GivenScenarioExists(); + + // when + await fixtures.WhenUpdatesScenarioWithInput( + scenarioId, + fixtures.scenarioMetadataWithInputKeys, + ); + }); + + // then + it(`should return set metdata but without input keys`, async () => { + await fixtures.ThenScenarioHasMetadata( + scenarioId, + fixtures.scenarioMetadata, + ); + }); +}); + +describe(`when a user updates scenario with invalid input data`, () => { + let scenarioId: string; + let result: request.Response; + beforeEach(async () => { + // given + scenarioId = await fixtures.GivenScenarioExists(); + + // when + result = await fixtures.WhenUpdatesScenarioWithInput( + scenarioId, + fixtures.scenarioMetadataInvalid, + ); + }); + + // then + it(`should return not changed metadata to user`, async () => { + await fixtures.ThenScenarioHasMetadata(scenarioId, { + metadata: null, + }); + }); + + // and + it(`should reject the request`, async () => { + await fixtures.ThenRequestWasRejected(result); + }); +}); + +async function getFixtures() { + const app = await bootstrapApplication(); + const cleanups: (() => Promise)[] = [() => app.close()]; + const scenarios = app.get>(getRepositoryToken(Scenario)); + let jwtToken: string; + const fixtures = { + async GivenScenarioExists() { + jwtToken = await GivenUserIsLoggedIn(app); + const { projectId, cleanup } = await GivenProjectExists(app, jwtToken); + cleanups.push(cleanup); + const scenario = await ScenariosTestUtils.createScenario(app, jwtToken, { + ...E2E_CONFIG.scenarios.valid.minimal(), + projectId, + }); + cleanups.push(() => scenarios.delete(scenario.data.id)); + return scenario.data.id; + }, + async cleanup() { + for (const cleanup of cleanups.reverse()) { + await cleanup(); + } + }, + get scenarioMetadata() { + const params: MarxanParameters = { + BLM: 2, + PROP: 1.5, + RANDSEED: -1.5, + BESTSCORE: 2, + NUMREPS: 12, + NUMITNS: 1000003, + STARTTEMP: 1000004, + COOLFAC: 5, + NUMTEMP: 10006, + COSTTHRESH: 7, + THRESHPEN1: 8, + THRESHPEN2: 9, + RUNMODE: RunMode.HeuristicAndIterativeImprovement, + MISSLEVEL: 11, + ITIMPTYPE: IterativeImprovementType.NormalFollowedByTwoStep, + HEURTYPE: HeuristicType.Greedy, + CLUMPTYPE: ClumpType.GraduatedPenalty, + }; + return { + metadata: { + marxanInputParameterFile: params, + }, + }; + }, + get scenarioMetadataWithVerbosity() { + const metadata = fixtures.scenarioMetadata; + (metadata.metadata.marxanInputParameterFile as any).VERBOSITY = 2; + return metadata; + }, + get scenarioMetadataWithInputKeys() { + const metadata = fixtures.scenarioMetadata; + (metadata.metadata.marxanInputParameterFile as any).INPUTDIR = 'inputdir'; + (metadata.metadata.marxanInputParameterFile as any).SPECNAME = 'specname'; + (metadata.metadata.marxanInputParameterFile as any).PUNAME = 'puname'; + (metadata.metadata.marxanInputParameterFile as any).PUVSPRNAME = + 'puvsprname'; + (metadata.metadata.marxanInputParameterFile as any).BOUNDNAME = + 'boundname'; + (metadata.metadata.marxanInputParameterFile as any).BLOCKDEFNAME = + 'blockdefname'; + return metadata; + }, + get scenarioMetadataInvalid() { + const metadata = fixtures.scenarioMetadata; + metadata.metadata.marxanInputParameterFile.NUMITNS = 'dir' as any; + return metadata; + }, + async WhenUpdatesScenarioWithInput( + id: string, + input: { + metadata: { + marxanInputParameterFile: MarxanParameters; + }; + }, + ) { + return await request(app.getHttpServer()) + .patch(`/api/v1/scenarios/${id}`) + .set('Authorization', `Bearer ${jwtToken}`) + .send(input); + }, + async ThenScenarioHasMetadata(id: string, metadata: any) { + const result = await request(app.getHttpServer()) + .get(`/api/v1/scenarios/${id}`) + .set('Authorization', `Bearer ${jwtToken}`) + .send() + .then((response) => response.body); + + expect(result).toStrictEqual({ + data: { + attributes: { + boundaryLengthModifier: null, + createdAt: expect.any(String), + description: null, + id, + lastModifiedAt: expect.any(String), + name: expect.any(String), + numberOfRuns: null, + projectId: expect.any(String), + protectedAreaFilterByIds: null, + status: null, + type: 'marxan', + wdpaIucnCategories: null, + wdpaThreshold: null, + ...metadata, + }, + id, + type: 'scenarios', + }, + }); + }, + ThenRequestWasRejected(result: request.Response) { + expect(result.status).toBe(400); + }, + }; + return fixtures; +}