Skip to content

Commit 895428d

Browse files
Merge pull request #854 from DavidRajnoha/test/incident-detection-stability
NO-JIRA: Incident Detection Tests Stabilization
2 parents dd34c12 + 495f5ab commit 895428d

10 files changed

Lines changed: 141 additions & 61 deletions

File tree

web/cypress.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default defineConfig({
5252
typeDelay: 200,
5353
},
5454
fixturesFolder: 'cypress/fixtures',
55+
pageLoadTimeout: 60000,
5556
defaultCommandTimeout: 80000, //due to performance loading issue on console
5657
readyTimeoutMilliseconds: 120000,
5758
installTimeoutMilliseconds: 600000,

web/cypress/e2e/incidents/01.incidents.cy.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
The test verifies the basic functionality of the Incidents page and serves
33
as a verification that the Incidents View is working as expected.
44
5-
Currently, it depends on an alert being present in the cluster.
6-
In the future, mocking requests / injecting alerts should be considered.
7-
Natural creation of the alert is done in the 00.coo_incidents_e2e.cy.ts test,
8-
but takes significant time.
5+
All tests use mocked data. Tests 1-3 use a default fixture (incident content
6+
is irrelevant for toolbar/filter verification). Tests 4-5 switch mocks
7+
mid-test for empty state and traversal scenarios.
98
*/
109

11-
import { commonPages } from '../../views/common';
1210
import { incidentsPage } from '../../views/incidents-page';
1311

1412
const MCP = {
@@ -26,24 +24,13 @@ const MP = {
2624
operatorName: 'Cluster Monitoring Operator',
2725
};
2826

29-
const ALERTNAME = 'Watchdog';
30-
const NAMESPACE = 'openshift-monitoring';
31-
const SEVERITY = 'Critical';
32-
const ALERT_DESC = 'This is an alert meant to ensure that the entire alerting pipeline is functional. This alert is always firing, therefore it should always be firing in Alertmanager and always fire against a receiver. There are integrations with various notification mechanisms that send a notification when this alert is not firing. For example the "DeadMansSnitch" integration in PagerDuty.'
33-
const ALERT_SUMMARY = 'An alert that should always be firing to certify that Alertmanager is working properly.'
3427
describe('BVT: Incidents - UI', { tags: ['@smoke', '@incidents'] }, () => {
3528
before(() => {
3629
cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false });
30+
cy.mockIncidentFixture('incident-scenarios/1-single-incident-firing-critical-and-warning-alerts.yaml');
3731
});
3832

3933

40-
beforeEach(() => {
41-
cy.log('Navigate to Observe → Incidents');
42-
incidentsPage.goTo();
43-
// Temporary workaround for testing against locally built instances.
44-
cy.transformMetrics();
45-
});
46-
4734
it('1. Admin perspective - Incidents page - Toolbar and charts toggle functionality', () => {
4835
cy.log('1.1 Verify toolbar and toggle charts button');
4936
incidentsPage.elements.toolbar().should('be.visible');
@@ -80,24 +67,23 @@ describe('BVT: Incidents - UI', { tags: ['@smoke', '@incidents'] }, () => {
8067
cy.log('4.1 Verify chart titles are visible');
8168
incidentsPage.elements.incidentsChartTitle().should('be.visible');
8269
incidentsPage.elements.alertsChartTitle().should('be.visible');
83-
8470
cy.log('4.2 Verify alerts chart shows empty state');
8571
incidentsPage.elements.alertsChartEmptyState().should('exist');
8672
});
8773

8874
it('5. Admin perspective - Incidents page - Traverse Incident Table', () => {
75+
incidentsPage.goTo();
76+
8977
cy.log('5.1 Traverse incident table');
90-
incidentsPage.clearAllFilters();
9178
cy.mockIncidents([]);
9279
incidentsPage.findIncidentWithAlert('TargetAlert').should('be.false');
9380

9481
cy.log('5.2 Verify traversing incident table works when the alert is not present');
9582
cy.mockIncidentFixture('incident-scenarios/1-single-incident-firing-critical-and-warning-alerts.yaml');
9683
incidentsPage.findIncidentWithAlert('TargetAlert').should('be.false');
9784

98-
incidentsPage.clearAllFilters
9985
cy.log('5.3 Verify traversing incident table works when the alert is present');
10086
cy.mockIncidentFixture('incident-scenarios/6-multi-incident-target-alert-scenario.yaml');
101-
incidentsPage.findIncidentWithAlert('TargetAlert').should('be.true');
87+
incidentsPage.findIncidentWithAlert('TargetAlert').should('be.true');
10288
});
10389
});

web/cypress/e2e/incidents/regression/01.reg_filtering.cy.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ describe('Regression: Incidents Filtering', { tags: ['@incidents'] }, () => {
3232
});
3333

3434
beforeEach(() => {
35-
cy.log('Navigate to Observe → Incidents');
36-
incidentsPage.goTo();
3735
cy.log('Setting up comprehensive filtering test scenarios');
3836
cy.mockIncidentFixture('incident-scenarios/7-comprehensive-filtering-test-scenarios.yaml');
3937
});

web/cypress/e2e/incidents/regression/02.reg_ui_charts_comprehensive.cy.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ describe('Regression: Charts UI - Comprehensive', { tags: ['@incidents'] }, () =
9292
});
9393

9494
beforeEach(() => {
95-
incidentsPage.goTo();
9695
cy.mockIncidentFixture('incident-scenarios/12-charts-ui-comprehensive.yaml');
9796
});
9897

web/cypress/e2e/incidents/regression/03-04.reg_e2e_firing_alerts.cy.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ const MP = {
3636
describe('Regression: Time-Based Alert Resolution (E2E with Firing Alerts)', { tags: ['@incidents', '@slow', '@e2e-real'] }, () => {
3737
let currentAlertName: string;
3838

39+
3940
before(() => {
4041
cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false });
4142

42-
cy.log('Create or reuse firing alert for testing');
43-
cy.createKubePodCrashLoopingAlert('TimeBasedResolution2').then((alertName) => {
43+
cy.log('Create firing alert for testing');
44+
cy.cleanupIncidentPrometheusRules();
45+
cy.createKubePodCrashLoopingAlert().then((alertName) => {
4446
currentAlertName = alertName;
4547
cy.log(`Test will monitor alert: ${currentAlertName}`);
4648
});
@@ -50,6 +52,7 @@ describe('Regression: Time-Based Alert Resolution (E2E with Firing Alerts)', { t
5052
it('1. Section 3.3 - Alert not incorrectly marked as resolved after time passes', () => {
5153
cy.log('1.1 Navigate to Incidents page and clear filters');
5254
incidentsPage.goTo();
55+
cy.wait(10000);
5356
incidentsPage.clearAllFilters();
5457

5558
const intervalMs = 60_000;
@@ -161,6 +164,7 @@ describe('Regression: Time-Based Alert Resolution (E2E with Firing Alerts)', { t
161164
it('2. Section 4.7 - Prometheus query end time updates to current time on filter refresh', () => {
162165
cy.log('2.1 Navigate to Incidents page and clear filters');
163166
incidentsPage.goTo();
167+
cy.wait(10000);
164168
incidentsPage.clearAllFilters();
165169

166170
cy.log('2.2 Capture initial page load time');
@@ -262,6 +266,7 @@ describe('Regression: Time-Based Alert Resolution (E2E with Firing Alerts)', { t
262266
it('3. Verify alert lifecycle - alert continues firing throughout test', () => {
263267
cy.log('3.1 Navigate to Incidents page');
264268
incidentsPage.goTo();
269+
cy.wait(10000);
265270
incidentsPage.clearAllFilters();
266271

267272
cy.log('3.2 Search for and select incident with custom alert');

web/cypress/e2e/incidents/regression/03.reg_api_calls.cy.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ describe('Regression: Silences Not Applied Correctly', { tags: ['@incidents'] },
3333
});
3434

3535
beforeEach(() => {
36-
cy.log('Navigate to Observe → Incidents');
37-
incidentsPage.goTo();
3836
cy.log('Setting up silenced alerts mixed scenario');
3937
cy.mockIncidentFixture('incident-scenarios/9-silenced-alerts-mixed-scenario.yaml');
4038
});

web/cypress/e2e/incidents/regression/04.reg_redux_effects.cy.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ describe('Regression: Redux State Management', { tags: ['@incidents', '@incident
3737
});
3838

3939
beforeEach(() => {
40-
cy.log('Navigate to Observe → Incidents');
41-
incidentsPage.goTo();
4240
cy.log('Setting up comprehensive filtering test scenarios');
4341
cy.mockIncidentFixture('incident-scenarios/7-comprehensive-filtering-test-scenarios.yaml');
4442
});
@@ -144,10 +142,8 @@ describe('Regression: Redux State Management', { tags: ['@incidents', '@incident
144142
it('3. Adding filter when incident selected should not remove the incident ID filter', () => {
145143
cy.log('3.1 Clear all filters and ensure critical incidents exist');
146144
incidentsPage.clearAllFilters();
147-
148145
cy.log('3.2 Apply critical severity filter');
149146
incidentsPage.toggleFilter('Critical');
150-
151147
incidentsPage.elements.incidentsChartBarsGroups().should('have.length.greaterThan', 0);
152148

153149
cy.log('3.3 Click on the first critical incident to select it by ID');
@@ -161,9 +157,12 @@ describe('Regression: Redux State Management', { tags: ['@incidents', '@incident
161157
cy.log('3.5 Verify both Critical and Incident ID chips are present');
162158
incidentsPage.elements.filterChipValue('Critical').should('be.visible');
163159
incidentsPage.elements.incidentIdFilterChip().should('be.visible');
164-
160+
165161
cy.log('3.6 Deselect Critical and Apply Warning filter (which does not match the critical incident)');
162+
cy.wait(500);
166163
incidentsPage.toggleFilter('Critical');
164+
incidentsPage.elements.filterChipValue('Critical').should('not.exist');
165+
167166
incidentsPage.toggleFilter('Warning');
168167

169168
cy.log('3.7 Verify incident is filtered out (no bars visible)');
@@ -177,7 +176,9 @@ describe('Regression: Redux State Management', { tags: ['@incidents', '@incident
177176
cy.log('SUCCESS: Incident ID filter was not removed when non-matching severity filter was added');
178177

179178
cy.log('3.9 Remove Warning filter and verify incident reappears');
180-
incidentsPage.toggleFilter('Warning');
179+
// Legacy path for quick rollback:
180+
// incidentsPage.toggleFilter('Warning');
181+
incidentsPage.deselectFilterValue('Warning');
181182

182183
cy.log('3.10 With only Incident ID filter, incident should be visible again');
183184
incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 1);

web/cypress/support/incidents_prometheus_query_mocks/prometheus-mocks.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { IncidentDefinition, PrometheusResponse, IncidentScenarioFixture } from './types';
22
import { createIncidentMock, createAlertDetailsMock } from './mock-generators';
33
import { convertFixtureToIncidents, parseYamlFixture } from './schema/fixture-converter';
4+
import { incidentsPage } from '../../views/incidents-page';
45

56
declare global {
67
namespace Cypress {
@@ -63,9 +64,15 @@ export function mockPrometheusQueryRange(incidents: IncidentDefinition[]): void
6364
console.log(`Responding with ${results.length} incident alerts from ${incidents.length} incidents`);
6465
req.reply(response);
6566

66-
});
67+
}).as('prometheusQueryMock');
6768
}
6869

70+
/**
71+
* Mock commands: register intercepts and navigate via goTo() to trigger a fresh data fetch.
72+
* Using SPA navigation instead of cy.reload() avoids the dynamic-plugin chunk loading
73+
* race condition that causes flaky empty-page failures in headless CI.
74+
*/
75+
6976
Cypress.Commands.add('mockIncidents', (incidents: IncidentDefinition[]) => {
7077
cy.log(`=== SETTING UP INCIDENT MOCKING (${incidents.length} incidents) ===`);
7178
if (!Array.isArray(incidents)) {
@@ -81,8 +88,7 @@ Cypress.Commands.add('mockIncidents', (incidents: IncidentDefinition[]) => {
8188

8289
cy.log(`=== SETTING UP INCIDENT MOCKING (${incidents.length} incidents) ===`);
8390
mockPrometheusQueryRange(incidents);
84-
// The mocking is not applied until the page is reloaded and the components fetch the new data
85-
cy.reload();
91+
incidentsPage.goTo();
8692
});
8793

8894
Cypress.Commands.add('mockIncidentFixture', (fixturePath: string) => {
@@ -101,9 +107,8 @@ Cypress.Commands.add('mockIncidentFixture', (fixturePath: string) => {
101107
});
102108
}
103109

104-
105-
// The mocking is not applied until the page is reloaded and the components fetch the new data
106-
cy.reload();
110+
incidentsPage.goTo();
111+
cy.wait('@prometheusQueryMock', { timeout: 30000 });
107112
});
108113

109114
Cypress.Commands.add('transformMetrics', () => {

0 commit comments

Comments
 (0)