diff --git a/services/API-service/test/email/dengue/email-phl-dengue.test.ts b/services/API-service/test/email/dengue/email-phl-dengue.test.ts new file mode 100644 index 000000000..6f72513ce --- /dev/null +++ b/services/API-service/test/email/dengue/email-phl-dengue.test.ts @@ -0,0 +1,29 @@ +import { EpidemicsScenario } from '../../../src/scripts/enum/mock-scenario.enum'; +import { getAccessToken, resetDB } from '../../helpers/utility.helper'; +import { testDengueScenario } from './test-dengue-scenario.helper'; + +const countryCodeISO3 = 'PHL'; +describe('Should send an email for phl dengue', () => { + let accessToken: string; + + beforeEach(async () => { + accessToken = await getAccessToken(); + await resetDB(accessToken); + }); + + it('default', async () => { + await testDengueScenario( + EpidemicsScenario.Default, + countryCodeISO3, + accessToken, + ); + }); + + it('no-trigger', async () => { + await testDengueScenario( + EpidemicsScenario.NoTrigger, + countryCodeISO3, + accessToken, + ); + }); +}); diff --git a/services/API-service/test/email/dengue/test-dengue-scenario.helper.ts b/services/API-service/test/email/dengue/test-dengue-scenario.helper.ts new file mode 100644 index 000000000..dd8e1818b --- /dev/null +++ b/services/API-service/test/email/dengue/test-dengue-scenario.helper.ts @@ -0,0 +1,70 @@ +import { JSDOM } from 'jsdom'; + +import { DisasterType } from '../../../src/api/disaster/disaster-type.enum'; +import { EpidemicsScenario } from '../../../src/scripts/enum/mock-scenario.enum'; +import { + getEventTitle, + mockEpidemics, + sendNotification, +} from '../../helpers/utility.helper'; + +export async function testDengueScenario( + scenario: EpidemicsScenario, + countryCodeISO3: string, + accessToken: string, +): Promise { + const eventNames = ['0-month', '1-month', '2-month']; + const disasterTypeLabel = DisasterType.Dengue; + + const mockResult = await mockEpidemics( + scenario, + countryCodeISO3, + accessToken, + ); + // Act + const response = await sendNotification( + countryCodeISO3, + DisasterType.Dengue, + accessToken, + ); + // Assert + // Also checking the status of the mockResult here as I think it also breaks often + expect(mockResult.status).toBe(202); + expect(response.status).toBe(201); + + if (scenario === EpidemicsScenario.Default) { + expect(response.body.activeEvents.email).toBeDefined(); + } else { + expect(response.body.activeEvents.email).toBeUndefined(); + } + + expect(response.body.activeEvents.whatsapp).toBeFalsy(); + expect(response.body.finishedEvents).toBeFalsy(); + + // Parse the HTML content + const dom = new JSDOM(response.body.activeEvents.email); + const document = dom.window.document; + + // Get all span elements with apiTest="eventName" and their lower case text content + const eventNamesInEmail = Array.from( + document.querySelectorAll('span[apiTest="eventName"]'), + (el) => (el as Element).textContent.toLowerCase(), + ).map((el) => el.trim()); + + if (scenario === EpidemicsScenario.Default) { + expect(eventNamesInEmail.length).toBe(eventNames.length); + } else { + expect(eventNamesInEmail.length).toBe(0); + } + + if (scenario === EpidemicsScenario.Default) { + // Check if each expected event name is included in at least one title + for (const eventName of eventNames) { + const eventTitle = getEventTitle(disasterTypeLabel, eventName); + const hasEvent = eventNamesInEmail.some((eventNameInEmail) => + eventNameInEmail.includes(eventTitle), + ); + expect(hasEvent).toBe(true); + } + } +} diff --git a/services/API-service/test/email/flash-flood/email-mwi-flash-flood.test.ts b/services/API-service/test/email/flash-flood/email-mwi-flash-flood.test.ts new file mode 100644 index 000000000..92f651fb0 --- /dev/null +++ b/services/API-service/test/email/flash-flood/email-mwi-flash-flood.test.ts @@ -0,0 +1,29 @@ +import { FlashFloodsScenario } from '../../../src/scripts/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 () => { + accessToken = await getAccessToken(); + await resetDB(accessToken); + }); + + it('default', async () => { + await testFlashFloodScenario( + FlashFloodsScenario.Default, + countryCodeISO3, + accessToken, + ); + }); + + it('no-trigger', async () => { + await testFlashFloodScenario( + FlashFloodsScenario.NoTrigger, + countryCodeISO3, + accessToken, + ); + }); +}); diff --git a/services/API-service/test/email/flash-flood/test-flash-flood-scenario.helper.ts b/services/API-service/test/email/flash-flood/test-flash-flood-scenario.helper.ts new file mode 100644 index 000000000..0fa5a763d --- /dev/null +++ b/services/API-service/test/email/flash-flood/test-flash-flood-scenario.helper.ts @@ -0,0 +1,70 @@ +import { JSDOM } from 'jsdom'; + +import { DisasterType } from '../../../src/api/disaster/disaster-type.enum'; +import { FlashFloodsScenario } from '../../../src/scripts/enum/mock-scenario.enum'; +import { + getEventTitle, + mockFlashFlood, + sendNotification, +} from '../../helpers/utility.helper'; + +export async function testFlashFloodScenario( + scenario: FlashFloodsScenario, + countryCodeISO3: string, + accessToken: string, +): Promise { + const eventNames = ['Rumphi', 'Rumphi', 'Karonga']; + const disasterTypeLabel = 'Flash Flood'; // DisasterType.FlashFloods does not match + + const mockResult = await mockFlashFlood( + scenario, + countryCodeISO3, + accessToken, + ); + // Act + const response = await sendNotification( + countryCodeISO3, + DisasterType.FlashFloods, + accessToken, + ); + // Assert + // Also checking the status of the mockResult here as I think it also breaks often + expect(mockResult.status).toBe(202); + expect(response.status).toBe(201); + + if (scenario === FlashFloodsScenario.Default) { + expect(response.body.activeEvents.email).toBeDefined(); + } else { + expect(response.body.activeEvents.email).toBeUndefined(); + } + + expect(response.body.activeEvents.whatsapp).toBeFalsy(); + expect(response.body.finishedEvents).toBeFalsy(); + + // Parse the HTML content + const dom = new JSDOM(response.body.activeEvents.email); + const document = dom.window.document; + + // Get all span elements with apiTest="eventName" and their lower case text content + const eventNamesInEmail = Array.from( + document.querySelectorAll('span[apiTest="eventName"]'), + (el) => (el as Element).textContent.toLowerCase(), + ).map((el) => el.trim()); + + if (scenario === FlashFloodsScenario.Default) { + expect(eventNamesInEmail.length).toBe(eventNames.length); + } else { + expect(eventNamesInEmail.length).toBe(0); + } + + if (scenario === FlashFloodsScenario.Default) { + // Check if each expected event name is included in at least one title + for (const eventName of eventNames) { + const eventTitle = getEventTitle(disasterTypeLabel, eventName); + const hasEvent = eventNamesInEmail.some((eventNameInEmail) => + eventNameInEmail.includes(eventTitle), + ); + expect(hasEvent).toBe(true); + } + } +} diff --git a/services/API-service/test/email/malaria/email-eth-malaria.test.ts b/services/API-service/test/email/malaria/email-eth-malaria.test.ts new file mode 100644 index 000000000..b99f0fe4a --- /dev/null +++ b/services/API-service/test/email/malaria/email-eth-malaria.test.ts @@ -0,0 +1,29 @@ +import { EpidemicsScenario } from '../../../src/scripts/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 () => { + accessToken = await getAccessToken(); + await resetDB(accessToken); + }); + + it('default', async () => { + await testMalariaScenario( + EpidemicsScenario.Default, + countryCodeISO3, + accessToken, + ); + }); + + it('no-trigger', async () => { + await testMalariaScenario( + EpidemicsScenario.NoTrigger, + countryCodeISO3, + accessToken, + ); + }); +}); diff --git a/services/API-service/test/email/malaria/test-malaria-scenario.helper.ts b/services/API-service/test/email/malaria/test-malaria-scenario.helper.ts new file mode 100644 index 000000000..0b5b2390e --- /dev/null +++ b/services/API-service/test/email/malaria/test-malaria-scenario.helper.ts @@ -0,0 +1,70 @@ +import { JSDOM } from 'jsdom'; + +import { DisasterType } from '../../../src/api/disaster/disaster-type.enum'; +import { EpidemicsScenario } from '../../../src/scripts/enum/mock-scenario.enum'; +import { + getEventTitle, + mockEpidemics, + sendNotification, +} from '../../helpers/utility.helper'; + +export async function testMalariaScenario( + scenario: EpidemicsScenario, + countryCodeISO3: string, + accessToken: string, +): Promise { + const eventNames = ['0-month', '1-month', '2-month']; + const disasterTypeLabel = DisasterType.Malaria; + + const mockResult = await mockEpidemics( + scenario, + countryCodeISO3, + accessToken, + ); + // Act + const response = await sendNotification( + countryCodeISO3, + DisasterType.Malaria, + accessToken, + ); + // Assert + // Also checking the status of the mockResult here as I think it also breaks often + expect(mockResult.status).toBe(202); + expect(response.status).toBe(201); + + if (scenario === EpidemicsScenario.Default) { + expect(response.body.activeEvents.email).toBeDefined(); + } else { + expect(response.body.activeEvents.email).toBeUndefined(); + } + + expect(response.body.activeEvents.whatsapp).toBeFalsy(); + expect(response.body.finishedEvents).toBeFalsy(); + + // Parse the HTML content + const dom = new JSDOM(response.body.activeEvents.email); + const document = dom.window.document; + + // Get all span elements with apiTest="eventName" and their lower case text content + const eventNamesInEmail = Array.from( + document.querySelectorAll('span[apiTest="eventName"]'), + (el) => (el as Element).textContent.toLowerCase(), + ).map((el) => el.trim()); + + if (scenario === EpidemicsScenario.Default) { + expect(eventNamesInEmail.length).toBe(eventNames.length); + } else { + expect(eventNamesInEmail.length).toBe(0); + } + + if (scenario === EpidemicsScenario.Default) { + // Check if each expected event name is included in at least one title + for (const eventName of eventNames) { + const eventTitle = getEventTitle(disasterTypeLabel, eventName); + const hasEvent = eventNamesInEmail.some((eventNameInEmail) => + eventNameInEmail.includes(eventTitle), + ); + expect(hasEvent).toBe(true); + } + } +} diff --git a/services/API-service/test/helpers/utility.helper.ts b/services/API-service/test/helpers/utility.helper.ts index 24d89f880..7198933cd 100644 --- a/services/API-service/test/helpers/utility.helper.ts +++ b/services/API-service/test/helpers/utility.helper.ts @@ -3,6 +3,8 @@ import TestAgent from 'supertest/lib/agent'; import { DisasterType } from '../../src/api/disaster/disaster-type.enum'; import { + EpidemicsScenario, + FlashFloodsScenario, FloodsScenario, TyphoonScenario, } from '../../src/scripts/enum/mock-scenario.enum'; @@ -65,6 +67,42 @@ export function mockFloods( }); } +export function mockEpidemics( + scenario: EpidemicsScenario, + countryCodeISO3: string, + accessToken: string, +): Promise { + return getServer() + .post('/mock/epidemics') + .set('Authorization', `Bearer ${accessToken}`) + .query({ isApiTest: true }) + .send({ + scenario, + secret: process.env.RESET_SECRET, + removeEvents: true, + date: new Date(), + countryCodeISO3, + }); +} + +export function mockFlashFlood( + scenario: FlashFloodsScenario, + countryCodeISO3: string, + accessToken: string, +): Promise { + return getServer() + .post('/mock/flash-floods') + .set('Authorization', `Bearer ${accessToken}`) + .query({ isApiTest: true }) + .send({ + scenario, + secret: process.env.RESET_SECRET, + removeEvents: true, + date: new Date(), + countryCodeISO3, + }); +} + export function mockTyphoon( scenario: TyphoonScenario, countryCodeISO3: string,