Skip to content

Commit 6f048b6

Browse files
Merge pull request #623 from DavidRajnoha/cypress-incidents-regression-charts-add-short-duration-incident
OBSINTA-777: [Incidents] Regression tests for short incidents visualisation
2 parents 4bb0127 + 5826bdb commit 6f048b6

3 files changed

Lines changed: 300 additions & 332 deletions

File tree

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

Lines changed: 153 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/*
2-
Regression test for Charts UI bugs (Section 2 of TESTING_CHECKLIST.md)
2+
Regression test for Charts UI bugs and Data Loading bugs (Sections 2 & 3.1 of TESTING_CHECKLIST.md)
33
44
This test loads comprehensive test data covering:
55
- 2.1: Tooltip Positioning Issues
66
- 2.2: Bar Sorting & Visibility Issues
77
- 2.3: Date/Time Display Issues
8+
- 3.1: Short Duration Incidents Visibility (< 5 min)
9+
810
9-
Test data: 12 incidents with 1-6 alerts each, varying durations (10m to 8h),
10-
alert names (4 to 180+ chars), multi-component and multi-severity scenarios.
1111
*/
1212

1313
import { incidentsPage } from '../../../views/incidents-page';
@@ -44,6 +44,31 @@ function verifyTooltipPositioning(
4444
}
4545
}
4646

47+
function verifyIncidentBarDimensions(index: number, context: string) {
48+
incidentsPage.getIncidentBarRect(index).then((barRect) => {
49+
expect(barRect.width, `${context} should have visible width`).to.be.greaterThan(0);
50+
expect(barRect.height, `${context} should have visible height`).to.be.greaterThan(0);
51+
});
52+
}
53+
54+
function verifyIncidentBarHasVisiblePaths(index: number, context: string) {
55+
incidentsPage.elements.incidentsChartBarsGroups()
56+
.eq(index)
57+
.find('path[role="presentation"]')
58+
.then(($paths) => {
59+
const visiblePath = $paths.filter((i, el) => {
60+
const fillOpacity = Cypress.$(el).css('fill-opacity') || Cypress.$(el).attr('fill-opacity');
61+
return parseFloat(fillOpacity || '0') > 0;
62+
}).first();
63+
64+
expect(visiblePath.length, `${context} should have visible path`).to.be.greaterThan(0);
65+
});
66+
}
67+
68+
function verifyIncidentBarIsVisible(index: number, context: string) {
69+
verifyIncidentBarDimensions(index, context);
70+
verifyIncidentBarHasVisiblePaths(index, context);
71+
}
4772
const MCP = {
4873
namespace: 'openshift-cluster-observability-operator',
4974
packageName: 'cluster-observability-operator',
@@ -78,40 +103,45 @@ describe('Regression: Charts UI - Comprehensive', () => {
78103
incidentsPage.clearAllFilters();
79104
incidentsPage.setDays('7 days');
80105
incidentsPage.elements.incidentsChartContainer().should('be.visible');
81-
incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 14);
106+
incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10);
82107

83-
// Chart order: Index 0 = newest (top), Index 13 = oldest (bottom)
84-
// 0: network-firing-short-002 (10m)
85-
// 13: version-short-name-001 (8h)
86-
87-
cy.log('1.2 Test top incident (newest) tooltip positioning');
88-
incidentsPage.getIncidentBarRect(0).then((barRect) => {
89-
incidentsPage.hoverOverIncidentBar(0);
90-
incidentsPage.elements.tooltip().then(($tooltip) => {
91-
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, 'Top incident');
92-
});
93-
});
94-
cy.log('Verified: Top incident tooltip appears above bar without overlapping');
95-
96-
cy.log('1.3 Test middle incident tooltip positioning');
97-
incidentsPage.getIncidentBarRect(7).then((barRect) => {
98-
incidentsPage.hoverOverIncidentBar(7);
99-
incidentsPage.elements.tooltip().then(($tooltip) => {
100-
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, 'Middle incident');
101-
});
102-
});
103-
cy.log('Verified: Middle incident tooltip appears above bar without overlapping');
104-
105-
cy.log('1.4 Test bottom incident (oldest) tooltip positioning');
106-
incidentsPage.getIncidentBarRect(13).then((barRect) => {
107-
incidentsPage.hoverOverIncidentBar(13);
108-
cy.window().then((win) => {
109-
incidentsPage.elements.tooltip().then(($tooltip) => {
110-
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, 'Bottom incident', win);
111-
});
112-
});
113-
});
114-
cy.log('Verified: Bottom incident tooltip appears above bar and stays within viewport');
108+
cy.log('1.1 Get total incident count for dynamic indexing');
109+
incidentsPage.elements.incidentsChartBarsGroups().its('length').then((count) => {
110+
cy.log(`Total incidents loaded: ${count}`);
111+
112+
const bottomIndex = 0;
113+
const topIndex = count - 1;
114+
const middleIndex = Math.floor(count / 2);
115+
116+
cy.log(`1.2 Test bottom incident (newest, index ${bottomIndex}) tooltip positioning`);
117+
incidentsPage.getIncidentBarRect(bottomIndex).then((barRect) => {
118+
incidentsPage.hoverOverIncidentBar(bottomIndex);
119+
incidentsPage.elements.tooltip().then(($tooltip) => {
120+
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, 'Bottom incident');
121+
});
122+
});
123+
cy.log('Verified: Bottom incident tooltip appears above bar without overlapping');
124+
125+
cy.log(`1.3 Test middle incident (index ${middleIndex}) tooltip positioning`);
126+
incidentsPage.getIncidentBarRect(middleIndex).then((barRect) => {
127+
incidentsPage.hoverOverIncidentBar(middleIndex);
128+
incidentsPage.elements.tooltip().then(($tooltip) => {
129+
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, 'Middle incident');
130+
});
131+
});
132+
cy.log('Verified: Middle incident tooltip appears above bar without overlapping');
133+
134+
cy.log(`1.4 Test top incident (oldest, index ${topIndex}) tooltip positioning`);
135+
incidentsPage.getIncidentBarRect(topIndex).then((barRect) => {
136+
incidentsPage.hoverOverIncidentBar(topIndex);
137+
cy.window().then((win) => {
138+
incidentsPage.elements.tooltip().then(($tooltip) => {
139+
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, 'Top incident', win);
140+
});
141+
});
142+
});
143+
cy.log('Verified: Top incident tooltip appears above bar and stays within viewport');
144+
});
115145

116146
cy.log('2-4: Multi-incident verification (single traversal optimization)');
117147
cy.log('3.1 Firing vs resolved incident tooltips');
@@ -178,45 +208,35 @@ describe('Regression: Charts UI - Comprehensive', () => {
178208
});
179209

180210
cy.log('5.1 Alert chart tooltip positioning');
181-
cy.log('5.2 Find and select incident with 6 alerts (etcd-six-alerts-001)');
211+
cy.log('5.2 Select incident with 6 alerts (etcd-six-alerts-001)');
182212

183-
incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => {
184-
const groupId = $group.attr('data-test');
185-
if (groupId && groupId.includes('etcd-six-alerts-001')) {
186-
cy.log(`Found etcd-six-alerts-001 at index ${index}`);
187-
incidentsPage.selectIncidentByBarIndex(index);
188-
189-
cy.log('5.2 Verify alerts chart displays alerts');
190-
incidentsPage.elements.alertsChartCard().should('be.visible');
191-
incidentsPage.elements.alertsChartBarsGroups()
192-
.should('have.length.greaterThan', 0);
193-
194-
cy.log('5.3 Test tooltip positioning for all alert bars');
195-
incidentsPage.elements.alertsChartBarsPaths()
196-
.its('length')
197-
.then((alertCount) => {
198-
cy.log(`Found ${alertCount} alert bars in chart`);
199-
200-
for (let i = 0; i < alertCount; i++) {
201-
if (i > 2) {
202-
// Expected failure for the latter alerts at this time
203-
break;
204-
}
205-
incidentsPage.getAlertBarRect(i).then((barRect) => {
206-
incidentsPage.hoverOverAlertBar(i);
207-
cy.window().then((win) => {
208-
incidentsPage.elements.alertsChartTooltip().first().then(($tooltip) => {
209-
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, `Alert ${i}`, win);
210-
});
211-
});
213+
incidentsPage.selectIncidentById('etcd-six-alerts-001');
214+
215+
cy.log('5.3 Verify alerts chart displays alerts');
216+
incidentsPage.elements.alertsChartCard().should('be.visible');
217+
incidentsPage.elements.alertsChartBarsGroups()
218+
.should('have.length.greaterThan', 0);
219+
220+
cy.log('5.4 Test tooltip positioning for all alert bars');
221+
incidentsPage.elements.alertsChartBarsVisiblePaths()
222+
.its('length')
223+
.then((alertCount) => {
224+
cy.log(`Found ${alertCount} alert bars in chart`);
225+
for (let i = 0; i < alertCount; i++) {
226+
if (i > 1) {
227+
break;
228+
}
229+
incidentsPage.getAlertBarRect(i).then((barRect) => {
230+
incidentsPage.hoverOverAlertBar(i);
231+
cy.window().then((win) => {
232+
incidentsPage.elements.alertsChartTooltip().first().then(($tooltip) => {
233+
verifyTooltipPositioning($tooltip[0].getBoundingClientRect(), barRect, `Alert ${i}`, win);
212234
});
213-
}
235+
});
214236
});
215-
cy.log('Verified: All alert tooltips appear correctly above their bars');
216-
217-
return false;
218-
}
219-
});
237+
}
238+
});
239+
cy.log('Verified: All alert tooltips appear correctly above their bars');
220240
});
221241
});
222242

@@ -226,42 +246,33 @@ describe('Regression: Charts UI - Comprehensive', () => {
226246
cy.log('Setup: Clear filters and verify all incidents loaded');
227247
incidentsPage.clearAllFilters();
228248
incidentsPage.setDays('7 days');
229-
incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 14);
230-
231-
cy.log('1.2 Verify newest incident is at top (index 0)');
232-
incidentsPage.hoverOverIncidentBar(0);
233-
234-
incidentsPage.elements.tooltip()
235-
.invoke('text')
236-
.should('contain', 'network-firing-short-002');
249+
incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10);
237250

238-
cy.log('1.3 Verify oldest incident is at bottom (index 13)');
239-
incidentsPage.hoverOverIncidentBar(13);
240-
241-
incidentsPage.elements.tooltip()
242-
.invoke('text')
243-
.should('contain', 'version-short-name-001');
244-
245-
cy.log('Verified: Incidents are sorted chronologically with newest at top, oldest at bottom');
251+
cy.log('1.1 Get total incident count');
252+
incidentsPage.elements.incidentsChartBarsGroups().its('length').then((count) => {
253+
const bottomIndex = 0;
254+
const topIndex = count - 1;
255+
256+
cy.log(`1.2 Verify newest incident is at bottom (index ${bottomIndex})`);
257+
incidentsPage.hoverOverIncidentBar(bottomIndex);
258+
259+
incidentsPage.elements.tooltip()
260+
.invoke('text')
261+
.should('contain', 'network-firing-short-002');
262+
263+
cy.log(`1.3 Verify oldest incident is at top (index ${topIndex})`);
264+
incidentsPage.hoverOverIncidentBar(topIndex);
265+
266+
incidentsPage.elements.tooltip()
267+
.invoke('text')
268+
.should('contain', 'VSN-001');
269+
270+
cy.log('Verified: Incidents are sorted chronologically with newest at bottom, oldest at top');
271+
});
246272

247273
cy.log('2.1 Short duration incidents have visible bars');
248274
cy.log('2.2 Check network-firing-short-002 (10 min duration, index 0)');
249-
incidentsPage.getIncidentBarRect(0).then((barRect) => {
250-
expect(barRect.width).to.be.greaterThan(0);
251-
expect(barRect.height).to.be.greaterThan(0);
252-
});
253-
254-
incidentsPage.elements.incidentsChartBarsGroups()
255-
.eq(0)
256-
.find('path[role="presentation"]')
257-
.then(($paths) => {
258-
const visiblePath = $paths.filter((i, el) => {
259-
const fillOpacity = Cypress.$(el).css('fill-opacity') || Cypress.$(el).attr('fill-opacity');
260-
return parseFloat(fillOpacity || '0') > 0;
261-
}).first();
262-
263-
expect(visiblePath.length).to.be.greaterThan(0);
264-
});
275+
verifyIncidentBarIsVisible(0, 'Short duration firing incident');
265276
cy.log('Verified: Short duration firing incident has visible bar and is not transparent');
266277

267278
cy.log('2.3 Find and check network-resolved-short-001 (10 min duration)');
@@ -270,21 +281,7 @@ describe('Regression: Charts UI - Comprehensive', () => {
270281
if (groupId && groupId.includes('network-resolved-short-001')) {
271282
cy.log(`Found network-resolved-short-001 at index ${index}`);
272283

273-
incidentsPage.getIncidentBarRect(index).then((barRect) => {
274-
expect(barRect.width).to.be.greaterThan(0);
275-
expect(barRect.height).to.be.greaterThan(0);
276-
});
277-
278-
cy.wrap($group)
279-
.find('path[role="presentation"]')
280-
.then(($paths) => {
281-
const visiblePath = $paths.filter((i, el) => {
282-
const fillOpacity = Cypress.$(el).css('fill-opacity') || Cypress.$(el).attr('fill-opacity');
283-
return parseFloat(fillOpacity || '0') > 0;
284-
}).first();
285-
286-
expect(visiblePath.length).to.be.greaterThan(0);
287-
});
284+
verifyIncidentBarIsVisible(index, 'Short duration resolved incident');
288285
cy.log('Verified: Short duration resolved incident has visible bar and is not transparent');
289286

290287
return false;
@@ -399,8 +396,9 @@ describe('Regression: Charts UI - Comprehensive', () => {
399396
cy.log('Verified: Tooltips display formatted date/time');
400397

401398
cy.log('4.1 Alert-level time verification in table');
402-
incidentsPage.selectIncidentByBarIndex(13);
403-
399+
cy.log('4.1.1 Select oldest incident for alert time verification');
400+
incidentsPage.selectIncidentById('VSN-001');
401+
404402
cy.log('4.2 Expand all rows to see alert details');
405403
incidentsPage.elements.incidentsTable().should('be.visible');
406404

@@ -429,5 +427,38 @@ describe('Regression: Charts UI - Comprehensive', () => {
429427
});
430428
});
431429

432-
});
430+
describe('Section 3.1: Short Duration Incidents Visibility', () => {
431+
432+
it('Very short duration incidents are visible and selectable', () => {
433+
cy.log('Setup: Clear filters and verify all incidents loaded');
434+
incidentsPage.clearAllFilters();
435+
incidentsPage.setDays('7 days');
436+
incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10);
437+
438+
cy.log('1.1 Test 5-minute duration incident (api-server-transient-001)');
439+
cy.log('1.2 Find the incident bar by ID and verify visibility');
440+
incidentsPage.elements.incidentsChartBarsGroups().then(($groups) => {
441+
const index = $groups.toArray().findIndex((el) =>
442+
el.getAttribute('data-test')?.includes('api-server-transient-001')
443+
);
444+
cy.log('1.3 Verify 1-min incident bar is visible and not transparent');
445+
verifyIncidentBarIsVisible(index, '1-min incident');
446+
});
447+
448+
cy.log('1.4 Verify incident can be selected and alerts load');
449+
incidentsPage.selectIncidentById('api-server-transient-001');
450+
incidentsPage.elements.incidentsTable().should('be.visible');
451+
incidentsPage.elements.incidentsDetailsTableRows().should('have.length.greaterThan', 0);
452+
453+
cy.log('1.5 Verify alert details are displayed');
454+
incidentsPage.getSelectedIncidentAlerts().then((alerts) => {
455+
expect(alerts.length, '1-min incident should have at least 1 alert').to.be.greaterThan(0);
456+
alerts[0].getAlertRuleCell().invoke('text').then((alertName) => {
457+
expect(alertName).to.contain('APIServerRequestLatencyBriefSpikeDetectedDuringHighTrafficPeriod001');
458+
});
459+
});
460+
cy.log('Verified: 1-minute duration incident is visible, not transparent, selectable, and loads alerts');
433461

462+
});
463+
});
464+
});

0 commit comments

Comments
 (0)