Skip to content

Commit

Permalink
test: [DI-22613] - ACLP: Automate Resource Details and Notification C…
Browse files Browse the repository at this point in the history
…hanges with enhanced test coverage (#11596)

* adding resource and add chanel

* adding resource and add chanel

* adding resource and add chanel

* DI-22613:Automate Resource Details and Notification Changes

* DI-22613:Automate Resource Details and Notification Changes

* add change set

* Address review feedback
  • Loading branch information
agorthi-akamai authored Feb 6, 2025
1 parent be5d96c commit 8914a3b
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 22 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-11596-tests-1738650165686.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tests
---

ACLP: Automate Resource Details and Notification Changes with enhanced test coverage ([#11596](https://github.com/linode/manager/pull/11596))
169 changes: 148 additions & 21 deletions packages/manager/cypress/e2e/core/cloudpulse/alert-show-details.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
/**
* @file Integration Tests for the CloudPulse DBaaS Alerts Show Detail Page.
* @file Integration Tests for the CloudPulse Alerts Show Detail Page.
*
* This file contains Cypress tests that validate the display and content of the DBaaS Alerts Show Detail Page in the CloudPulse application.
* This file contains Cypress tests that validate the display and content of the Alerts Show Detail Page in the CloudPulse application.
* It ensures that all alert details, criteria, and resource information are displayed correctly.
*/
import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags';
import {
accountFactory,
alertFactory,
alertRulesFactory,
databaseFactory,
notificationChannelFactory,
regionFactory,
} from 'src/factories';
import { mockGetAccount } from 'support/intercepts/account';
import type { Flags } from 'src/featureFlags';

import {
mockGetAlertChannels,
mockGetAlertDefinitions,
mockGetAllAlertDefinitions,
} from 'support/intercepts/cloudpulse';
Expand All @@ -27,15 +30,39 @@ import {
aggregationTypeMap,
} from 'support/constants/alert';
import { ui } from 'support/ui';
import { Database } from '@linode/api-v4';
import { mockGetDatabases } from 'support/intercepts/databases';

const flags: Partial<Flags> = { aclp: { enabled: true, beta: true } };
const mockAccount = accountFactory.build();
const regions = [
regionFactory.build({
capabilities: ['Managed Databases'],
id: 'us-ord',
label: 'Chicago, IL',
country: 'us',
}),
regionFactory.build({
capabilities: ['Managed Databases'],
id: 'us-east',
label: 'Newark',
country: 'us',
}),
];

const databases: Database[] = databaseFactory.buildList(5).map((db, index) => ({
...db,
type: 'MySQL',
region: regions[index % regions.length].id,
engine: 'mysql',
}));

const alertDetails = alertFactory.build({
service_type: 'dbaas',
severity: 1,
status: 'enabled',
type: 'system',
entity_ids: ['1', '2'],
entity_ids: databases.slice(0, 4).map((db) => db.id.toString()),
rule_criteria: { rules: alertRulesFactory.buildList(2) },
});
const {
Expand All @@ -49,24 +76,23 @@ const {
updated,
} = alertDetails;
const { rules } = rule_criteria;
const regions = [
regionFactory.build({
capabilities: ['Managed Databases'],
id: 'us-ord',
label: 'Chicago, IL',
}),
regionFactory.build({
capabilities: ['Managed Databases'],
id: 'us-east',
label: 'US, Newark',
}),
];
const notificationChannels = notificationChannelFactory.build();

const verifyRowOrder = (expectedIds: string[]) => {
cy.get('[data-qa-alert-row]').then(($rows) => {
const alertRowIds = $rows
.map((index, row) => row.getAttribute('data-qa-alert-row'))
.get();
expectedIds.forEach((expectedId, index) => {
expect(alertRowIds[index]).to.equal(expectedId);
});
});
};
/**
* Integration tests for the CloudPulse DBaaS Alerts Detail Page, ensuring that the alert details, criteria, and resource information are correctly displayed and validated, including various fields like name, description, status, severity, and trigger conditions.
* Integration tests for the CloudPulse Alerts Detail Page, ensuring that the alert details, criteria, and resource information are correctly displayed and validated, including various fields like name, description, status, severity, and trigger conditions.
*/

describe('Integration Tests for Dbaas Alert Show Detail Page', () => {
describe('Integration Tests for Alert Show Detail Page', () => {
beforeEach(() => {
mockAppendFeatureFlags(flags);
mockGetAccount(mockAccount);
Expand All @@ -75,6 +101,8 @@ describe('Integration Tests for Dbaas Alert Show Detail Page', () => {
mockGetAlertDefinitions(service_type, id, alertDetails).as(
'getDBaaSAlertDefinitions'
);
mockGetDatabases(databases).as('getMockedDbaasDatabases');
mockGetAlertChannels([notificationChannels]);
});

it('navigates to the Show Details page from the list page', () => {
Expand Down Expand Up @@ -106,6 +134,7 @@ describe('Integration Tests for Dbaas Alert Show Detail Page', () => {
cy.visitWithLogin(
`/monitor/alerts/definitions/detail/${service_type}/${id}`
);
cy.wait(['@getDBaaSAlertDefinitions', '@getMockedDbaasDatabases']);

// Validating contents of Overview Section
cy.get('[data-qa-section="Overview"]').within(() => {
Expand All @@ -121,10 +150,9 @@ describe('Integration Tests for Dbaas Alert Show Detail Page', () => {
cy.findByText('Status:').should('be.visible');
cy.findByText('Enabled').should('be.visible');

cy.get('[data-qa-item="Severity"]').within(() => {
cy.findByText('Severity:').should('be.visible');
cy.findByText(severityMap[severity]).should('be.visible');
});
cy.findByText('Severity:').should('be.visible');
cy.findByText(severityMap[severity]).should('be.visible');

// Validate Service field
cy.findByText('Service:').should('be.visible');
cy.findByText('Databases').should('be.visible');
Expand Down Expand Up @@ -235,5 +263,104 @@ describe('Integration Tests for Dbaas Alert Show Detail Page', () => {
.should('be.visible')
.should('have.text', 'consecutive occurrences.');
});
// Validate the Resources section (Resource and Region columns)
cy.get('[data-qa-section="Resources"]').within(() => {
ui.heading
.findByText('resource')
.scrollIntoView()
.should('be.visible')
.should('have.text', 'Resource');

ui.heading
.findByText('region')
.should('be.visible')
.should('have.text', 'Region');

cy.findByPlaceholderText('Search for a Region or Resource').should(
'be.visible'
);

cy.findByPlaceholderText('Select Regions').should('be.visible');

cy.get('[data-qa-alert-row]').should('have.length', 4);

// Validate resource-region mapping for each row in the table

const regionMap = new Map(regions.map((r) => [r.id, r.label]));

cy.get('[data-qa-alert-row]')
.should('have.length', 4)
.each((row, index) => {
const db = databases[index];
const rowNumber = index + 1;
const regionLabel = regionMap.get(db.region) || 'Unknown Region';

cy.wrap(row).within(() => {
cy.get(`[data-qa-alert-cell="${rowNumber}_resource"]`).should(
'have.text',
db.label
);

cy.get(`[data-qa-alert-cell="${rowNumber}_region"]`).should(
'have.text',
`US, ${regionLabel} (${db.region})`
);
});
});

// Sorting by Resource and Region columns
ui.heading.findByText('resource').should('be.visible').click();
verifyRowOrder(['4', '3', '2', '1']);

ui.heading.findByText('resource').should('be.visible').click();
verifyRowOrder(['1', '2', '3', '4']);

ui.heading.findByText('region').should('be.visible').click();
verifyRowOrder(['2', '4', '1', '3']);

ui.heading.findByText('region').should('be.visible').click();
verifyRowOrder(['1', '3', '2', '4']);

// Search by Resource
cy.findByPlaceholderText('Search for a Region or Resource')
.should('be.visible')
.type(databases[0].label);

cy.get('[data-qa-alert-table="true"]')
.find('[data-qa-alert-row]')
.should('have.length', 1);

cy.findByText(databases[0].label).should('be.visible');
[1, 2, 3].forEach((i) =>
cy.findByText(databases[i].label).should('not.exist')
);

// Search by region
cy.findByPlaceholderText('Search for a Region or Resource').clear();

ui.regionSelect.find().click().type(`${regions[0].label}{enter}`);
ui.regionSelect.find().click();

cy.get('[data-qa-alert-table="true"]')
.find('[data-qa-alert-row]')
.should('have.length', 2);

[0, 2].forEach((i) =>
cy.get(`[data-qa-alert-cell="${i}_region"]`).should('not.exist')
);
[1, 3].forEach((i) =>
cy.get(`[data-qa-alert-cell="${i}_region"]`).should('be.visible')
);
});
// Validate Notification Channels Section
cy.get('[data-qa-section="Notification Channels"]').within(() => {
cy.findByText('Type:').should('be.visible');
cy.findByText('Email').should('be.visible');
cy.findByText('Channel:').should('be.visible');
cy.findByText('Channel-1').should('be.visible');
cy.findByText('To:').should('be.visible');
cy.findByText('[email protected]').should('be.visible');
cy.findByText('[email protected]').should('be.visible');
});
});
});
25 changes: 24 additions & 1 deletion packages/manager/cypress/support/intercepts/cloudpulse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { paginateResponse } from 'support/util/paginate';
import { randomString } from 'support/util/random';
import { makeResponse } from 'support/util/response';

import type { Alert } from '@linode/api-v4';
import type { Alert, NotificationChannel } from '@linode/api-v4';
import type {
CloudPulseMetricsResponse,
Dashboard,
Expand Down Expand Up @@ -307,3 +307,26 @@ export const mockGetAllAlertDefinitions = (
paginateResponse(alert)
);
};

/**
* Mocks the API response for retrieving all alert channels from the monitoring service.
* This function intercepts a GET request to fetch alert channels and returns a mock
* response, simulating the behavior of the real API by providing a list of alert channels.
*
* The mock response is created using the provided `channel` object, allowing the test
* to simulate various scenarios with different alert channel configurations.
*
* @param {NotificationChannel} channel - An object representing the notification channel to mock as the response.
* This should represent the alert channel being fetched by the API.
*
* @returns {Cypress.Chainable<null>} - A Cypress chainable object that represents the intercepted request.
*/
export const mockGetAlertChannels = (
channel: NotificationChannel[]
): Cypress.Chainable<null> => {
return cy.intercept(
'GET',
apiMatcher('/monitor/alert-channels*'),
paginateResponse(channel)
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export const AlertDetail = () => {
...getAlertBoxStyles(theme),
overflow: 'auto',
}}
data-qa-section="Resources"
>
<AlertResources
alertResourceIds={entityIds}
Expand All @@ -132,6 +133,7 @@ export const AlertDetail = () => {
...getAlertBoxStyles(theme),
overflow: 'auto',
}}
data-qa-section="Notification Channels"
>
<AlertDetailNotification
channelIds={alertDetails.channels.map(({ id }) => id)}
Expand Down

0 comments on commit 8914a3b

Please sign in to comment.