diff --git a/.claude/commands/cypress/cypress-run.md b/.claude/commands/cypress/cypress-run.md index 85fe2943f..ca6d007b4 100644 --- a/.claude/commands/cypress/cypress-run.md +++ b/.claude/commands/cypress/cypress-run.md @@ -1,5 +1,5 @@ --- -name: cypress-run +name: cypress-run description: Display Cypress test commands - choose execution mode (headless recommended) parameters: - name: execution-mode @@ -10,7 +10,8 @@ parameters: # Cypress Test Commands -**Prerequisites**: +**Prerequisites**: + 1. Run `/cypress-setup` first to configure your environment. 2. Ensure the "Cypress Tests" terminal window is open (created by `/cypress-setup`) @@ -31,25 +32,28 @@ parameters: All npm commands should be executed in the "Cypress Tests" terminal using the helper scripts: **macOS:** + ```bash ./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run " ``` **Linux:** + ```bash ./.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh --run "npm run " ``` **Instructions**: Based on the `execution-mode` parameter provided by the user: + - If `execution-mode` is "interactive": Display ONLY the "Interactive Mode" section below - If `execution-mode` is "headless": display ONLY the "Headless Mode" section with interactive options to be chosen - If `execution-mode` is "headed": display ONLY the "Headed Mode" section with interactive options to be chosen **IMPORTANT**: Always execute the selected command using the appropriate script: + - macOS: `./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run ""` - Linux: `./.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh --run ""` - --- # Interactive Mode @@ -59,6 +63,7 @@ All npm commands should be executed in the "Cypress Tests" terminal using the he ## What is Interactive Mode? Interactive mode opens the Cypress Test Runner UI where you can: + - Browse and select tests visually - Watch tests run in real-time with time-travel debugging - Inspect DOM snapshots at each step @@ -71,16 +76,19 @@ Interactive mode opens the Cypress Test Runner UI where you can: **Open Cypress Interactive UI (run in Cypress Tests terminal):** macOS: + ```bash ./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run cypress:open" ``` Linux: + ```bash ./.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh --run "npm run cypress:open" ``` This opens a visual interface where you can: + 1. Choose a browser (Chrome, Firefox, Edge, Electron) 2. Browse your test files 3. Click any test to run it @@ -113,10 +121,12 @@ All commands below run tests in headless mode (no visible browser). **IMPORTANT**: Before showing test commands, you MUST dynamically read: ### 1. Available NPM Scripts + Read `web/package.json` and extract all scripts matching `test-cypress-*` and `cypress:*` patterns. Present them as available test suite commands. -### 2. Available Test Spec Files +### 2. Available Test Spec Files + Scan `web/cypress/e2e/` directory recursively and list all `.cy.ts` files. Present them as available spec file targets for `--spec` option. @@ -125,21 +135,25 @@ Present them as available spec file targets for `--spec` option. ## Quick Reference - Base Commands **Run with npm script (if defined in package.json):** + ```bash npm run ``` **Run all tests headless:** + ```bash npm run cypress:run ``` **Run specific spec file:** + ```bash npm run cypress:run -- --spec "cypress/e2e/.cy.ts" ``` **Run with custom tags:** + ```bash npm run cypress:run -- --env grepTags="" ``` @@ -149,10 +163,12 @@ npm run cypress:run -- --env grepTags="" ## NPM Scripts from package.json **Instructions**: Read `web/package.json` and list ALL scripts that start with: + - `test-cypress-*` (predefined test suites) - `cypress:*` (base cypress commands) For each script found, display: + ```bash npm run ``` @@ -166,6 +182,7 @@ Add a brief description based on the grepTags or other flags in the script defin **Instructions**: Scan `web/cypress/e2e/` recursively and organize by folder: For each `.cy.ts` file found, show the command: + ```bash npm run cypress:run -- --spec "cypress/e2e/" ``` @@ -177,29 +194,30 @@ Group files by their parent folder (monitoring, coo, perses, virtualization, inc ## Custom Tag Combinations - Headless **Base command for custom tags:** + ```bash npm run cypress:run -- --env grepTags="YOUR_TAGS_HERE" ``` **Tag Operators:** -- `+` = AND (e.g., `@alerts+@smoke` = alerts AND smoke) -- `--` = NOT (e.g., `@monitoring --@flaky` = monitoring but NOT flaky) -- `,` = OR (e.g., `@alerts,@metrics` = alerts OR metrics) + +- `+` = AND (e.g., `@alerting+@metrics` = alerts AND metrics) +- `--` = NOT (e.g., `@alerting --@flaky` = alerting but NOT flaky) +- `,` = OR (e.g., `@alerting,@metrics` = alerts OR metrics) **Common tag patterns:** -| Goal | Command | -|------|---------| -| Smoke tests only | `npm run cypress:run -- --env grepTags="@smoke"` | +| Goal | Command | +| ------------- | -------------------------------------------------------- | | Exclude flaky | `npm run cypress:run -- --env grepTags=" --@flaky"` | -| Exclude demo | `npm run cypress:run -- --env grepTags=" --@demo"` | -| Fast smoke | `npm run cypress:run -- --env grepTags="@smoke --@slow --@flaky"` | +| Exclude slow | `npm run cypress:run -- --env grepTags=" --@slow"` | --- ## Running Multiple Spec Files **Comma-separate spec paths:** + ```bash npm run cypress:run -- --spec "cypress/e2e/.cy.ts,cypress/e2e/.cy.ts" ``` @@ -209,6 +227,7 @@ npm run cypress:run -- --spec "cypress/e2e/.cy.ts,cypress/e2e/.cy. ## Advanced Headless Options **Run with specific browser:** + ```bash npm run cypress:run -- --browser firefox npm run cypress:run -- --browser edge @@ -216,11 +235,13 @@ npm run cypress:run -- --browser chrome ``` **Disable video recording:** + ```bash npm run cypress:run -- --config video=false ``` **Disable screenshots:** + ```bash npm run cypress:run -- --config screenshotOnRunFailure=false ``` @@ -234,11 +255,13 @@ All commands below open a visible browser window. ## Quick Start - Headed **Interactive Mode (Cypress UI, pick tests manually):** + ```bash npm run cypress:open ``` **Base headed mode command:** + ```bash npm run cypress:run -- --headed ``` @@ -249,11 +272,13 @@ npm run cypress:run -- --headed **IMPORTANT**: Before showing test commands, you MUST dynamically read: -### 1. Available Test Spec Files +### 1. Available Test Spec Files + Scan `web/cypress/e2e/` directory recursively and list all `.cy.ts` files. Present them as available spec file targets with `--headed` flag. ### 2. Available Tags + Extract grepTags patterns from `web/package.json` scripts to show common tag combinations. --- @@ -261,17 +286,16 @@ Extract grepTags patterns from `web/package.json` scripts to show common tag com ## Running Test Suites - Headed To run any tag-based suite in headed mode, add `--headed` flag: + ```bash npm run cypress:run -- --headed --env grepTags="" ``` **Examples based on common tags:** + ```bash # Monitoring tests (headed) -npm run cypress:run -- --headed --env grepTags="@monitoring --@flaky" - -# Smoke tests (headed) -npm run cypress:run -- --headed --env grepTags="@smoke --@flaky" +npm run cypress:run -- --headed --env grepTags="@alerting @metrics @legacy-dashboards @targets --@flaky" # COO tests (headed) npm run cypress:run -- --headed --env grepTags="@coo --@flaky" @@ -282,11 +306,13 @@ npm run cypress:run -- --headed --env grepTags="@coo --@flaky" ## Running Specific Files - Headed **Template:** + ```bash npm run cypress:run -- --headed --spec "cypress/e2e/.cy.ts" ``` **Instructions**: Scan `web/cypress/e2e/` and for each `.cy.ts` file, the headed command is: + ```bash npm run cypress:run -- --headed --spec "cypress/e2e/" ``` @@ -296,6 +322,7 @@ npm run cypress:run -- --headed --spec "cypress/e2e/" ## Advanced Headed Options **Headed with specific browser:** + ```bash npm run cypress:run -- --headed --browser chrome npm run cypress:run -- --headed --browser firefox @@ -303,6 +330,7 @@ npm run cypress:run -- --headed --browser edge ``` **Headed without video:** + ```bash npm run cypress:run -- --headed --config video=false ``` @@ -314,27 +342,21 @@ npm run cypress:run -- --headed --config video=false Use these tags with `--env grepTags`: **Feature Tags:** -- `@monitoring` - Core monitoring plugin tests -- `@monitoring-dev` - Developer user tests -- `@alerts` - Alert-related tests + +- `@acm-alerting` - Alert-related tests in ACM perspective +- `@alerting` - Alert-related tests +- `@legacy-dashboards` - Legacy dashboard tests - `@metrics` - Metrics explorer tests -- `@dashboards` - Legacy dashboard tests -- `@perses` - Perses dashboard tests +- `@perses-dashboards` - Perses dashboard tests - `@coo` - Observability Operator tests -- `@acm` - Advanced Cluster Management tests - `@virtualization` - OpenShift Virtualization tests - `@cluster-health-analyzer` - Incidents feature tests +- `@targets` - Targets page tests **Modifier Tags:** -- `@smoke` - Quick smoke tests + - `@slow` - Longer running tests - `@flaky` - Known flaky tests -- `@demo` - Demo/showcase tests - -**Tag Operators:** -- `+` = AND (e.g., `@alerts+@smoke` = alerts AND smoke) -- `--` = NOT (e.g., `@monitoring --@flaky` = monitoring but NOT flaky) -- `,` = OR (e.g., `@alerts,@metrics` = alerts OR metrics) --- @@ -349,25 +371,25 @@ Use these tags with `--env grepTags`: All cypress commands should be executed in the "Cypress Tests" terminal using: **macOS:** + ```bash ./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "" ``` **Linux:** + ```bash ./.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh --run "" ``` **Examples:** -```bash -# Run smoke tests (macOS) -./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run test-cypress-smoke" +```bash # Run specific spec file (macOS) ./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run cypress:run -- --spec 'cypress/e2e/monitoring/00.bvt_admin.cy.ts'" # Run with custom tags (macOS) -./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run cypress:run -- --env grepTags='@monitoring --@flaky'" +./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run cypress:run -- --env grepTags='@alerting @legacy-dashboards @metrics @targets --@flaky'" # Open interactive mode (macOS) ./.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh --run "npm run cypress:open" diff --git a/.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh b/.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh index 07b430089..2e343e01b 100755 --- a/.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh +++ b/.claude/commands/cypress/scripts/open-cypress-terminal-linux.sh @@ -26,7 +26,6 @@ Examples: $(basename "$0") # Open terminal and source export-env.sh $(basename "$0") --configure # Run configure-env.sh interactively $(basename "$0") --run "npm run cypress:open" # Run a cypress command - $(basename "$0") --run "npm run test-cypress-smoke" # Run smoke tests EOF } @@ -84,10 +83,10 @@ open_terminal() { echo "Using terminal: $terminal" case "$terminal" in - gnome-terminal) open_gnome_terminal "$cmd" ;; - konsole) open_konsole "$cmd" ;; - xfce4-terminal) open_xfce4_terminal "$cmd" ;; - xterm) open_xterm "$cmd" ;; + gnome-terminal) open_gnome_terminal "$cmd" ;; + konsole) open_konsole "$cmd" ;; + xfce4-terminal) open_xfce4_terminal "$cmd" ;; + xterm) open_xterm "$cmd" ;; esac } @@ -98,48 +97,47 @@ main() { while [[ $# -gt 0 ]]; do case "$1" in - --configure) - mode="configure" - shift - ;; - --run) - mode="run" - cmd="${2:-}" - if [[ -z "$cmd" ]]; then - echo "Error: --run requires a command argument" >&2 - exit 1 - fi - shift 2 - ;; - --help|-h) - show_usage - exit 0 - ;; - *) - echo "Unknown option: $1" >&2 - show_usage + --configure) + mode="configure" + shift + ;; + --run) + mode="run" + cmd="${2:-}" + if [[ -z "$cmd" ]]; then + echo "Error: --run requires a command argument" >&2 exit 1 - ;; + fi + shift 2 + ;; + --help | -h) + show_usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + show_usage + exit 1 + ;; esac done case "$mode" in - source) - echo "Opening '$TERMINAL_NAME' terminal..." - open_terminal "source ./export-env.sh && echo '✅ Environment loaded from export-env.sh' && echo 'You can now run Cypress tests.'" - ;; - configure) - echo "Opening '$TERMINAL_NAME' terminal with configuration..." - open_terminal "./configure-env.sh && source ./export-env.sh && echo '' && echo '✅ Environment configured and loaded.'" - ;; - run) - echo "Opening '$TERMINAL_NAME' terminal and running: $cmd" - open_terminal "source ./export-env.sh && $cmd" - ;; + source) + echo "Opening '$TERMINAL_NAME' terminal..." + open_terminal "source ./export-env.sh && echo '✅ Environment loaded from export-env.sh' && echo 'You can now run Cypress tests.'" + ;; + configure) + echo "Opening '$TERMINAL_NAME' terminal with configuration..." + open_terminal "./configure-env.sh && source ./export-env.sh && echo '' && echo '✅ Environment configured and loaded.'" + ;; + run) + echo "Opening '$TERMINAL_NAME' terminal and running: $cmd" + open_terminal "source ./export-env.sh && $cmd" + ;; esac echo "Done." } main "$@" - diff --git a/.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh b/.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh index 68510100d..6671ef988 100755 --- a/.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh +++ b/.claude/commands/cypress/scripts/open-cypress-terminal-macos.sh @@ -26,7 +26,6 @@ Examples: $(basename "$0") # Open terminal and source export-env.sh $(basename "$0") --configure # Run configure-env.sh interactively $(basename "$0") --run "npm run cypress:open" # Run a cypress command - $(basename "$0") --run "npm run test-cypress-smoke" # Run smoke tests EOF } @@ -91,71 +90,70 @@ main() { while [[ $# -gt 0 ]]; do case "$1" in - --configure) - mode="configure" - shift - ;; - --run) - mode="run" - cmd="${2:-}" - if [[ -z "$cmd" ]]; then - echo "Error: --run requires a command argument" >&2 - exit 1 - fi - shift 2 - ;; - --help|-h) - show_usage - exit 0 - ;; - *) - echo "Unknown option: $1" >&2 - show_usage + --configure) + mode="configure" + shift + ;; + --run) + mode="run" + cmd="${2:-}" + if [[ -z "$cmd" ]]; then + echo "Error: --run requires a command argument" >&2 exit 1 - ;; - esac - done - - case "$mode" in - source) - local existing_id - existing_id=$(find_cypress_terminal) - if [[ -n "$existing_id" ]]; then - echo "Found existing '$TERMINAL_NAME' terminal, reusing it..." - run_in_existing_terminal "source ./export-env.sh && echo '✅ Environment reloaded.'" - else - echo "Opening new '$TERMINAL_NAME' terminal..." - open_with_source fi + shift 2 ;; - configure) - local existing_id - existing_id=$(find_cypress_terminal) - if [[ -n "$existing_id" ]]; then - echo "Found existing '$TERMINAL_NAME' terminal, running configure-env.sh..." - run_in_existing_terminal "./configure-env.sh && source ./export-env.sh && echo '' && echo '✅ Environment reconfigured.'" - else - echo "Opening new '$TERMINAL_NAME' terminal with configuration..." - open_with_configure - fi + --help | -h) + show_usage + exit 0 ;; - run) - local existing_id - existing_id=$(find_cypress_terminal) - if [[ -n "$existing_id" ]]; then - echo "Running command in '$TERMINAL_NAME' terminal: $cmd" - run_in_existing_terminal "$cmd" - else - echo "No '$TERMINAL_NAME' terminal found. Opening new one first..." - open_with_source - sleep 1 - run_in_existing_terminal "$cmd" - fi + *) + echo "Unknown option: $1" >&2 + show_usage + exit 1 ;; + esac + done + + case "$mode" in + source) + local existing_id + existing_id=$(find_cypress_terminal) + if [[ -n "$existing_id" ]]; then + echo "Found existing '$TERMINAL_NAME' terminal, reusing it..." + run_in_existing_terminal "source ./export-env.sh && echo '✅ Environment reloaded.'" + else + echo "Opening new '$TERMINAL_NAME' terminal..." + open_with_source + fi + ;; + configure) + local existing_id + existing_id=$(find_cypress_terminal) + if [[ -n "$existing_id" ]]; then + echo "Found existing '$TERMINAL_NAME' terminal, running configure-env.sh..." + run_in_existing_terminal "./configure-env.sh && source ./export-env.sh && echo '' && echo '✅ Environment reconfigured.'" + else + echo "Opening new '$TERMINAL_NAME' terminal with configuration..." + open_with_configure + fi + ;; + run) + local existing_id + existing_id=$(find_cypress_terminal) + if [[ -n "$existing_id" ]]; then + echo "Running command in '$TERMINAL_NAME' terminal: $cmd" + run_in_existing_terminal "$cmd" + else + echo "No '$TERMINAL_NAME' terminal found. Opening new one first..." + open_with_source + sleep 1 + run_in_existing_terminal "$cmd" + fi + ;; esac echo "Done." } main "$@" - diff --git a/.cursor/commands/generate-regression-test.md b/.cursor/commands/generate-regression-test.md index 12a819076..8af627c75 100644 --- a/.cursor/commands/generate-regression-test.md +++ b/.cursor/commands/generate-regression-test.md @@ -14,6 +14,7 @@ Generate automated regression tests from test documentation in [`docs/incident_d **Input**: Section number (e.g., "Section 2.1", "1.2", "3") **Actions**: + - Read test flow files from [`docs/incident_detection/tests/`](../../docs/incident_detection/tests/) (e.g., `1.filtering_flows.md`, `2.ui_display_flows.md`) - Locate the specified section by number - Extract: @@ -26,18 +27,21 @@ Generate automated regression tests from test documentation in [`docs/incident_d ### 2. Analyze Test Requirements **Extract from documentation**: + - **Test data needs**: What incidents, alerts, severities are required - **Test actions**: User interactions (clicks, hovers, filters, selections) - **Assertions**: Expected outcomes (visibility, counts, content, positions) - **Edge cases**: Special scenarios to verify **Design test flows following Cypress e2e best practices**: + - **Think user journeys**: How would a real user interact with this feature? - **Combine related actions**: Don't split filtering, verification, and interaction into separate tests - **Prefer comprehensive flows**: Each `it()` should test a complete, realistic workflow - **Avoid unit test mindset**: Don't create many tiny isolated tests **Map to existing patterns**: + - Identify which `incidentsPage` elements/methods are needed - Identify any missing page object functionality - Determine fixture requirements @@ -49,14 +53,15 @@ Generate automated regression tests from test documentation in [`docs/incident_d **Naming convention**: `XX-descriptive-name.yaml` (e.g., `13-tooltip-positioning-scenarios.yaml`) **Process**: + 1. Check if appropriate fixture exists for the test requirements 2. If missing, prompt user: ``` Fixture not found for this test scenario. - + Required test data: - [List incidents, alerts, severities needed] - + Should I create a fixture using the generate-incident-fixture command? ``` 3. If user approves, delegate to `generate-incident-fixture` command @@ -70,11 +75,13 @@ Generate automated regression tests from test documentation in [`docs/incident_d **File location**: `web/cypress/e2e/incidents/regression/` **Naming convention**: `XX.reg_.cy.ts` + - Use next available number (check existing files) - Convert section title to kebab-case - Examples: `05.reg_tooltip_positioning.cy.ts`, `06.reg_silence_matching.cy.ts` **File structure**: + ```typescript /* [Brief description of what this test verifies] @@ -84,45 +91,44 @@ Generate automated regression tests from test documentation in [`docs/incident_d Verifies: OU-XXX */ -import { incidentsPage } from '../../../views/incidents-page'; +import { incidentsPage } from "../../../views/incidents-page"; const MCP = { - namespace: 'openshift-cluster-observability-operator', - packageName: 'cluster-observability-operator', - operatorName: 'Cluster Observability Operator', + namespace: "openshift-cluster-observability-operator", + packageName: "cluster-observability-operator", + operatorName: "Cluster Observability Operator", config: { - kind: 'UIPlugin', - name: 'monitoring', + kind: "UIPlugin", + name: "monitoring", }, }; const MP = { - namespace: 'openshift-monitoring', - operatorName: 'Cluster Monitoring Operator', + namespace: "openshift-monitoring", + operatorName: "Cluster Monitoring Operator", }; -describe('Regression: [Section Name]', () => { - +describe("Regression: [Section Name]", () => { before(() => { cy.beforeBlockCOO(MCP, MP); }); beforeEach(() => { - cy.log('Navigate to Observe → Incidents'); + cy.log("Navigate to Observe → Incidents"); incidentsPage.goTo(); - cy.log('[Brief description of scenario being loaded]'); - cy.mockIncidentFixture('incident-scenarios/XX-scenario-name.yaml'); + cy.log("[Brief description of scenario being loaded]"); + cy.mockIncidentFixture("incident-scenarios/XX-scenario-name.yaml"); }); - it('1. [First test case description]', () => { - cy.log('1.1 [First step description]'); + it("1. [First test case description]", () => { + cy.log("1.1 [First step description]"); incidentsPage.clearAllFilters(); - - incidentsPage.elements.incidentsChartContainer().should('be.visible'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', N); + + incidentsPage.elements.incidentsChartContainer().should("be.visible"); + incidentsPage.elements.incidentsChartBarsGroups().should("have.length", N); cy.pause(); // Manual verification point - - cy.log('1.2 [Second step description]'); + + cy.log("1.2 [Second step description]"); // More test steps with assertions cy.pause(); // Manual verification point @@ -136,6 +142,7 @@ describe('Regression: [Section Name]', () => { Convert manual verification steps from documentation to automated assertions. **IMPORTANT - E2E Test Flow Design**: + - **Combine related steps**: Group filtering, verification, interaction, and results checking in one test - **Test complete workflows**: Each `it()` should tell a complete story of user interaction - **Multiple assertions per test**: Don't split every assertion into a separate test @@ -143,12 +150,14 @@ Convert manual verification steps from documentation to automated assertions. - Tests can be 50-100+ lines if they represent a complete, realistic user workflow **IMPORTANT - Two-Phase Approach**: + - **Initial test generation**: Include `cy.pause()` statements after key setup steps for manual verification - **Purpose**: Allow user to manually verify behavior before adding complex assertions - **User workflow**: User will manually delete `cy.pause()` statements once verified - **Follow-up edits**: Do NOT reintroduce `cy.pause()` if user has already removed them **When to include cy.pause()**: + - Include in newly generated test files - Include when adding new test cases to existing files - Do NOT include if editing existing test cases that already have assertions @@ -156,40 +165,52 @@ Convert manual verification steps from documentation to automated assertions. **Common assertion patterns**: #### Visibility and Existence + ```typescript -incidentsPage.elements.incidentsChartContainer().should('be.visible'); -incidentsPage.elements.incidentsTable().should('not.exist'); +incidentsPage.elements.incidentsChartContainer().should("be.visible"); +incidentsPage.elements.incidentsTable().should("not.exist"); ``` #### Counts and Length + ```typescript -incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 12); -incidentsPage.elements.incidentsDetailsTableRows().should('have.length.greaterThan', 0); +incidentsPage.elements.incidentsChartBarsGroups().should("have.length", 12); +incidentsPage.elements + .incidentsDetailsTableRows() + .should("have.length.greaterThan", 0); ``` #### Text Content + ```typescript -incidentsPage.elements.daysSelectToggle().should('contain.text', '7 days'); -incidentsPage.elements.incidentsTableComponentCell(0) - .invoke('text') - .should('contain', 'monitoring'); +incidentsPage.elements.daysSelectToggle().should("contain.text", "7 days"); +incidentsPage.elements + .incidentsTableComponentCell(0) + .invoke("text") + .should("contain", "monitoring"); ``` #### Conditional Waiting + ```typescript cy.waitUntil( - () => incidentsPage.elements.incidentsChartBarsGroups().then($groups => $groups.length === 12), + () => + incidentsPage.elements + .incidentsChartBarsGroups() + .then(($groups) => $groups.length === 12), { timeout: 10000, interval: 500, - errorMsg: 'All 12 incidents should load within 10 seconds' - } + errorMsg: "All 12 incidents should load within 10 seconds", + }, ); ``` #### Position and Layout Checks + ```typescript -incidentsPage.elements.incidentsChartBarsVisiblePaths() +incidentsPage.elements + .incidentsChartBarsVisiblePaths() .first() .then(($element) => { const rect = $element[0].getBoundingClientRect(); @@ -199,25 +220,28 @@ incidentsPage.elements.incidentsChartBarsVisiblePaths() ``` #### Tooltip Interactions + ```typescript -incidentsPage.elements.incidentsChartBarsVisiblePaths() +incidentsPage.elements + .incidentsChartBarsVisiblePaths() .first() - .trigger('mouseover', { force: true }); + .trigger("mouseover", { force: true }); -cy.get('[role="tooltip"]').should('be.visible'); -cy.get('[role="tooltip"]').should('contain.text', 'Expected content'); +cy.get('[role="tooltip"]').should("be.visible"); +cy.get('[role="tooltip"]').should("contain.text", "Expected content"); ``` #### Filter Chips + ```typescript -incidentsPage.elements.severityFilterChip().should('be.visible'); -incidentsPage.elements.severityFilterChip() - .should('contain.text', 'Critical'); +incidentsPage.elements.severityFilterChip().should("be.visible"); +incidentsPage.elements.severityFilterChip().should("contain.text", "Critical"); ``` ### 6. Page Object Usage **Priority order**: + 1. Use existing `incidentsPage.elements.*` selectors 2. Use existing `incidentsPage.*` methods 3. Suggest adding new elements/methods to page object @@ -226,6 +250,7 @@ incidentsPage.elements.severityFilterChip() **When missing functionality is identified**: Prompt user: + ``` The following elements/methods are needed but not present in incidents-page.ts: @@ -246,38 +271,42 @@ Should I add these to incidents-page.ts? **Page Object Patterns**: -*Element selector*: +_Element selector_: + ```typescript elements: { simpleElement: () => cy.byTestID(DataTestIDs.Component.Element), - - parameterizedElement: (param: string) => + + parameterizedElement: (param: string) => cy.byTestID(`${DataTestIDs.Component.Element}-${param.toLowerCase()}`), - - compositeSelector: () => + + compositeSelector: () => incidentsPage.elements.toolbar().contains('span', 'Category').parent(), } ``` -*Action method*: +_Action method_: + ```typescript actionName: (param: Type) => { - cy.log('incidentsPage.actionName'); + cy.log("incidentsPage.actionName"); incidentsPage.elements.something().click(); - incidentsPage.elements.result().should('be.visible'); -} + incidentsPage.elements.result().should("be.visible"); +}; ``` -*Query method returning Chainable*: +_Query method returning Chainable_: + ```typescript getData: (): Cypress.Chainable => { - cy.log('incidentsPage.getData'); - return incidentsPage.elements.container() - .invoke('text') + cy.log("incidentsPage.getData"); + return incidentsPage.elements + .container() + .invoke("text") .then((text) => { return cy.wrap(processData(text)); }); -} +}; ``` #### 6.5. Type Safety Guidelines @@ -296,6 +325,7 @@ const verifyProperty = (selector: any, value: any) => { ... } ``` **Common Cypress patterns**: + - DOM elements: `Cypress.Chainable>` - Data returns: `Cypress.Chainable` - Actions: `Cypress.Chainable` or omit return type @@ -312,6 +342,7 @@ Handle common failure scenarios gracefully and make reasonable decisions when re **When**: Test documentation is unclear, incomplete, or contradictory. **Actions**: + 1. Check similar test sections and existing regression tests for patterns 2. Make reasonable assumptions based on common UI testing patterns 3. Document assumptions in test comments with TODO markers @@ -323,19 +354,21 @@ Handle common failure scenarios gracefully and make reasonable decisions when re ``` **Example**: + ```typescript // TODO: Documentation unclear on severity filter - assuming 'Critical' based on similar tests -incidentsPage.toggleFilter('Critical'); +incidentsPage.toggleFilter("Critical"); ``` #### 7.3. Fixture Not Found or Multiple Fixtures Match **Scenario A - No fixture exists**: + 1. Search for similar fixtures in `web/cypress/fixtures/incident-scenarios/` 2. Prompt with options: ``` No fixture found. Required: [list requirements] - + Options: 1. Create new fixture (recommended) 2. Modify existing: [list closest matches] @@ -343,6 +376,7 @@ incidentsPage.toggleFilter('Critical'); ``` **Scenario B - Multiple fixtures match**: + 1. Rank by specificity (incident count, severities, components match) 2. Prompt with comparison: ``` @@ -358,6 +392,7 @@ incidentsPage.toggleFilter('Critical'); **When**: Documentation describes behavior differently than existing tests implement. **Actions**: + ``` Conflict detected: @@ -375,12 +410,13 @@ Which to follow? **When**: `incidents-page.ts` not found or structure differs significantly. **Actions**: + 1. Search likely locations: `web/cypress/views/`, `web/cypress/support/page-objects/` 2. If different structure, attempt to adapt 3. If not found: ``` incidents-page.ts not found. - + Options: 1. Provide correct path 2. Use custom selectors (not recommended) @@ -392,6 +428,7 @@ Which to follow? **When**: Element needs DataTestID that doesn't exist in page object. **Actions**: + ``` DataTestID not found: [name] @@ -408,6 +445,7 @@ Which approach? **When**: Test needs scenarios impossible with fixtures (exact timing, external services, animations). **Actions**: + ``` Requirement may not be fully testable with fixtures: "[exact requirement]" @@ -431,6 +469,7 @@ Approaches: 4. **Document workarounds** in comments **Template**: + ``` [Issue] - [Why it matters] @@ -444,12 +483,13 @@ Continue? (y/n/specify) ``` ### 8. Refactoring -**Note on Refactoring**: Initial test generation focuses on functionality and coverage. After manual verification, use the `/refactor-regression-test` command to clean up duplications and improve readability by extracting helper functions. +**Note on Refactoring**: Initial test generation focuses on functionality and coverage. After manual verification, use the `/refactor-regression-test` command to clean up duplications and improve readability by extracting helper functions. ### 9. Validation Before Output **Automated checks (AI should verify):** + - [ ] File naming matches `XX.reg_.cy.ts` - [ ] Standard MCP/MP configuration blocks present - [ ] Uses `cy.beforeBlockCOO(MCP, MP)` in `before()` hook @@ -460,12 +500,14 @@ Continue? (y/n/specify) - [ ] **For new tests**: Includes `cy.pause()` after key verification points **Human judgment (AI provides evidence):** + - [ ] **Tests follow e2e philosophy**: Each `it()` covers a complete user flow Evidence: List test structure, count of `it()` blocks, steps per test - [ ] **Test reads like a story**: Implementation details hidden in helpers Evidence: Show helper functions extracted, test body readability **For complete detailed checklist**, see `incidents-testing-guidelines.mdc` + ## Example Usage ### Example 1: Generate Tooltip Positioning Test @@ -473,6 +515,7 @@ Continue? (y/n/specify) **User Input**: "Generate regression test for Section 2.1: Tooltip Positioning" **AI Actions**: + 1. Parse Section 2.1 from testing_flows_ui.md 2. Identify requirements: - Test tooltip positioning for incidents at different chart positions @@ -496,99 +539,105 @@ Tests both incidents chart and alerts chart tooltip behavior. Verifies: OU-XXX */ -import { incidentsPage } from '../../../views/incidents-page'; +import { incidentsPage } from "../../../views/incidents-page"; const MCP = { - namespace: 'openshift-cluster-observability-operator', - packageName: 'cluster-observability-operator', - operatorName: 'Cluster Observability Operator', + namespace: "openshift-cluster-observability-operator", + packageName: "cluster-observability-operator", + operatorName: "Cluster Observability Operator", config: { - kind: 'UIPlugin', - name: 'monitoring', + kind: "UIPlugin", + name: "monitoring", }, }; const MP = { - namespace: 'openshift-monitoring', - operatorName: 'Cluster Monitoring Operator', + namespace: "openshift-monitoring", + operatorName: "Cluster Monitoring Operator", }; -describe('Regression: Tooltip Positioning', () => { - +describe("Regression: Tooltip Positioning", () => { before(() => { cy.beforeBlockCOO(MCP, MP); }); beforeEach(() => { - cy.log('Navigate to Observe → Incidents'); + cy.log("Navigate to Observe → Incidents"); incidentsPage.goTo(); - cy.log('Loading tooltip positioning test scenarios'); - cy.mockIncidentFixture('incident-scenarios/13-tooltip-positioning-scenarios.yaml'); + cy.log("Loading tooltip positioning test scenarios"); + cy.mockIncidentFixture( + "incident-scenarios/13-tooltip-positioning-scenarios.yaml", + ); }); - it('1. Complete tooltip interaction flow - positioning, content, and navigation', () => { - cy.log('1.1 Verify all incidents loaded'); + it("1. Complete tooltip interaction flow - positioning, content, and navigation", () => { + cy.log("1.1 Verify all incidents loaded"); incidentsPage.clearAllFilters(); - incidentsPage.setDays('7 days'); - incidentsPage.elements.incidentsChartContainer().should('be.visible'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 14); + incidentsPage.setDays("7 days"); + incidentsPage.elements.incidentsChartContainer().should("be.visible"); + incidentsPage.elements.incidentsChartBarsGroups().should("have.length", 14); cy.pause(); // Verify incidents loaded correctly - - cy.log('1.2 Test bottom bar tooltip positioning'); - incidentsPage.elements.incidentsChartBarsVisiblePaths() + + cy.log("1.2 Test bottom bar tooltip positioning"); + incidentsPage.elements + .incidentsChartBarsVisiblePaths() .first() - .trigger('mouseover', { force: true }); - - cy.get('[role="tooltip"]').should('be.visible'); + .trigger("mouseover", { force: true }); + + cy.get('[role="tooltip"]').should("be.visible"); cy.get('[role="tooltip"]').then(($tooltip) => { const tooltipRect = $tooltip[0].getBoundingClientRect(); expect(tooltipRect.top).to.be.greaterThan(0); expect(tooltipRect.left).to.be.greaterThan(0); }); cy.pause(); // Verify bottom tooltip positioning - - cy.log('1.3 Test middle bar tooltip and verify content'); - incidentsPage.elements.incidentsChartBarsVisiblePaths() + + cy.log("1.3 Test middle bar tooltip and verify content"); + incidentsPage.elements + .incidentsChartBarsVisiblePaths() .eq(7) - .trigger('mouseover', { force: true }); - - cy.get('[role="tooltip"]').should('be.visible'); - cy.get('[role="tooltip"]').should('contain.text', 'Incident'); + .trigger("mouseover", { force: true }); + + cy.get('[role="tooltip"]').should("be.visible"); + cy.get('[role="tooltip"]').should("contain.text", "Incident"); cy.pause(); // Verify middle tooltip - - cy.log('1.4 Test top bar tooltip positioning'); - incidentsPage.elements.incidentsChartBarsVisiblePaths() + + cy.log("1.4 Test top bar tooltip positioning"); + incidentsPage.elements + .incidentsChartBarsVisiblePaths() .last() - .trigger('mouseover', { force: true }); - - cy.get('[role="tooltip"]').should('be.visible'); + .trigger("mouseover", { force: true }); + + cy.get('[role="tooltip"]').should("be.visible"); cy.get('[role="tooltip"]').then(($tooltip) => { const tooltipRect = $tooltip[0].getBoundingClientRect(); const viewportHeight = Cypress.$(window).height(); expect(tooltipRect.bottom).to.be.lessThan(viewportHeight); }); cy.pause(); // Verify top tooltip positioning - - cy.log('1.5 Hover over multi-component incident and verify content'); - incidentsPage.elements.incidentsChartBarsVisiblePaths() + + cy.log("1.5 Hover over multi-component incident and verify content"); + incidentsPage.elements + .incidentsChartBarsVisiblePaths() .eq(3) - .trigger('mouseover', { force: true }); - + .trigger("mouseover", { force: true }); + cy.get('[role="tooltip"]') - .should('be.visible') - .should('contain.text', 'network') - .should('contain.text', 'compute') - .should('contain.text', 'storage'); + .should("be.visible") + .should("contain.text", "network") + .should("contain.text", "compute") + .should("contain.text", "storage"); cy.pause(); // Verify multi-component tooltip content - - cy.log('1.6 Click incident bar and verify details panel opens'); + + cy.log("1.6 Click incident bar and verify details panel opens"); incidentsPage.elements.incidentsChartBarsVisiblePaths().eq(3).click(); - incidentsPage.elements.incidentsDetailsPanel().should('be.visible'); - incidentsPage.elements.incidentsDetailsTableRows() - .should('have.length.greaterThan', 0); + incidentsPage.elements.incidentsDetailsPanel().should("be.visible"); + incidentsPage.elements + .incidentsDetailsTableRows() + .should("have.length.greaterThan", 0); cy.pause(); // Verify details panel - - cy.log('Verified: Complete tooltip interaction and navigation workflow'); + + cy.log("Verified: Complete tooltip interaction and navigation workflow"); }); }); ``` @@ -600,6 +649,7 @@ describe('Regression: Tooltip Positioning', () => { **User Input**: "Generate regression test for Section 1: Filtering Bugs" **AI Actions**: + 1. Parse Section 1 from testing_flows_ui.md 2. Note: Fixture `7-comprehensive-filtering-test-scenarios.yaml` already exists 3. **Design comprehensive flow**: Instead of separate tests for each filter type, create complete filtering workflows @@ -611,9 +661,10 @@ describe('Regression: Tooltip Positioning', () => { ## Output Format Provide: + 1. **Test file path and name**: Full path to generated test file 2. **Test file content**: Complete TypeScript test file -3. **Fixture status**: +3. **Fixture status**: - If existing: "Using fixture: incident-scenarios/X-name.yaml" - If new: "Created fixture: incident-scenarios/X-name.yaml" + YAML content 4. **Page object changes**: If any elements/methods need to be added, list them with implementation @@ -636,8 +687,7 @@ Provide: ## Workflow **Recommended workflow**: + 1. Use this command to generate initial test from documentation 2. Manually verify the test works (using `cy.pause()` points) 3. Once verified, use `/refactor-regression-test` to clean up and improve code quality - - diff --git a/docs/incident_detection/tests/performance/03.endurance_test_source.md b/docs/incident_detection/tests/performance/03.endurance_test_source.md index d8f69e29d..7d22eb9da 100644 --- a/docs/incident_detection/tests/performance/03.endurance_test_source.md +++ b/docs/incident_detection/tests/performance/03.endurance_test_source.md @@ -5,21 +5,21 @@ Shelved due to Cypress DOM snapshot accumulation causing ~10x degradation over 1 **To re-enable:** save the code block below as `web/cypress/e2e/incidents/performance/03.performance_endurance.cy.ts`. ```typescript -import { incidentsPage } from '../../../views/incidents-page'; +import { incidentsPage } from "../../../views/incidents-page"; const MCP = { - namespace: Cypress.env('COO_NAMESPACE'), - packageName: 'cluster-observability-operator', - operatorName: 'Cluster Observability Operator', + namespace: Cypress.env("COO_NAMESPACE"), + packageName: "cluster-observability-operator", + operatorName: "Cluster Observability Operator", config: { - kind: 'UIPlugin', - name: 'monitoring', + kind: "UIPlugin", + name: "monitoring", }, }; const MP = { - namespace: 'openshift-monitoring', - operatorName: 'Cluster Monitoring Operator', + namespace: "openshift-monitoring", + operatorName: "Cluster Monitoring Operator", }; const INCIDENT_COUNT = 20; @@ -27,126 +27,147 @@ const CYCLES_PER_INCIDENT = 5; const TOTAL_CYCLES = INCIDENT_COUNT * CYCLES_PER_INCIDENT; const DEGRADATION_FACTOR = 5; -const INCIDENT_IDS = Array.from({ length: INCIDENT_COUNT }, (_, i) => - `bench-${String(i + 1).padStart(2, '0')}`, +const INCIDENT_IDS = Array.from( + { length: INCIDENT_COUNT }, + (_, i) => `bench-${String(i + 1).padStart(2, "0")}`, ); -const TRACKED_AVERAGE = 'bench-01'; -const TRACKED_HEAVIEST = 'bench-03'; - -describe('Performance: Endurance - Select/Deselect Cycling', { tags: ['@incidents', '@performance', '@endurance'] }, () => { - - before(() => { - cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); - }); - - it('8.1 Endurance: Incident select/deselect cycling across 20 incidents', () => { - cy.mockIncidentFixture('incident-scenarios/22-benchmark-20-incidents.yaml'); - incidentsPage.clearAllFilters(); - incidentsPage.setDays('1 day'); - incidentsPage.elements.incidentsChartBarsGroups() - .should('have.length', 20); - - const cycleTimes: number[] = []; - const trackedTimes: Record = { - [TRACKED_AVERAGE]: [], - [TRACKED_HEAVIEST]: [], - }; - - const sum = (arr: number[]) => arr.reduce((a, b) => a + b, 0); - const avg = (arr: number[]) => Math.round(sum(arr) / arr.length); - - const logTrackedSnapshot = (label: string) => { - const lines: string[] = [label]; - for (const [id, times] of Object.entries(trackedTimes)) { - if (times.length === 0) continue; - lines.push( - ` ${id} (${times.length} cycles): avg ${avg(times)}ms, last ${times[times.length - 1]}ms`, - ); - } - lines.forEach((line) => { - cy.log(line); - cy.task('log', line); +const TRACKED_AVERAGE = "bench-01"; +const TRACKED_HEAVIEST = "bench-03"; + +describe( + "Performance: Endurance - Select/Deselect Cycling", + { tags: ["@cluster-health-analyzer", "@coo"] }, + () => { + before(() => { + cy.beforeBlockCOO(MCP, MP, { + dashboards: false, + troubleshootingPanel: false, }); - }; - - cy.window({ log: false }).then((win) => { - win.performance.clearMarks('endurance-start'); - win.performance.mark('endurance-start'); }); - const runCycle = (cycleIndex: number) => { - if (cycleIndex >= TOTAL_CYCLES) return; - - const incidentId = INCIDENT_IDS[cycleIndex % INCIDENT_IDS.length]; - const cycleMark = `cycle-${cycleIndex}`; + it("8.1 Endurance: Incident select/deselect cycling across 20 incidents", () => { + cy.mockIncidentFixture( + "incident-scenarios/22-benchmark-20-incidents.yaml", + ); + incidentsPage.clearAllFilters(); + incidentsPage.setDays("1 day"); + incidentsPage.elements + .incidentsChartBarsGroups() + .should("have.length", 20); + + const cycleTimes: number[] = []; + const trackedTimes: Record = { + [TRACKED_AVERAGE]: [], + [TRACKED_HEAVIEST]: [], + }; + + const sum = (arr: number[]) => arr.reduce((a, b) => a + b, 0); + const avg = (arr: number[]) => Math.round(sum(arr) / arr.length); + + const logTrackedSnapshot = (label: string) => { + const lines: string[] = [label]; + for (const [id, times] of Object.entries(trackedTimes)) { + if (times.length === 0) continue; + lines.push( + ` ${id} (${times.length} cycles): avg ${avg(times)}ms, last ${times[times.length - 1]}ms`, + ); + } + lines.forEach((line) => { + cy.log(line); + cy.task("log", line); + }); + }; cy.window({ log: false }).then((win) => { - win.performance.mark(cycleMark); + win.performance.clearMarks("endurance-start"); + win.performance.mark("endurance-start"); }); - incidentsPage.selectIncidentById(incidentId); - incidentsPage.elements.alertsChartCard().should('be.visible'); - - incidentsPage.deselectIncidentById(incidentId); + const runCycle = (cycleIndex: number) => { + if (cycleIndex >= TOTAL_CYCLES) return; + + const incidentId = INCIDENT_IDS[cycleIndex % INCIDENT_IDS.length]; + const cycleMark = `cycle-${cycleIndex}`; + + cy.window({ log: false }).then((win) => { + win.performance.mark(cycleMark); + }); + + incidentsPage.selectIncidentById(incidentId); + incidentsPage.elements.alertsChartCard().should("be.visible"); + + incidentsPage.deselectIncidentById(incidentId); + + cy.window({ log: false }).then((win) => { + const measure = win.performance.measure( + `${cycleMark}-measure`, + cycleMark, + ); + const elapsed = Math.round(measure.duration); + cycleTimes.push(elapsed); + + if (incidentId in trackedTimes) { + trackedTimes[incidentId].push(elapsed); + } + + if ((cycleIndex + 1) % 20 === 0 || cycleIndex === 0) { + const totalMeasure = win.performance.measure( + "endurance-progress", + "endurance-start", + ); + const totalElapsed = Math.round(totalMeasure.duration / 1000); + win.performance.clearMeasures("endurance-progress"); + const msg = `Cycle ${cycleIndex + 1}/${TOTAL_CYCLES} [${incidentId}]: ${elapsed}ms (${totalElapsed}s elapsed)`; + cy.log(msg); + cy.task("log", msg); + logTrackedSnapshot("--- Tracked incidents snapshot ---"); + } + }); + + cy.then(() => { + runCycle(cycleIndex + 1); + }); + }; + + runCycle(0); cy.window({ log: false }).then((win) => { - const measure = win.performance.measure(`${cycleMark}-measure`, cycleMark); - const elapsed = Math.round(measure.duration); - cycleTimes.push(elapsed); - - if (incidentId in trackedTimes) { - trackedTimes[incidentId].push(elapsed); - } - - if ((cycleIndex + 1) % 20 === 0 || cycleIndex === 0) { - const totalMeasure = win.performance.measure('endurance-progress', 'endurance-start'); - const totalElapsed = Math.round(totalMeasure.duration / 1000); - win.performance.clearMeasures('endurance-progress'); - const msg = `Cycle ${cycleIndex + 1}/${TOTAL_CYCLES} [${incidentId}]: ${elapsed}ms (${totalElapsed}s elapsed)`; - cy.log(msg); - cy.task('log', msg); - logTrackedSnapshot('--- Tracked incidents snapshot ---'); - } - }); - - cy.then(() => { runCycle(cycleIndex + 1); }); - }; - - runCycle(0); - - cy.window({ log: false }).then((win) => { - const totalMeasure = win.performance.measure('endurance-total', 'endurance-start'); - const totalElapsed = totalMeasure.duration; - - const min = Math.min(...cycleTimes); - const max = Math.max(...cycleTimes); - const mean = avg(cycleTimes); - const first10Avg = avg(cycleTimes.slice(0, 10)); - const last10Avg = avg(cycleTimes.slice(-10)); - - const summary = [ - `=== ENDURANCE TEST SUMMARY ===`, - `Total cycles: ${cycleTimes.length}`, - `Total time: ${Math.round(totalElapsed / 1000)}s`, - `Cycle times - min: ${min}ms, max: ${max}ms, avg: ${mean}ms`, - `First 10 avg: ${first10Avg}ms`, - `Last 10 avg: ${last10Avg}ms`, - `Degradation ratio: ${(last10Avg / first10Avg).toFixed(2)}x (threshold: ${DEGRADATION_FACTOR}x)`, - ]; - - summary.forEach((line) => { - cy.log(line); - cy.task('log', line); + const totalMeasure = win.performance.measure( + "endurance-total", + "endurance-start", + ); + const totalElapsed = totalMeasure.duration; + + const min = Math.min(...cycleTimes); + const max = Math.max(...cycleTimes); + const mean = avg(cycleTimes); + const first10Avg = avg(cycleTimes.slice(0, 10)); + const last10Avg = avg(cycleTimes.slice(-10)); + + const summary = [ + `=== ENDURANCE TEST SUMMARY ===`, + `Total cycles: ${cycleTimes.length}`, + `Total time: ${Math.round(totalElapsed / 1000)}s`, + `Cycle times - min: ${min}ms, max: ${max}ms, avg: ${mean}ms`, + `First 10 avg: ${first10Avg}ms`, + `Last 10 avg: ${last10Avg}ms`, + `Degradation ratio: ${(last10Avg / first10Avg).toFixed(2)}x (threshold: ${DEGRADATION_FACTOR}x)`, + ]; + + summary.forEach((line) => { + cy.log(line); + cy.task("log", line); + }); + + logTrackedSnapshot("=== TRACKED INCIDENTS FINAL ==="); + + expect( + last10Avg, + `Last 10 cycles avg (${last10Avg}ms) should not exceed ${DEGRADATION_FACTOR}x first 10 avg (${first10Avg}ms)`, + ).to.be.lessThan(first10Avg * DEGRADATION_FACTOR); }); - - logTrackedSnapshot('=== TRACKED INCIDENTS FINAL ==='); - - expect( - last10Avg, - `Last 10 cycles avg (${last10Avg}ms) should not exceed ${DEGRADATION_FACTOR}x first 10 avg (${first10Avg}ms)`, - ).to.be.lessThan(first10Avg * DEGRADATION_FACTOR); }); - }); -}); + }, +); ``` diff --git a/web/cypress/E2E_TEST_SCENARIOS.md b/web/cypress/E2E_TEST_SCENARIOS.md index 6898f8d49..2989645ba 100644 --- a/web/cypress/E2E_TEST_SCENARIOS.md +++ b/web/cypress/E2E_TEST_SCENARIOS.md @@ -3,6 +3,7 @@ This document provides a comprehensive overview of all End-to-End (E2E) test scenarios for the Monitoring Plugin, including COO (Cluster Observability Operator) and standard Monitoring tests. ## Table of Contents + - [COO (Cluster Observability Operator) Tests](#coo-cluster-observability-operator-tests) - [Virtualization Tests](#virtualization-tests) - [Monitoring Tests](#monitoring-tests) @@ -16,22 +17,22 @@ Located in `e2e/coo/` ### Build Verification Tests (BVT) -| File | Test Suite | Test Scenario | Description | -|------|------------|---------------|-------------| -| `01.coo_bvt.cy.ts` | BVT: COO | 1. Admin perspective - Observe Menu | Verifies Observe menu navigation and submenus (Alerting, Silences, Alerting rules, Dashboards (Perses)) | +| File | Test Suite | Test Scenario | Description | +| ------------------ | ---------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `01.coo_bvt.cy.ts` | BVT: COO | 1. Admin perspective - Observe Menu | Verifies Observe menu navigation and submenus (Alerting, Silences, Alerting rules, Dashboards (Perses)) | ### ACM Alerting UI Tests -| File | Test Suite | Test Scenario | Description | -|------|------------|---------------|-------------| +| File | Test Suite | Test Scenario | Description | +| -------------------------- | --------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `02.acm_alerting_ui.cy.ts` | ACM Alerting UI | 1. Fleet Management perspective - ACM Alerting | Validates ACM integration with COO, Fleet Management perspective navigation, local-cluster access, and ACM alert visibility (Watchdog, Watchdog-spoke, ClusterCPUHealth) | ### OLS (OpenShift LightSpeed) Integration Tests -| File | Test Suite | Test Scenario | Description | -|------|------------|---------------|-------------| -| `03.coo_lightspeed_show_timeseries.cy.ts` | COO-LightSpeed: show_timeseries | switches to troubleshooting mode, sends a prompt, and renders a Perses dashboard | **Non-deterministic** — sends a natural-language prompt to the live OLS AI and asserts it responds with a `show_timeseries` tool call that renders a Perses chart. Tagged `@ols`, must not gate CI. | -| `03.coo_lightspeed_show_timeseries.cy.ts` | COO-LightSpeed: show_timeseries | adds the rendered chart to a new Perses dashboard via Add to Dashboard button | **Non-deterministic** — creates a new Perses dashboard, sends a prompt to OLS, then uses the "Add to Dashboard" button to add the rendered chart to the dashboard. Verifies the panel appears and persists after save. Tagged `@ols`, must not gate CI. | +| File | Test Suite | Test Scenario | Description | +| ----------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `03.coo_lightspeed_show_timeseries.cy.ts` | COO-LightSpeed: show_timeseries | switches to troubleshooting mode, sends a prompt, and renders a Perses dashboard | **Non-deterministic** — sends a natural-language prompt to the live OLS AI and asserts it responds with a `show_timeseries` tool call that renders a Perses chart. | +| `03.coo_lightspeed_show_timeseries.cy.ts` | COO-LightSpeed: show_timeseries | adds the rendered chart to a new Perses dashboard via Add to Dashboard button | **Non-deterministic** — creates a new Perses dashboard, sends a prompt to OLS, then uses the "Add to Dashboard" button to add the rendered chart to the dashboard. Verifies the panel appears and persists after save. | --- @@ -43,27 +44,27 @@ These tests verify the Monitoring Plugin functionality within the Virtualization ### Integration Verification Tests (IVT) -| File | Test Suite | Test Scenario | Perspective | Namespace Scope | -|------|------------|---------------|-------------|-----------------| -| `01.coo_ivt.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | -| `01.coo_ivt.cy.ts` | Installation: Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | -| `01.coo_ivt.cy.ts` | IVT: Monitoring + Virtualization | *Runs BVT Monitoring Tests* | Virtualization | All Projects | -| `01.coo_ivt.cy.ts` | IVT: Monitoring + Virtualization - Namespaced | *Runs BVT Monitoring Tests (Namespace)* | Virtualization | openshift-monitoring | -| | | | | -| `02.coo_ivt_alerts.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | -| `02.coo_ivt_alerts.cy.ts` | IVT: Monitoring UIPlugin + Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | -| `02.coo_ivt_alerts.cy.ts` | Regression: Monitoring - Alerts (Virtualization) | *Runs All Regression Alerts Tests* | Virtualization | All Projects | -| `02.coo_ivt_alerts.cy.ts` | Regression: Monitoring - Alerts Namespaced (Virtualization) | *Runs All Regression Alerts Tests (Namespace)* | Virtualization | openshift-monitoring | -| | | | | -| `03.coo_ivt_metrics.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | -| `03.coo_ivt_metrics.cy.ts` | IVT: Monitoring UIPlugin + Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | -| `03.coo_ivt_metrics.cy.ts` | Regression: Monitoring - Metrics (Virtualization) | *Runs All Regression Metrics Tests* | Virtualization | All Projects | -| `03.coo_ivt_metrics.cy.ts` | Regression: Monitoring - Metrics Namespaced (Virtualization) | *Runs All Regression Metrics Tests (Namespace)* | Virtualization | openshift-monitoring | -| | | | | -| `04.coo_ivt_legacy_dashboards.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | -| `04.coo_ivt_legacy_dashboards.cy.ts` | IVT: Monitoring UIPlugin + Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | -| `04.coo_ivt_legacy_dashboards.cy.ts` | Regression: Monitoring - Legacy Dashboards (Virtualization) | *Runs All Regression Legacy Dashboards Tests* | Virtualization | All Projects | -| `04.coo_ivt_legacy_dashboards.cy.ts` | Regression: Monitoring - Legacy Dashboards Namespaced (Virtualization) | *Runs All Regression Legacy Dashboards Tests (Namespace)* | Virtualization | openshift-monitoring | +| File | Test Suite | Test Scenario | Perspective | Namespace Scope | +| ------------------------------------ | ---------------------------------------------------------------------- | --------------------------------------------------------- | -------------- | -------------------- | +| `01.coo_ivt.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | +| `01.coo_ivt.cy.ts` | Installation: Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | +| `01.coo_ivt.cy.ts` | IVT: Monitoring + Virtualization | _Runs BVT Monitoring Tests_ | Virtualization | All Projects | +| `01.coo_ivt.cy.ts` | IVT: Monitoring + Virtualization - Namespaced | _Runs BVT Monitoring Tests (Namespace)_ | Virtualization | openshift-monitoring | +| | | | | +| `02.coo_ivt_alerts.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | +| `02.coo_ivt_alerts.cy.ts` | IVT: Monitoring UIPlugin + Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | +| `02.coo_ivt_alerts.cy.ts` | Regression: Monitoring - Alerts (Virtualization) | _Runs All Regression Alerts Tests_ | Virtualization | All Projects | +| `02.coo_ivt_alerts.cy.ts` | Regression: Monitoring - Alerts Namespaced (Virtualization) | _Runs All Regression Alerts Tests (Namespace)_ | Virtualization | openshift-monitoring | +| | | | | +| `03.coo_ivt_metrics.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | +| `03.coo_ivt_metrics.cy.ts` | IVT: Monitoring UIPlugin + Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | +| `03.coo_ivt_metrics.cy.ts` | Regression: Monitoring - Metrics (Virtualization) | _Runs All Regression Metrics Tests_ | Virtualization | All Projects | +| `03.coo_ivt_metrics.cy.ts` | Regression: Monitoring - Metrics Namespaced (Virtualization) | _Runs All Regression Metrics Tests (Namespace)_ | Virtualization | openshift-monitoring | +| | | | | +| `04.coo_ivt_legacy_dashboards.cy.ts` | Setting up Monitoring Plugin | 1. Setting up Monitoring Plugin | N/A | N/A | +| `04.coo_ivt_legacy_dashboards.cy.ts` | IVT: Monitoring UIPlugin + Virtualization | 1. Virtualization perspective - Observe Menu | Virtualization | N/A | +| `04.coo_ivt_legacy_dashboards.cy.ts` | Regression: Monitoring - Legacy Dashboards (Virtualization) | _Runs All Regression Legacy Dashboards Tests_ | Virtualization | All Projects | +| `04.coo_ivt_legacy_dashboards.cy.ts` | Regression: Monitoring - Legacy Dashboards Namespaced (Virtualization) | _Runs All Regression Legacy Dashboards Tests (Namespace)_ | Virtualization | openshift-monitoring | --- @@ -73,30 +74,30 @@ Located in `e2e/monitoring/` ### Basic Verification Tests (BVT) -| File | Test Suite | Test Scenario | Description | Namespace Scope | -|------|------------|---------------|-------------|-----------------| -| `00.bvt_admin.cy.ts` | BVT: Monitoring | 1. Admin perspective - Observe Menu | Verifies all Observe submenus navigation | All Projects | -| `00.bvt_admin.cy.ts` | BVT: Monitoring | 2. Admin perspective - Overview Page > Status - View alerts | Verifies navigation from Overview status card to Alerting page | All Projects | -| `00.bvt_admin.cy.ts` | BVT: Monitoring | 3. Admin perspective - Cluster Utilization - Metrics | Verifies navigation from cluster utilization to Metrics page | All Projects | -| `00.bvt_admin.cy.ts` | BVT: Monitoring | *Runs BVT Monitoring Tests* | Additional monitoring scenarios from support module | All Projects | -| | | | | | -| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | Admin perspective - Observe Menu | Verifies all Observe submenus navigation with namespace scope | openshift-monitoring | -| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | Admin perspective - Overview Page > Status - View alerts | Verifies navigation from Overview status card to Alerting page | openshift-monitoring | -| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | Admin perspective - Cluster Utilization - Metrics | Verifies navigation from cluster utilization to Metrics page | openshift-monitoring | -| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | *Runs BVT Monitoring Tests (Namespace)* | Additional monitoring scenarios from support module | openshift-monitoring | +| File | Test Suite | Test Scenario | Description | Namespace Scope | +| -------------------- | ---------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------- | -------------------- | +| `00.bvt_admin.cy.ts` | BVT: Monitoring | 1. Admin perspective - Observe Menu | Verifies all Observe submenus navigation | All Projects | +| `00.bvt_admin.cy.ts` | BVT: Monitoring | 2. Admin perspective - Overview Page > Status - View alerts | Verifies navigation from Overview status card to Alerting page | All Projects | +| `00.bvt_admin.cy.ts` | BVT: Monitoring | 3. Admin perspective - Cluster Utilization - Metrics | Verifies navigation from cluster utilization to Metrics page | All Projects | +| `00.bvt_admin.cy.ts` | BVT: Monitoring | _Runs BVT Monitoring Tests_ | Additional monitoring scenarios from support module | All Projects | +| | | | | | +| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | Admin perspective - Observe Menu | Verifies all Observe submenus navigation with namespace scope | openshift-monitoring | +| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | Admin perspective - Overview Page > Status - View alerts | Verifies navigation from Overview status card to Alerting page | openshift-monitoring | +| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | Admin perspective - Cluster Utilization - Metrics | Verifies navigation from cluster utilization to Metrics page | openshift-monitoring | +| `00.bvt_admin.cy.ts` | BVT: Monitoring - Namespaced | _Runs BVT Monitoring Tests (Namespace)_ | Additional monitoring scenarios from support module | openshift-monitoring | ### Regression Tests -| File | Test Suite | Test Scenario | Feature Area | Namespace Scope | -|------|------------|---------------|--------------|-----------------| -| `regression/01.reg_alerts_admin.cy.ts` | Regression: Monitoring - Alerts (Administrator) | *Runs All Regression Alerts Tests* | Alerts | All Projects | -| `regression/01.reg_alerts_admin.cy.ts` | Regression: Monitoring - Alerts Namespaced (Administrator) | *Runs All Regression Alerts Tests (Namespace)* | Alerts | openshift-monitoring | -| | | | | | -| `regression/02.reg_metrics_admin.cy.ts` | Regression: Monitoring - Metrics (Administrator) | *Runs All Regression Metrics Tests* | Metrics | All Projects | -| `regression/02.reg_metrics_admin.cy.ts` | Regression: Monitoring - Metrics Namespaced (Administrator) | *Runs All Regression Metrics Tests (Namespace)* | Metrics | openshift-monitoring | -| | | | | | -| `regression/03.reg_legacy_dashboards_admin.cy.ts` | Regression: Monitoring - Legacy Dashboards (Administrator) | *Runs All Regression Legacy Dashboards Tests* | Dashboards | All Projects | -| `regression/03.reg_legacy_dashboards_admin.cy.ts` | Regression: Monitoring - Legacy Dashboards Namespaced (Administrator) | *Runs All Regression Legacy Dashboards Tests (Namespace)* | Dashboards | openshift-monitoring | +| File | Test Suite | Test Scenario | Feature Area | Namespace Scope | +| ------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------- | ------------ | -------------------- | +| `regression/01.reg_alerts_admin.cy.ts` | Regression: Monitoring - Alerts (Administrator) | _Runs All Regression Alerts Tests_ | Alerts | All Projects | +| `regression/01.reg_alerts_admin.cy.ts` | Regression: Monitoring - Alerts Namespaced (Administrator) | _Runs All Regression Alerts Tests (Namespace)_ | Alerts | openshift-monitoring | +| | | | | | +| `regression/02.reg_metrics_admin.cy.ts` | Regression: Monitoring - Metrics (Administrator) | _Runs All Regression Metrics Tests_ | Metrics | All Projects | +| `regression/02.reg_metrics_admin.cy.ts` | Regression: Monitoring - Metrics Namespaced (Administrator) | _Runs All Regression Metrics Tests (Namespace)_ | Metrics | openshift-monitoring | +| | | | | | +| `regression/03.reg_legacy_dashboards_admin.cy.ts` | Regression: Monitoring - Legacy Dashboards (Administrator) | _Runs All Regression Legacy Dashboards Tests_ | Dashboards | All Projects | +| `regression/03.reg_legacy_dashboards_admin.cy.ts` | Regression: Monitoring - Legacy Dashboards Namespaced (Administrator) | _Runs All Regression Legacy Dashboards Tests (Namespace)_ | Dashboards | openshift-monitoring | --- @@ -108,44 +109,44 @@ These test scenarios are reusable test suites called by the main E2E test files. #### Non-Namespaced Alerts (`01.reg_alerts.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| `{perspective} perspective - Alerting > Alerts page - Filtering` | Tests all filtering options: Alert State, Severity, Source filters; Export CSV; Search by name and label | -| `{perspective} perspective - Alerting > Silences page > Create silence` | Tests silence creation form validation: comment validation, creator validation, label name/value validation | +| Test Scenario | Description | +| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `{perspective} perspective - Alerting > Alerts page - Filtering` | Tests all filtering options: Alert State, Severity, Source filters; Export CSV; Search by name and label | +| `{perspective} perspective - Alerting > Silences page > Create silence` | Tests silence creation form validation: comment validation, creator validation, label name/value validation | | `{perspective} perspective - Alerting > Alerts / Silences > Kebab icon on List and Details` | Comprehensive test covering: silence creation, silence expiration, kebab menu actions on alerts and silences, recreate/edit silence functionality | -| `{perspective} perspective - Alerting > Alerting Rules` | Tests alerting rules page: filtering, searching, silence creation from alerting rule, kebab menu validation | +| `{perspective} perspective - Alerting > Alerting Rules` | Tests alerting rules page: filtering, searching, silence creation from alerting rule, kebab menu validation | #### Namespaced Alerts (`04.reg_alerts_namespace.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| `{perspective} perspective - Alerting > Alerts page - Filtering` | Same as non-namespaced but validates Source filter is not available in namespace scope | -| `{perspective} perspective - Alerting > Silences page > Create silence` | Tests silence creation with namespace scope validation (namespace label should be disabled) | -| `{perspective} perspective - Alerting > Alerts / Silences > Kebab icon on List and Details` | Same comprehensive tests as non-namespaced with namespace context | -| `{perspective} perspective - Alerting > Alerting Rules` | Same alerting rules tests with namespace scope | -| `{perspective} perspective - Alerting > Empty state` | Tests empty state for Alerts, Silences, and Alerting Rules when switching to empty namespace | +| Test Scenario | Description | +| ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| `{perspective} perspective - Alerting > Alerts page - Filtering` | Same as non-namespaced but validates Source filter is not available in namespace scope | +| `{perspective} perspective - Alerting > Silences page > Create silence` | Tests silence creation with namespace scope validation (namespace label should be disabled) | +| `{perspective} perspective - Alerting > Alerts / Silences > Kebab icon on List and Details` | Same comprehensive tests as non-namespaced with namespace context | +| `{perspective} perspective - Alerting > Alerting Rules` | Same alerting rules tests with namespace scope | +| `{perspective} perspective - Alerting > Empty state` | Tests empty state for Alerts, Silences, and Alerting Rules when switching to empty namespace | ### Metrics Tests #### Non-Namespaced Metrics (`02.reg_metrics.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| `{perspective} perspective - Metrics` | Validates Metrics page loading, Units dropdown, Refresh interval, Actions dropdown, Predefined queries, Kebab menu | -| `{perspective} perspective - Metrics > Actions - No query added` | Tests Add query, Collapse/Expand all queries, Delete all queries when no query is entered | -| `{perspective} perspective - Metrics > Actions - One query added` | Tests same actions with an active query loaded | -| `{perspective} perspective - Metrics > Insert Example Query` | Tests example query insertion, graph timespan dropdown/input, Reset zoom, Hide/Show graph, Stacked/Disconnected checkbox | +| Test Scenario | Description | +| ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `{perspective} perspective - Metrics` | Validates Metrics page loading, Units dropdown, Refresh interval, Actions dropdown, Predefined queries, Kebab menu | +| `{perspective} perspective - Metrics > Actions - No query added` | Tests Add query, Collapse/Expand all queries, Delete all queries when no query is entered | +| `{perspective} perspective - Metrics > Actions - One query added` | Tests same actions with an active query loaded | +| `{perspective} perspective - Metrics > Insert Example Query` | Tests example query insertion, graph timespan dropdown/input, Reset zoom, Hide/Show graph, Stacked/Disconnected checkbox | | `{perspective} perspective - Metrics > Add Query - Run Queries - Kebab icon` | Comprehensive test: Add/run queries, Disable/Enable query via kebab and switch, Hide/Show all series, Select/Unselect series, Delete/Duplicate query | -| `{perspective} perspective - Metrics > Predefined Queries > Export as CSV` | Tests CSV export for all 9 predefined queries (CPU, Memory, Filesystem, Network metrics) | -| `{perspective} perspective - Metrics > Ungraphable results` | Tests ungraphable results error state when too many queries are added | -| `{perspective} perspective - Metrics > No Datapoints` | Tests empty state when query returns no data | -| `{perspective} perspective - Metrics > No Datapoints with alert` | Tests error alert display for invalid queries | +| `{perspective} perspective - Metrics > Predefined Queries > Export as CSV` | Tests CSV export for all 9 predefined queries (CPU, Memory, Filesystem, Network metrics) | +| `{perspective} perspective - Metrics > Ungraphable results` | Tests ungraphable results error state when too many queries are added | +| `{perspective} perspective - Metrics > No Datapoints` | Tests empty state when query returns no data | +| `{perspective} perspective - Metrics > No Datapoints with alert` | Tests error alert display for invalid queries | #### Namespaced Metrics (`05.reg_metrics_namespace.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| All scenarios from non-namespaced | Same 9 test scenarios as non-namespaced metrics | +| Test Scenario | Description | +| --------------------------------------------------- | ----------------------------------------------------------------- | +| All scenarios from non-namespaced | Same 9 test scenarios as non-namespaced metrics | | `{perspective} perspective - Metrics > Empty state` | Additional test for empty state when switching to empty namespace | **Total Metrics Scenarios:** 9 (non-namespaced), 10 (namespaced) @@ -154,37 +155,37 @@ These test scenarios are reusable test suites called by the main E2E test files. #### Non-Namespaced Legacy Dashboards (`03.reg_legacy_dashboards.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| `{perspective} perspective - Dashboards (legacy)` | Tests dashboard page loading, time range dropdown, refresh interval, dashboard dropdown, API Performance dashboard panels, Inspect functionality | -| `{perspective} perspective - Dashboards (legacy) - Inspect and Export as CSV` | Tests Export CSV functionality and disabled state for empty data | -| `{perspective} perspective - Dashboards (legacy) - No kebab dropdown` | Validates that Single Stat and Table panels don't show kebab menu | -| `{perspective} perspective - OU-897 - Hide Graph / Show Graph on Metrics, Alert Details and Dashboards` | Tests Hide/Show graph state persistence across Metrics, Dashboards, Alert details, and Alerting rule details pages | +| Test Scenario | Description | +| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `{perspective} perspective - Dashboards (legacy)` | Tests dashboard page loading, time range dropdown, refresh interval, dashboard dropdown, API Performance dashboard panels, Inspect functionality | +| `{perspective} perspective - Dashboards (legacy) - Inspect and Export as CSV` | Tests Export CSV functionality and disabled state for empty data | +| `{perspective} perspective - Dashboards (legacy) - No kebab dropdown` | Validates that Single Stat and Table panels don't show kebab menu | +| `{perspective} perspective - OU-897 - Hide Graph / Show Graph on Metrics, Alert Details and Dashboards` | Tests Hide/Show graph state persistence across Metrics, Dashboards, Alert details, and Alerting rule details pages | #### Namespaced Legacy Dashboards (`06.reg_legacy_dashboards_namespace.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| `{perspective} perspective - Dashboards (legacy)` | Tests Kubernetes Compute Resources Namespace Pods dashboard with namespace scope | -| `{perspective} perspective - Dashboards (legacy) - Export as CSV` | Tests CSV export with namespace scope and empty state validation | -| `{perspective} perspective - Dashboards (legacy) - No kebab dropdown` | Validates kebab menu absence for specific chart types | -| `{perspective} perspective - OU-897 - Hide Graph / Show Graph on Metrics, Alert Details and Dashboards` | Same Hide/Show graph tests with namespace context | +| Test Scenario | Description | +| ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `{perspective} perspective - Dashboards (legacy)` | Tests Kubernetes Compute Resources Namespace Pods dashboard with namespace scope | +| `{perspective} perspective - Dashboards (legacy) - Export as CSV` | Tests CSV export with namespace scope and empty state validation | +| `{perspective} perspective - Dashboards (legacy) - No kebab dropdown` | Validates kebab menu absence for specific chart types | +| `{perspective} perspective - OU-897 - Hide Graph / Show Graph on Metrics, Alert Details and Dashboards` | Same Hide/Show graph tests with namespace context | ### BVT Monitoring Tests #### Non-Namespaced BVT (`00.bvt_monitoring.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| +| Test Scenario | Description | +| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `{perspective} perspective - Alerting > Alerting Details page > Alerting Rule > Metrics` | Tests full navigation flow: Alerts list → Alert details → Alerting rule details → Metrics page, validates expression query | -| `{perspective} perspective - Creates and expires a Silence` | Tests complete silence lifecycle: creation, validation on multiple pages (Alerts, Silences, Alerting Rules), expiration | +| `{perspective} perspective - Creates and expires a Silence` | Tests complete silence lifecycle: creation, validation on multiple pages (Alerts, Silences, Alerting Rules), expiration | #### Namespaced BVT (`00.bvt_monitoring_namespace.cy.ts`) -| Test Scenario | Description | -|---------------|-------------| -| `{perspective} perspective - Alerting > Alerting Details page > Alerting Rule > Metrics` | Same flow as non-namespaced with namespace scope validation | -| `{perspective} perspective - Creates and expires a Silence` | Same silence lifecycle with namespace scope, validates namespace label is disabled in forms | +| Test Scenario | Description | +| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | +| `{perspective} perspective - Alerting > Alerting Details page > Alerting Rule > Metrics` | Same flow as non-namespaced with namespace scope validation | +| `{perspective} perspective - Creates and expires a Silence` | Same silence lifecycle with namespace scope, validates namespace label is disabled in forms | --- @@ -204,9 +205,8 @@ These test scenarios are reusable test suites called by the main E2E test files. ## Notes -1. **Support Module Tests**: Test scenarios marked with *Runs X Tests* are implemented in support files and called by the main E2E test files with different perspectives. +1. **Support Module Tests**: Test scenarios marked with _Runs X Tests_ are implemented in support files and called by the main E2E test files with different perspectives. 2. **Perspective Parameter**: `{perspective}` is dynamically replaced with the actual perspective name (Administrator, Virtualization) when tests run. 3. **Empty State Tests**: Namespaced tests include additional empty state validation by switching to empty namespaces like `default`. - diff --git a/web/cypress/README.md b/web/cypress/README.md index 8d1213d41..dd7406947 100644 --- a/web/cypress/README.md +++ b/web/cypress/README.md @@ -49,14 +49,17 @@ source ./configure-env.sh ``` **Features**: -- Automatic prompting for all CYPRESS_ variables + +- Automatic prompting for all CYPRESS\_ variables - Automatic discovery and numbered selection of `*kubeconfig*` files in `$HOME/Downloads` - Validates required variables **Alternative - Generate Export File**: + ```bash ./configure-env.sh ``` + Creates `export-env.sh` that you can source later: `source export-env.sh` --- @@ -67,24 +70,24 @@ All scenarios require the [standard variables](#required-variables) (`CYPRESS_BA ### General Scenarios -| Scenario | Key Variables | Description | -|----------|---------------|-------------| -| **Released Version** | `CYPRESS_COO_UI_INSTALL=true` | Install operators from redhat-operators catalog. Production-like testing. | -| **Pre-provisioned COO** | `CYPRESS_SKIP_COO_INSTALL=true`, optionally `CYPRESS_COO_NAMESPACE=` | COO already installed. Tests still enable the monitoring plugin. Specify namespace if non-default. | -| **Pre-provisioned Virtualization** | `CYPRESS_SKIP_KBV_INSTALL=true` | OpenShift Virtualization already installed. | -| **Local Dev / PR Testing** | `CYPRESS_SKIP_ALL_INSTALL=true` | Run UI locally via `make start-feature-frontend` ([details](../../README.md#development)). Skips all setup. | -| **Custom Images** | `CYPRESS_MP_IMAGE`, `CYPRESS_MCP_CONSOLE_IMAGE`, `CYPRESS_CHA_IMAGE`, `CYPRESS_CUSTOM_COO_BUNDLE_IMAGE` | Patch component images in the CSV, or replace the operator bundle. Combine with an installation method above. | -| **FBC Image** | `CYPRESS_FBC_STAGE_COO_IMAGE` | Install COO from File-Based Catalog image. For release validation. | -| **Konflux CI Bundle** | `CYPRESS_KONFLUX_COO_BUNDLE_IMAGE=` | Install COO from Konflux CI bundle. For PR/CI testing. | +| Scenario | Key Variables | Description | +| ---------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| **Released Version** | `CYPRESS_COO_UI_INSTALL=true` | Install operators from redhat-operators catalog. Production-like testing. | +| **Pre-provisioned COO** | `CYPRESS_SKIP_COO_INSTALL=true`, optionally `CYPRESS_COO_NAMESPACE=` | COO already installed. Tests still enable the monitoring plugin. Specify namespace if non-default. | +| **Pre-provisioned Virtualization** | `CYPRESS_SKIP_KBV_INSTALL=true` | OpenShift Virtualization already installed. | +| **Local Dev / PR Testing** | `CYPRESS_SKIP_ALL_INSTALL=true` | Run UI locally via `make start-feature-frontend` ([details](../../README.md#development)). Skips all setup. | +| **Custom Images** | `CYPRESS_MP_IMAGE`, `CYPRESS_MCP_CONSOLE_IMAGE`, `CYPRESS_CHA_IMAGE`, `CYPRESS_CUSTOM_COO_BUNDLE_IMAGE` | Patch component images in the CSV, or replace the operator bundle. Combine with an installation method above. | +| **FBC Image** | `CYPRESS_FBC_STAGE_COO_IMAGE` | Install COO from File-Based Catalog image. For release validation. | +| **Konflux CI Bundle** | `CYPRESS_KONFLUX_COO_BUNDLE_IMAGE=` | Install COO from Konflux CI bundle. For PR/CI testing. | ### Test Areas -| Area | Description | Run Command | -|------|-------------|-------------| -| **Monitoring (CMO)** | Core monitoring tests against CMO stack. No additional operator installation needed. | `npm run test-cypress-monitoring` | -| **COO (Perses, Dashboards, Incidents)** | Requires COO installation. | `npm run test-cypress-coo` | -| **Incidents** | COO subset. Set `CYPRESS_TIMEZONE` to match cluster timezone. | `npm run test-cypress-incidents` | -| **Virtualization** | Requires OpenShift Virtualization (KubeVirt) installation. | `npm run test-cypress-virtualization` | +| Area | Description | Run Command | +| --------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------- | +| **Monitoring (CMO)** | Core monitoring tests against CMO stack. No additional operator installation needed. | `npm run test-cypress-monitoring` | +| **COO (Perses, Dashboards, Incidents)** | Requires COO installation. | `npm run test-cypress-coo` | +| **Incidents** | COO subset. Set `CYPRESS_TIMEZONE` to match cluster timezone. | `npm run test-cypress-incidents` | +| **Virtualization** | Requires OpenShift Virtualization (KubeVirt) installation. | `npm run test-cypress-virtualization` | --- @@ -92,65 +95,66 @@ All scenarios require the [standard variables](#required-variables) (`CYPRESS_BA ### Required Variables -| Variable | Description | Example | -|----------|-------------|---------| -| `CYPRESS_BASE_URL` | OpenShift Console URL | `https://console-openshift-console.apps...` | -| `CYPRESS_LOGIN_IDP` | Identity provider name | `flexy-htpasswd-provider` or `kube:admin` | -| `CYPRESS_LOGIN_IDP_DEV_USER`| Identity provider name for devuser | `flexy-htpasswd-provider` or `my_htpasswd_provider`| -| `CYPRESS_LOGIN_USERS` | Login credentials | `username:password` or `kubeadmin:password` or `kubeadmin:password,user1:password,user2:password` | -| `CYPRESS_KUBECONFIG_PATH` | Path to kubeconfig file | `~/Downloads/kubeconfig` | +| Variable | Description | Example | +| ---------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------- | +| `CYPRESS_BASE_URL` | OpenShift Console URL | `https://console-openshift-console.apps...` | +| `CYPRESS_LOGIN_IDP` | Identity provider name | `flexy-htpasswd-provider` or `kube:admin` | +| `CYPRESS_LOGIN_IDP_DEV_USER` | Identity provider name for devuser | `flexy-htpasswd-provider` or `my_htpasswd_provider` | +| `CYPRESS_LOGIN_USERS` | Login credentials | `username:password` or `kubeadmin:password` or `kubeadmin:password,user1:password,user2:password` | +| `CYPRESS_KUBECONFIG_PATH` | Path to kubeconfig file | `~/Downloads/kubeconfig` | ### Plugin Image Configuration -| Variable | Description | Use Case | -|----------|-------------|----------| -| `CYPRESS_MP_IMAGE` | Custom Monitoring Plugin image | Testing custom MP builds | +| Variable | Description | Use Case | +| --------------------------- | -------------------------------------- | ------------------------- | +| `CYPRESS_MP_IMAGE` | Custom Monitoring Plugin image | Testing custom MP builds | | `CYPRESS_MCP_CONSOLE_IMAGE` | Custom Monitoring Console Plugin image | Testing custom MCP builds | -| `CYPRESS_CHA_IMAGE` | Custom cluster-health-analyzer image | Testing custom CHA builds | +| `CYPRESS_CHA_IMAGE` | Custom cluster-health-analyzer image | Testing custom CHA builds | ### Operator Installation Control -| Variable | Default | Description | -|----------|---------|-------------| -| `CYPRESS_SKIP_COO_INSTALL` | `false` | Skip Cluster Observability Operator installation | -| `CYPRESS_SKIP_KBV_INSTALL` | `false` | Skip OpenShift Virtualization installation | +| Variable | Default | Description | +| -------------------------- | ------- | -------------------------------------------------------------- | +| `CYPRESS_SKIP_COO_INSTALL` | `false` | Skip Cluster Observability Operator installation | +| `CYPRESS_SKIP_KBV_INSTALL` | `false` | Skip OpenShift Virtualization installation | | `CYPRESS_SKIP_ALL_INSTALL` | `false` | Skip all operator installations (for pre-provisioned clusters) | -| `CYPRESS_COO_UI_INSTALL` | `false` | Install COO from redhat-operators catalog | -| `CYPRESS_KBV_UI_INSTALL` | `false` | Install Virtualization from redhat-operators catalog | +| `CYPRESS_COO_UI_INSTALL` | `false` | Install COO from redhat-operators catalog | +| `CYPRESS_KBV_UI_INSTALL` | `false` | Install Virtualization from redhat-operators catalog | ### Bundle Images -| Variable | Description | -|----------|-------------| -| `CYPRESS_KONFLUX_COO_BUNDLE_IMAGE` | COO bundle image from Konflux | -| `CYPRESS_CUSTOM_COO_BUNDLE_IMAGE` | Custom COO bundle image | +| Variable | Description | +| ---------------------------------- | ---------------------------------------- | +| `CYPRESS_KONFLUX_COO_BUNDLE_IMAGE` | COO bundle image from Konflux | +| `CYPRESS_CUSTOM_COO_BUNDLE_IMAGE` | Custom COO bundle image | | `CYPRESS_KONFLUX_KBV_BUNDLE_IMAGE` | Virtualization bundle image from Konflux | -| `CYPRESS_CUSTOM_KBV_BUNDLE_IMAGE` | Custom Virtualization bundle image | +| `CYPRESS_CUSTOM_KBV_BUNDLE_IMAGE` | Custom Virtualization bundle image | ### FBC images -| Variable | Description | -|----------|-------------| +| Variable | Description | +| ----------------------------- | ---------------------------------------- | | `CYPRESS_FBC_STAGE_COO_IMAGE` | Cluster Observability Operator FBC image | -| `CYPRESS_FBC_STAGE_KBV_IMAGE` | Virtualization FBC image | +| `CYPRESS_FBC_STAGE_KBV_IMAGE` | Virtualization FBC image | ### Testing Configuration -| Variable | Default | Description | -|----------|---------|-------------| +| Variable | Default | Description | +| ----------------- | ------- | ---------------------------------------------- | | `CYPRESS_SESSION` | `false` | Enable session management for faster execution | -| `CYPRESS_DEBUG` | `false` | Enable debug mode logging in headless mode | +| `CYPRESS_DEBUG` | `false` | Enable debug mode logging in headless mode | ### Incidents Testing Configuration **Used primarily for Incidents feature testing:** -| Variable | Default | Description | -|----------|---------|-------------| -| `CYPRESS_TIMEZONE` | `UTC` | Cluster timezone for incident timeline calculations | +| Variable | Default | Description | +| -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | +| `CYPRESS_TIMEZONE` | `UTC` | Cluster timezone for incident timeline calculations | | `CYPRESS_MOCK_NEW_METRICS` | `false` | Transform old metric names to new format in mocks (temporary workaround for testing against locally built instances) | **Example:** + ```bash export CYPRESS_TIMEZONE="America/New_York" export CYPRESS_MOCK_NEW_METRICS=true @@ -211,44 +215,35 @@ Tests are organized using tags for selective execution using [@cypress/grep](htt #### Tag Categories **1. Basic Tags:** -- `@smoke` - Fast BVT tests -- `@demo` - Interactive demo tests (no assertions, skipped in CI) + - `@flaky` - Tests that don't pass reliably - `@xfail` - Tests for known bugs expected to fail - `@slow` - Long-running e2e tests (15+ minutes) **2. High-Level Component Tags:** -- `@monitoring` - Monitoring plugin tests + - `@coo` - Cluster Observability Operator functionality tests (operator installation, ACM integration) - `@virtualization` - Virtualization integration tests -- `@alerts` - Alert-related tests -- `@metrics` - Metrics-related tests -- `@dashboards` - Dashboard-related tests (includes Perses) -**3. Specific Feature Tags** (format: `@{component}-{label}`): -- Example: `@incidents-redux` -- Add specific feature tags as needed +**3. Specific Feature Tags** (format: `@{component}`): + +- `@acm-alerting` - Alert-related tests in ACM perspective +- `@alerting` - Alert-related tests +- `@legacy-dashboards` - Legacy dashboard tests +- `@metrics` - Metrics explorer tests +- `@targets` - Targets tests +- `@perses-dashboards` - Perses dashboard tests - `@cluster-health-analyzer` - Incidents feature tests **4. JIRA Tags** (format: `@JIRA-{ID}`): + - Example: `@JIRA-OU-1033` - Link tests to specific JIRA issues #### Running Tests by Tags -**Run smoke tests (BVT):** -```bash -npx cypress run --env grepTags=@smoke -# or -npm run test-cypress-smoke -``` - -**Run regression tests (all non-smoke tests):** -```bash -npx cypress run --env grepTags="--@smoke --@flaky --@demo" -``` - **Run component-specific tests:** + ```bash npm run test-cypress-monitoring # All monitoring tests npm run test-cypress-incidents # All incidents tests @@ -259,40 +254,45 @@ npm run test-cypress-metrics # All metrics tests npm run test-cypress-dashboards # All dashboards tests (includes Perses) ``` -**Run smoke tests for specific component:** +**Run tests for specific component:** + ```bash -npm run test-cypress-monitoring-bvt # Monitoring smoke tests -npm run test-cypress-coo-bvt # COO smoke tests +npm run test-cypress-monitoring-bvt # Monitoring tests +npm run test-cypress-coo-bvt # COO tests ``` **Run regression for specific component:** + ```bash -npm run test-cypress-monitoring-regression # All monitoring except smoke +npm run test-cypress-monitoring-regression # All monitoring ``` **Run tests with multiple tags (OR logic):** + ```bash -npx cypress run --env grepTags="@smoke @slow" +npx cypress run --env grepTags="@alerting @cluster-health-analyzer" ``` **Run tests with BOTH tags (AND logic):** + ```bash -npx cypress run --env grepTags="@smoke+@cluster-health-analyzer" +npx cypress run --env grepTags="@alerting+@cluster-health-analyzer" ``` **Complex filtering:** + ```bash npx cypress run --env grepTags="@cluster-health-analyzer --@slow --@flaky" ``` --- - ## Test Results ### Videos Test recordings are saved automatically: + - **Location**: `web/cypress/videos/` - **Format**: `.mp4` - **Generated**: For all test runs (pass or fail) @@ -300,6 +300,7 @@ Test recordings are saved automatically: ### Screenshots Screenshots captured on test failures: + - **Location**: `web/cypress/screenshots/` - **Format**: `.png` - **Generated**: Only on failures @@ -311,6 +312,7 @@ Screenshots captured on test failures: ### Issue: Cypress Cannot Find Chrome/Browser **Solution**: Install Chrome or specify browser + ```bash npm run cypress:open --browser firefox ``` @@ -319,7 +321,8 @@ npm run cypress:open --browser firefox **Symptoms**: Tests fail with "BASE_URL is not defined" -**Solution**: +**Solution**: + 1. Verify variables are exported: `echo $CYPRESS_BASE_URL` 2. Re-run configuration: `source ./configure-env.sh` 3. Ensure you're in the correct shell session @@ -329,6 +332,7 @@ npm run cypress:open --browser firefox **Symptoms**: "ENOENT: no such file or directory" **Solution**: + ```bash # Check file exists ls -la $CYPRESS_KUBECONFIG_PATH @@ -342,6 +346,7 @@ export CYPRESS_KUBECONFIG_PATH=/correct/path/to/kubeconfig **Symptoms**: "User authentication failed" **Solution**: + 1. Verify IDP name: Check OpenShift OAuth configuration 2. Verify credentials are correct 3. For kubeadmin, use `kube:admin` as IDP @@ -349,6 +354,7 @@ export CYPRESS_KUBECONFIG_PATH=/correct/path/to/kubeconfig ### Issue: Tests Are Slow **Solution**: Enable session management + ```bash export CYPRESS_SESSION=true ``` @@ -416,10 +422,10 @@ For configuration scenarios, see [COO Tests](#test-configuration-scenarios) abov ### Incidents-Specific Variables -| Variable | Default | Description | -|----------|---------|-------------| -| `CYPRESS_TIMEZONE` | `UTC` | Cluster timezone for incident timeline calculations | -| `CYPRESS_MOCK_NEW_METRICS` | `false` | Transform old metric names to new format in mocks | +| Variable | Default | Description | +| -------------------------- | ------- | --------------------------------------------------- | +| `CYPRESS_TIMEZONE` | `UTC` | Cluster timezone for incident timeline calculations | +| `CYPRESS_MOCK_NEW_METRICS` | `false` | Transform old metric names to new format in mocks | ### Test Case Documentation @@ -427,4 +433,4 @@ Detailed test documentation: [`docs/incident_detection/tests/`](../../docs/incid --- -*For questions about test architecture, creating tests, or testing workflows, refer to [CYPRESS_TESTING_GUIDE.md](CYPRESS_TESTING_GUIDE.md)* +_For questions about test architecture, creating tests, or testing workflows, refer to [CYPRESS_TESTING_GUIDE.md](CYPRESS_TESTING_GUIDE.md)_ diff --git a/web/cypress/e2e/coo/01.coo_bvt.cy.ts b/web/cypress/e2e/coo/01.coo_bvt.cy.ts index 53e9f41e7..eba132f12 100644 --- a/web/cypress/e2e/coo/01.coo_bvt.cy.ts +++ b/web/cypress/e2e/coo/01.coo_bvt.cy.ts @@ -18,7 +18,7 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('BVT: COO', { tags: ['@smoke', '@coo'] }, () => { +describe('BVT: COO', { tags: ['@alerting', '@acm-alerting', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP); }); diff --git a/web/cypress/e2e/coo/01.coo_ivt.cy.ts b/web/cypress/e2e/coo/01.coo_ivt.cy.ts index 48f5d48c8..c6c19ff2d 100644 --- a/web/cypress/e2e/coo/01.coo_ivt.cy.ts +++ b/web/cypress/e2e/coo/01.coo_ivt.cy.ts @@ -16,20 +16,24 @@ const KBV = { }, }; -describe('IVT: Monitoring UIPlugin + Virtualization', { tags: ['@smoke', '@coo'] }, () => { - before(() => { - cy.beforeBlockVirtualization(KBV); - }); +describe( + 'IVT: Monitoring UIPlugin + Virtualization', + { tags: ['@alerting', '@coo', '@virtualization'] }, + () => { + before(() => { + cy.beforeBlockVirtualization(KBV); + }); - it('1. Virtualization perspective - Observe Menu', () => { - cy.log('Virtualization perspective - Observe Menu and verify all submenus'); - cy.switchPerspective('Virtualization', 'Fleet virtualization'); - guidedTour.closeKubevirtTour(); - troubleshootingPanelPage.signalCorrelationShouldNotBeVisible(); - cy.switchPerspective('Core platform', 'Administrator'); - }); + it('1. Virtualization perspective - Observe Menu', () => { + cy.log('Virtualization perspective - Observe Menu and verify all submenus'); + cy.switchPerspective('Virtualization', 'Fleet virtualization'); + guidedTour.closeKubevirtTour(); + troubleshootingPanelPage.signalCorrelationShouldNotBeVisible(); + cy.switchPerspective('Core platform', 'Administrator'); + }); - /** - * TODO: To be replaced by COO validation such as Dashboards (Perses) scenarios - */ -}); + /** + * TODO: To be replaced by COO validation such as Dashboards (Perses) scenarios + */ + }, +); diff --git a/web/cypress/e2e/coo/02.acm_alerting_ui.cy.ts b/web/cypress/e2e/coo/02.acm_alerting_ui.cy.ts index a4e712a07..fd200d879 100644 --- a/web/cypress/e2e/coo/02.acm_alerting_ui.cy.ts +++ b/web/cypress/e2e/coo/02.acm_alerting_ui.cy.ts @@ -24,7 +24,7 @@ const MP = { }; const expectedAlerts = ['Watchdog', 'Watchdog-spoke', 'ClusterCPUHealth-jb']; -describe('ACM Alerting UI', { tags: ['@coo', '@alerts', '@acm'] }, () => { +describe('ACM Alerting UI', { tags: ['@alerting', '@acm-alerting', '@coo'] }, () => { before(() => { cy.beforeBlockACM(MCP, MP); }); diff --git a/web/cypress/e2e/coo/03.coo_lightspeed_show_timeseries.cy.ts b/web/cypress/e2e/coo/03.coo_lightspeed_show_timeseries.cy.ts index 808b080d9..87de89a6e 100644 --- a/web/cypress/e2e/coo/03.coo_lightspeed_show_timeseries.cy.ts +++ b/web/cypress/e2e/coo/03.coo_lightspeed_show_timeseries.cy.ts @@ -30,13 +30,12 @@ const SEL = { /** * Non-deterministic test: relies on a live LLM (OLS) to produce a show_timeseries * tool call. The AI response is not guaranteed to be identical across runs. - * This test is tagged @ols and must NOT gate CI. It validates the end-to-end - * integration path: prompt -> tool call -> Perses chart rendering. + * It validates the end-to-end integration path: prompt -> tool call -> Perses chart rendering. * * Prerequisites: COO and OLS operators must be pre-installed. * Only authentication is needed — operator lifecycle is not managed here. */ -describe('COO-LightSpeed: show_timeseries', { tags: ['@ols'] }, () => { +describe('COO-LightSpeed: show_timeseries', { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { operatorAuthUtils.loginAndAuth(); cy.visit('/'); @@ -58,7 +57,9 @@ describe('COO-LightSpeed: show_timeseries', { tags: ['@ols'] }, () => { ).then(() => { // Fallback: delete any dashboard whose CR name matches the display name pattern cy.exec( - `oc get persesdashboard -n ${DASHBOARD_PROJECT} -o name --kubeconfig ${Cypress.env('KUBECONFIG_PATH')}`, + `oc get persesdashboard -n ${DASHBOARD_PROJECT} -o name --kubeconfig ${Cypress.env( + 'KUBECONFIG_PATH', + )}`, { failOnNonZeroExit: false }, ).then((result) => { if (result.stdout) { diff --git a/web/cypress/e2e/incidents/00.coo_incidents_e2e.cy.ts b/web/cypress/e2e/incidents/00.coo_incidents_e2e.cy.ts index 90ae69acb..f6cf6664d 100644 --- a/web/cypress/e2e/incidents/00.coo_incidents_e2e.cy.ts +++ b/web/cypress/e2e/incidents/00.coo_incidents_e2e.cy.ts @@ -20,7 +20,7 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('BVT: Incidents - e2e', { tags: ['@slow', '@cluster-health-analyzer'] }, () => { +describe('BVT: Incidents - e2e', { tags: ['@slow', '@cluster-health-analyzer', '@coo'] }, () => { let currentAlertName: string; before(() => { diff --git a/web/cypress/e2e/incidents/01.incidents.cy.ts b/web/cypress/e2e/incidents/01.incidents.cy.ts index c8f28d008..d5fa0983a 100644 --- a/web/cypress/e2e/incidents/01.incidents.cy.ts +++ b/web/cypress/e2e/incidents/01.incidents.cy.ts @@ -24,7 +24,7 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('BVT: Incidents - UI', { tags: ['@cluster-health-analyzer'] }, () => { +describe('BVT: Incidents - UI', { tags: ['@cluster-health-analyzer', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); incidentsPage.warmUpForPlugin(); diff --git a/web/cypress/e2e/incidents/02.incidents-mocking-example.cy.ts b/web/cypress/e2e/incidents/02.incidents-mocking-example.cy.ts index 97e583567..260468074 100644 --- a/web/cypress/e2e/incidents/02.incidents-mocking-example.cy.ts +++ b/web/cypress/e2e/incidents/02.incidents-mocking-example.cy.ts @@ -24,7 +24,7 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('Incidents - Mocking Examples', { tags: ['@cluster-health-analyzer'] }, () => { +describe('Incidents - Mocking Examples', { tags: ['@cluster-health-analyzer', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); }); diff --git a/web/cypress/e2e/incidents/performance/01.performance_benchmark.cy.ts b/web/cypress/e2e/incidents/performance/01.performance_benchmark.cy.ts index 98efcef99..b393354af 100644 --- a/web/cypress/e2e/incidents/performance/01.performance_benchmark.cy.ts +++ b/web/cypress/e2e/incidents/performance/01.performance_benchmark.cy.ts @@ -54,7 +54,7 @@ const collector = new BenchmarkCollector('01.performance_benchmark.cy.ts'); describe( 'Regression: Performance Benchmark', - { tags: ['@cluster-health-analyzer'], numTestsKeptInMemory: 0 }, + { tags: ['@cluster-health-analyzer', '@coo'], numTestsKeptInMemory: 0 }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/incidents/performance/02.performance_walkthrough.cy.ts b/web/cypress/e2e/incidents/performance/02.performance_walkthrough.cy.ts index 06ffe577a..efc987fa1 100644 --- a/web/cypress/e2e/incidents/performance/02.performance_walkthrough.cy.ts +++ b/web/cypress/e2e/incidents/performance/02.performance_walkthrough.cy.ts @@ -38,7 +38,7 @@ const collector = new BenchmarkCollector('02.performance_walkthrough.cy.ts'); describe( 'Performance: Interactive Walkthrough', - { tags: ['@cluster-health-analyzer'], numTestsKeptInMemory: 0 }, + { tags: ['@cluster-health-analyzer', '@coo'], numTestsKeptInMemory: 0 }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/incidents/regression/01.reg_filtering.cy.ts b/web/cypress/e2e/incidents/regression/01.reg_filtering.cy.ts index 8e3e4d3e7..168fb8a36 100644 --- a/web/cypress/e2e/incidents/regression/01.reg_filtering.cy.ts +++ b/web/cypress/e2e/incidents/regression/01.reg_filtering.cy.ts @@ -25,7 +25,7 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('Regression: Incidents Filtering', { tags: ['@cluster-health-analyzer'] }, () => { +describe('Regression: Incidents Filtering', { tags: ['@cluster-health-analyzer', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); }); diff --git a/web/cypress/e2e/incidents/regression/02.reg_ui_charts_comprehensive.cy.ts b/web/cypress/e2e/incidents/regression/02.reg_ui_charts_comprehensive.cy.ts index e2d3b3f71..71d883346 100644 --- a/web/cypress/e2e/incidents/regression/02.reg_ui_charts_comprehensive.cy.ts +++ b/web/cypress/e2e/incidents/regression/02.reg_ui_charts_comprehensive.cy.ts @@ -100,443 +100,447 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('Regression: Charts UI - Comprehensive', { tags: ['@cluster-health-analyzer'] }, () => { - before(() => { - cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); - incidentsPage.warmUpForPlugin(); - }); +describe( + 'Regression: Charts UI - Comprehensive', + { tags: ['@cluster-health-analyzer', '@coo'] }, + () => { + before(() => { + cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); + incidentsPage.warmUpForPlugin(); + }); - beforeEach(() => { - cy.mockIncidentFixture('incident-scenarios/12-charts-ui-comprehensive.yaml'); - }); + beforeEach(() => { + cy.mockIncidentFixture('incident-scenarios/12-charts-ui-comprehensive.yaml'); + }); - describe('Section 2.1: Tooltip Positioning', () => { - it('Tooltip positioning and content validation', () => { - cy.log('Setup: Clear filters and verify all incidents loaded'); - incidentsPage.clearAllFilters(); - incidentsPage.setDays('7 days'); - incidentsPage.elements.incidentsChartContainer().should('be.visible'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10); - - cy.log('1.1 Get total incident count for dynamic indexing'); - incidentsPage.elements - .incidentsChartBarsGroups() - .its('length') - .then((count) => { - cy.log(`Total incidents loaded: ${count}`); - - const bottomIndex = 0; - const topIndex = count - 1; - const middleIndex = Math.floor(count / 2); - - cy.log(`1.2 Test bottom incident (newest, index ${bottomIndex}) tooltip positioning`); - incidentsPage.getIncidentBarRect(bottomIndex).then((barRect) => { - incidentsPage.hoverOverIncidentBar(bottomIndex); - incidentsPage.elements.tooltip().then(($tooltip) => { - verifyTooltipPositioning( - $tooltip[0].getBoundingClientRect(), - barRect, - 'Bottom incident', - ); + describe('Section 2.1: Tooltip Positioning', () => { + it('Tooltip positioning and content validation', () => { + cy.log('Setup: Clear filters and verify all incidents loaded'); + incidentsPage.clearAllFilters(); + incidentsPage.setDays('7 days'); + incidentsPage.elements.incidentsChartContainer().should('be.visible'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10); + + cy.log('1.1 Get total incident count for dynamic indexing'); + incidentsPage.elements + .incidentsChartBarsGroups() + .its('length') + .then((count) => { + cy.log(`Total incidents loaded: ${count}`); + + const bottomIndex = 0; + const topIndex = count - 1; + const middleIndex = Math.floor(count / 2); + + cy.log(`1.2 Test bottom incident (newest, index ${bottomIndex}) tooltip positioning`); + incidentsPage.getIncidentBarRect(bottomIndex).then((barRect) => { + incidentsPage.hoverOverIncidentBar(bottomIndex); + incidentsPage.elements.tooltip().then(($tooltip) => { + verifyTooltipPositioning( + $tooltip[0].getBoundingClientRect(), + barRect, + 'Bottom incident', + ); + }); }); - }); - cy.log('Verified: Bottom incident tooltip appears above bar without overlapping'); - - cy.log(`1.3 Test middle incident (index ${middleIndex}) tooltip positioning`); - incidentsPage.getIncidentBarRect(middleIndex).then((barRect) => { - incidentsPage.hoverOverIncidentBar(middleIndex); - incidentsPage.elements.tooltip().then(($tooltip) => { - verifyTooltipPositioning( - $tooltip[0].getBoundingClientRect(), - barRect, - 'Middle incident', - ); + cy.log('Verified: Bottom incident tooltip appears above bar without overlapping'); + + cy.log(`1.3 Test middle incident (index ${middleIndex}) tooltip positioning`); + incidentsPage.getIncidentBarRect(middleIndex).then((barRect) => { + incidentsPage.hoverOverIncidentBar(middleIndex); + incidentsPage.elements.tooltip().then(($tooltip) => { + verifyTooltipPositioning( + $tooltip[0].getBoundingClientRect(), + barRect, + 'Middle incident', + ); + }); }); - }); - cy.log('Verified: Middle incident tooltip appears above bar without overlapping'); + cy.log('Verified: Middle incident tooltip appears above bar without overlapping'); - cy.log(`1.4 Test top incident (oldest, index ${topIndex}) tooltip positioning`); - incidentsPage.getIncidentBarRect(topIndex).then((barRect) => { - incidentsPage.hoverOverIncidentBar(topIndex); - cy.window().then((win) => { - incidentsPage.elements - .tooltip() - .first() - .then(($tooltip) => { - verifyTooltipPositioning( - $tooltip[0].getBoundingClientRect(), - barRect, - 'Top incident', - win, - ); - }); + cy.log(`1.4 Test top incident (oldest, index ${topIndex}) tooltip positioning`); + incidentsPage.getIncidentBarRect(topIndex).then((barRect) => { + incidentsPage.hoverOverIncidentBar(topIndex); + cy.window().then((win) => { + incidentsPage.elements + .tooltip() + .first() + .then(($tooltip) => { + verifyTooltipPositioning( + $tooltip[0].getBoundingClientRect(), + barRect, + 'Top incident', + win, + ); + }); + }); }); + cy.log('Verified: Top incident tooltip appears above bar and stays within viewport'); }); - cy.log('Verified: Top incident tooltip appears above bar and stays within viewport'); - }); - cy.log('2-4: Multi-incident verification (single traversal optimization)'); - cy.log('3.1 Firing vs resolved incident tooltips'); - cy.log('3.2 Find and verify firing incident (network-firing-short-002)'); - incidentsPage.hoverOverIncidentBar(0); - incidentsPage.elements - .tooltip() - .invoke('text') - .then((text) => { - expect(text).to.contain('network-firing-short-002'); - expect(text).to.match(/End.*---/); + cy.log('2-4: Multi-incident verification (single traversal optimization)'); + cy.log('3.1 Firing vs resolved incident tooltips'); + cy.log('3.2 Find and verify firing incident (network-firing-short-002)'); + incidentsPage.hoverOverIncidentBar(0); + incidentsPage.elements + .tooltip() + .invoke('text') + .then((text) => { + expect(text).to.contain('network-firing-short-002'); + expect(text).to.match(/End.*---/); + }); + cy.log('Verified: Firing incident shows --- for end time'); + + let foundMultiComponent = false; + let foundResolved = false; + let foundLongName = false; + + incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { + if (!foundMultiComponent || !foundResolved || !foundLongName) { + incidentsPage.hoverOverIncidentBar(index); + incidentsPage.elements + .tooltip() + .invoke('text') + .then((text) => { + if (!foundMultiComponent && text.includes('network-three-alerts-001')) { + cy.log('2.1 Multi-component tooltip content'); + cy.log(`Found network-three-alerts-001 at index ${index}`); + cy.log('2.3 Verify tooltip shows all 3 components'); + expect(text).to.contain('network'); + expect(text).to.contain('compute'); + expect(text).to.contain('storage'); + cy.log('Verified: Multi-component tooltip displays all components'); + foundMultiComponent = true; + } + + if (!foundResolved && text.includes('network-resolved-short-001')) { + cy.log('3.3 Find and verify resolved incident (network-resolved-short-001)'); + cy.log(`Found network-resolved-short-001 at index ${index}`); + expect(text).to.contain('Start'); + expect(text).to.contain('End'); + expect(text).to.not.match(/End.*---/); + cy.log('Verified: Resolved incident shows actual end time'); + foundResolved = true; + } + + if (!foundLongName && text.includes('others-very-long-name-001')) { + cy.log('4.1 Long alert name tooltip handling'); + cy.log(`Found others-very-long-name-001 at index ${index}`); + cy.log('4.2 Verify tooltip with long name stays within viewport'); + cy.window().then((win) => { + incidentsPage.elements + .tooltip() + .first() + .then(($tooltip) => { + const tooltipRect = $tooltip[0].getBoundingClientRect(); + expect(tooltipRect.right).to.be.lessThan(win.innerWidth); + expect(tooltipRect.bottom).to.be.lessThan(win.innerHeight); + expect(tooltipRect.left).to.be.greaterThan(0); + expect(tooltipRect.top).to.be.greaterThan(0); + }); + }); + cy.log('Verified: Tooltip with 180+ char alert name stays within viewport'); + foundLongName = true; + } + }); + } }); - cy.log('Verified: Firing incident shows --- for end time'); - let foundMultiComponent = false; - let foundResolved = false; - let foundLongName = false; + cy.log('5.1 Alert chart tooltip positioning'); + cy.log('5.2 Select incident with 6 alerts (etcd-six-alerts-001)'); - incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { - if (!foundMultiComponent || !foundResolved || !foundLongName) { - incidentsPage.hoverOverIncidentBar(index); - incidentsPage.elements - .tooltip() - .invoke('text') - .then((text) => { - if (!foundMultiComponent && text.includes('network-three-alerts-001')) { - cy.log('2.1 Multi-component tooltip content'); - cy.log(`Found network-three-alerts-001 at index ${index}`); - cy.log('2.3 Verify tooltip shows all 3 components'); - expect(text).to.contain('network'); - expect(text).to.contain('compute'); - expect(text).to.contain('storage'); - cy.log('Verified: Multi-component tooltip displays all components'); - foundMultiComponent = true; - } + incidentsPage.selectIncidentById('etcd-six-alerts-001'); - if (!foundResolved && text.includes('network-resolved-short-001')) { - cy.log('3.3 Find and verify resolved incident (network-resolved-short-001)'); - cy.log(`Found network-resolved-short-001 at index ${index}`); - expect(text).to.contain('Start'); - expect(text).to.contain('End'); - expect(text).to.not.match(/End.*---/); - cy.log('Verified: Resolved incident shows actual end time'); - foundResolved = true; - } + cy.log('5.3 Verify alerts chart displays alerts'); + incidentsPage.elements.alertsChartCard().should('be.visible'); + incidentsPage.elements.alertsChartBarsGroups().should('have.length.greaterThan', 0); - if (!foundLongName && text.includes('others-very-long-name-001')) { - cy.log('4.1 Long alert name tooltip handling'); - cy.log(`Found others-very-long-name-001 at index ${index}`); - cy.log('4.2 Verify tooltip with long name stays within viewport'); + cy.log('5.4 Test tooltip positioning for all alert bars'); + incidentsPage.elements + .alertsChartBarsVisiblePaths() + .its('length') + .then((alertCount) => { + cy.log(`Found ${alertCount} alert bars in chart`); + for (let i = 0; i < alertCount; i++) { + if (i > 1) { + break; + } + incidentsPage.getAlertBarRect(i).then((barRect) => { + incidentsPage.hoverOverAlertBar(i); cy.window().then((win) => { incidentsPage.elements - .tooltip() + .alertsChartTooltip() .first() .then(($tooltip) => { - const tooltipRect = $tooltip[0].getBoundingClientRect(); - expect(tooltipRect.right).to.be.lessThan(win.innerWidth); - expect(tooltipRect.bottom).to.be.lessThan(win.innerHeight); - expect(tooltipRect.left).to.be.greaterThan(0); - expect(tooltipRect.top).to.be.greaterThan(0); + verifyTooltipPositioning( + $tooltip[0].getBoundingClientRect(), + barRect, + `Alert ${i}`, + win, + ); }); }); - cy.log('Verified: Tooltip with 180+ char alert name stays within viewport'); - foundLongName = true; - } - }); - } + }); + } + }); + cy.log('Verified: All alert tooltips appear correctly above their bars'); }); + }); - cy.log('5.1 Alert chart tooltip positioning'); - cy.log('5.2 Select incident with 6 alerts (etcd-six-alerts-001)'); + describe('Section 2.2: Bar Sorting & Visibility', () => { + it('Bar sorting, visibility, and filtering', () => { + cy.log('Setup: Clear filters and verify all incidents loaded'); + incidentsPage.clearAllFilters(); + incidentsPage.setDays('7 days'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10); + + cy.log('1.1 Get total incident count'); + incidentsPage.elements + .incidentsChartBarsGroups() + .its('length') + .then((count) => { + const bottomIndex = 0; + const topIndex = count - 1; + + cy.log(`1.2 Verify newest incident is at bottom (index ${bottomIndex})`); + incidentsPage.hoverOverIncidentBar(bottomIndex); - incidentsPage.selectIncidentById('etcd-six-alerts-001'); + incidentsPage.elements + .tooltip() + .invoke('text') + .should('contain', 'network-firing-short-002'); - cy.log('5.3 Verify alerts chart displays alerts'); - incidentsPage.elements.alertsChartCard().should('be.visible'); - incidentsPage.elements.alertsChartBarsGroups().should('have.length.greaterThan', 0); + cy.log(`1.3 Verify oldest incident is at top (index ${topIndex})`); + incidentsPage.hoverOverIncidentBar(topIndex); - cy.log('5.4 Test tooltip positioning for all alert bars'); - incidentsPage.elements - .alertsChartBarsVisiblePaths() - .its('length') - .then((alertCount) => { - cy.log(`Found ${alertCount} alert bars in chart`); - for (let i = 0; i < alertCount; i++) { - if (i > 1) { - break; - } - incidentsPage.getAlertBarRect(i).then((barRect) => { - incidentsPage.hoverOverAlertBar(i); - cy.window().then((win) => { - incidentsPage.elements - .alertsChartTooltip() - .first() - .then(($tooltip) => { - verifyTooltipPositioning( - $tooltip[0].getBoundingClientRect(), - barRect, - `Alert ${i}`, - win, - ); - }); - }); - }); - } - }); - cy.log('Verified: All alert tooltips appear correctly above their bars'); - }); - }); + incidentsPage.elements.tooltip().invoke('text').should('contain', 'VSN-001'); - describe('Section 2.2: Bar Sorting & Visibility', () => { - it('Bar sorting, visibility, and filtering', () => { - cy.log('Setup: Clear filters and verify all incidents loaded'); - incidentsPage.clearAllFilters(); - incidentsPage.setDays('7 days'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10); - - cy.log('1.1 Get total incident count'); - incidentsPage.elements - .incidentsChartBarsGroups() - .its('length') - .then((count) => { - const bottomIndex = 0; - const topIndex = count - 1; - - cy.log(`1.2 Verify newest incident is at bottom (index ${bottomIndex})`); - incidentsPage.hoverOverIncidentBar(bottomIndex); - - incidentsPage.elements - .tooltip() - .invoke('text') - .should('contain', 'network-firing-short-002'); + cy.log( + 'Verified: Incidents are sorted chronologically with newest at bottom, oldest at top', + ); + }); - cy.log(`1.3 Verify oldest incident is at top (index ${topIndex})`); - incidentsPage.hoverOverIncidentBar(topIndex); + cy.log('2.1 Short duration incidents have visible bars'); + cy.log('2.2 Check network-firing-short-002 (10 min duration, index 0)'); + verifyIncidentBarIsVisible(0, 'Short duration firing incident'); + cy.log('Verified: Short duration firing incident has visible bar and is not transparent'); - incidentsPage.elements.tooltip().invoke('text').should('contain', 'VSN-001'); + cy.log('2.3 Find and check network-resolved-short-001 (10 min duration)'); + incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { + const groupId = $group.attr('data-test'); + if (groupId && groupId.includes('network-resolved-short-001')) { + cy.log(`Found network-resolved-short-001 at index ${index}`); - cy.log( - 'Verified: Incidents are sorted chronologically with newest at bottom, oldest at top', - ); + verifyIncidentBarIsVisible(index, 'Short duration resolved incident'); + cy.log( + 'Verified: Short duration resolved incident has visible bar and is not transparent', + ); + + return false; + } }); - cy.log('2.1 Short duration incidents have visible bars'); - cy.log('2.2 Check network-firing-short-002 (10 min duration, index 0)'); - verifyIncidentBarIsVisible(0, 'Short duration firing incident'); - cy.log('Verified: Short duration firing incident has visible bar and is not transparent'); + cy.log('3.1 Filtered bars maintain uniform Y-axis spacing'); - cy.log('2.3 Find and check network-resolved-short-001 (10 min duration)'); - incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { - const groupId = $group.attr('data-test'); - if (groupId && groupId.includes('network-resolved-short-001')) { - cy.log(`Found network-resolved-short-001 at index ${index}`); + const verifyUniformSpacing = ( + positions: number[], + context: string, + maxAllowedDeviation = 2, + ) => { + const spacings: number[] = []; + for (let i = 0; i < positions.length - 1; i++) { + spacings.push(positions[i + 1] - positions[i]); + } + + const avgSpacing = spacings.reduce((a, b) => a + b, 0) / spacings.length; + const maxDeviation = Math.max(...spacings.map((s) => Math.abs(s - avgSpacing))); - verifyIncidentBarIsVisible(index, 'Short duration resolved incident'); cy.log( - 'Verified: Short duration resolved incident has visible bar and is not transparent', + `${context}: ${positions.length} bars, avg spacing: ${avgSpacing.toFixed( + 2, + )}px, max deviation: ${maxDeviation.toFixed(2)}px`, ); + expect(maxDeviation, `${context}: spacing should be uniform`).to.be.lessThan( + maxAllowedDeviation, + ); + }; + + cy.log('3.2 Verify uniform spacing before filtering'); + const barPositionsBefore: number[] = []; + incidentsPage.elements + .incidentsChartBarsGroups() + .each(($group) => { + const rect = $group[0].getBoundingClientRect(); + barPositionsBefore.push(rect.top); + }) + .then(() => { + verifyUniformSpacing(barPositionsBefore, 'Before filter'); + }); - return false; - } - }); - - cy.log('3.1 Filtered bars maintain uniform Y-axis spacing'); - - const verifyUniformSpacing = ( - positions: number[], - context: string, - maxAllowedDeviation = 2, - ) => { - const spacings: number[] = []; - for (let i = 0; i < positions.length - 1; i++) { - spacings.push(positions[i + 1] - positions[i]); - } - - const avgSpacing = spacings.reduce((a, b) => a + b, 0) / spacings.length; - const maxDeviation = Math.max(...spacings.map((s) => Math.abs(s - avgSpacing))); + cy.log('3.3 Apply Critical filter'); + incidentsPage.toggleFilter('Critical'); + incidentsPage.elements.severityFilterChip().should('be.visible'); + + cy.log('3.4 Verify uniform spacing after filtering'); + const barPositionsAfter: number[] = []; + incidentsPage.elements + .incidentsChartBarsGroups() + .each(($group) => { + const rect = $group[0].getBoundingClientRect(); + barPositionsAfter.push(rect.top); + }) + .then(() => { + verifyUniformSpacing(barPositionsAfter, 'After filter'); + }); cy.log( - `${context}: ${positions.length} bars, avg spacing: ${avgSpacing.toFixed( - 2, - )}px, max deviation: ${maxDeviation.toFixed(2)}px`, + 'Verified: Critical filter applied and visible bars maintain uniform spacing without gaps', ); - expect(maxDeviation, `${context}: spacing should be uniform`).to.be.lessThan( - maxAllowedDeviation, - ); - }; - - cy.log('3.2 Verify uniform spacing before filtering'); - const barPositionsBefore: number[] = []; - incidentsPage.elements - .incidentsChartBarsGroups() - .each(($group) => { - const rect = $group[0].getBoundingClientRect(); - barPositionsBefore.push(rect.top); - }) - .then(() => { - verifyUniformSpacing(barPositionsBefore, 'Before filter'); - }); - - cy.log('3.3 Apply Critical filter'); - incidentsPage.toggleFilter('Critical'); - incidentsPage.elements.severityFilterChip().should('be.visible'); - - cy.log('3.4 Verify uniform spacing after filtering'); - const barPositionsAfter: number[] = []; - incidentsPage.elements - .incidentsChartBarsGroups() - .each(($group) => { - const rect = $group[0].getBoundingClientRect(); - barPositionsAfter.push(rect.top); - }) - .then(() => { - verifyUniformSpacing(barPositionsAfter, 'After filter'); - }); - - cy.log( - 'Verified: Critical filter applied and visible bars maintain uniform spacing without gaps', - ); + }); }); - }); - - describe('Section 2.3: Date/Time Display', () => { - it('Date and time display validation', () => { - cy.log('Setup: Clear filters'); - incidentsPage.clearAllFilters(); - - cy.log('1.2 Hover over firing incident and verify end shows ---'); - incidentsPage.hoverOverIncidentBar(0); - - incidentsPage.elements - .tooltip() - .invoke('text') - .then((text) => { - expect(text).to.contain('network-firing-short-002'); - expect(text).to.contain('Start'); - expect(text).to.match(/End.*---/); - }); - cy.log('Verified: Firing incident shows start time and --- for end'); - - cy.log('1.3 Find and verify resolved incident shows both start and end times'); - incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { - const groupId = $group.attr('data-test'); - if (groupId && groupId.includes('network-resolved-short-001')) { - cy.log(`Found network-resolved-short-001 at index ${index}`); - incidentsPage.hoverOverIncidentBar(index); - incidentsPage.elements - .tooltip() - .invoke('text') - .then((text) => { - expect(text).to.contain('Start'); - expect(text).to.contain('End'); - expect(text).to.not.match(/End.*---/); - }); - cy.log('Verified: Resolved incident shows both start and end times as timestamps'); + describe('Section 2.3: Date/Time Display', () => { + it('Date and time display validation', () => { + cy.log('Setup: Clear filters'); + incidentsPage.clearAllFilters(); - return false; - } - }); + cy.log('1.2 Hover over firing incident and verify end shows ---'); + incidentsPage.hoverOverIncidentBar(0); - cy.log('2.1 Multi-severity incident segments'); - cy.log('2.2 Find monitoring-gradual-alerts-001 incident'); - incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { - const groupId = $group.attr('data-test'); - if (groupId && groupId.includes('monitoring-gradual-alerts-001')) { - cy.log(`Found monitoring-gradual-alerts-001 at index ${index}`); + incidentsPage.elements + .tooltip() + .invoke('text') + .then((text) => { + expect(text).to.contain('network-firing-short-002'); + expect(text).to.contain('Start'); + expect(text).to.match(/End.*---/); + }); + cy.log('Verified: Firing incident shows start time and --- for end'); + + cy.log('1.3 Find and verify resolved incident shows both start and end times'); + incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { + const groupId = $group.attr('data-test'); + if (groupId && groupId.includes('network-resolved-short-001')) { + cy.log(`Found network-resolved-short-001 at index ${index}`); + incidentsPage.hoverOverIncidentBar(index); + + incidentsPage.elements + .tooltip() + .invoke('text') + .then((text) => { + expect(text).to.contain('Start'); + expect(text).to.contain('End'); + expect(text).to.not.match(/End.*---/); + }); + cy.log('Verified: Resolved incident shows both start and end times as timestamps'); - cy.log('2.3 Verify bar has multiple severity segments'); - cy.wrap($group).find('path[role="presentation"]').should('have.length.greaterThan', 1); - cy.log('Verified: Multi-severity incident has multiple colored segments'); + return false; + } + }); - return false; - } - }); + cy.log('2.1 Multi-severity incident segments'); + cy.log('2.2 Find monitoring-gradual-alerts-001 incident'); + incidentsPage.elements.incidentsChartBarsGroups().each(($group, index) => { + const groupId = $group.attr('data-test'); + if (groupId && groupId.includes('monitoring-gradual-alerts-001')) { + cy.log(`Found monitoring-gradual-alerts-001 at index ${index}`); - cy.log('3.1 Date format validation'); - incidentsPage.hoverOverIncidentBar(0); + cy.log('2.3 Verify bar has multiple severity segments'); + cy.wrap($group).find('path[role="presentation"]').should('have.length.greaterThan', 1); + cy.log('Verified: Multi-severity incident has multiple colored segments'); - cy.log('3.2 Verify tooltip contains formatted timestamps'); - incidentsPage.elements - .tooltip() - .invoke('text') - .then((text) => { - expect(text).to.match(/\d{1,2}:\d{2}/); + return false; + } }); - cy.log('Verified: Tooltips display formatted date/time'); - - cy.log('4.1 Alert-level time verification in table'); - cy.log('4.1.1 Select oldest incident for alert time verification'); - incidentsPage.selectIncidentById('VSN-001'); - cy.log('4.2 Expand all rows to see alert details'); - incidentsPage.elements.incidentsTable().should('be.visible'); + cy.log('3.1 Date format validation'); + incidentsPage.hoverOverIncidentBar(0); - cy.log('4.3 Get alert information'); - incidentsPage.getSelectedIncidentAlerts().then((alerts) => { - expect(alerts.length).to.be.greaterThan(0); - - cy.log('4.4 Verify each alert has start time'); - alerts.forEach((alert, index) => { - alert - .getStartCell() - .invoke('text') - .then((startText) => { - expect(startText.trim()).to.not.equal(''); - expect(startText.trim()).to.not.be.equal('-'); - cy.log(`Alert ${index + 1} start time: ${startText.trim()}`); - }); - }); + cy.log('3.2 Verify tooltip contains formatted timestamps'); + incidentsPage.elements + .tooltip() + .invoke('text') + .then((text) => { + expect(text).to.match(/\d{1,2}:\d{2}/); + }); + cy.log('Verified: Tooltips display formatted date/time'); + + cy.log('4.1 Alert-level time verification in table'); + cy.log('4.1.1 Select oldest incident for alert time verification'); + incidentsPage.selectIncidentById('VSN-001'); + + cy.log('4.2 Expand all rows to see alert details'); + incidentsPage.elements.incidentsTable().should('be.visible'); + + cy.log('4.3 Get alert information'); + incidentsPage.getSelectedIncidentAlerts().then((alerts) => { + expect(alerts.length).to.be.greaterThan(0); + + cy.log('4.4 Verify each alert has start time'); + alerts.forEach((alert, index) => { + alert + .getStartCell() + .invoke('text') + .then((startText) => { + expect(startText.trim()).to.not.equal(''); + expect(startText.trim()).to.not.be.equal('-'); + cy.log(`Alert ${index + 1} start time: ${startText.trim()}`); + }); + }); - cy.log('4.5 Verify firing alerts show --- or Firing for end time'); - alerts.forEach((alert, index) => { - alert - .getEndCell() - .invoke('text') - .then((endText) => { - expect(endText.trim()).to.not.equal(''); - cy.log(`Alert ${index + 1} end time: ${endText.trim()}`); - }); + cy.log('4.5 Verify firing alerts show --- or Firing for end time'); + alerts.forEach((alert, index) => { + alert + .getEndCell() + .invoke('text') + .then((endText) => { + expect(endText.trim()).to.not.equal(''); + cy.log(`Alert ${index + 1} end time: ${endText.trim()}`); + }); + }); }); + cy.log('Verified: Alert times in table display correctly with valid timestamps'); }); - cy.log('Verified: Alert times in table display correctly with valid timestamps'); }); - }); - describe('Section 3.1: Short Duration Incidents Visibility', () => { - it('Very short duration incidents are visible and selectable', () => { - cy.log('Setup: Clear filters and verify all incidents loaded'); - incidentsPage.clearAllFilters(); - incidentsPage.setDays('7 days'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10); - - cy.log('1.1 Test 5-minute duration incident (api-server-transient-001)'); - cy.log('1.2 Find the incident bar by ID and verify visibility'); - incidentsPage.elements.incidentsChartBarsGroups().then(($groups) => { - const index = $groups - .toArray() - .findIndex((el) => el.getAttribute('data-test')?.includes('api-server-transient-001')); - cy.log('1.3 Verify 1-min incident bar is visible and not transparent'); - verifyIncidentBarIsVisible(index, '1-min incident'); - }); + describe('Section 3.1: Short Duration Incidents Visibility', () => { + it('Very short duration incidents are visible and selectable', () => { + cy.log('Setup: Clear filters and verify all incidents loaded'); + incidentsPage.clearAllFilters(); + incidentsPage.setDays('7 days'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 10); + + cy.log('1.1 Test 5-minute duration incident (api-server-transient-001)'); + cy.log('1.2 Find the incident bar by ID and verify visibility'); + incidentsPage.elements.incidentsChartBarsGroups().then(($groups) => { + const index = $groups + .toArray() + .findIndex((el) => el.getAttribute('data-test')?.includes('api-server-transient-001')); + cy.log('1.3 Verify 1-min incident bar is visible and not transparent'); + verifyIncidentBarIsVisible(index, '1-min incident'); + }); - cy.log('1.4 Verify incident can be selected and alerts load'); - incidentsPage.selectIncidentById('api-server-transient-001'); - incidentsPage.elements.incidentsTable().should('be.visible'); - incidentsPage.elements.incidentsDetailsTableRows().should('have.length.greaterThan', 0); + cy.log('1.4 Verify incident can be selected and alerts load'); + incidentsPage.selectIncidentById('api-server-transient-001'); + incidentsPage.elements.incidentsTable().should('be.visible'); + incidentsPage.elements.incidentsDetailsTableRows().should('have.length.greaterThan', 0); - cy.log('1.5 Verify alert details are displayed'); - incidentsPage.getSelectedIncidentAlerts().then((alerts) => { - expect(alerts.length, '1-min incident should have at least 1 alert').to.be.greaterThan(0); - alerts[0] - .getAlertRuleCell() - .invoke('text') - .then((alertName) => { - expect(alertName).to.contain( - 'APIServerRequestLatencyBriefSpikeDetectedDuringHighTrafficPeriod001', - ); - }); + cy.log('1.5 Verify alert details are displayed'); + incidentsPage.getSelectedIncidentAlerts().then((alerts) => { + expect(alerts.length, '1-min incident should have at least 1 alert').to.be.greaterThan(0); + alerts[0] + .getAlertRuleCell() + .invoke('text') + .then((alertName) => { + expect(alertName).to.contain( + 'APIServerRequestLatencyBriefSpikeDetectedDuringHighTrafficPeriod001', + ); + }); + }); + cy.log( + 'Verified: 1-minute duration incident is visible, not transparent, selectable, and loads alerts', + ); }); - cy.log( - 'Verified: 1-minute duration incident is visible, not transparent, selectable, and loads alerts', - ); }); - }); -}); + }, +); diff --git a/web/cypress/e2e/incidents/regression/02.reg_ui_tooltip_boundary_times.cy.ts b/web/cypress/e2e/incidents/regression/02.reg_ui_tooltip_boundary_times.cy.ts index dfc8cfadd..e14001afb 100644 --- a/web/cypress/e2e/incidents/regression/02.reg_ui_tooltip_boundary_times.cy.ts +++ b/web/cypress/e2e/incidents/regression/02.reg_ui_tooltip_boundary_times.cy.ts @@ -30,7 +30,7 @@ const MP = { describe( 'Regression: Mixed Severity Interval Boundary Times', - { tags: ['@cluster-health-analyzer', '@xfail'] }, + { tags: ['@cluster-health-analyzer', '@xfail', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/incidents/regression/03-04.reg_e2e_firing_alerts.cy.ts b/web/cypress/e2e/incidents/regression/03-04.reg_e2e_firing_alerts.cy.ts index 0763ce8b4..3496ec6ca 100644 --- a/web/cypress/e2e/incidents/regression/03-04.reg_e2e_firing_alerts.cy.ts +++ b/web/cypress/e2e/incidents/regression/03-04.reg_e2e_firing_alerts.cy.ts @@ -36,7 +36,7 @@ const MP = { describe( 'Regression: Time-Based Alert Resolution (E2E with Firing Alerts)', - { tags: ['@cluster-health-analyzer', '@slow'] }, + { tags: ['@cluster-health-analyzer', '@slow', '@coo'] }, () => { let currentAlertName: string; diff --git a/web/cypress/e2e/incidents/regression/03.reg_api_calls.cy.ts b/web/cypress/e2e/incidents/regression/03.reg_api_calls.cy.ts index 0e8440f65..0ee3f6f97 100644 --- a/web/cypress/e2e/incidents/regression/03.reg_api_calls.cy.ts +++ b/web/cypress/e2e/incidents/regression/03.reg_api_calls.cy.ts @@ -33,7 +33,7 @@ const MP = { describe( 'Regression: Silences Not Applied Correctly', - { tags: ['@cluster-health-analyzer'] }, + { tags: ['@cluster-health-analyzer', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); @@ -141,47 +141,51 @@ describe( }, ); -describe('Regression: Permission Denied Handling', { tags: ['@cluster-health-analyzer'] }, () => { - before(() => { - cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); - }); - - beforeEach(() => { - cy.log('Mock all API endpoints as 403 Forbidden'); - cy.mockPermissionDenied(); - cy.log('Navigate to Observe -> Incidents'); - // Using custom navigation commands to avoid waiting for the page - // to load which never happens in this test - nav.sidenav.clickNavLink(['Observe', 'Alerting']); - nav.tabs.switchTab('Incidents'); - }); - - it('Page displays access denied state when all API endpoints return 403 Forbidden', () => { - cy.log('1.1 Verify 403 requests were intercepted'); - const waitTimeout = { timeout: 120000 }; - cy.wait('@rulesPermissionDenied', waitTimeout) - .its('response') - .should('exist') - .its('statusCode') - .should('eq', 403); - cy.wait('@silencesPermissionDenied', waitTimeout) - .its('response') - .should('exist') - .its('statusCode') - .should('eq', 403); - cy.wait('@prometheusQueryRangePermissionDenied', waitTimeout) - .its('response') - .should('exist') - .its('statusCode') - .should('eq', 403); - - cy.log('1.2 Verify access denied empty state is displayed'); - cy.byTestID('access-denied').should('be.visible'); - cy.byTestID('access-denied').should( - 'contain.text', - "You don't have access to this section due to cluster policy", - ); - - cy.log('Verified: Page displays restricted access state for permission denied'); - }); -}); +describe( + 'Regression: Permission Denied Handling', + { tags: ['@cluster-health-analyzer', '@coo'] }, + () => { + before(() => { + cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); + }); + + beforeEach(() => { + cy.log('Mock all API endpoints as 403 Forbidden'); + cy.mockPermissionDenied(); + cy.log('Navigate to Observe -> Incidents'); + // Using custom navigation commands to avoid waiting for the page + // to load which never happens in this test + nav.sidenav.clickNavLink(['Observe', 'Alerting']); + nav.tabs.switchTab('Incidents'); + }); + + it('Page displays access denied state when all API endpoints return 403 Forbidden', () => { + cy.log('1.1 Verify 403 requests were intercepted'); + const waitTimeout = { timeout: 120000 }; + cy.wait('@rulesPermissionDenied', waitTimeout) + .its('response') + .should('exist') + .its('statusCode') + .should('eq', 403); + cy.wait('@silencesPermissionDenied', waitTimeout) + .its('response') + .should('exist') + .its('statusCode') + .should('eq', 403); + cy.wait('@prometheusQueryRangePermissionDenied', waitTimeout) + .its('response') + .should('exist') + .its('statusCode') + .should('eq', 403); + + cy.log('1.2 Verify access denied empty state is displayed'); + cy.byTestID('access-denied').should('be.visible'); + cy.byTestID('access-denied').should( + 'contain.text', + "You don't have access to this section due to cluster policy", + ); + + cy.log('Verified: Page displays restricted access state for permission denied'); + }); + }, +); diff --git a/web/cypress/e2e/incidents/regression/04.reg_redux_effects.cy.ts b/web/cypress/e2e/incidents/regression/04.reg_redux_effects.cy.ts index 8b636961e..3dd7d7f32 100644 --- a/web/cypress/e2e/incidents/regression/04.reg_redux_effects.cy.ts +++ b/web/cypress/e2e/incidents/regression/04.reg_redux_effects.cy.ts @@ -30,164 +30,181 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('Regression: Redux State Management', { tags: ['@cluster-health-analyzer'] }, () => { - before(() => { - cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); - incidentsPage.warmUpForPlugin(); - }); - - beforeEach(() => { - cy.log('Setting up comprehensive filtering test scenarios'); - cy.mockIncidentFixture('incident-scenarios/7-comprehensive-filtering-test-scenarios.yaml'); - }); - - it('1. Fresh load should display all 12 incidents without days filter manipulation', () => { - cy.log('1.1 Verify all incidents load immediately on fresh page load'); - - incidentsPage.clearAllFilters(); - incidentsPage.elements.incidentsChartContainer().should('be.visible'); - - // The bug: initially not all incidents are loaded, requiring days filter toggle - // Use waitUntil to give it time to load, but it should load quickly if working properly - cy.waitUntil( - () => - incidentsPage.elements.incidentsChartBarsGroups().then(($groups) => $groups.length === 12), - { - timeout: 10000, - interval: 500, - errorMsg: 'All 12 incidents should load within 10 seconds on fresh page load', - }, - ); - cy.log('SUCCESS: All 12 incidents loaded on fresh page load'); - - cy.log('1.2 Verify incident count remains stable without manipulation'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 12); - cy.log('Incident count stable: 12 incidents maintained'); - - cy.log('1.3 Verify days filter is set to default value'); - incidentsPage.elements.daysSelectToggle().should('contain.text', '7 days'); - cy.log('Default days filter confirmed: 7 days'); - }); - - it('2. Dropdown should close and not reposition after incident deselection', () => { - const dropdownScenarios = [ - { - name: 'Filter type', - setup: () => {}, - toggleElement: () => incidentsPage.elements.filtersSelectToggle(), - listElement: () => incidentsPage.elements.filtersSelectList(), - }, - { - name: 'Severity value', - setup: () => { - incidentsPage.elements.filtersSelectToggle().click(); - incidentsPage.elements.filtersSelectOption('Severity').click(); - }, - toggleElement: () => incidentsPage.elements.severityFilterToggle(), - listElement: () => incidentsPage.elements.severityFilterList(), - }, - { - name: 'Days filter', - setup: () => {}, - toggleElement: () => incidentsPage.elements.daysSelectToggle(), - listElement: () => incidentsPage.elements.daysSelectList(), - }, - ]; - - const deselectionMethods = [ - { - name: 'bar click', - action: () => { +describe( + 'Regression: Redux State Management', + { tags: ['@cluster-health-analyzer', '@coo'] }, + () => { + before(() => { + cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); + incidentsPage.warmUpForPlugin(); + }); + + beforeEach(() => { + cy.log('Setting up comprehensive filtering test scenarios'); + cy.mockIncidentFixture('incident-scenarios/7-comprehensive-filtering-test-scenarios.yaml'); + }); + + it('1. Fresh load should display all 12 incidents without days filter manipulation', () => { + cy.log('1.1 Verify all incidents load immediately on fresh page load'); + + incidentsPage.clearAllFilters(); + incidentsPage.elements.incidentsChartContainer().should('be.visible'); + + // The bug: initially not all incidents are loaded, requiring days filter toggle + // Use waitUntil to give it time to load, but it should load quickly if working properly + cy.waitUntil( + () => incidentsPage.elements - .incidentsChartBarsVisiblePathsNonEmpty() - .first() - .click({ force: true }); + .incidentsChartBarsGroups() + .then(($groups) => $groups.length === 12), + { + timeout: 10000, + interval: 500, + errorMsg: 'All 12 incidents should load within 10 seconds on fresh page load', + }, + ); + cy.log('SUCCESS: All 12 incidents loaded on fresh page load'); + + cy.log('1.2 Verify incident count remains stable without manipulation'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 12); + cy.log('Incident count stable: 12 incidents maintained'); + + cy.log('1.3 Verify days filter is set to default value'); + incidentsPage.elements.daysSelectToggle().should('contain.text', '7 days'); + cy.log('Default days filter confirmed: 7 days'); + }); + + it('2. Dropdown should close and not reposition after incident deselection', () => { + const dropdownScenarios = [ + { + name: 'Filter type', + setup: () => {}, + toggleElement: () => incidentsPage.elements.filtersSelectToggle(), + listElement: () => incidentsPage.elements.filtersSelectList(), }, - }, - { - name: 'chip removal', - action: () => { - incidentsPage.removeFilterCategory('Incident ID'); + { + name: 'Severity value', + setup: () => { + incidentsPage.elements.filtersSelectToggle().click(); + incidentsPage.elements.filtersSelectOption('Severity').click(); + }, + toggleElement: () => incidentsPage.elements.severityFilterToggle(), + listElement: () => incidentsPage.elements.severityFilterList(), }, - }, - ]; + { + name: 'Days filter', + setup: () => {}, + toggleElement: () => incidentsPage.elements.daysSelectToggle(), + listElement: () => incidentsPage.elements.daysSelectList(), + }, + ]; + + const deselectionMethods = [ + { + name: 'bar click', + action: () => { + incidentsPage.elements + .incidentsChartBarsVisiblePathsNonEmpty() + .first() + .click({ force: true }); + }, + }, + { + name: 'chip removal', + action: () => { + incidentsPage.removeFilterCategory('Incident ID'); + }, + }, + ]; - incidentsPage.clearAllFilters(); + incidentsPage.clearAllFilters(); - dropdownScenarios.forEach((dropdown) => { - deselectionMethods.forEach((deselection) => { - cy.log(`Testing: ${dropdown.name} dropdown with ${deselection.name} deselection`); + dropdownScenarios.forEach((dropdown) => { + deselectionMethods.forEach((deselection) => { + cy.log(`Testing: ${dropdown.name} dropdown with ${deselection.name} deselection`); - incidentsPage.elements - .incidentsChartBarsVisiblePathsNonEmpty() - .first() - .click({ force: true }); + incidentsPage.elements + .incidentsChartBarsVisiblePathsNonEmpty() + .first() + .click({ force: true }); - incidentsPage.elements.alertsChartContainer().first().scrollIntoView().should('be.visible'); - incidentsPage.elements.incidentIdFilterChip().first().scrollIntoView().should('be.visible'); + incidentsPage.elements + .alertsChartContainer() + .first() + .scrollIntoView() + .should('be.visible'); + incidentsPage.elements + .incidentIdFilterChip() + .first() + .scrollIntoView() + .should('be.visible'); - dropdown.setup(); + dropdown.setup(); - dropdown.toggleElement().click(); - dropdown.listElement().should('be.visible'); + dropdown.toggleElement().click(); + dropdown.listElement().should('be.visible'); - deselection.action(); + deselection.action(); - cy.wait(2000); + cy.wait(2000); - dropdown.listElement().should('not.exist'); - cy.log(`SUCCESS: ${dropdown.name} dropdown closed after ${deselection.name}`); + dropdown.listElement().should('not.exist'); + cy.log(`SUCCESS: ${dropdown.name} dropdown closed after ${deselection.name}`); + }); }); }); - }); - - it('3. Adding filter when incident selected should not remove the incident ID filter', () => { - cy.log('3.1 Clear all filters and ensure critical incidents exist'); - incidentsPage.clearAllFilters(); - - cy.log('3.2 Apply critical severity filter'); - incidentsPage.toggleFilter('Critical'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length.greaterThan', 0); - - cy.log('3.3 Click on the first critical incident to select it by ID'); - incidentsPage.elements.incidentsChartBarsVisiblePathsNonEmpty().first().click({ force: true }); - - cy.log('3.4 Verify incident ID filter chip appears'); - incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); - - cy.log('3.5 Verify both Critical and Incident ID chips are present'); - incidentsPage.elements.filterChipValue('Critical').should('be.visible'); - incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); - - cy.log( - '3.6 Deselect Critical and Apply Warning filter (which does not match the critical incident)', - ); - cy.wait(500); - incidentsPage.toggleFilter('Critical'); - incidentsPage.elements.filterChipValue('Critical').should('not.exist'); - - incidentsPage.toggleFilter('Warning'); - - cy.log('3.7 Verify incident is filtered out (no bars visible)'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 0); - cy.log('Incident correctly filtered out due to Warning filter'); - - cy.log('3.8 Verify BOTH Warning filter and Incident ID filter are still applied'); - incidentsPage.elements.filterChipValue('Warning').should('be.visible'); - incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); - - cy.log( - 'SUCCESS: Incident ID filter was not removed when non-matching severity filter was added', - ); - - cy.log('3.9 Remove Warning filter and verify incident reappears'); - // Legacy path for quick rollback: - // incidentsPage.toggleFilter('Warning'); - incidentsPage.deselectFilterValue('Warning'); - - cy.log('3.10 With only Incident ID filter, incident should be visible again'); - incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 1); - incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); - cy.log('SUCCESS: Incident reappears when conflicting filter removed'); - }); -}); + + it('3. Adding filter when incident selected should not remove the incident ID filter', () => { + cy.log('3.1 Clear all filters and ensure critical incidents exist'); + incidentsPage.clearAllFilters(); + + cy.log('3.2 Apply critical severity filter'); + incidentsPage.toggleFilter('Critical'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length.greaterThan', 0); + + cy.log('3.3 Click on the first critical incident to select it by ID'); + incidentsPage.elements + .incidentsChartBarsVisiblePathsNonEmpty() + .first() + .click({ force: true }); + + cy.log('3.4 Verify incident ID filter chip appears'); + incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); + + cy.log('3.5 Verify both Critical and Incident ID chips are present'); + incidentsPage.elements.filterChipValue('Critical').should('be.visible'); + incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); + + cy.log( + '3.6 Deselect Critical and Apply Warning filter (which does not match the critical incident)', + ); + cy.wait(500); + incidentsPage.toggleFilter('Critical'); + incidentsPage.elements.filterChipValue('Critical').should('not.exist'); + + incidentsPage.toggleFilter('Warning'); + + cy.log('3.7 Verify incident is filtered out (no bars visible)'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 0); + cy.log('Incident correctly filtered out due to Warning filter'); + + cy.log('3.8 Verify BOTH Warning filter and Incident ID filter are still applied'); + incidentsPage.elements.filterChipValue('Warning').should('be.visible'); + incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); + + cy.log( + 'SUCCESS: Incident ID filter was not removed when non-matching severity filter was added', + ); + + cy.log('3.9 Remove Warning filter and verify incident reappears'); + // Legacy path for quick rollback: + // incidentsPage.toggleFilter('Warning'); + incidentsPage.deselectFilterValue('Warning'); + + cy.log('3.10 With only Incident ID filter, incident should be visible again'); + incidentsPage.elements.incidentsChartBarsGroups().should('have.length', 1); + incidentsPage.elements.incidentIdFilterChip().first().should('be.visible'); + cy.log('SUCCESS: Incident reappears when conflicting filter removed'); + }); + }, +); diff --git a/web/cypress/e2e/incidents/regression/05.reg_stress_testing_ui.cy.ts b/web/cypress/e2e/incidents/regression/05.reg_stress_testing_ui.cy.ts index ee8793ab7..7d0c700ae 100644 --- a/web/cypress/e2e/incidents/regression/05.reg_stress_testing_ui.cy.ts +++ b/web/cypress/e2e/incidents/regression/05.reg_stress_testing_ui.cy.ts @@ -31,7 +31,7 @@ const MP = { const MAX_GAP_STANDARD = 250; const MAX_GAP_RELAXED = 500; -describe('Regression: Stress Testing UI', { tags: ['@cluster-health-analyzer'] }, () => { +describe('Regression: Stress Testing UI', { tags: ['@cluster-health-analyzer', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: false, troubleshootingPanel: false }); incidentsPage.warmUpForPlugin(); diff --git a/web/cypress/e2e/monitoring/00.bvt_admin.cy.ts b/web/cypress/e2e/monitoring/00.bvt_admin.cy.ts index b082cab6b..7c2445512 100644 --- a/web/cypress/e2e/monitoring/00.bvt_admin.cy.ts +++ b/web/cypress/e2e/monitoring/00.bvt_admin.cy.ts @@ -9,70 +9,74 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('BVT: Monitoring', { tags: ['@smoke', '@monitoring'] }, () => { - before(() => { - cy.beforeBlock(MP); - }); +describe( + 'BVT: Monitoring', + { tags: ['@alerting', '@legacy-dashboards', '@metrics', '@targets'] }, + () => { + before(() => { + cy.beforeBlock(MP); + }); - beforeEach(() => { - nav.sidenav.clickNavLink(['Observe', 'Metrics']); - commonPages.titleShouldHaveText('Metrics'); - cy.changeNamespace('All Projects'); - alerts.getWatchdogAlert(); - nav.sidenav.clickNavLink(['Observe', 'Alerting']); - commonPages.titleShouldHaveText('Alerting'); - alerts.getWatchdogAlert(); - }); + beforeEach(() => { + nav.sidenav.clickNavLink(['Observe', 'Metrics']); + commonPages.titleShouldHaveText('Metrics'); + cy.changeNamespace('All Projects'); + alerts.getWatchdogAlert(); + nav.sidenav.clickNavLink(['Observe', 'Alerting']); + commonPages.titleShouldHaveText('Alerting'); + alerts.getWatchdogAlert(); + }); - it(`1. Admin perspective - Observe Menu`, () => { - cy.log(`Admin perspective - Observe Menu and verify all submenus`); - nav.sidenav.clickNavLink(['Administration', 'Cluster Settings']); - commonPages.detailsPage.administration_clusterSettings(); - nav.sidenav.clickNavLink(['Observe', 'Alerting']); - commonPages.titleShouldHaveText('Alerting'); - nav.tabs.switchTab('Silences'); - nav.sidenav.clickNavLink(['Observe', 'Metrics']); - commonPages.titleShouldHaveText('Metrics'); - nav.sidenav.clickNavLink(['Observe', 'Dashboards']); - commonPages.titleShouldHaveText('Dashboards'); - nav.sidenav.clickNavLink(['Observe', 'Targets']); - commonPages.titleShouldHaveText('Metrics targets'); - }); - // TODO: Intercept Bell GET request to inject an alert (Watchdog to have it opened in - // Alert Details page?) - // it('Admin perspective - Bell > Alert details > Alerting rule details > Metrics flow', () => { - // cy.visit('/'); - // commonPages.clickBellIcon(); - // commonPages.bellIconClickAlert('TargetDown'); - // commonPages.titleShouldHaveText('TargetDown') + it(`1. Admin perspective - Observe Menu`, () => { + cy.log(`Admin perspective - Observe Menu and verify all submenus`); + nav.sidenav.clickNavLink(['Administration', 'Cluster Settings']); + commonPages.detailsPage.administration_clusterSettings(); + nav.sidenav.clickNavLink(['Observe', 'Alerting']); + commonPages.titleShouldHaveText('Alerting'); + nav.tabs.switchTab('Silences'); + nav.sidenav.clickNavLink(['Observe', 'Metrics']); + commonPages.titleShouldHaveText('Metrics'); + nav.sidenav.clickNavLink(['Observe', 'Dashboards']); + commonPages.titleShouldHaveText('Dashboards'); + nav.sidenav.clickNavLink(['Observe', 'Targets']); + commonPages.titleShouldHaveText('Metrics targets'); + }); + // TODO: Intercept Bell GET request to inject an alert (Watchdog to have it opened in + // Alert Details page?) + // it('Admin perspective - Bell > Alert details > Alerting rule details > Metrics flow', () => { + // cy.visit('/'); + // commonPages.clickBellIcon(); + // commonPages.bellIconClickAlert('TargetDown'); + // commonPages.titleShouldHaveText('TargetDown') - // }); + // }); - it(`2. Admin perspective - Overview Page > Status - View alerts`, () => { - nav.sidenav.clickNavLink(['Home', 'Overview']); - overviewPage.clickStatusViewAlerts(); - commonPages.titleShouldHaveText('Alerting'); - }); + it(`2. Admin perspective - Overview Page > Status - View alerts`, () => { + nav.sidenav.clickNavLink(['Home', 'Overview']); + overviewPage.clickStatusViewAlerts(); + commonPages.titleShouldHaveText('Alerting'); + }); - // TODO: Intercept and inject a valid alert into status-card to be opened correctly to Alerting / - // Alerts page - // I couldn't make Watchdog working on status-card - // it('3. Admin perspective - Overview Page > Status - View details', () => { - // cy.visit('/'); - // nav.sidenav.clickNavLink(['Home', 'Overview']); - // overviewPage.clickStatusViewDetails(0); - // detailsPage.sectionHeaderShouldExist('Alert details'); - // }); + // TODO: Intercept and inject a valid alert into status-card to be opened correctly to Alerting + // Alerts page + // I couldn't make Watchdog working on status-card + // it('3. Admin perspective - Overview Page > Status - View details', () => { + // cy.visit('/'); + // nav.sidenav.clickNavLink(['Home', 'Overview']); + // overviewPage.clickStatusViewDetails(0); + // detailsPage.sectionHeaderShouldExist('Alert details'); + // }); - it(`3. Admin perspective - Cluster Utilization - Metrics`, () => { - nav.sidenav.clickNavLink(['Home', 'Overview']); - overviewPage.clickClusterUtilizationViewCPU(); - commonPages.titleShouldHaveText('Metrics'); - commonPages.projectDropdownShouldExist(); - }); + it(`3. Admin perspective - Cluster Utilization - Metrics`, () => { + nav.sidenav.clickNavLink(['Home', 'Overview']); + overviewPage.clickClusterUtilizationViewCPU(); + commonPages.titleShouldHaveText('Metrics'); + commonPages.projectDropdownShouldExist(); + }); - // Run tests in Administrator perspective - runBVTMonitoringTests({ - name: 'Administrator', - }); -}); + // Run tests in Administrator perspective + runBVTMonitoringTests({ + name: 'Administrator', + }); + }, +); diff --git a/web/cypress/e2e/monitoring/00.bvt_dev.cy.ts b/web/cypress/e2e/monitoring/00.bvt_dev.cy.ts index a5b66eb9e..ab142a647 100644 --- a/web/cypress/e2e/monitoring/00.bvt_dev.cy.ts +++ b/web/cypress/e2e/monitoring/00.bvt_dev.cy.ts @@ -8,7 +8,7 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -describe('BVT: Monitoring - Namespaced', { tags: ['@monitoring-dev', '@smoke-dev'] }, () => { +describe('BVT: Monitoring - Namespaced', { tags: ['@alerting'] }, () => { before(() => { cy.beforeBlock(MP); }); diff --git a/web/cypress/e2e/monitoring/regression/01.reg_alerts_admin.cy.ts b/web/cypress/e2e/monitoring/regression/01.reg_alerts_admin.cy.ts index 832eba1dd..b24a4bfd3 100644 --- a/web/cypress/e2e/monitoring/regression/01.reg_alerts_admin.cy.ts +++ b/web/cypress/e2e/monitoring/regression/01.reg_alerts_admin.cy.ts @@ -11,7 +11,7 @@ const MP = { // Test suite for Core platform perspective describe( 'Regression: Monitoring - Alerts (Core platform)', - { tags: ['@monitoring', '@alerts'] }, + { tags: ['@alerting', '@metrics'] }, () => { before(() => { cy.beforeBlock(MP); diff --git a/web/cypress/e2e/monitoring/regression/01.reg_alerts_dev.cy.ts b/web/cypress/e2e/monitoring/regression/01.reg_alerts_dev.cy.ts index 55e27bcb0..80e031fdf 100644 --- a/web/cypress/e2e/monitoring/regression/01.reg_alerts_dev.cy.ts +++ b/web/cypress/e2e/monitoring/regression/01.reg_alerts_dev.cy.ts @@ -10,7 +10,7 @@ const MP = { describe( 'Regression: Monitoring - Alerts Namespaced (Administrator)', - { tags: ['@monitoring-dev', '@alerts-dev'] }, + { tags: ['@alerting'] }, () => { before(() => { cy.beforeBlock(MP); diff --git a/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_1.cy.ts b/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_1.cy.ts index 7e710abbd..09a4ef6f7 100644 --- a/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_1.cy.ts +++ b/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_1.cy.ts @@ -9,31 +9,27 @@ const MP = { }; // Test suite for Administrator perspective -describe( - 'Regression: Monitoring - Metrics (Administrator)', - { tags: ['@monitoring', '@metrics'] }, - () => { - before(() => { - cy.beforeBlock(MP); - }); +describe('Regression: Monitoring - Metrics (Administrator)', { tags: ['@metrics'] }, () => { + before(() => { + cy.beforeBlock(MP); + }); - beforeEach(() => { - nav.sidenav.clickNavLink(['Observe', 'Metrics']); - commonPages.titleShouldHaveText('Metrics'); - cy.changeNamespace('All Projects'); - }); + beforeEach(() => { + nav.sidenav.clickNavLink(['Observe', 'Metrics']); + commonPages.titleShouldHaveText('Metrics'); + cy.changeNamespace('All Projects'); + }); - // Run tests in Administrator perspective - runAllRegressionMetricsTests1({ - name: 'Administrator', - }); - }, -); + // Run tests in Administrator perspective + runAllRegressionMetricsTests1({ + name: 'Administrator', + }); +}); // Test suite for Administrator perspective describe( 'Regression: Monitoring - Metrics Namespaced (Administrator)', - { tags: ['@monitoring', '@metrics'] }, + { tags: ['@metrics'] }, () => { before(() => { cy.beforeBlock(MP); diff --git a/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_2.cy.ts b/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_2.cy.ts index 82e1672af..d5d7cfcdf 100644 --- a/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_2.cy.ts +++ b/web/cypress/e2e/monitoring/regression/02.reg_metrics_admin_2.cy.ts @@ -9,31 +9,27 @@ const MP = { }; // Test suite for Administrator perspective -describe( - 'Regression: Monitoring - Metrics (Administrator)', - { tags: ['@monitoring', '@metrics'] }, - () => { - before(() => { - cy.beforeBlock(MP); - }); +describe('Regression: Monitoring - Metrics (Administrator)', { tags: ['@metrics'] }, () => { + before(() => { + cy.beforeBlock(MP); + }); - beforeEach(() => { - nav.sidenav.clickNavLink(['Observe', 'Metrics']); - commonPages.titleShouldHaveText('Metrics'); - cy.changeNamespace('All Projects'); - }); + beforeEach(() => { + nav.sidenav.clickNavLink(['Observe', 'Metrics']); + commonPages.titleShouldHaveText('Metrics'); + cy.changeNamespace('All Projects'); + }); - // Run tests in Administrator perspective - runAllRegressionMetricsTests2({ - name: 'Administrator', - }); - }, -); + // Run tests in Administrator perspective + runAllRegressionMetricsTests2({ + name: 'Administrator', + }); +}); // Test suite for Administrator perspective describe( 'Regression: Monitoring - Metrics Namespaced (Administrator)', - { tags: ['@monitoring', '@metrics'] }, + { tags: ['@metrics'] }, () => { before(() => { cy.beforeBlock(MP); diff --git a/web/cypress/e2e/monitoring/regression/03.reg_legacy_dashboards_admin.cy.ts b/web/cypress/e2e/monitoring/regression/03.reg_legacy_dashboards_admin.cy.ts index 5439930a9..eac3d5a38 100644 --- a/web/cypress/e2e/monitoring/regression/03.reg_legacy_dashboards_admin.cy.ts +++ b/web/cypress/e2e/monitoring/regression/03.reg_legacy_dashboards_admin.cy.ts @@ -11,7 +11,7 @@ const MP = { // Test suite for Administrator perspective describe( 'Regression: Monitoring - Legacy Dashboards (Administrator)', - { tags: ['@monitoring', '@dashboards'] }, + { tags: ['@legacy-dashboards'] }, () => { before(() => { cy.beforeBlock(MP); @@ -39,7 +39,7 @@ describe( // Test suite for Administrator perspective describe( 'Regression: Monitoring - Legacy Dashboards Namespaced (Administrator)', - { tags: ['@monitoring', '@dashboards'] }, + { tags: ['@legacy-dashboards'] }, () => { before(() => { cy.beforeBlock(MP); diff --git a/web/cypress/e2e/perses/00.coo_bvt_perses_admin.cy.ts b/web/cypress/e2e/perses/00.coo_bvt_perses_admin.cy.ts index 78c6a05f0..ce30ef3be 100644 --- a/web/cypress/e2e/perses/00.coo_bvt_perses_admin.cy.ts +++ b/web/cypress/e2e/perses/00.coo_bvt_perses_admin.cy.ts @@ -18,10 +18,9 @@ const MP = { operatorName: 'Cluster Monitoring Operator', }; -//TODO: change tag to @smoke, @dashboards, @perses when customizable-dashboards gets merged describe( 'BVT: COO - Dashboards (Perses) - Core platform perspective', - { tags: ['@smoke', '@dashboards', '@perses'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: true, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/perses/01.coo_list_perses_admin.cy.ts b/web/cypress/e2e/perses/01.coo_list_perses_admin.cy.ts index be954d224..0e7ace83e 100644 --- a/web/cypress/e2e/perses/01.coo_list_perses_admin.cy.ts +++ b/web/cypress/e2e/perses/01.coo_list_perses_admin.cy.ts @@ -24,7 +24,7 @@ const MP = { //TODO: change tag to @dashboards when customizable-dashboards gets merged describe( 'COO - Dashboards (Perses) - List perses dashboards', - { tags: ['@perses', '@dashboards'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: true, troubleshootingPanel: false }); @@ -51,7 +51,7 @@ describe( //TODO: change tag to @dashboards when customizable-dashboards gets merged describe( 'COO - Dashboards (Perses) - List perses dashboards - Namespace', - { tags: ['@perses', '@dashboards'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP, { dashboards: true, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/perses/02.coo_edit_perses_admin.cy.ts b/web/cypress/e2e/perses/02.coo_edit_perses_admin.cy.ts index dda15c4a1..fc102bdc2 100644 --- a/web/cypress/e2e/perses/02.coo_edit_perses_admin.cy.ts +++ b/web/cypress/e2e/perses/02.coo_edit_perses_admin.cy.ts @@ -22,7 +22,7 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; //TODO: change tag to @dashboards when customizable-dashboards gets merged describe( 'COO - Dashboards (Perses) - Edit perses dashboard', - { tags: ['@perses', '@dashboards'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { // cy.beforeBlockCOO(MCP, MP, { dashboards: true, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/perses/03.coo_create_perses_admin.cy.ts b/web/cypress/e2e/perses/03.coo_create_perses_admin.cy.ts index d0ee0c21e..28c552861 100644 --- a/web/cypress/e2e/perses/03.coo_create_perses_admin.cy.ts +++ b/web/cypress/e2e/perses/03.coo_create_perses_admin.cy.ts @@ -21,7 +21,7 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; //TODO: change tag to @dashboards when customizable-dashboards gets merged describe( 'COO - Dashboards (Perses) - Create perses dashboard', - { tags: ['@perses', '@dashboards'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { // cy.beforeBlockCOO(MCP, MP, { dashboards: true, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/perses/04.coo_import_perses_admin.cy.ts b/web/cypress/e2e/perses/04.coo_import_perses_admin.cy.ts index 42019c82d..14a10df3b 100644 --- a/web/cypress/e2e/perses/04.coo_import_perses_admin.cy.ts +++ b/web/cypress/e2e/perses/04.coo_import_perses_admin.cy.ts @@ -21,7 +21,7 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; //TODO: change tag to @dashboards when customizable-dashboards gets merged describe( 'COO - Dashboards (Perses) - Import perses dashboard', - { tags: ['@perses', '@dashboards'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { // cy.beforeBlockCOO(MCP, MP, { dashboards: true, troubleshootingPanel: false }); diff --git a/web/cypress/e2e/perses/05.coo_tempo_loki_admin.cy.ts b/web/cypress/e2e/perses/05.coo_tempo_loki_admin.cy.ts index c8ec6f391..846657280 100644 --- a/web/cypress/e2e/perses/05.coo_tempo_loki_admin.cy.ts +++ b/web/cypress/e2e/perses/05.coo_tempo_loki_admin.cy.ts @@ -43,7 +43,7 @@ const CLO = { describe( 'COO - Dashboards (Perses) - Perses Global Datasources with Tempo and Loki', - { tags: ['@perses-ivt', '@dashboards', '@xfail'] }, + { tags: ['@perses-dashboards', '@xfail', '@coo'] }, () => { before(() => { cy.beforeBlockTempo(TEMPO); diff --git a/web/cypress/e2e/perses/99.coo_rbac_perses_user1.cy.ts b/web/cypress/e2e/perses/99.coo_rbac_perses_user1.cy.ts index 8e3f7da79..927d1b542 100644 --- a/web/cypress/e2e/perses/99.coo_rbac_perses_user1.cy.ts +++ b/web/cypress/e2e/perses/99.coo_rbac_perses_user1.cy.ts @@ -19,7 +19,7 @@ const MP = { describe( 'RBAC User1: COO - Dashboards (Perses) - Administrator perspective', - { tags: ['@perses-dev'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { // Setup COO and Perses dashboards (requires admin privileges) diff --git a/web/cypress/e2e/perses/99.coo_rbac_perses_user2.cy.ts b/web/cypress/e2e/perses/99.coo_rbac_perses_user2.cy.ts index 1159e59df..17db97ae2 100644 --- a/web/cypress/e2e/perses/99.coo_rbac_perses_user2.cy.ts +++ b/web/cypress/e2e/perses/99.coo_rbac_perses_user2.cy.ts @@ -18,10 +18,9 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; // operatorName: 'Cluster Monitoring Operator', // }; -//TODO: change tag to @smoke, @dashboards, @perses when customizable-dashboards gets merged describe( 'RBAC User2: COO - Dashboards (Perses) - Administrator perspective', - { tags: ['@perses-dev'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { //TODO: https://issues.redhat.com/browse/OCPBUGS-58468 - when it gets fixed, installation can be don using non-admin user diff --git a/web/cypress/e2e/perses/99.coo_rbac_perses_user3.cy.ts b/web/cypress/e2e/perses/99.coo_rbac_perses_user3.cy.ts index 51e0ec226..64363f45f 100644 --- a/web/cypress/e2e/perses/99.coo_rbac_perses_user3.cy.ts +++ b/web/cypress/e2e/perses/99.coo_rbac_perses_user3.cy.ts @@ -18,10 +18,9 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; // operatorName: 'Cluster Monitoring Operator', // }; -//TODO: change tag to @smoke, @dashboards, @perses when customizable-dashboards gets merged describe( 'RBAC User3: COO - Dashboards (Perses) - Administrator perspective', - { tags: ['@perses-dev'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { //TODO: https://issues.redhat.com/browse/OCPBUGS-58468 - when it gets fixed, installation can be don using non-admin user diff --git a/web/cypress/e2e/perses/99.coo_rbac_perses_user4.cy.ts b/web/cypress/e2e/perses/99.coo_rbac_perses_user4.cy.ts index 8ceb2c2b6..a3c396802 100644 --- a/web/cypress/e2e/perses/99.coo_rbac_perses_user4.cy.ts +++ b/web/cypress/e2e/perses/99.coo_rbac_perses_user4.cy.ts @@ -18,10 +18,9 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; // operatorName: 'Cluster Monitoring Operator', // }; -//TODO: change tag to @smoke, @dashboards, @perses when customizable-dashboards gets merged describe( 'RBAC User4: COO - Dashboards (Perses) - Administrator perspective', - { tags: ['@perses-dev'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { //TODO: https://issues.redhat.com/browse/OCPBUGS-58468 - when it gets fixed, installation can be don using non-admin user diff --git a/web/cypress/e2e/perses/99.coo_rbac_perses_user5.cy.ts b/web/cypress/e2e/perses/99.coo_rbac_perses_user5.cy.ts index 261fb7ab0..46466d622 100644 --- a/web/cypress/e2e/perses/99.coo_rbac_perses_user5.cy.ts +++ b/web/cypress/e2e/perses/99.coo_rbac_perses_user5.cy.ts @@ -18,10 +18,9 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; // operatorName: 'Cluster Monitoring Operator', // }; -//TODO: change tag to @smoke, @dashboards, @perses when customizable-dashboards gets merged describe( 'RBAC User5: COO - Dashboards (Perses) - Administrator perspective', - { tags: ['@perses-dev'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { //TODO: https://issues.redhat.com/browse/OCPBUGS-58468 - when it gets fixed, installation can be don using non-admin user diff --git a/web/cypress/e2e/perses/99.coo_rbac_perses_user6.cy.ts b/web/cypress/e2e/perses/99.coo_rbac_perses_user6.cy.ts index 2e4aae3bf..fc79ca4d8 100644 --- a/web/cypress/e2e/perses/99.coo_rbac_perses_user6.cy.ts +++ b/web/cypress/e2e/perses/99.coo_rbac_perses_user6.cy.ts @@ -18,10 +18,9 @@ import { operatorAuthUtils } from '../../support/commands/auth-commands'; // operatorName: 'Cluster Monitoring Operator', // }; -//TODO: change tag to @smoke, @dashboards, @perses when customizable-dashboards gets merged describe( 'RBAC User6: COO - Dashboards (Perses) - Administrator perspective', - { tags: ['@perses-dev'] }, + { tags: ['@perses-dashboards', '@coo'] }, () => { before(() => { //TODO: https://issues.redhat.com/browse/OCPBUGS-58468 - when it gets fixed, installation can be don using non-admin user diff --git a/web/cypress/e2e/virtualization/00.coo_ivt.cy.ts b/web/cypress/e2e/virtualization/00.coo_ivt.cy.ts index 30280889f..8a379395e 100644 --- a/web/cypress/e2e/virtualization/00.coo_ivt.cy.ts +++ b/web/cypress/e2e/virtualization/00.coo_ivt.cy.ts @@ -35,7 +35,7 @@ const KBV = { describe( 'Installation: COO and setting up Monitoring Plugin', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@coo', '@slow'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP); @@ -47,7 +47,7 @@ describe( }, ); -describe('Installation: Virtualization', { tags: ['@virtualization', '@slow'] }, () => { +describe('Installation: Virtualization', { tags: ['@virtualization', '@coo', '@slow'] }, () => { before(() => { cy.beforeBlockVirtualization(KBV); }); @@ -59,24 +59,28 @@ describe('Installation: Virtualization', { tags: ['@virtualization', '@slow'] }, }); }); -describe('IVT: Monitoring + Virtualization', { tags: ['@smoke', '@virtualization'] }, () => { - beforeEach(() => { - cy.visit('/'); - guidedTour.close(); - cy.validateLogin(); - cy.switchPerspective('Virtualization', 'Fleet virtualization'); - guidedTour.closeKubevirtTour(); - nav.sidenav.clickNavLink(['Observe', 'Metrics']); - commonPages.titleShouldHaveText('Metrics'); - cy.changeNamespace('All Projects'); - alerts.getWatchdogAlert(); - nav.sidenav.clickNavLink(['Observe', 'Alerting']); - commonPages.titleShouldHaveText('Alerting'); - alerts.getWatchdogAlert(); - }); +describe( + 'IVT: Monitoring + Virtualization', + { tags: ['@metrics', '@alerting', '@virtualization', '@coo'] }, + () => { + beforeEach(() => { + cy.visit('/'); + guidedTour.close(); + cy.validateLogin(); + cy.switchPerspective('Virtualization', 'Fleet virtualization'); + guidedTour.closeKubevirtTour(); + nav.sidenav.clickNavLink(['Observe', 'Metrics']); + commonPages.titleShouldHaveText('Metrics'); + cy.changeNamespace('All Projects'); + alerts.getWatchdogAlert(); + nav.sidenav.clickNavLink(['Observe', 'Alerting']); + commonPages.titleShouldHaveText('Alerting'); + alerts.getWatchdogAlert(); + }); - // Run tests in Administrator perspective - runBVTMonitoringTests({ - name: 'Virtualization', - }); -}); + // Run tests in Administrator perspective + runBVTMonitoringTests({ + name: 'Virtualization', + }); + }, +); diff --git a/web/cypress/e2e/virtualization/01.coo_ivt_alerts.cy.ts b/web/cypress/e2e/virtualization/01.coo_ivt_alerts.cy.ts index 3e2bb8677..090700965 100644 --- a/web/cypress/e2e/virtualization/01.coo_ivt_alerts.cy.ts +++ b/web/cypress/e2e/virtualization/01.coo_ivt_alerts.cy.ts @@ -35,7 +35,7 @@ const KBV = { describe( 'Installation: COO and setting up Monitoring Plugin', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@alerting', '@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP); @@ -49,7 +49,7 @@ describe( describe( 'IVT: Monitoring UIPlugin + Virtualization', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@alerting', '@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockVirtualization(KBV); @@ -65,7 +65,7 @@ describe( describe( 'Regression: Monitoring - Alerts (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@alerting', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); diff --git a/web/cypress/e2e/virtualization/02.coo_ivt_metrics_1.cy.ts b/web/cypress/e2e/virtualization/02.coo_ivt_metrics_1.cy.ts index ccac18457..9c84c795c 100644 --- a/web/cypress/e2e/virtualization/02.coo_ivt_metrics_1.cy.ts +++ b/web/cypress/e2e/virtualization/02.coo_ivt_metrics_1.cy.ts @@ -35,7 +35,7 @@ const KBV = { describe( 'Installation: COO and setting up Monitoring Plugin', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP); @@ -49,7 +49,7 @@ describe( describe( 'IVT: Monitoring UIPlugin + Virtualization', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockVirtualization(KBV); @@ -65,7 +65,7 @@ describe( describe( 'Regression: Monitoring - Metrics (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@metrics', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); @@ -87,7 +87,7 @@ describe( describe( 'Regression: Monitoring - Metrics Namespaced (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@metrics', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); diff --git a/web/cypress/e2e/virtualization/02.coo_ivt_metrics_2.cy.ts b/web/cypress/e2e/virtualization/02.coo_ivt_metrics_2.cy.ts index b840804fe..46ebf954a 100644 --- a/web/cypress/e2e/virtualization/02.coo_ivt_metrics_2.cy.ts +++ b/web/cypress/e2e/virtualization/02.coo_ivt_metrics_2.cy.ts @@ -35,7 +35,7 @@ const KBV = { describe( 'Installation: COO and setting up Monitoring Plugin', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP); @@ -49,7 +49,7 @@ describe( describe( 'IVT: Monitoring UIPlugin + Virtualization', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockVirtualization(KBV); @@ -65,7 +65,7 @@ describe( describe( 'Regression: Monitoring - Metrics (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@metrics', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); @@ -87,7 +87,7 @@ describe( describe( 'Regression: Monitoring - Metrics Namespaced (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@metrics', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); diff --git a/web/cypress/e2e/virtualization/03.coo_ivt_legacy_dashboards.cy.ts b/web/cypress/e2e/virtualization/03.coo_ivt_legacy_dashboards.cy.ts index 28fe440d2..97dcb3705 100644 --- a/web/cypress/e2e/virtualization/03.coo_ivt_legacy_dashboards.cy.ts +++ b/web/cypress/e2e/virtualization/03.coo_ivt_legacy_dashboards.cy.ts @@ -34,7 +34,7 @@ const KBV = { describe( 'Installation: COO and setting up Monitoring Plugin', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockCOO(MCP, MP); @@ -48,7 +48,7 @@ describe( describe( 'IVT: Monitoring UIPlugin + Virtualization', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@virtualization', '@slow', '@coo'] }, () => { before(() => { cy.beforeBlockVirtualization(KBV); @@ -64,7 +64,7 @@ describe( describe( 'Regression: Monitoring - Legacy Dashboards (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@legacy-dashboards', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); @@ -84,7 +84,7 @@ describe( describe( 'Regression: Monitoring - Legacy Dashboards Namespaced (Virtualization)', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@legacy-dashboards', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); diff --git a/web/cypress/e2e/virtualization/04.coo_ivt_perses.cy.ts b/web/cypress/e2e/virtualization/04.coo_ivt_perses.cy.ts index ce9a43f60..92654ba0a 100644 --- a/web/cypress/e2e/virtualization/04.coo_ivt_perses.cy.ts +++ b/web/cypress/e2e/virtualization/04.coo_ivt_perses.cy.ts @@ -61,7 +61,7 @@ describe('Installation: Virtualization', { tags: ['@virtualization', '@slow'] }, describe( 'IVT: COO - Dashboards (Perses) - Virtualization perspective', - { tags: ['@virtualization', '@slow'] }, + { tags: ['@perses-dashboards', '@slow', '@virtualization', '@coo'] }, () => { beforeEach(() => { cy.visit('/'); diff --git a/web/cypress/support/monitoring/00.bvt_monitoring_namespace.cy.ts b/web/cypress/support/monitoring/00.bvt_monitoring_namespace.cy.ts index 7224ebee4..1efe6015f 100644 --- a/web/cypress/support/monitoring/00.bvt_monitoring_namespace.cy.ts +++ b/web/cypress/support/monitoring/00.bvt_monitoring_namespace.cy.ts @@ -34,7 +34,7 @@ export function testBVTMonitoringTestsNamespace(perspective: PerspectiveConfig) listPage.tabShouldHaveText('Silences'); listPage.tabShouldHaveText('Alerting rules'); commonPages.linkShouldExist('Export as CSV'); - commonPages.linkShouldExist('Clear filters'); + commonPages.linkShouldExist('Clear all filters'); listPage.ARRows.shouldBeLoaded(); cy.log('4.2. filter Alerts and click on Alert'); @@ -125,19 +125,12 @@ export function testBVTMonitoringTestsNamespace(perspective: PerspectiveConfig) false, false, ); - // silenceAlertPage.assertLabelNameLabelValueRegExNegMatcher( - // 'severity', `${SEVERITY}`, false, false); silenceAlertPage.assertLabelNameLabelValueRegExNegMatcher( 'namespace', `${WatchdogAlert.NAMESPACE}`, false, false, ); - silenceAlertPage.assertNamespaceLabelNamespaceValueDisabled( - 'namespace', - `${WatchdogAlert.NAMESPACE}`, - true, - ); silenceAlertPage.assertLabelNameLabelValueRegExNegMatcher( 'prometheus', 'openshift-monitoring/k8s', @@ -195,7 +188,7 @@ export function testBVTMonitoringTestsNamespace(perspective: PerspectiveConfig) cy.log('5.8 verify on Alerting Rules list page again'); nav.sidenav.clickNavLink(['Observe', 'Alerting']); nav.tabs.switchTab('Alerting rules'); - listPage.filter.byName(`${WatchdogAlert.ALERTNAME}`); + alertingRuleListPage.filter.byName(`${WatchdogAlert.ALERTNAME}`); alertingRuleListPage.ARShouldBe( `${WatchdogAlert.ALERTNAME}`, `${WatchdogAlert.SEVERITY}`, diff --git a/web/cypress/support/test-tags.d.ts b/web/cypress/support/test-tags.d.ts index 3c5932162..57ce6d520 100644 --- a/web/cypress/support/test-tags.d.ts +++ b/web/cypress/support/test-tags.d.ts @@ -1,12 +1,14 @@ -type BasicTag = '@smoke' | '@demo' | '@flaky' | '@xfail' | '@slow'; +type BasicTag = '@flaky' | '@xfail' | '@slow'; type HighLevelComponentTag = - | '@monitoring' | '@coo' | '@virtualization' - | '@alerts' + | '@acm-alerting' + | '@alerting' + | '@legacy-dashboards' | '@metrics' - | '@dashboards' + | '@targets' + | '@perses-dashboards' | '@cluster-health-analyzer'; type SpecificFeatureTag = `@${string}-${string}`; diff --git a/web/package.json b/web/package.json index d14e79aac..612a4d0be 100644 --- a/web/package.json +++ b/web/package.json @@ -30,24 +30,22 @@ "test": "npm run cypress:run:ci", "test-cypress-console": "./node_modules/.bin/cypress open --browser chrome", "test-cypress-console-headless": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless", - "test-cypress-monitoring": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@monitoring --@flaky --@demo --@xfail'", - "test-cypress-monitoring-dev": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@monitoring-dev --@demo --@xfail'", - "test-cypress-monitoring-bvt": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@monitoring+@smoke --@demo --@xfail'", - "test-cypress-monitoring-regression": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@monitoring --@smoke --@flaky --@demo --@xfail'", - "test-cypress-alerts": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@alerts --@flaky --@demo --@xfail'", - "test-cypress-metrics": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@metrics --@flaky --@demo --@xfail'", - "test-cypress-dashboards": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@dashboards --@flaky --@demo --@xfail'", - "test-cypress-coo": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@coo --@flaky --@demo --@xfail'", - "test-cypress-coo-bvt": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@coo+@smoke --@demo --@xfail'", - "test-cypress-virtualization": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@virtualization --@flaky --@demo --@xfail'", - "test-cypress-smoke": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@smoke --@flaky --@demo --@xfail'", - "test-cypress-fast": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@smoke --@slow --@demo --@flaky --@xfail'", - "test-cypress-perses-dev": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@perses-dev --@demo --@xfail'", - "test-cypress-perses": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@perses --@smoke --@flaky --@demo --@xfail'", - "test-cypress-perses-ivt": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@perses-ivt --@smoke --@flaky --@demo --@xfail'", + "test-cypress-monitoring": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@alerting @legacy-dashboards @metrics @targets --@flaky --@xfail --@virtualization --@coo'", + "test-cypress-monitoring-dev": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@alerting @legacy-dashboards @metrics @targets --@xfail --@virtualization --@coo'", + "test-cypress-monitoring-bvt": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@alerting @legacy-dashboards @metrics @targets --@xfail --@virtualization --@coo'", + "test-cypress-monitoring-regression": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@alerting @legacy-dashboards @metrics @targets --@flaky --@xfail --@virtualization --@coo'", + "test-cypress-alerts": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@alerting --@flaky --@xfail'", + "test-cypress-metrics": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@metrics --@flaky --@xfail'", + "test-cypress-dashboards": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@legacy-dashboards --@flaky --@xfail'", + "test-cypress-coo": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@coo --@flaky --@xfail'", + "test-cypress-coo-bvt": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@coo --@xfail'", + "test-cypress-virtualization": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@virtualization --@flaky --@xfail'", "test-cypress-incidents": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@cluster-health-analyzer --@flaky --@xfail'", "test-cypress-incidents-e2e": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@cluster-health-analyzer --@flaky --@xfail'", - "ts-node": "ts-node -O '{\"module\":\"commonjs\"}'" + "ts-node": "ts-node -O '{\"module\":\"commonjs\"}'", + "test-cypress-perses-dev": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@perses-dashboards --@xfail'", + "test-cypress-perses": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@perses-dashboards --@flaky --@xfail'", + "test-cypress-perses-ivt": "node --max-old-space-size=4096 ./node_modules/.bin/cypress run --browser chrome --headless --env grepTags='@perses-ivt --@flaky --@xfail'" }, "dependencies": { "@codemirror/autocomplete": "^6.0.4",