From 6461adce09e94394d7cf7ad27a67baac0ba94095 Mon Sep 17 00:00:00 2001 From: piotrk39 Date: Tue, 14 Jan 2025 15:27:42 +0100 Subject: [PATCH 1/2] Add testID and test base --- .../areas-of-focus-summary.component.html | 1 + tests/e2e/Pages/ActionsSummaryComponent.ts | 31 ++ .../IBF-Dashboard/TriggerScenarios.spec.ts | 296 ++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 tests/e2e/Pages/ActionsSummaryComponent.ts create mode 100644 tests/e2e/tests/IBF-Dashboard/TriggerScenarios.spec.ts diff --git a/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.html b/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.html index 4b79bb977a..91438c5c84 100644 --- a/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.html +++ b/interfaces/IBF-dashboard/src/app/components/areas-of-focus-summary/areas-of-focus-summary.component.html @@ -93,6 +93,7 @@ { + sharedPage = await browser.newPage(); + // Initialize instances after sharedPage is assigned + dashboard = new DashboardPage(sharedPage); + aggregates = new AggregatesComponent(sharedPage); + loginPage = new LoginPage(sharedPage); + chat = new ChatComponent(sharedPage); + userState = new UserStateComponent(sharedPage); + map = new MapComponent(sharedPage); + actionsSummary = new ActionsSummaryComponent(sharedPage); + + // Login + accessToken = await getAccessToken(); + await resetDB(accessToken); + + // We should maybe create one mock for all different disaster types for now we can just use floods + await mockFloods( + TriggerDataSet.TriggerScenario, + TriggerDataSet.CountryCode, + accessToken, + ); + + await sharedPage.goto('/'); + await loginPage.login(TriggerDataSet.UserMail, TriggerDataSet.UserPassword); +}); + +test.beforeEach(async () => { + await dashboard.waitForPageToBeLoadedAndStable(); +}); + +// AGGREGATES TRIGGER TESTS +// https://app.qase.io/project/IBF?case=39&previewMode=side&suite=7 +test( + qase(39, '[Trigger] Aggregated number of events should be non-zero'), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + + // get the number of warning events and aggregated events + const aggregatesEventCount = await aggregates.getNumberOfPredictedEvents(); + + // check if the number of warning events is equal to the number of aggregated events + expect(aggregatesEventCount).toBeGreaterThan(0); + await page.reload(); + }, +); + +// https://app.qase.io/project/IBF?previewMode=side&suite=7&case=40 +test(qase(40, '[Trigger] header colour is purple'), async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + + // Validate that the aggregates header is purple by class + await aggregates.validateColorOfAggregatesHeaderByClass({ + isTrigger: true, + }); + await page.reload(); +}); + +// CHAT SECTION TRIGGER TESTS +// https://app.qase.io/project/IBF?case=44&previewMode=side&suite=6 +test( + qase(44, '[Trigger] Show prediction button is clickable'), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + await chat.chatColumnIsVisibleForTriggerState({ + firstName: TriggerDataSet.firstName, + lastName: TriggerDataSet.lastName, + }); + await chat.allDefaultButtonsArePresent(); + await chat.predictionButtonsAreActive(); + await page.reload(); + }, +); + +// https://app.qase.io/project/IBF?case=43&previewMode=side&suite=6 +test( + qase(43, '[Trigger] Amount of events should equal the aggregate number'), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + await chat.chatColumnIsVisibleForTriggerState({ + firstName: TriggerDataSet.firstName, + lastName: TriggerDataSet.lastName, + }); + await chat.allDefaultButtonsArePresent(); + + // get the number of warning events and aggregated events + const chatEventCount = await chat.predictionButtonsAreActive(); + const aggregatesEventCount = await aggregates.getNumberOfPredictedEvents(); + + // check if the number of warning events is equal to the number of aggregated events + expect(chatEventCount).toEqual(aggregatesEventCount); + await page.reload(); + }, +); + +// https://app.qase.io/project/IBF?case=45&previewMode=side&suite=6 +test( + qase(45, '[Trigger] Info icon is clickable and opens popover'), + async ({ page }) => { + const dashboard = new DashboardPage(sharedPage); + const userState = new UserStateComponent(sharedPage); + const chat = new ChatComponent(sharedPage); + + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + await chat.chatColumnIsVisibleForTriggerState({ + firstName: TriggerDataSet.firstName, + lastName: TriggerDataSet.lastName, + }); + await chat.validateEventsInfoButtonsAreClickable(); + await page.reload(); + }, +); + +// MAP TRIGGER TESTS +// https://app.qase.io/project/IBF?previewMode=side&suite=3&tab=&case=37 +test( + qase( + 37, + '[Trigger] Map layer: "Flood extent" and "Exposed population" should be active by default', + ), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + // Wait for the sharedPage to load + await dashboard.waitForLoaderToDisappear(); + + await map.mapComponentIsVisible(); + + await map.clickLayerMenu(); + await map.isLayerMenuOpen({ layerMenuOpen: true }); + await map.verifyLayerCheckboxCheckedByName({ + layerName: 'Flood extent', + }); + await map.verifyLayerRadioButtonCheckedByName({ + layerName: 'Exposed population', + }); + // Validate legend + await map.isLegendOpen({ legendOpen: true }); + await map.assertLegendElementIsVisible({ + legendComponentName: 'Flood extent', + }); + await map.assertLegendElementIsVisible({ + legendComponentName: 'Exposed population', + }); + // Validatge that the layer checked with radio button is visible on the map in this case 'Exposed population' only one such layer can be checked at a time + await map.validateAggregatePaneIsNotEmpty(); + // Validate rest of the map + await map.validateLayerIsVisibleInMapBySrcElement({ + layerName: 'flood_extent', + }); + await page.reload(); + }, +); + +// https://app.qase.io/project/IBF?previewMode=side&suite=3&tab=&case=35 +test( + qase( + 35, + '[Trigger] Flood extent legend is visible when flood extent layer is active', + ), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + // Wait for the sharedPage to load + await dashboard.waitForLoaderToDisappear(); + + await map.mapComponentIsVisible(); + await map.isLegendOpen({ legendOpen: true }); + await map.assertLegendElementIsVisible({ + legendComponentName: 'Flood extent', + }); + await page.reload(); + }, +); + +// https://app.qase.io/project/IBF?case=38&previewMode=side&suite=3 +test( + qase( + 38, + '[Trigger] At least one red/orange/yellow GloFAS station should be visible', + ), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + // Wait for the sharedPage to load + await dashboard.waitForLoaderToDisappear(); + + await map.mapComponentIsVisible(); + await map.isLegendOpen({ legendOpen: true }); + await map.isLayerMenuOpen({ layerMenuOpen: false }); + await map.clickLayerMenu(); + await map.verifyLayerCheckboxCheckedByName({ + layerName: 'Glofas stations', + }); + await map.assertLegendElementIsVisible({ + legendComponentName: 'GloFAS No action', + }); + + // At least one red/orange/yellow GloFAS station should be visible by default in trigger mode + await map.gloFASMarkersAreVisibleByWarning({ + glosfasStationStatus: 'glofas-station-max-trigger', + isVisible: true, + }); + await page.reload(); + }, +); + +// ACTIONS SUMMARY TRIGGER TESTS +// https://app.qase.io/project/IBF?previewMode=side&suite=24&case=46 +test( + qase( + 46, + '[Trigger] Info icon is clickable and opens popover in Actions summary', + ), + async ({ page }) => { + // Navigate to disaster type the data was mocked for + await dashboard.navigateToFloodDisasterType(); + // Assertions + await userState.headerComponentIsVisible({ + countryName: TriggerDataSet.CountryName, + }); + // Wait for the sharedPage to load + await dashboard.waitForLoaderToDisappear(); + + await actionsSummary.validateActionsSummaryInfoButtons(); + await page.reload(); + }, +); + +test.afterAll(async () => { + await sharedPage.close(); +}); From d43e53fe52d222194094208f163c0f41ab154719 Mon Sep 17 00:00:00 2001 From: piotrk39 Date: Tue, 21 Jan 2025 14:46:21 +0100 Subject: [PATCH 2/2] Add test validations and dashboard functions --- tests/e2e/Pages/ActionsSummaryComponent.ts | 10 +++++++++- tests/e2e/Pages/DashboardPage.ts | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Pages/ActionsSummaryComponent.ts b/tests/e2e/Pages/ActionsSummaryComponent.ts index b0dd8ddeef..c72376269d 100644 --- a/tests/e2e/Pages/ActionsSummaryComponent.ts +++ b/tests/e2e/Pages/ActionsSummaryComponent.ts @@ -1,5 +1,6 @@ import { Locator, Page } from 'playwright'; +import areasOfFocus from '../../../services/API-service/src/scripts/json/areas-of-focus.json'; import DashboardPage from './DashboardPage'; class ActionsSummaryComponent extends DashboardPage { @@ -21,8 +22,15 @@ class ActionsSummaryComponent extends DashboardPage { for (let i = 0; i < counttoolTipInfoButton; i++) { const toolTipInfoButton = this.tooltipButton.nth(i); + const descriptionText = areasOfFocus[i].description?.replace( + /
|
    |
  • ||<\/ul>|<\/li>|<\/strong>/g, + '', + ); + await toolTipInfoButton.click(); - // await this.validatePopOverText({ text: eventTooltipContent }); + await this.page.waitForTimeout(200); + await this.validateLabel({ text: areasOfFocus[i].label }); + await this.validateDescription({ text: descriptionText }); await this.page.getByTestId('close-matrix-icon').click(); } } diff --git a/tests/e2e/Pages/DashboardPage.ts b/tests/e2e/Pages/DashboardPage.ts index 3e5ccb11ff..96e1a06d44 100644 --- a/tests/e2e/Pages/DashboardPage.ts +++ b/tests/e2e/Pages/DashboardPage.ts @@ -12,6 +12,8 @@ class DashboardPage { readonly countrySwitcherDropdownOption: Locator; readonly dashboardDevControlCloseButton: Locator; readonly loader: Locator; + readonly tooltipLabel: Locator; + readonly tooltipContent: Locator; constructor(page: Page) { this.page = page; @@ -32,6 +34,8 @@ class DashboardPage { 'dashboard-dev-control-close-button', ); this.loader = this.page.getByTestId('loader'); + this.tooltipLabel = this.page.getByTestId('layer-info-title'); + this.tooltipContent = this.page.getByTestId('layer-info-content'); } getRandomInt(min: number, max: number): number { @@ -75,6 +79,16 @@ class DashboardPage { expect(popOverTextTrimmed).toContain(text); } + async validateLabel({ text }: { text: string }) { + const label = await this.tooltipLabel.textContent(); + expect(label).toContain(text); + } + + async validateDescription({ text }: { text: string }) { + const description = await this.tooltipContent.textContent(); + expect(description).toContain(text); + } + async waitForPageToBeLoadedAndStable() { await this.page.waitForLoadState('domcontentloaded'); await this.page.waitForTimeout(500);