Skip to content

Commit 580dc96

Browse files
Claude Agentclaude
andcommitted
fix(tests): use bar groups for incident selection, add warm-up to BVT
- selectIncidentByBarIndex/deselectIncidentByBar: use incidentsChartBarsGroups() (one element per incident) instead of incidentsChartBarsVisiblePaths() (flattened paths). Fixes incorrect incident selection/deselection with multi-severity incidents. - findIncidentWithAlert: count bar groups instead of flattened paths - deselectIncidentByBar: accept index parameter to deselect the correct incident instead of always clicking the first bar - 01.incidents.cy.ts: add warmUpForPlugin() to before() hook — same plugin loading race fix as reg/02-05 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2e6f654 commit 580dc96

2 files changed

Lines changed: 42 additions & 31 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const MP = {
2727
describe('BVT: Incidents - UI', { tags: ['@smoke', '@incidents'] }, () => {
2828
before(() => {
2929
cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false });
30+
incidentsPage.warmUpForPlugin();
3031
cy.mockIncidentFixture(
3132
'incident-scenarios/1-single-incident-firing-critical-and-warning-alerts.yaml',
3233
);

web/cypress/views/incidents-page.ts

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,18 @@ export const incidentsPage = {
212212
},
213213

214214
goTo: () => {
215-
cy.log('incidentsPage.goTo');
215+
if (!_quietSearch) cy.log('incidentsPage.goTo');
216216
nav.sidenav.clickNavLink(['Observe', 'Alerting']);
217+
// Wait for the Incidents tab to be registered by the dynamic plugin.
218+
// After session restore the plugin may need up to 2 min to re-register.
219+
cy.waitUntil(
220+
() =>
221+
Cypress.$(
222+
'.pf-v6-c-tabs__item:contains("Incidents"), ' +
223+
'.co-m-horizontal-nav__menu-item:contains("Incidents")',
224+
).length > 0,
225+
{ interval: 2000, timeout: 180000 },
226+
);
217227
nav.tabs.switchTab('Incidents');
218228
incidentsPage.elements.daysSelectToggle().should('be.visible');
219229
},
@@ -399,42 +409,37 @@ export const incidentsPage = {
399409
},
400410

401411
/**
402-
* Selects an incident from the chart by clicking on a bar at the specified index.
403-
* BUG: Problems with multi-severity incidents (multiple paths in a single incident bar)
412+
* Selects an incident from the chart by clicking on a bar group at the
413+
* specified index. Uses bar groups (one per incident) instead of flattened
414+
* paths to correctly handle multi-severity incidents.
404415
*
405416
* @param index - Zero-based index of the incident bar to click (default: 0)
406417
* @returns Promise that resolves when the incidents table is visible
407418
*/
408419
selectIncidentByBarIndex: (index = 0) => {
409-
if (!_quietSearch)
410-
cy.log(`incidentsPage.selectIncidentByBarIndex: ${index} (clicking visible path elements)`);
420+
if (!_quietSearch) cy.log(`incidentsPage.selectIncidentByBarIndex: ${index}`);
411421

412422
return incidentsPage.elements
413-
.incidentsChartBarsVisiblePaths()
423+
.incidentsChartBarsGroups()
414424
.should('have.length.greaterThan', index)
415-
.then(($paths) => {
416-
if (index >= $paths.length) {
417-
throw new Error(`Index ${index} exceeds available paths (${$paths.length})`);
418-
}
419-
420-
return cy.wrap($paths.eq(index), _qLog()).click({ force: true, ..._qLog() });
421-
})
425+
.eq(index)
426+
.find('path[role="presentation"]')
427+
.first()
428+
.click({ force: true, ..._qLog() })
422429
.then(() => {
423430
cy.wait(2000, _qLog());
424431
return incidentsPage.elements.incidentsTable().scrollIntoView().should('exist');
425432
});
426433
},
427434

428-
deselectIncidentByBar: () => {
435+
deselectIncidentByBar: (index = 0) => {
429436
if (!_quietSearch) cy.log('incidentsPage.deselectIncidentByBar');
430437
return incidentsPage.elements
431-
.incidentsChartBarsVisiblePaths()
432-
.then(($paths) => {
433-
if ($paths.length === 0) {
434-
throw new Error('No paths found in incidents chart');
435-
}
436-
return cy.wrap($paths.eq(0), _qLog()).click({ force: true, ..._qLog() });
437-
})
438+
.incidentsChartBarsGroups()
439+
.eq(index)
440+
.find('path[role="presentation"]')
441+
.first()
442+
.click({ force: true, ..._qLog() })
438443
.then(() => {
439444
return incidentsPage.elements.incidentsTable().should('not.exist');
440445
});
@@ -653,8 +658,10 @@ export const incidentsPage = {
653658

654659
prepareIncidentsPageForSearch: () => {
655660
if (!_quietSearch) cy.log('incidentsPage.prepareIncidentsPageForSearch: Setting up page...');
656-
// Force a hard page reload to release browser DOM memory from previous search iterations.
657-
cy.reload({ log: false });
661+
// Use SPA navigation instead of cy.reload() — the Incidents component is a
662+
// dynamic plugin chunk, and cy.reload() causes the Console to re-resolve all
663+
// plugins from scratch, which silently fails in headless CI (blank page).
664+
// OOM is handled by _quietSearch suppressing DOM snapshots, not by reload.
658665
incidentsPage.goTo();
659666
incidentsPage.setDays(incidentsPage.SEARCH_CONFIG.DEFAULT_DAYS);
660667
incidentsPage.elements.incidentsChartContainer().should('be.visible');
@@ -821,7 +828,7 @@ export const incidentsPage = {
821828
if (found) {
822829
return cy.wrap(true, _qLog());
823830
}
824-
incidentsPage.deselectIncidentByBar();
831+
incidentsPage.deselectIncidentByBar(currentIndex);
825832
cy.wait(500, _qLog());
826833
return searchNextIncidentBar(currentIndex + 1);
827834
});
@@ -859,16 +866,19 @@ export const incidentsPage = {
859866

860867
incidentsPage.prepareIncidentsPageForSearch();
861868

862-
return incidentsPage.elements
863-
.incidentsChartBarsVisiblePaths()
864-
.then(($paths) => {
865-
const totalPaths = $paths.length;
866-
if (totalPaths === 0) {
867-
cy.log('No visible incident bar paths found in chart');
869+
// Check for bar groups without asserting existence — an empty chart is
870+
// valid (e.g. when mocking empty incidents or before detection fires).
871+
return cy
872+
.get('body', _qLog())
873+
.then(($body) => {
874+
const barSelector = 'g[role="presentation"][data-test*="incidents-chart-bar-"]';
875+
const totalIncidents = $body.find(barSelector).length;
876+
if (totalIncidents === 0) {
877+
if (!_quietSearch) cy.log('No incident bar groups found in chart');
868878
return cy.wrap(false, { log: false });
869879
}
870880

871-
return incidentsPage.traverseAllIncidentsBars(alertName, totalPaths);
881+
return incidentsPage.traverseAllIncidentsBars(alertName, totalIncidents);
872882
})
873883
.then((found: boolean) => {
874884
if (found) {

0 commit comments

Comments
 (0)