Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions e2etests/mocks/recommendation-card-metadata.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,7 @@ export const getCardMetaData = (recommendationsPage: RecommendationsPage): CardM
tableLocator: recommendationsPage.notDeallocatedInstancesTableSavingsValue,
modalColumnLocator: recommendationsPage.modalColumn6,
},
{
name: 'Obsolete Images',
savingsValue: recommendationsPage.obsoleteImagesCardSavingsValue,
seeAllBtn: recommendationsPage.obsoleteImagesSeeAllBtn,
errorLocator: recommendationsPage.obsoleteImagesError,
tableLocator: recommendationsPage.obsoleteImagesTableSavingsValue,
modalColumnLocator: recommendationsPage.modalColumn6,
},
{
{
name: 'Obsolete IPs',
savingsValue: recommendationsPage.obsoleteIPsCardSavingsValue,
seeAllBtn: recommendationsPage.obsoleteIPsSeeAllBtn,
Expand Down Expand Up @@ -174,6 +166,14 @@ export const getCardMetaData = (recommendationsPage: RecommendationsPage): CardM
seeAllBtn: recommendationsPage.resourcesWithInsecureSecurityGroupsSettingsSeeAllBtn,
errorLocator: recommendationsPage.resourcesWithInsecureSecurityGroupsSettingsError,
},
{
name: 'Snapshots with non-used Images',
savingsValue: recommendationsPage.snapshotsWithNonUsedImagesCardSavingsValue,
seeAllBtn: recommendationsPage.snapshotsWithNonUsedImagesSeeAllBtn,
errorLocator: recommendationsPage.snapshotsWithNonUsedImagesError,
tableLocator: recommendationsPage.snapshotsWithNonUsedImagesTableSavingsValue,
modalColumnLocator: undefined, //TODO: Unable to determine which column this card uses without any savings data
},
{
name: 'Under Utilized Instances',
savingsValue: recommendationsPage.underutilizedInstancesCardSavingsValue,
Expand Down
7 changes: 4 additions & 3 deletions e2etests/pages/header.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BasePage } from './base-page';
import { Locator, Page } from '@playwright/test';
import { EEnvironment } from '../types/enums';

/**
* Represents the Header component of the page.
Expand Down Expand Up @@ -68,10 +69,10 @@ export class Header extends BasePage {
getOrganizationNameForEnvironment(): string {
const env = process.env.ENVIRONMENT;
switch (env) {
case 'dev':
case 'test':
case EEnvironment.DEV:
case EEnvironment.TEST:
return 'SoftwareOne (Test Env';
case 'staging':
case EEnvironment.STAGING:
return 'Marketplace Platform';

default:
Expand Down
49 changes: 7 additions & 42 deletions e2etests/pages/recommendations-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,6 @@ export class RecommendationsPage extends BasePage {
readonly notDeallocatedInstancesSeeAllBtn: Locator;
readonly notDeallocatedInstancesError: Locator;
readonly notDeallocatedInstancesTableSavingsValue: Locator;
readonly obsoleteImagesCardSavingsValue: Locator;
readonly obsoleteImagesSeeAllBtn: Locator;
readonly obsoleteImagesError: Locator;
readonly obsoleteImagesTableSavingsValue: Locator;
readonly obsoleteIPsCardSavingsValue: Locator;
readonly obsoleteIPsSeeAllBtn: Locator;
readonly obsoleteIPsError: Locator;
Expand Down Expand Up @@ -189,6 +185,10 @@ export class RecommendationsPage extends BasePage {
readonly underutilizedRDSInstancesSeeAllBtn: Locator;
readonly underutilizedRDSInstancesError: Locator;
readonly underutilizedRDSInstancesTableSavingsValue: Locator;
readonly snapshotsWithNonUsedImagesCardSavingsValue: Locator;
readonly snapshotsWithNonUsedImagesSeeAllBtn: Locator;
readonly snapshotsWithNonUsedImagesError: Locator;
readonly snapshotsWithNonUsedImagesTableSavingsValue: Locator;

/**
* Initializes a new instance of the RecommendationsPage class.
Expand Down Expand Up @@ -323,13 +323,13 @@ export class RecommendationsPage extends BasePage {
intelligentTiering: 'Intelligent Tiering',
notAttachedVolumes: 'Not attached Volumes',
notDeallocatedInstances: 'Not deallocated Instances',
obsoleteImages: 'Obsolete images',
obsoleteIPs: 'Obsolete IPs',
obsoleteSnapshotChains: 'Obsolete snapshot chains',
obsoleteSnapshots: 'Obsolete snapshots',
publicS3Buckets: 'Public S3 buckets',
reservedInstancesOpportunities: 'Reserved instances opportunities',
resourcesWithInsecureSecurityGroupsSettings: 'Resources with insecure Security Groups settings',
snapshotsWithNonUsedImages: 'Snapshots with non-used Images',
underutilizedInstances: 'Underutilized instances',
underutilizedRDSInstances: 'Underutilized RDS Instances',
};
Expand Down Expand Up @@ -365,21 +365,6 @@ export class RecommendationsPage extends BasePage {
await this.selectFromComboBox(this.dataSourcesSelect, dataSource, true);
}

/**
* Clicks the RI/SP card on the Recommendations page.
*
* This method interacts with the `ri_spCard` locator to simulate a user clicking
* on the RI/SP card element. The action is typically used to navigate to a specific
* section or trigger functionality associated with the RI/SP card.
*
* @returns {Promise<void>} Resolves when the click action is complete.
*/
async clickRI_SPCard(): Promise<void> {
await this.page.waitForLoadState();
await this.delay(2000);
await this.ri_spCard.click();
}

/**
* Selects a category from the categories combo box.
* @param {string} category - The category to select.
Expand Down Expand Up @@ -452,27 +437,6 @@ export class RecommendationsPage extends BasePage {
await this.s3DuplicatesCard.click();
}

/**
* Retrieves the saved amount with commitments value from the page.
* Parses the text content of the saved value element into a numeric value.
*
* @returns {Promise<number>} The parsed saved amount with commitments value.
*/
async getSavedWithCommitmentsValue(): Promise<number> {
const value = await this.savedWithCommitmentsValue.textContent();
return this.parseCurrencyValue(value);
}

/**
* Retrieves the percentage of saved expenses covered with commitments.
* Extracts the text content of the relevant element.
*
* @returns {Promise<string>} The percentage value as a string.
*/
async getSavedExpensesWithCommitmentsPercentageValue(): Promise<string> {
return await this.computeExpensesWithCommitmentsValue.textContent();
}

/**
* Retrieves a currency value given its locator.
*
Expand Down Expand Up @@ -518,11 +482,12 @@ export class RecommendationsPage extends BasePage {
{ label: 'Intelligent Tiering', locator: this.intelligentTieringCardSavingsValue },
{ label: 'Not Attached Volumes', locator: this.notAttachedVolumesCardSavingsValue },
{ label: 'Not Deallocated Instances', locator: this.notDeallocatedInstancesCardSavingsValue },
{ label: 'Obsolete Images', locator: this.obsoleteImagesCardSavingsValue },
{ label: 'Obsolete IPs', locator: this.obsoleteIPsCardSavingsValue },
{ label: 'Obsolete Snapshots', locator: this.obsoleteSnapshotsCardSavingsValue },
{ label: 'Obsolete Snapshot Chains', locator: this.obsoleteSnapshotChainsCardSavingsValue },
{ label: 'Reserved Instances Opportunities', locator: this.reservedInstancesOpportunitiesCardSavingsValue },
{ label: 'Public S3 Buckets', locator: this.publicS3BucketsCardSavingsValue },
{ label: 'Snapshots With Non-used Images', locator: this.snapshotsWithNonUsedImagesCardSavingsValue},
{ label: 'Underutilized Instances', locator: this.underutilizedInstancesCardSavingsValue },
{ label: 'Underutilized RDS Instances', locator: this.underutilizedRDSInstancesCardSavingsValue },
];
Expand Down
4 changes: 2 additions & 2 deletions e2etests/tests/anomalies-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ test.describe('[MPT-14737] Anomalies Tests', { tag: ['@ui', '@anomalies'] }, ()

// Validate timestamps are reasonable (within last 14 days for safety)
const now = Math.floor(Date.now() / 1000);
const thirtyDaysAgo = now - 14 * 86400;
expect.soft(oldestTimestamp).toBeGreaterThan(thirtyDaysAgo);
const fifteenDaysAgo = now - 15 * 86400;
expect.soft(oldestTimestamp).toBeGreaterThan(fifteenDaysAgo);
expect.soft(latestTimestamp).toBeLessThanOrEqual(now);

// Validate each breakdown value is a number
Expand Down
2 changes: 1 addition & 1 deletion e2etests/tests/pools-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ test.describe('[MPT-12743] Pools Tests', { tag: ['@ui', '@pools'] }, () => {

const multiplier = extractMultiplier(await poolsPage.subPoolColumn4.first().textContent());
subPoolForecast = await poolsPage.getSubPoolForecastThisMonth(1);
expect.soft(multiplier).toBe(calculateMultiplier(subPoolForecast, subPoolLimit));
expect.soft(isWithinRoundingDrift(multiplier, calculateMultiplier(subPoolForecast, subPoolLimit), 0.1)).toBe(true);
});

await test.step('Assert that expand requiring attention does expand when sub-pools limits are exceeded', async () => {
Expand Down
126 changes: 67 additions & 59 deletions e2etests/tests/recommendations-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
await recommendationsPage.selectCategory('All');
});

test('[230511] Verify Card total savings match possible monthly savings', {tag: '@p1'}, async ({ recommendationsPage }) => {
test('[230511] Verify Card total savings match possible monthly savings', { tag: '@p1' }, async ({ recommendationsPage }) => {
let possibleMonthlySavings: number;
let cardTotalSavings: number;

Expand Down Expand Up @@ -68,6 +68,7 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
await test.step('Verify behaviour is correct if no completed duplicate checks', async () => {
debugLog('No successfully completed checks found.');

// eslint-disable-next-line playwright/no-nested-step
await test.step('Verify S3 Duplicate Finder table shows no duplicate checks message', async () => {
await recommendationsPage.clickS3DuplicatesCard();
await expect
Expand Down Expand Up @@ -99,72 +100,76 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
await expect(recommendationsPage.allCardHeadings.first()).toHaveText('Public S3 buckets');
});

test('[230598] Verify only the correct applicable services are displayed for SWO Customisation', {tag: '@p1'}, async ({ recommendationsPage }) => {
await test.step('Verify applicable services combo box options shows expected items', async () => {
await recommendationsPage.applicableServices.click();
const expectedVisibleServices = [
recommendationsPage.liAwsIAM,
recommendationsPage.liAwsEC2,
recommendationsPage.liAwsEC2EBS,
recommendationsPage.liAwsEC2VPC,
recommendationsPage.liAwsRDS,
recommendationsPage.liAwsS3,
recommendationsPage.liAwsKinesis,
recommendationsPage.liAzureCompute,
recommendationsPage.liAzureNetwork,
recommendationsPage.liGcpIAM,
recommendationsPage.liGcpCloudStorage,
];
const expectedHiddenServices = [
recommendationsPage.liAliBabaECS,
recommendationsPage.liAliBabaVPC,
recommendationsPage.liAliBabaEBS,
recommendationsPage.liAliBabaSLB,
];

for (const service of expectedVisibleServices) {
await expect.soft(service).toBeVisible();
}
for (const service of expectedHiddenServices) {
await expect.soft(service).toBeHidden();
}
});

await test.step('Verify that no AliBaba applicable services are displayed on any cards', async () => {
await recommendationsPage.liAll.click();
await recommendationsPage.allCardHeadings.last().waitFor();
const aliBabaIcons = [
recommendationsPage.aliBabaEBS_Icon,
recommendationsPage.aliBabaECS_Icon,
recommendationsPage.aliBabaSLB_Icon,
recommendationsPage.aliBabaECS_VPC_Icon,
recommendationsPage.aliBabaRDS_Icon,
];

for (const icon of aliBabaIcons) {
await expect.soft(icon).toBeHidden();
}
});
test(
'[230598] Verify only the correct applicable services are displayed for SWO Customisation',
{ tag: '@p1' },
async ({ recommendationsPage }) => {
await test.step('Verify applicable services combo box options shows expected items', async () => {
await recommendationsPage.applicableServices.click();
const expectedVisibleServices = [
recommendationsPage.liAwsIAM,
recommendationsPage.liAwsEC2,
recommendationsPage.liAwsEC2EBS,
recommendationsPage.liAwsEC2VPC,
recommendationsPage.liAwsRDS,
recommendationsPage.liAwsS3,
recommendationsPage.liAwsKinesis,
recommendationsPage.liAzureCompute,
recommendationsPage.liAzureNetwork,
recommendationsPage.liGcpIAM,
recommendationsPage.liGcpCloudStorage,
];
const expectedHiddenServices = [
recommendationsPage.liAliBabaECS,
recommendationsPage.liAliBabaVPC,
recommendationsPage.liAliBabaEBS,
recommendationsPage.liAliBabaSLB,
];

await test.step('Verify that no AliBaba applicable services are displayed in the applicable services column of the table', async () => {
await recommendationsPage.clickTableButton();
await recommendationsPage.allNameTableButtons.last().waitFor();
const cells = await recommendationsPage.applicableServicesColumn.all();
for (const service of expectedVisibleServices) {
await expect.soft(service).toBeVisible();
}
for (const service of expectedHiddenServices) {
await expect.soft(service).toBeHidden();
}
});

for (const cell of cells) {
await test.step('Verify that no AliBaba applicable services are displayed on any cards', async () => {
await recommendationsPage.liAll.click();
await recommendationsPage.allCardHeadings.last().waitFor();
const aliBabaIcons = [
recommendationsPage.aliBabaEBS_Icon,
recommendationsPage.aliBabaECS_Icon,
recommendationsPage.aliBabaSLB_Icon,
recommendationsPage.aliBabaECS_VPC_Icon,
recommendationsPage.aliBabaRDS_Icon,
];

for (const icon of aliBabaIcons) {
await expect.soft(cell.locator(icon)).toBeHidden();
await expect.soft(icon).toBeHidden();
}
}
});
});
});

await test.step('Verify that no AliBaba applicable services are displayed in the applicable services column of the table', async () => {
await recommendationsPage.clickTableButton();
await recommendationsPage.allNameTableButtons.last().waitFor();
const cells = await recommendationsPage.applicableServicesColumn.all();

for (const cell of cells) {
const aliBabaIcons = [
recommendationsPage.aliBabaEBS_Icon,
recommendationsPage.aliBabaECS_Icon,
recommendationsPage.aliBabaSLB_Icon,
recommendationsPage.aliBabaECS_VPC_Icon,
recommendationsPage.aliBabaRDS_Icon,
];
for (const icon of aliBabaIcons) {
await expect.soft(cell.locator(icon)).toBeHidden();
}
}
});
}
);

const verifyCardsAndTable = async (recommendationsPage: any, category: string, expectedCardHeadings: string[]) => {
await recommendationsPage.selectCategory(category);
Expand Down Expand Up @@ -208,16 +213,17 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
'Intelligent Tiering',
'Not attached Volumes',
'Not deallocated Instances',
'Obsolete images',
'Obsolete IPs',
'Obsolete snapshot chains',
'Obsolete snapshots',
'Public S3 buckets',
'Reserved instances opportunities',
'Snapshots with non-used Images',
'Underutilized instances',
'Underutilized RDS Instances',
];

// eslint-disable-next-line playwright/expect-expect
test('[230515] Verify all expected cards are present when All category selected', async ({ recommendationsPage }) => {
await verifyCardsAndTable(recommendationsPage, 'All', allExpectedCardHeadings);
});
Expand All @@ -239,6 +245,7 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
}
expect(errorCount, 'No cards should be displaying errors').toBe(0);
});
// eslint-disable-next-line playwright/expect-expect
test('[230518] Verify all expected cards are present when Savings category selected', async ({ recommendationsPage }) => {
const expectedCardHeadings = [
'Abandoned Amazon S3 buckets',
Expand All @@ -254,17 +261,18 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
'Intelligent Tiering',
'Not attached Volumes',
'Not deallocated Instances',
'Obsolete images',
'Obsolete IPs',
'Obsolete snapshot chains',
'Obsolete snapshots',
'Reserved instances opportunities',
'Snapshots with non-used Images',
'Underutilized instances',
'Underutilized RDS Instances',
];
await verifyCardsAndTable(recommendationsPage, 'Savings', expectedCardHeadings);
});

// eslint-disable-next-line playwright/expect-expect
test('[230519] Verify all expected cards are present when Security category selected', async ({ recommendationsPage }) => {
const expectedCardHeadings = [
'IAM users with unused console access',
Expand Down Expand Up @@ -374,13 +382,13 @@ test.describe('[MPT-11310] Recommendations page tests', { tag: ['@ui', '@recomme
'Intelligent Tiering',
'Not Attached Volumes',
'Not Deallocated Instances',
'Obsolete Images',
'Obsolete IPs',
'Obsolete Snapshot Chains',
'Obsolete Snapshots',
`Public S3 Buckets`,
'Reserved Instances Opportunities',
`Resources With Insecure Security Groups Settings`,
'Snapshots with non-used Images',
'Under Utilized Instances',
'Under Utilized RDS Instances',
];
Expand Down