Skip to content

CNV-87995 Add Cypress E2E tests for NNCP, Physical networks, VM networks, and NNS#228

Open
lkladnit wants to merge 1 commit into
openshift:mainfrom
lkladnit:qe-ui
Open

CNV-87995 Add Cypress E2E tests for NNCP, Physical networks, VM networks, and NNS#228
lkladnit wants to merge 1 commit into
openshift:mainfrom
lkladnit:qe-ui

Conversation

@lkladnit

@lkladnit lkladnit commented Jun 9, 2026

Copy link
Copy Markdown

Migrates tests from kubevirt-ui to a standalone ui-tests-cy/ folder with its own package.json (Cypress 15). Covers NNCP CRUD, Physical network wizard, Virtual machine network lifecycle, NNS list, and topology view.

Jira: CNV-87995

CI Verification

All 22 tests pass on Jenkins: build #243 (SUCCESS)

Includes fix for JUnit XML path — copies test results to cypress/gui-test-screenshots/ where the Jenkins pipeline expects them.

Summary by CodeRabbit

  • Tests

    • Added comprehensive end-to-end test suite for the UI with Cypress framework
    • Included test coverage for Physical networks, Node network state, Virtual machine networks, and network policies
    • Added login and navigation tests for core functionality
  • Chores

    • Added test configuration, setup, and cleanup scripts
    • Added environment variables and build artifacts configuration

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 9, 2026
@openshift-ci

openshift-ci Bot commented Jun 9, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR introduces a complete Cypress end-to-end test suite for the NMState console plugin. It provides test infrastructure, configuration, support utilities, and comprehensive test coverage for Physical networks, NodeNetworkConfigurationPolicy, NodeNetworkState/Topology, and Virtual machine networks features, along with login and navigation flows.

Changes

Cypress E2E Test Framework and Suites

Layer / File(s) Summary
Test Infrastructure & Environment Setup
.env.example, .gitignore, cleanup.sh, setup.sh, test-cypress.sh
Environment configuration for Cypress tests, test resource cleanup/namespace setup via shell functions, and a main test runner that supports GUI and headless modes with report generation via tee and npm run cypress-postreport.
Cypress Framework Configuration
ui-tests-cy/.eslintrc, ui-tests-cy/cypress.config.js, ui-tests-cy/package.json, ui-tests-cy/tsconfig.json, ui-tests-cy/plugins/index.ts, ui-tests-cy/reporter-config.json
ESLint rules for Cypress, Cypress config with security/timeout/reporter settings, npm package with Cypress/tooling dependencies, TypeScript config, plugins entry that loads .env and wires webpack preprocessing, and multi-reporter JSON/XML/HTML output configuration.
Core Support Commands and Selectors
ui-tests-cy/support/commands.ts, ui-tests-cy/support/login.ts, ui-tests-cy/support/nav.ts, ui-tests-cy/support/selectors.ts, ui-tests-cy/support/index.ts
Custom Cypress Chainables for resource deletion via oc, project switching, login/logout flows, navigation to NMState pages, and element selection by data-test attributes and text; global exception suppression and conditional XHR/fetch logging hiding.
Test Constants and View Helper Functions
ui-tests-cy/utils/const/base.ts, ui-tests-cy/views/selector-common.ts, ui-tests-cy/views/nncp.ts, ui-tests-cy/views/physicalNetwork.ts, ui-tests-cy/views/vmNetwork.ts
Test constants (timing, namespaces, Kubernetes kinds), shared selectors, and UI flow helpers for creating/editing/deleting NodeNetworkConfigurationPolicy, Physical networks, and Virtual machine networks; prerequisite resource management for VMN tests.
Test Suites and Specifications
ui-tests-cy/tests/all.cy.ts, ui-tests-cy/tests/setup/login.cy.ts, ui-tests-cy/tests/nmstate/nncp.cy.ts, ui-tests-cy/tests/nmstate/nns.cy.ts, ui-tests-cy/tests/nmstate/physical.cy.ts, ui-tests-cy/tests/nmstate/vmn.cy.ts, ui-tests-cy/tests/nmstate/visit-pages.cy.ts
Aggregated test entrypoint and feature-specific test suites: login authentication, NNCP creation/editing/filtering/deletion, NodeNetworkState table/expand/collapse and topology visualization, Physical network creation/listing/expansion, Virtual machine network creation with project/label mapping and deletion, and sidebar navigation to all NMState features.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 13 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ❓ Inconclusive Custom check targets Ginkgo test patterns (Go), but PR adds Cypress E2E tests (JavaScript/TypeScript). While quality principles apply universally, the check's specific instruction examples (BeforeE... Clarify whether this check applies to Cypress tests; if so, rewrite instructions using Cypress patterns (before/after, cy.should, cy.contains timeouts) instead of Ginkgo-specific syntax.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main addition of Cypress E2E tests for multiple features (NNCP, Physical networks, VM networks, NNS), which aligns with the substantial test suite additions across the ui-tests-cy/ directory.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All 28 test titles in the new Cypress test suite use stable, deterministic names without dynamic values (timestamps, UUIDs, generated identifiers, node names, IP addresses, etc.). Test titles are d...
Microshift Test Compatibility ✅ Passed PR adds Cypress (TypeScript) E2E tests, not Ginkgo tests. Custom check targets Ginkgo tests only; therefore check is not applicable to this PR.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The PR adds Cypress UI/e2e tests in TypeScript, not Go-based Ginkgo tests. The custom check is designed for Ginkgo e2e tests (checking for It(), Describe(), exutil.IsSingleNode(), g.Skip(), etc.) a...
Topology-Aware Scheduling Compatibility ✅ Passed PR adds only Cypress E2E test code and test infrastructure (setup/cleanup scripts, configs). No deployment manifests, operator code, or controller changes present—custom check not applicable.
Ote Binary Stdout Contract ✅ Passed OTE Binary Stdout Contract check is not applicable: PR contains no Go code, no Ginkgo framework, and no OTE binary entrypoints. This is a JavaScript/TypeScript Cypress E2E test addition to a web co...
Ipv6 And Disconnected Network Test Compatibility ✅ Passed This PR adds Cypress (JavaScript/TypeScript) e2e tests, not Ginkgo (Go) e2e tests. The custom check specifically applies to Ginkgo tests with Go patterns (It(), Describe(), Context(), When()). This...
No-Weak-Crypto ✅ Passed No direct weak crypto usage found in PR code. MD5 is an indirect transitive dependency from mocha-junit-reporter, used internally for test report filenames—not a security-critical operation.
Container-Privileges ✅ Passed PR adds Cypress E2E tests only; no container/K8s manifest files modified. Check for privileged container configurations is not applicable.
No-Sensitive-Data-In-Logs ✅ Passed No logging of sensitive data found. BRIDGE_KUBEADMIN_PASSWORD is only used in cy.get('#inputPassword').type() without logging. No console.log or cy.log statements expose passwords, tokens, or PII.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci

openshift-ci Bot commented Jun 9, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lkladnit
Once this PR has been reviewed and has the lgtm label, please assign vojtechszocs for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@lkladnit

lkladnit commented Jun 9, 2026

Copy link
Copy Markdown
Author

/assign @lkladnit

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (11)
ui-tests-cy/support/selectors.ts (1)

69-77: 💤 Low value

Use descriptive variable names.

The variable t_o is an abbreviation and reduces readability. Consider using timeout or timeoutValue instead.

♻️ Proposed fix
 Cypress.Commands.add('checkTitle', (title: string, timeout?: number) => {
-  const t_o = timeout ? timeout : MINUTE * 3;
-  cy.contains('h1', title, { timeout: t_o }).should('exist');
+  const timeoutValue = timeout ?? MINUTE * 3;
+  cy.contains('h1', title, { timeout: timeoutValue }).should('exist');
 });

 Cypress.Commands.add('checkSubTitle', (subTitle: string, timeout?: number) => {
-  const t_o = timeout ? timeout : MINUTE * 3;
-  cy.contains('h2', subTitle, { timeout: t_o }).should('exist');
+  const timeoutValue = timeout ?? MINUTE * 3;
+  cy.contains('h2', subTitle, { timeout: timeoutValue }).should('exist');
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/support/selectors.ts` around lines 69 - 77, The local variable
name t_o in the Cypress custom commands for checkTitle and checkSubTitle is
abbreviated and harms readability; rename t_o to a descriptive name like
timeoutValue (or timeout) in both functions, update the assignment (const
timeoutValue = timeout ? timeout : MINUTE * 3) and replace all uses of t_o with
timeoutValue so the commands Cypress.Commands.add('checkTitle', ...) and
Cypress.Commands.add('checkSubTitle', ...) remain functionally identical but
clearer.
ui-tests-cy/support/index.ts (1)

10-18: 💤 Low value

Return value missing when suppressing logs.

When displayName is 'fetch' or 'xhr', the function returns undefined instead of a log object. While this may work in practice, it breaks the expected return contract of Cypress.log. Consider returning null or a stub log object to avoid potential downstream issues.

♻️ Proposed fix
 if (Cypress.env('HIDE_XHR')) {
   const origLog = Cypress.log;
   Cypress.log = function (opts, ...other) {
     if (opts.displayName === 'fetch' || opts.displayName === 'xhr') {
-      return;
+      return null;
     }
     return origLog(opts, ...other);
   };
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/support/index.ts` around lines 10 - 18, The custom Cypress.log
override suppresses entries for displayName 'fetch' or 'xhr' but returns
undefined, violating the expected return contract; update the override in the
Cypress.log function (the override referencing origLog and opts.displayName) to
return a safe value when suppressing logs—either return null or a minimal stub
log object with the same shape the caller expects (e.g., id/message properties)
instead of returning undefined so downstream code receives a predictable return
value.
ui-tests-cy/.eslintrc (1)

1-15: ⚡ Quick win

Consider adding import sorting to align with the main project's linting standards.

The main project enforces import sorting via simple-import-sort (per CONTRIBUTING.md), but this Cypress ESLint config doesn't include it. This could lead to inconsistent import organization between source code and test files.

♻️ Proposed addition
 {
   "env": {
     "cypress/globals": true,
     "node": true
   },
   "extends": ["plugin:cypress/recommended"],
-  "plugins": ["cypress"],
+  "plugins": ["cypress", "simple-import-sort"],
   "rules": {
     "no-console": "off",
     "no-namespace": "off",
     "no-redeclare": "off",
     "`@typescript-eslint/no-var-requires`": "off",
-    "`@typescript-eslint/no-namespace`": "off"
+    "`@typescript-eslint/no-namespace`": "off",
+    "simple-import-sort/imports": "error",
+    "simple-import-sort/exports": "error"
   }
 }

Note: This requires adding eslint-plugin-simple-import-sort to ui-tests-cy/package.json devDependencies.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/.eslintrc` around lines 1 - 15, Add import-sorting to the Cypress
ESLint config by installing eslint-plugin-simple-import-sort as a devDependency
in ui-tests-cy/package.json and then update .eslintrc to include
"plugin:simple-import-sort/recommended" in the "extends" array (and/or add
"simple-import-sort" to "plugins") so that the simple-import-sort rules are
applied to the Cypress tests; ensure the rule set is consistent with the main
project's configuration and don't remove existing rules like "no-console" or
"`@typescript-eslint/no-namespace`".

Source: Coding guidelines

ui-tests-cy/views/physicalNetwork.ts (2)

17-20: ⚡ Quick win

Remove redundant hardcoded wait.

Line 18 introduces a 2-second hardcoded wait immediately after Line 17 already waits for the input to be visible. This is redundant and can slow tests unnecessarily. Cypress's .should('be.visible') already includes retry logic.

♻️ Proposed fix
   // Step 1: Network identity
   cy.get(physicalNetworkNameInput, { timeout: MINUTE }).should('be.visible');
-  cy.wait(2 * SECOND);
   cy.get(physicalNetworkNameInput).clear();
   cy.get(physicalNetworkNameInput).type(networkName);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/physicalNetwork.ts` around lines 17 - 20, Remove the
redundant hardcoded wait: after confirming the input is visible with
cy.get(physicalNetworkNameInput, { timeout: MINUTE }).should('be.visible'),
delete the cy.wait(2 * SECOND) call and proceed to clear and type into the
element (the subsequent cy.get(physicalNetworkNameInput).clear() and
.type(networkName)); this relies on Cypress's retry behavior on the visible
assertion and avoids unnecessary test slowdown.

36-39: ⚡ Quick win

Document missing Step 4 and replace hardcoded wait with assertion.

The comment jumps from "Step 3" to "Step 5" without documenting Step 4. Additionally, Line 39's hardcoded 3-second wait should be replaced with an assertion-based wait for the expected post-creation state (e.g., navigation completion or success message).

♻️ Proposed improvements
   // Step 3: Uplink connection
   cy.get('.pf-v6-c-wizard__main', { timeout: MINUTE }).should('contain', 'Uplink');
   cy.contains(submitBtn, 'Next').click();

+  // Step 4: [Document what step 4 does, or confirm it's skipped]
+
   // Step 5: Review and Create
   cy.contains('button', 'Create network', { timeout: MINUTE }).should('be.visible');
   cy.contains('button', 'Create network').click();
-  cy.wait(3 * SECOND);
+  // Consider waiting for a success indicator or navigation instead of fixed timeout
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/physicalNetwork.ts` around lines 36 - 39, The test jumps
from "Step 3" to "Step 5" and uses a hardcoded cy.wait(3 * SECOND); update the
comments to add a "Step 4: Confirm creation initiated" line and replace the
fixed wait with an assertion-based wait that verifies the post-create state (for
example, after clicking the 'Create network' button use cy.contains('Network
created', { timeout: MINUTE }).should('be.visible') or assert navigation with
cy.url().should('include', '/networks') or another app-specific success
indicator); keep the existing selectors ('Create network' button, MINUTE,
SECOND) but remove the static wait and assert the actual success condition
instead.
ui-tests-cy/views/nncp.ts (1)

19-31: ⚡ Quick win

Replace hardcoded waits and improve error detection.

Lines 23 and 25 use hardcoded waits (cy.wait(3 * SECOND) and cy.wait(5 * SECOND)), and Line 27 checks the entire page body for "already exists". This pattern is fragile and can cause flakiness.

♻️ Proposed improvements
 export const createNNCPFromYAML = () => {
   cy.get(itemCreateBtn).click();
   cy.contains('button', 'With YAML').click();
   cy.url({ timeout: MINUTE }).should('include', '~new');
-  cy.wait(3 * SECOND);
   cy.get('button').contains('Create').click();
-  cy.wait(5 * SECOND);
-  cy.get('body').then(($body) => {
-    if ($body.text().includes('already exists')) {
+  // Wait for either success navigation or error alert
+  cy.get('body', { timeout: 10000 }).then(($body) => {
+    if ($body.find('[role="alert"]').text().includes('already exists')) {
       cy.contains('button', 'Cancel').click();
     }
   });
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/nncp.ts` around lines 19 - 31, The createNNCPFromYAML
helper uses fragile hardcoded waits and a broad page-text check for duplicate
errors; replace cy.wait(3 * SECOND) and cy.wait(5 * SECOND) with targeted
assertions/commands that wait for specific elements or network calls (e.g., wait
for the YAML modal to be visible, wait for the Create button to become enabled,
or intercept the create request and wait on its route), and replace the body
text check with a scoped assertion that looks for the precise duplicate error
element or toast (search within the modal or the notification container) and
then click the Cancel button if that specific error is present; update
references in createNNCPFromYAML and usages of itemCreateBtn/Create button
selectors accordingly.
ui-tests-cy/views/vmNetwork.ts (2)

20-44: ⚡ Quick win

Replace hardcoded waits with assertions.

Lines 23, 38, 51, 53, and 55 use hardcoded cy.wait() calls with fixed timeouts. This is a Cypress anti-pattern that can lead to flaky tests (too short) or unnecessarily slow tests (too long). Replace with assertion-based waiting for specific UI states.

♻️ Examples of assertion-based alternatives
   cy.get(itemCreateBtn).click();
   cy.contains('h1', 'Create virtual machine network', { timeout: MINUTE }).should('exist');
-  cy.wait(2 * SECOND);

   cy.get(vmnNameInput, { timeout: MINUTE })
     .should('be.visible')
   cy.contains(submitBtn, 'Create').click();
-  cy.wait(5 * SECOND);
   cy.get('body').then(($body) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 20 - 44, The createVMNetwork
function uses hardcoded cy.wait() calls; replace them with assertions that wait
for specific UI states: after opening the create dialog assert the modal header
appears (already present) and wait for vmnNameInput to be visible before
interacting instead of wait(2*SECOND); after clicking Next assert the next step
or a form section (e.g., project mapping controls or a stepper indicator) is
visible instead of wait(5*SECOND); after clicking Create assert success or error
toast/text (e.g., look for confirmation message or for the "already exists"
text) and if the "already exists" text is present call navigateToVMN(); remove
all cy.wait() calls and use should('be.visible'), contains(...).should('exist'),
or intercept+wait for network responses as appropriate to ensure deterministic
timing while keeping selectors like itemCreateBtn, vmnNameInput, submitBtn, and
navigateToVMN referenced for locating changes.

39-43: ⚡ Quick win

Scope error detection to alert elements.

Lines 39-43 check the entire page body for "already exists". Similar to the pattern in nncp.ts, this is fragile and could match unrelated text.

♻️ Proposed improvement
   cy.get('body').then(($body) => {
-    if ($body.text().includes('already exists')) {
+    // Check for error in alert/notification area instead of entire body
+    if ($body.find('[role="alert"]').text().includes('already exists')) {
       navigateToVMN();
     }
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 39 - 43, The test is scanning
the whole page body for the string "already exists", which can produce false
positives; change the check to only inspect alert elements (e.g., use selectors
like [role="alert"], .pf-c-alert or the same alert selector used in nncp.ts)
instead of cy.get('body'), then call navigateToVMN() only if an alert's text
includes "already exists" so the match is limited to real UI alerts.
research-flakiness.sh (2)

58-58: 💤 Low value

Integer division truncates failure rate.

Line 58 uses integer arithmetic $((FAIL_COUNT * 100 / TOTAL_RUNS)) which truncates to whole percentages. With TOTAL_RUNS=10, 1 failure shows as 10%, but if this is later changed to 100 runs, 1 failure would show as 1% instead of 1.0%.

♻️ Proposed fix for precise percentage
-- **Failure rate:** $((FAIL_COUNT * 100 / TOTAL_RUNS))%
+- **Failure rate:** $(awk "BEGIN {printf \"%.1f\", ($FAIL_COUNT * 100.0 / $TOTAL_RUNS)}")%
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@research-flakiness.sh` at line 58, The current expression $((FAIL_COUNT * 100
/ TOTAL_RUNS)) uses integer division and truncates percentages; replace it by
computing a floating-point percentage (e.g., using awk or bc with a set scale)
and format it to at least one decimal place, store that result in a variable
like FAILURE_RATE, and then use that variable in the markdown line instead of
the integer expression so the displayed failure rate shows decimal precision.

18-20: 💤 Low value

Add validation before destructive operations.

Line 18 runs rm -rf without checking if the directory exists, and Line 20 invokes ./test-cypress.sh without validating it exists or is executable. While not critical, adding guards improves robustness.

🛡️ Proposed validation guards
+  if [ ! -x "./test-cypress.sh" ]; then
+    echo "Error: test-cypress.sh not found or not executable"
+    exit 1
+  fi
+
-  rm -rf ui-tests-cy/gui-test-screenshots/*
+  if [ -d "ui-tests-cy/gui-test-screenshots" ]; then
+    rm -rf ui-tests-cy/gui-test-screenshots/*
+  fi

   ./test-cypress.sh

Note: The validation for test-cypress.sh should be before the loop (line 13), not inside it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@research-flakiness.sh` around lines 18 - 20, Before running destructive
removal and launching the test script, add existence and executability checks:
verify the directory "ui-tests-cy/gui-test-screenshots" exists (e.g., test -d)
before running rm -rf on its contents, and verify "./test-cypress.sh" exists and
is executable (e.g., test -x or test -f and chmod +x) before invoking it;
perform the "./test-cypress.sh" validation once before entering the loop
referenced near the existing loop start (the comment mentioned line 13) and
fail-fast with a clear error message if checks fail.
ui-tests-cy/tests/nmstate/nns.cy.ts (1)

13-13: ⚡ Quick win

Replace fixed sleeps with condition-based waits.

cy.wait(...) here will make this suite slower and flaky under load. Prefer waiting on concrete UI state transitions (target element/attribute change) instead of fixed time delays.

Also applies to: 25-25, 30-30

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nns.cy.ts` at line 13, Replace the fixed sleep
cy.wait(2 * SECOND) (and the other occurrences noted) with a condition-based
Cypress wait that targets the specific UI element/state change instead of a
timed delay: locate the test steps surrounding cy.wait(2 * SECOND), identify the
DOM selector or text that indicates the app progressed (e.g., a button
enabling/disabling, a status text change, or an element appearing/disappearing),
and replace the sleep with an assertion like cy.get(<selector>, { timeout: <ms>
}).should(<expectedCondition>) or cy.contains(<text>, { timeout: <ms>
}).should(<expectedCondition>) so the test waits until the real UI state is
reached rather than a fixed interval; apply the same replacement for the other
cy.wait occurrences referenced in the comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cleanup.sh`:
- Around line 7-12: The cleanup function uses a different default TEST_NS and
omits namespace scoping for the virtualmachinenetwork delete; change TEST_NS
default to match setup.sh's value (cy-test-ns) and ensure all oc delete
invocations in cleanup (including the virtualmachinenetwork delete and the first
oc delete of nncp resources) explicitly target the namespace by adding -n
"$TEST_NS" (or equivalent) so cleanup consistently operates in the intended
namespace; update references to TEST_NS in the cleanup() function accordingly.

In `@setup.sh`:
- Around line 7-11: The TEST_NS defaulting is using substring expansion
(${TEST_NS:cy-test-ns}) which is wrong; update the variable expansion to use the
default-value operator so TEST_NS falls back when unset or null (replace the
current expansion with the correct form), leaving the setup() function and the
oc get/create logic unchanged; look for the TEST_NS definition and change it to
use the ":-" default operator (TEST_NS=${TEST_NS:-cy-test-ns}) so the namespace
creation in setup() works reliably.

In `@test-cypress.sh`:
- Around line 3-4: The script currently disables immediate exit on error with
"set +e" and never returns the actual Cypress/test exit status; update the
control flow to capture and propagate failures by recording the exit code of
setup and cypress runs into a variable (e.g., test_exit_code) after each
critical command (the Cypress invocation and any setup steps referenced in lines
22-27 and 32-40), and add a final "exit $test_exit_code" at the end so the
script exits non-zero when any step failed; ensure you still allow teardown if
needed but preserve and return the first non-zero exit code from the named
variable.

In `@ui-tests-cy/package.json`:
- Around line 13-23: The devDependencies in ui-tests-cy package.json are using
caret ranges which reduces reproducibility; update the dependency entries for
"`@cypress/webpack-preprocessor`", "cypress", "cypress-multi-reporters", "dotenv",
"esbuild-loader", "mocha-junit-reporter", "mochawesome", "mochawesome-merge",
"mochawesome-report-generator", "typescript", and "webpack" to pin exact
versions by removing the leading '^' from each version string so the
package.json lists exact versions.

In `@ui-tests-cy/plugins/index.ts`:
- Line 28: The code sets config.env.HIDE_XHR to the raw process.env.HIDE_XHR
string which treats "false" as truthy; update the assignment in plugins/index.ts
so that the value is normalized to a boolean (e.g., convert process.env.HIDE_XHR
to true only when it equals the string "true", otherwise false, and default to
false if undefined) before assigning to config.env.HIDE_XHR so Cypress receives
a real boolean.

In `@ui-tests-cy/support/commands.ts`:
- Around line 12-24: The deleteResource command builds shell strings with
unvalidated kind/name/namespace and calls cy.exec, causing a command-injection
risk; fix it by validating each parameter (kind, name, namespace) with a strict
whitelist regex (e.g., alphanumerics, dashes, dots, and underscores only) inside
the Cypress.Commands.add('deleteResource'...) function and reject or throw on
invalid values, then call cy.exec only with validated values (still using the
same oc delete invocation) to ensure no unsafe characters can be injected;
reference the deleteResource function and the cy.exec call to locate where to
add validation.

In `@ui-tests-cy/support/selectors.ts`:
- Around line 29-34: The custom Cypress command byTestID currently calls
cy.get(`[data-test="${selector}"]`, options) but does not return it, breaking
Cypress chaining; update the implementation of byTestID to return the result of
cy.get(...) so callers like cy.byTestID('foo').click() continue to work, i.e.,
ensure the function registered with Cypress.Commands.add('byTestID', ...)
returns the cy.get call.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts`:
- Around line 17-20: The test(s) call createNNCPFromYAML() and visitNNCP() but
lack assertions; update the create/edit/delete YAML flow tests (the test that
calls createNNCPFromYAML() and the similar cases around lines 35-38 and 40-42)
to assert final state: after create, assert the new NNCP row is visible (use the
NNCP name/identifier produced by createNNCPFromYAML() with cy.contains or a
table row selector); after edit, assert the updated field(s) appear in that row;
after delete, assert the NNCP row is not present. If createNNCPFromYAML() does
not return the resource name, modify it to return or expose the created NNCP
identifier so tests can assert against it.

In `@ui-tests-cy/tests/nmstate/vmn.cy.ts`:
- Around line 17-44: The "view Virtual machine network details" test depends on
prior creates; make it independent by ensuring it creates and cleans up its own
fixture: call createVMNetwork(VM_NETWORK_PROJECT_NAME) and navigateToVMN() at
the start of the it('view Virtual machine network details', ...) test, perform
the detail assertions, then call navigateToVMN() and
deleteVMNetwork(VM_NETWORK_PROJECT_NAME) in teardown, or alternatively collapse
the related specs into a single comprehensive test that runs createVMNetwork,
asserts list presence, clicks to view details, then deletes via deleteVMNetwork
— use the existing helpers createVMNetwork, navigateToVMN, and deleteVMNetwork
to implement this.

In `@ui-tests-cy/tsconfig.json`:
- Line 5: Update the TypeScript config so single-file transpilation matches the
esbuild-loader setup: set "isolatedModules": true in ui-tests-cy/tsconfig.json
to align with the esbuild-loader rule for /\.ts$/ used in
ui-tests-cy/plugins/index.ts; this prevents TypeScript constructs that esbuild
can't safely emit (e.g., const enums or certain export-from patterns) from
slipping through and causing runtime/build issues. Ensure no other tsconfig
option contradicts isolatedModules before committing.

In `@ui-tests-cy/views/nncp.ts`:
- Around line 33-41: The final existence check is too broad; update deleteNNCP
to scope the post-delete assertion to the table row or table container so it
only verifies the row for the deleted policy is gone — e.g., after the second
Delete click, change the global cy.contains(name).should('not.exist') to a
scoped check like cy.contains('tr', name).should('not.exist') or
cy.get('<tableSelector>').contains('tr', name).should('not.exist'); keep the
rest of deleteNNCP (actionsBtn usage, confirmation typing) the same.

In `@ui-tests-cy/views/vmNetwork.ts`:
- Around line 52-54: Remove the { force: true } usage on both the
'`#delete-vm-network-modal-acknowledge-checkbox`' click and the "button" that
contains 'Delete'; instead assert actionability and interact normally so Cypress
can surface real UI issues. Specifically, replace forced clicks with checks like
ensuring the modal and elements are visible/enabled (e.g.,
cy.get('`#delete-vm-network-modal`').should('be.visible'),
cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').check()
or .click(), and
cy.get('button').contains('Delete').should('be.visible').click()) and wait for
any animation/overlay to disappear before clicking the Delete button; remove the
{ force: true } on both selectors so tests fail if the UI is not actually
actionable.

---

Nitpick comments:
In `@research-flakiness.sh`:
- Line 58: The current expression $((FAIL_COUNT * 100 / TOTAL_RUNS)) uses
integer division and truncates percentages; replace it by computing a
floating-point percentage (e.g., using awk or bc with a set scale) and format it
to at least one decimal place, store that result in a variable like
FAILURE_RATE, and then use that variable in the markdown line instead of the
integer expression so the displayed failure rate shows decimal precision.
- Around line 18-20: Before running destructive removal and launching the test
script, add existence and executability checks: verify the directory
"ui-tests-cy/gui-test-screenshots" exists (e.g., test -d) before running rm -rf
on its contents, and verify "./test-cypress.sh" exists and is executable (e.g.,
test -x or test -f and chmod +x) before invoking it; perform the
"./test-cypress.sh" validation once before entering the loop referenced near the
existing loop start (the comment mentioned line 13) and fail-fast with a clear
error message if checks fail.

In `@ui-tests-cy/.eslintrc`:
- Around line 1-15: Add import-sorting to the Cypress ESLint config by
installing eslint-plugin-simple-import-sort as a devDependency in
ui-tests-cy/package.json and then update .eslintrc to include
"plugin:simple-import-sort/recommended" in the "extends" array (and/or add
"simple-import-sort" to "plugins") so that the simple-import-sort rules are
applied to the Cypress tests; ensure the rule set is consistent with the main
project's configuration and don't remove existing rules like "no-console" or
"`@typescript-eslint/no-namespace`".

In `@ui-tests-cy/support/index.ts`:
- Around line 10-18: The custom Cypress.log override suppresses entries for
displayName 'fetch' or 'xhr' but returns undefined, violating the expected
return contract; update the override in the Cypress.log function (the override
referencing origLog and opts.displayName) to return a safe value when
suppressing logs—either return null or a minimal stub log object with the same
shape the caller expects (e.g., id/message properties) instead of returning
undefined so downstream code receives a predictable return value.

In `@ui-tests-cy/support/selectors.ts`:
- Around line 69-77: The local variable name t_o in the Cypress custom commands
for checkTitle and checkSubTitle is abbreviated and harms readability; rename
t_o to a descriptive name like timeoutValue (or timeout) in both functions,
update the assignment (const timeoutValue = timeout ? timeout : MINUTE * 3) and
replace all uses of t_o with timeoutValue so the commands
Cypress.Commands.add('checkTitle', ...) and
Cypress.Commands.add('checkSubTitle', ...) remain functionally identical but
clearer.

In `@ui-tests-cy/tests/nmstate/nns.cy.ts`:
- Line 13: Replace the fixed sleep cy.wait(2 * SECOND) (and the other
occurrences noted) with a condition-based Cypress wait that targets the specific
UI element/state change instead of a timed delay: locate the test steps
surrounding cy.wait(2 * SECOND), identify the DOM selector or text that
indicates the app progressed (e.g., a button enabling/disabling, a status text
change, or an element appearing/disappearing), and replace the sleep with an
assertion like cy.get(<selector>, { timeout: <ms> }).should(<expectedCondition>)
or cy.contains(<text>, { timeout: <ms> }).should(<expectedCondition>) so the
test waits until the real UI state is reached rather than a fixed interval;
apply the same replacement for the other cy.wait occurrences referenced in the
comment.

In `@ui-tests-cy/views/nncp.ts`:
- Around line 19-31: The createNNCPFromYAML helper uses fragile hardcoded waits
and a broad page-text check for duplicate errors; replace cy.wait(3 * SECOND)
and cy.wait(5 * SECOND) with targeted assertions/commands that wait for specific
elements or network calls (e.g., wait for the YAML modal to be visible, wait for
the Create button to become enabled, or intercept the create request and wait on
its route), and replace the body text check with a scoped assertion that looks
for the precise duplicate error element or toast (search within the modal or the
notification container) and then click the Cancel button if that specific error
is present; update references in createNNCPFromYAML and usages of
itemCreateBtn/Create button selectors accordingly.

In `@ui-tests-cy/views/physicalNetwork.ts`:
- Around line 17-20: Remove the redundant hardcoded wait: after confirming the
input is visible with cy.get(physicalNetworkNameInput, { timeout: MINUTE
}).should('be.visible'), delete the cy.wait(2 * SECOND) call and proceed to
clear and type into the element (the subsequent
cy.get(physicalNetworkNameInput).clear() and .type(networkName)); this relies on
Cypress's retry behavior on the visible assertion and avoids unnecessary test
slowdown.
- Around line 36-39: The test jumps from "Step 3" to "Step 5" and uses a
hardcoded cy.wait(3 * SECOND); update the comments to add a "Step 4: Confirm
creation initiated" line and replace the fixed wait with an assertion-based wait
that verifies the post-create state (for example, after clicking the 'Create
network' button use cy.contains('Network created', { timeout: MINUTE
}).should('be.visible') or assert navigation with cy.url().should('include',
'/networks') or another app-specific success indicator); keep the existing
selectors ('Create network' button, MINUTE, SECOND) but remove the static wait
and assert the actual success condition instead.

In `@ui-tests-cy/views/vmNetwork.ts`:
- Around line 20-44: The createVMNetwork function uses hardcoded cy.wait()
calls; replace them with assertions that wait for specific UI states: after
opening the create dialog assert the modal header appears (already present) and
wait for vmnNameInput to be visible before interacting instead of
wait(2*SECOND); after clicking Next assert the next step or a form section
(e.g., project mapping controls or a stepper indicator) is visible instead of
wait(5*SECOND); after clicking Create assert success or error toast/text (e.g.,
look for confirmation message or for the "already exists" text) and if the
"already exists" text is present call navigateToVMN(); remove all cy.wait()
calls and use should('be.visible'), contains(...).should('exist'), or
intercept+wait for network responses as appropriate to ensure deterministic
timing while keeping selectors like itemCreateBtn, vmnNameInput, submitBtn, and
navigateToVMN referenced for locating changes.
- Around line 39-43: The test is scanning the whole page body for the string
"already exists", which can produce false positives; change the check to only
inspect alert elements (e.g., use selectors like [role="alert"], .pf-c-alert or
the same alert selector used in nncp.ts) instead of cy.get('body'), then call
navigateToVMN() only if an alert's text includes "already exists" so the match
is limited to real UI alerts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 08975f2f-7732-47c1-954a-3bd7a6ca6dfb

📥 Commits

Reviewing files that changed from the base of the PR and between 11466ba and f93ba4f.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • ui-tests-cy/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (27)
  • .env.example
  • .gitignore
  • cleanup.sh
  • research-flakiness.sh
  • setup.sh
  • test-cypress.sh
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/package.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/support/commands.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/views/vmNetwork.ts

Comment thread cleanup.sh Outdated
Comment on lines +7 to +12
TEST_NS="${TEST_NS:-nmstate-test-ns}"

cleanup () {
echo "Cleaning up nmstate test resources..."
oc delete nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network --ignore-not-found --wait=true --timeout=180s
oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled --wait=true --timeout=60s 2>/dev/null || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Cleanup namespace contract is inconsistent and partially ignored.

setup.sh defaults to cy-test-ns, but this file defaults to nmstate-test-ns, and the virtualmachinenetwork delete command does not target TEST_NS. That can leave leftovers or clean the wrong namespace.

Suggested patch
-TEST_NS="${TEST_NS:-nmstate-test-ns}"
+TEST_NS="${TEST_NS:-cy-test-ns}"
@@
-  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled --wait=true --timeout=60s 2>/dev/null || true
+  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled -n "${TEST_NS}" --wait=true --timeout=60s 2>/dev/null || true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` around lines 7 - 12, The cleanup function uses a different
default TEST_NS and omits namespace scoping for the virtualmachinenetwork
delete; change TEST_NS default to match setup.sh's value (cy-test-ns) and ensure
all oc delete invocations in cleanup (including the virtualmachinenetwork delete
and the first oc delete of nncp resources) explicitly target the namespace by
adding -n "$TEST_NS" (or equivalent) so cleanup consistently operates in the
intended namespace; update references to TEST_NS in the cleanup() function
accordingly.

Comment thread setup.sh Outdated
Comment thread test-cypress.sh Outdated
Comment thread ui-tests-cy/package.json
Comment on lines +13 to +23
"@cypress/webpack-preprocessor": "^6.0.2",
"cypress": "^15.3.0",
"cypress-multi-reporters": "^2.0.4",
"dotenv": "^16.4.7",
"esbuild-loader": "^4.2.2",
"mocha-junit-reporter": "^2.2.1",
"mochawesome": "^7.1.3",
"mochawesome-merge": "^4.3.0",
"mochawesome-report-generator": "^6.2.0",
"typescript": "^5.9.3",
"webpack": "^5.104.1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
# Verify whether package.json still contains semver ranges in dependencies/devDependencies
jq -r '
  .devDependencies // {} | to_entries[] | select(.value|test("^[\\^~]")) | "\(.key)=\(.value)"
' ui-tests-cy/package.json

Repository: openshift/nmstate-console-plugin

Length of output: 340


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Check for semver ranges in dependencies AND devDependencies
jq -r '
  ( .dependencies // {} ) | to_entries[] | select(.value|test("^[\\^~]")) | "dependencies:\(.key)=\(.value)"
' ui-tests-cy/package.json

jq -r '
  ( .devDependencies // {} ) | to_entries[] | select(.value|test("^[\\^~]")) | "devDependencies:\(.key)=\(.value)"
' ui-tests-cy/package.json

Repository: openshift/nmstate-console-plugin

Length of output: 516


Pin exact devDependencies versions in ui-tests-cy/package.json (remove ^ ranges).

ui-tests-cy/package.json devDependencies use caret semver ranges (e.g., cypress, webpack, typescript), which weakens supply-chain reproducibility.

Suggested patch
-    "`@cypress/webpack-preprocessor`": "^6.0.2",
-    "cypress": "^15.3.0",
-    "cypress-multi-reporters": "^2.0.4",
-    "dotenv": "^16.4.7",
-    "esbuild-loader": "^4.2.2",
-    "mocha-junit-reporter": "^2.2.1",
-    "mochawesome": "^7.1.3",
-    "mochawesome-merge": "^4.3.0",
-    "mochawesome-report-generator": "^6.2.0",
-    "typescript": "^5.9.3",
-    "webpack": "^5.104.1"
+    "`@cypress/webpack-preprocessor`": "6.0.2",
+    "cypress": "15.3.0",
+    "cypress-multi-reporters": "2.0.4",
+    "dotenv": "16.4.7",
+    "esbuild-loader": "4.2.2",
+    "mocha-junit-reporter": "2.2.1",
+    "mochawesome": "7.1.3",
+    "mochawesome-merge": "4.3.0",
+    "mochawesome-report-generator": "6.2.0",
+    "typescript": "5.9.3",
+    "webpack": "5.104.1"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/package.json` around lines 13 - 23, The devDependencies in
ui-tests-cy package.json are using caret ranges which reduces reproducibility;
update the dependency entries for "`@cypress/webpack-preprocessor`", "cypress",
"cypress-multi-reporters", "dotenv", "esbuild-loader", "mocha-junit-reporter",
"mochawesome", "mochawesome-merge", "mochawesome-report-generator",
"typescript", and "webpack" to pin exact versions by removing the leading '^'
from each version string so the package.json lists exact versions.

Source: Coding guidelines

config.baseUrl = `${process.env.BRIDGE_BASE_ADDRESS || 'http://localhost:9000/'}`;
config.env.BRIDGE_KUBEADMIN_PASSWORD = process.env.BRIDGE_KUBEADMIN_PASSWORD;
config.env.TEST_NS = process.env.TEST_NS;
config.env.HIDE_XHR = process.env.HIDE_XHR;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize HIDE_XHR to boolean before injecting into Cypress env.

Passing raw string env values means "false" is treated as truthy, which can incorrectly enable log hiding.

Suggested patch
-  config.env.HIDE_XHR = process.env.HIDE_XHR;
+  config.env.HIDE_XHR = String(process.env.HIDE_XHR).toLowerCase() === 'true';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
config.env.HIDE_XHR = process.env.HIDE_XHR;
config.env.HIDE_XHR = String(process.env.HIDE_XHR).toLowerCase() === 'true';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/plugins/index.ts` at line 28, The code sets config.env.HIDE_XHR
to the raw process.env.HIDE_XHR string which treats "false" as truthy; update
the assignment in plugins/index.ts so that the value is normalized to a boolean
(e.g., convert process.env.HIDE_XHR to true only when it equals the string
"true", otherwise false, and default to false if undefined) before assigning to
config.env.HIDE_XHR so Cypress receives a real boolean.

Comment on lines +17 to +20
it('create NNCP with YAML', () => {
createNNCPFromYAML();
cy.visitNNCP();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add outcome assertions for YAML create/edit/delete flows.

These cases currently perform actions without asserting final state, so they can pass even when behavior regresses. Please assert success criteria (e.g., created/updated row visible, deleted row absent) after each operation.

Also applies to: 35-38, 40-42

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts` around lines 17 - 20, The test(s) call
createNNCPFromYAML() and visitNNCP() but lack assertions; update the
create/edit/delete YAML flow tests (the test that calls createNNCPFromYAML() and
the similar cases around lines 35-38 and 40-42) to assert final state: after
create, assert the new NNCP row is visible (use the NNCP name/identifier
produced by createNNCPFromYAML() with cy.contains or a table row selector);
after edit, assert the updated field(s) appear in that row; after delete, assert
the NNCP row is not present. If createNNCPFromYAML() does not return the
resource name, modify it to return or expose the created NNCP identifier so
tests can assert against it.

Comment thread ui-tests-cy/tests/nmstate/vmn.cy.ts Outdated
Comment on lines +17 to +44
it('create prerequisites from warning page', () => {
attemptToCreateVMNetwork();
});

it('create Virtual machine network', () => {
createVMNetwork(VM_NETWORK_PROJECT_NAME);
navigateToVMN();
cy.contains(VM_NETWORK_PROJECT_NAME, { timeout: MINUTE }).should('exist');
});

it('create second Virtual machine network', () => {
createVMNetwork(VM_NETWORK_LABELED_NAME);
navigateToVMN();
cy.contains(VM_NETWORK_LABELED_NAME, { timeout: MINUTE }).should('exist');
});

it('view Virtual machine network details', () => {
cy.contains('a', VM_NETWORK_PROJECT_NAME).click();
cy.contains('h1', VM_NETWORK_PROJECT_NAME, { timeout: MINUTE }).should('exist');
cy.contains('Virtual machine network details').should('be.visible');
cy.contains('Connected projects').should('be.visible');
navigateToVMN();
});

it('delete Virtual machine networks', () => {
deleteVMNetwork(VM_NETWORK_PROJECT_NAME);
deleteVMNetwork(VM_NETWORK_LABELED_NAME);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Tests lack independence - failures will cascade.

The test at lines 33-39 ("view Virtual machine network details") depends on the earlier tests (lines 21-31) having successfully created VM_NETWORK_PROJECT_NAME. If test creation fails or is skipped, the details test will also fail. This violates the Cypress best practice that each test should be independently runnable.

Consider restructuring to ensure each test sets up its own required state, or use a single comprehensive test for the full workflow.

💡 Example restructuring approach

Option 1: Single comprehensive test

it('complete VM network lifecycle', () => {
  // Create, verify, view details, delete all in one test
  createVMNetwork(VM_NETWORK_PROJECT_NAME);
  navigateToVMN();
  cy.contains(VM_NETWORK_PROJECT_NAME, { timeout: MINUTE }).should('exist');
  
  // View details
  cy.contains('a', VM_NETWORK_PROJECT_NAME).click();
  cy.contains('h1', VM_NETWORK_PROJECT_NAME, { timeout: MINUTE }).should('exist');
  // ... rest of assertions
  
  // Cleanup
  navigateToVMN();
  deleteVMNetwork(VM_NETWORK_PROJECT_NAME);
});

Option 2: Independent tests with setup

it('view Virtual machine network details', () => {
  // Ensure prerequisite exists
  createVMNetwork(VM_NETWORK_PROJECT_NAME);
  navigateToVMN();
  
  // Now test details view
  cy.contains('a', VM_NETWORK_PROJECT_NAME).click();
  // ... assertions
  
  // Cleanup this test's resources
  navigateToVMN();
  deleteVMNetwork(VM_NETWORK_PROJECT_NAME);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/vmn.cy.ts` around lines 17 - 44, The "view Virtual
machine network details" test depends on prior creates; make it independent by
ensuring it creates and cleans up its own fixture: call
createVMNetwork(VM_NETWORK_PROJECT_NAME) and navigateToVMN() at the start of the
it('view Virtual machine network details', ...) test, perform the detail
assertions, then call navigateToVMN() and
deleteVMNetwork(VM_NETWORK_PROJECT_NAME) in teardown, or alternatively collapse
the related specs into a single comprehensive test that runs createVMNetwork,
asserts list presence, clicks to view details, then deletes via deleteVMNetwork
— use the existing helpers createVMNetwork, navigateToVMN, and deleteVMNetwork
to implement this.

Comment thread ui-tests-cy/tsconfig.json
"compilerOptions": {
"noEmit": true,
"types": ["cypress", "node"],
"isolatedModules": false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check esbuild and isolated modules documentation/requirements

# Search for any existing TypeScript files in the Cypress tests that might rely on non-isolated module patterns
rg -n -C3 'export.*from' ui-tests-cy/ --type=ts

# Check if there are any const enums (which require isolatedModules: false)
rg -n 'const enum' ui-tests-cy/ --type=ts

Repository: openshift/nmstate-console-plugin

Length of output: 58


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== ui-tests-cy/tsconfig.json ==" 
if [ -f ui-tests-cy/tsconfig.json ]; then
  cat -n ui-tests-cy/tsconfig.json | head -n 120
else
  echo "Missing ui-tests-cy/tsconfig.json"
fi

echo
echo "== ui-tests-cy/plugins/index.ts (lines 1-120) =="
if [ -f ui-tests-cy/plugins/index.ts ]; then
  cat -n ui-tests-cy/plugins/index.ts | head -n 160
else
  echo "Missing ui-tests-cy/plugins/index.ts"
fi

echo
echo "== Search: isolatedModules usage across repo =="
rg -n --hidden --glob '!*node_modules/*' "isolatedModules" .

echo
echo "== Search: export ... from (non-type-only) =="
rg -n --type=ts '^\s*export\s+\{[^}]+\}\s+from\s+["'\'']' ui-tests-cy/ || true
echo
echo "== Search: export * from (non-type-only) =="
rg -n --type=ts '^\s*export\s+\*\s+from\s+["'\'']' ui-tests-cy/ || true

echo
echo "== Search: import { ... } from (non-type-only) =="
rg -n --type=ts '^\s*import\s+\{[^}]+\}\s+from\s+["'\'']' ui-tests-cy/ || true

echo
echo "== Search: import type { ... } from =="
rg -n --type=ts '^\s*import\s+type\s+\{[^}]+\}\s+from\s+["'\'']' ui-tests-cy/ || true

echo
echo "== Search: const enum in ui-tests-cy =="
rg -n --type=ts 'const enum' ui-tests-cy/ || true

Repository: openshift/nmstate-console-plugin

Length of output: 3823


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search: export { ... } from =="
rg -n --type=ts '^\s*export\s*\{\s*[^}]+\s*\}\s*from\s*["'\''']' ui-tests-cy/ || true

echo
echo "== Search: export type { ... } from =="
rg -n --type=ts '^\s*export\s+type\s*\{\s*[^}]+\s*\}\s*from\s*["'\''']' ui-tests-cy/ || true

echo
echo "== Search: export { type ... } from =="
rg -n --type=ts '^\s*export\s*\{\s*type\s+[^}]+\}\s*from\s*["'\''']' ui-tests-cy/ || true

echo
echo "== Search: export * from (again, but scoped) =="
rg -n --type=ts '^\s*export\s*\*\s*from\s*["'\''']' ui-tests-cy/ || true

Repository: openshift/nmstate-console-plugin

Length of output: 198


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search: export { ... } from =="
rg -n --type=ts '^\s*export\s*\{\s*[^}]+\s*\}\s*from\s*["'\'']' ui-tests-cy/ || true

echo
echo "== Search: export type { ... } from =="
rg -n --type=ts '^\s*export\s+type\s*\{\s*[^}]+\s*\}\s*from\s*["'\'']' ui-tests-cy/ || true

echo
echo "== Search: export { type ... } from =="
rg -n --type=ts '^\s*export\s*\{\s*type\s+[^}]+\}\s*from\s*["'\'']' ui-tests-cy/ || true

echo
echo "== Search: export * from =="
rg -n --type=ts '^\s*export\s*\*\s*from\s*["'\'']' ui-tests-cy/ || true

echo
echo "== Search: type-only imports =="
rg -n --type=ts '^\s*import\s+type\s+\{[^}]+\}\s+from\s*["'\'']' ui-tests-cy/ || true

Repository: openshift/nmstate-console-plugin

Length of output: 252


🌐 Web query:

esbuild-loader isolatedModules true requirement

💡 Result:

In esbuild-loader, it is required to set isolatedModules to true in your tsconfig.json to prevent mis-compilation errors [1][2]. Because esbuild is a single-file transpiler, it does not have knowledge of the full TypeScript type system or external file dependencies when processing an individual file [3]. Setting isolatedModules: true instructs the TypeScript compiler to warn you if you write code that cannot be safely transpiled in isolation—such as re-exporting types or certain uses of namespaces and ambient const enums [1][3]. Without this setting, these features could lead to runtime errors because the transpiler may be unable to correctly replace or remove code that requires type-level information [3].

Citations:


🌐 Web query:

esbuild const enum isolatedModules

💡 Result:

esbuild fully supports const enums by inlining their values during compilation [1][2][3], provided the enum is not ambient (i.e., not declared with the declare keyword) [4][2][3]. Because esbuild operates by transpiling each file in isolation, it lacks the full type-checking context required to resolve ambient const enum declarations that exist only in type definitions [5][3][6]. Consequently, referencing ambient const enum members results in a runtime error because the enum object is not emitted, and the reference cannot be inlined [4][5][3]. To ensure your project remains safe and avoids these runtime errors, it is highly recommended to enable the isolatedModules: true option in your tsconfig.json [5][6][7]. When this flag is set, the TypeScript compiler will detect and error on unsafe patterns—such as referencing ambient const enum members—before you even run your build [5][2][3]. Key takeaways: * Standard const enum usage is supported and will be inlined correctly [4][2][3]. * Ambient const enum (i.e., declare const enum) is not supported, as it cannot be inlined by a single-file transpiler [4][3]. You should remove the declare modifier if you want to use it [4][3]. * Always enable isolatedModules: true when using esbuild to prevent accidental usage of TypeScript features that require multi-file type analysis [3][6][7].

Citations:


🌐 Web query:

site:npmjs.com/package/esbuild-loader isolatedModules true

💡 Result:

The isolatedModules option is a TypeScript compiler setting that ensures each file can be safely transpiled without relying on other files for type information. When set to true, TypeScript will issue a warning or error if it encounters code that cannot be processed in isolation [1]. Key aspects of isolatedModules: 1. Transpilation Compatibility: It is essential when using transpilers that perform single-file compilation, such as esbuild, Babel, or SWC [1]. These tools process files individually and do not have access to the full type-checking context of a project. 2. Unsupported Features: When isolatedModules is enabled, TypeScript prevents the use of certain language features that require cross-file knowledge or complex type interpretation to compile correctly. For example, it helps prevent mis-compilation issues related to re-exporting types, which might not exist in the emitted JavaScript but could cause issues in tools that expect pure single-file processing [1]. 3. Recommended Usage: It is highly recommended to set isolatedModules to true if you are using modern build pipelines or bundlers that rely on transpilers other than the standard TypeScript compiler (tsc) for emission [1]. This ensures that your code remains compatible with the constraints of these tools. While this setting enforces stricter rules on how you write code, it does not change the core type-checking behavior of the TypeScript compiler itself; rather, it makes your codebase more portable and robust across different build environments.

Citations:


🌐 Web query:

site:github.com/evanw/esbuild isolatedModules

💡 Result:

The isolatedModules flag in TypeScript is a configuration option in tsconfig.json that instructs the TypeScript compiler to ensure that every file can be safely transpiled in isolation, without relying on type information from other files [1][2]. When isolatedModules is enabled (set to true), TypeScript will flag code patterns that cannot be safely transpiled if the compiler only looks at the single file currently being processed [3][2]. This is critical for build tools that process files one by one—such as esbuild, Babel, or the TypeScript transpileModule API—as these tools cannot perform cross-file type analysis to determine if an imported symbol is a value or a type [3][4][2]. Key implications of enabling isolatedModules include: - Prevents problematic re-exports: It forces the use of export type {T} from '...' instead of export {T} from '...', ensuring that type-only exports are explicitly marked so the compiler knows they can be safely removed during transpilation [3][1]. - Ensures safe transpilation: It guarantees that the generated JavaScript will work correctly even if the transpiler lacks knowledge of the broader project structure or type definitions [4][2]. - Standardizes behavior: By enforcing these constraints at compile time, it ensures that your TypeScript code is compatible with transpilers that operate independently of full type-checking [5][2]. It is highly recommended to enable isolatedModules when using modern, fast build tools like esbuild, Vite, or others that rely on single-file transpilation, as it helps prevent runtime errors caused by missing imports or incorrectly preserved types [3][6][2].

Citations:


Set isolatedModules: true for Cypress esbuild-loader TypeScript transpilation.

ui-tests-cy/plugins/index.ts configures esbuild-loader for \.ts$, but ui-tests-cy/tsconfig.json sets isolatedModules: false (line 5). Single-file transpilation benefits from isolatedModules: true to avoid TS patterns that esbuild may not emit safely; the current Cypress tests don’t contain obvious problematic export ... from/const enum usage, but the mismatch can still cause future build/runtime issues.

🔧 Proposed fix
 {
   "compilerOptions": {
     "noEmit": true,
     "types": ["cypress", "node"],
-    "isolatedModules": false,
+    "isolatedModules": true,
     "module": "esnext",
     "target": "es2016",
     "moduleResolution": "node",
     "esModuleInterop": true,
     "strict": false
   },
   "include": ["node_modules/cypress", "./**/*.ts"]
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"isolatedModules": false,
{
"compilerOptions": {
"noEmit": true,
"types": ["cypress", "node"],
"isolatedModules": true,
"module": "esnext",
"target": "es2016",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": false
},
"include": ["node_modules/cypress", "./**/*.ts"]
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tsconfig.json` at line 5, Update the TypeScript config so
single-file transpilation matches the esbuild-loader setup: set
"isolatedModules": true in ui-tests-cy/tsconfig.json to align with the
esbuild-loader rule for /\.ts$/ used in ui-tests-cy/plugins/index.ts; this
prevents TypeScript constructs that esbuild can't safely emit (e.g., const enums
or certain export-from patterns) from slipping through and causing runtime/build
issues. Ensure no other tsconfig option contradicts isolatedModules before
committing.

Comment thread ui-tests-cy/views/nncp.ts
Comment on lines +33 to +41
export const deleteNNCP = (name: string) => {
cy.contains('tr', name).within(() => {
cy.get(actionsBtn).first().click();
});
cy.contains('button', 'Delete').click();
cy.get('#text-confirmation').type(name);
cy.contains('button', 'Delete').click();
cy.contains(name).should('not.exist');
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Scope the deletion verification assertion.

Line 40's assertion cy.contains(name).should('not.exist') will match the policy name anywhere on the page (breadcrumbs, navigation, headers). This could pass even if the resource still exists in the table.

🐛 Proposed fix to scope the assertion
   cy.contains('tr', name).within(() => {
     cy.get(actionsBtn).first().click();
   });
   cy.contains('button', 'Delete').click();
   cy.get('`#text-confirmation`').type(name);
   cy.contains('button', 'Delete').click();
-  cy.contains(name).should('not.exist');
+  // Verify the row is removed from the table
+  cy.contains('tr', name).should('not.exist');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/nncp.ts` around lines 33 - 41, The final existence check is
too broad; update deleteNNCP to scope the post-delete assertion to the table row
or table container so it only verifies the row for the deleted policy is gone —
e.g., after the second Delete click, change the global
cy.contains(name).should('not.exist') to a scoped check like cy.contains('tr',
name).should('not.exist') or cy.get('<tableSelector>').contains('tr',
name).should('not.exist'); keep the rest of deleteNNCP (actionsBtn usage,
confirmation typing) the same.

Comment on lines +52 to +54
cy.get('#delete-vm-network-modal-acknowledge-checkbox').click({ force: true });
cy.wait(SECOND);
cy.get('button').contains('Delete').last().click({ force: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove { force: true } - it bypasses Cypress safety checks.

Lines 52 and 54 use { force: true } to click the checkbox and delete button. This bypasses Cypress's actionability checks (visibility, enabled state, not covered by other elements) and can hide real UI issues such as overlapping modals, disabled buttons, or elements not actually visible to users.

🔒 Recommended fix
-  cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').click({ force: true });
+  cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').click();
   cy.wait(SECOND);
-  cy.get('button').contains('Delete').last().click({ force: true });
+  cy.get('button').contains('Delete').last().should('be.enabled').click();

If the elements are genuinely not actionable without force, that indicates a real UI issue that should be fixed rather than bypassed in tests.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cy.get('#delete-vm-network-modal-acknowledge-checkbox').click({ force: true });
cy.wait(SECOND);
cy.get('button').contains('Delete').last().click({ force: true });
cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').click();
cy.wait(SECOND);
cy.get('button').contains('Delete').last().should('be.enabled').click();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 52 - 54, Remove the { force:
true } usage on both the '`#delete-vm-network-modal-acknowledge-checkbox`' click
and the "button" that contains 'Delete'; instead assert actionability and
interact normally so Cypress can surface real UI issues. Specifically, replace
forced clicks with checks like ensuring the modal and elements are
visible/enabled (e.g., cy.get('`#delete-vm-network-modal`').should('be.visible'),
cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').check()
or .click(), and
cy.get('button').contains('Delete').should('be.visible').click()) and wait for
any animation/overlay to disappear before clicking the Delete button; remove the
{ force: true } on both selectors so tests fail if the UI is not actually
actionable.

@lkladnit lkladnit changed the title WIP: Add Cypress E2E tests for NNCP, Physical networks, VM networks, and NNS WIP: CNV-87995 Add Cypress E2E tests for NNCP, Physical networks, VM networks, and NNS Jun 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (6)
ui-tests-cy/support/selectors.ts (1)

29-34: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing return statement breaks Cypress command chaining.

The byTestID command does not return the result of cy.get(...), breaking Cypress's chainable API. All subsequent .click(), .should(), etc., chained to cy.byTestID(...) will fail.

🐛 Proposed fix
 Cypress.Commands.add(
   'byTestID',
   (selector: string, options?: Partial<Loggable & Shadow & Timeoutable & Withinable>) => {
-    cy.get(`[data-test="${selector}"]`, options);
+    return cy.get(`[data-test="${selector}"]`, options);
   },
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/support/selectors.ts` around lines 29 - 34, The custom Cypress
command 'byTestID' currently calls cy.get(`[data-test="${selector}"]`, options)
but does not return it, which breaks Cypress chaining; update the command
implementation for 'byTestID' (the Cypress.Commands.add call) to return the
result of cy.get(...) so callers can chain .click(), .should(), etc. normally.
setup.sh (1)

7-11: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix namespace defaulting; current expansion is incorrect.

Line 7 uses substring expansion ${TEST_NS:cy-test-ns} instead of the fallback default operator ${TEST_NS:-cy-test-ns}. This will fail when TEST_NS is unset. Line 11 also needs quotes around ${TEST_NS} to prevent globbing and word splitting.

🐛 Proposed fix
-TEST_NS="${TEST_NS:cy-test-ns}"
+TEST_NS="${TEST_NS:-cy-test-ns}"
@@
-  oc get namespace ${TEST_NS} 2>/dev/null || oc create namespace ${TEST_NS}
+  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace "${TEST_NS}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@setup.sh` around lines 7 - 11, The TEST_NS default expansion is wrong and the
variable is unquoted; change the parameter expansion to use the fallback
operator and quote usages: replace occurrences of TEST_NS definition
`${TEST_NS:cy-test-ns}` with `${TEST_NS:-cy-test-ns}` and wrap variable
references in the setup function (the oc get namespace and oc create namespace
calls inside the setup() function) with double quotes around `${TEST_NS}` to
prevent globbing/word-splitting.
cleanup.sh (1)

7-12: ⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoff

Cleanup namespace contract is inconsistent and partially ignored.

setup.sh defaults to cy-test-ns, but this file defaults to nmstate-test-ns. The oc delete commands on Lines 11-12 do not specify a namespace with -n "${TEST_NS}", which can leave leftovers in the intended namespace or clean the wrong scope.

🛠️ Proposed fix
-TEST_NS="${TEST_NS:-nmstate-test-ns}"
+TEST_NS="${TEST_NS:-cy-test-ns}"
@@
-  oc delete nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network --ignore-not-found --wait=true --timeout=180s
-  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled --wait=true --timeout=60s 2>/dev/null || true
+  oc delete -n "${TEST_NS}" nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network --ignore-not-found --wait=true --timeout=180s
+  oc delete -n "${TEST_NS}" --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled --wait=true --timeout=60s 2>/dev/null || true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` around lines 7 - 12, The cleanup function uses a different
default TEST_NS and omits namespace scope when deleting resources; change the
TEST_NS default to match setup.sh (use TEST_NS="${TEST_NS:-cy-test-ns}") and
update the oc delete invocations inside cleanup (the commands in function
cleanup and the second oc delete line) to include -n "${TEST_NS}" so deletes
target the intended namespace; keep --ignore-not-found and timeouts as-is and
preserve the 2>/dev/null || true behavior if desired.
test-cypress.sh (1)

3-40: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Propagate failures reliably from setup and test execution.

With set +e on Line 4 and no final exit "${test_exit_code}", this script will exit 0 even when Cypress fails. This can silently green-light broken E2E runs in CI.

🔧 Proposed fix
-set -x
-set +e
+set -xeuo pipefail
@@
-  node --max-old-space-size=4096 ./node_modules/.bin/cypress run --env openshift=true --browser ${BRIDGE_E2E_BROWSER_NAME:=electron} --spec "$spec" | tee ./gui-test-screenshots/build.log
+  node --max-old-space-size=4096 ./node_modules/.bin/cypress run --env openshift=true --browser "${BRIDGE_E2E_BROWSER_NAME:=electron}" --spec "$spec" | tee ./gui-test-screenshots/build.log
   test_exit_code=${PIPESTATUS[0]}
@@
   if [ ${test_exit_code} -eq 0 ]; then
     cleanup
   fi
+  exit "${test_exit_code}"
 fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` around lines 3 - 40, The script currently uses set +e so
failures from setup() or the Cypress run can be ignored; ensure failures are
propagated by enabling strict exit handling and exiting with the Cypress status:
enable errexit (replace set +e with set -e or add set -euo pipefail) and after
running Cypress use the captured test_exit_code to exit the script (add a final
exit "${test_exit_code}" so CI sees failures); also check the return value of
setup and cleanup calls (call setup and immediately exit on non-zero) to ensure
setup failures don't get swallowed.
ui-tests-cy/support/commands.ts (1)

12-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Command injection vulnerability via string interpolation.

The deleteResource command constructs shell commands by directly interpolating kind, name, and namespace into cy.exec calls. This violates the coding guideline: "Command: no shell=True, os.system, or backtick exec with user input." Although parameters come from test code, the pattern is unsafe. As per coding guidelines, command injection prevention requires avoiding shell execution with interpolated variables.

🛡️ Proposed fix using input validation
 Cypress.Commands.add('deleteResource', (kind: string, name: string, namespace?: string) => {
+  // Validate inputs contain only alphanumeric, dash, and underscore
+  const safePattern = /^[a-zA-Z0-9_-]+$/;
+  if (!safePattern.test(kind) || !safePattern.test(name)) {
+    throw new Error('Invalid resource kind or name');
+  }
+  if (namespace && !safePattern.test(namespace)) {
+    throw new Error('Invalid namespace');
+  }
+
   if (!namespace) {
     cy.exec(`oc delete --ignore-not-found=true ${kind} ${name} --wait=true --timeout=300s`, {
       failOnNonZeroExit: false,
       timeout: 5 * MINUTE,
     });
     return;
   }
   cy.exec(
     `oc delete --ignore-not-found=true -n ${namespace} ${kind} ${name} --wait=true --timeout=300s`,
     { failOnNonZeroExit: false, timeout: 5 * MINUTE },
   );
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/support/commands.ts` around lines 12 - 24, The deleteResource
command is vulnerable because it interpolates user-controlled strings into a
shell command; fix it by validating and sanitizing the three parameters in the
deleteResource function (kind, name, namespace) before calling cy.exec: enforce
strict allowlists/regexes (e.g., only letters, numbers, '-', '.', and length
limits) or map known resource kinds to an enum, reject anything that doesn't
match, and only then build the command; update the cy.exec calls in
deleteResource to use those validated values (or fail fast) so no unvalidated
input is ever interpolated into the shell string.

Source: Coding guidelines

ui-tests-cy/package.json (1)

13-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pin exact devDependencies versions (remove ^ ranges).

All devDependencies use caret semver ranges, which weakens supply-chain reproducibility. As per coding guidelines, exact versions should be pinned.

🔒 Proposed fix
-    "`@cypress/webpack-preprocessor`": "^6.0.2",
-    "cypress": "^15.3.0",
-    "cypress-multi-reporters": "^2.0.4",
-    "dotenv": "^16.4.7",
-    "esbuild-loader": "^4.2.2",
-    "mocha-junit-reporter": "^2.2.1",
-    "mochawesome": "^7.1.3",
-    "mochawesome-merge": "^4.3.0",
-    "mochawesome-report-generator": "^6.2.0",
-    "typescript": "^5.9.3",
-    "webpack": "^5.104.1"
+    "`@cypress/webpack-preprocessor`": "6.0.2",
+    "cypress": "15.3.0",
+    "cypress-multi-reporters": "2.0.4",
+    "dotenv": "16.4.7",
+    "esbuild-loader": "4.2.2",
+    "mocha-junit-reporter": "2.2.1",
+    "mochawesome": "7.1.3",
+    "mochawesome-merge": "4.3.0",
+    "mochawesome-report-generator": "6.2.0",
+    "typescript": "5.9.3",
+    "webpack": "5.104.1"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/package.json` around lines 13 - 23, The devDependencies in
package.json currently use caret ranges (e.g., "`@cypress/webpack-preprocessor`",
"cypress", "cypress-multi-reporters", "dotenv", "esbuild-loader",
"mocha-junit-reporter", "mochawesome", "mochawesome-merge",
"mochawesome-report-generator", "typescript", "webpack"); change each version
string to an exact pinned version (remove the leading '^' so entries become e.g.
"cypress": "15.3.0") and then regenerate the lockfile by running your package
manager install command to persist the pinned versions.

Source: Coding guidelines

🧹 Nitpick comments (5)
ui-tests-cy/tests/nmstate/physical.cy.ts (3)

4-7: ⚡ Quick win

Add an after hook to clean up created resources.

The before hook deletes any existing PhysicalNetwork, but there is no after hook to clean up resources created during the test suite. If tests fail or are interrupted, the test resource will persist in the cluster.

♻️ Suggested cleanup hook
 adminOnlyDescribe('Test Physical networks', () => {
   before(() => {
     cy.deleteResource(K8S_KIND.NNCP, PHYSICAL_NETWORK_TEST_NAME);
   });
+
+  after(() => {
+    cy.deleteResource(K8S_KIND.NNCP, PHYSICAL_NETWORK_TEST_NAME);
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/physical.cy.ts` around lines 4 - 7, Add an after
hook to ensure created PhysicalNetwork resources are removed after the suite: in
the adminOnlyDescribe block that contains the before hook, add an after(() => {
... }) that calls cy.deleteResource(K8S_KIND.NNCP, PHYSICAL_NETWORK_TEST_NAME)
(matching the before) so the resource is cleaned up even if tests fail or are
interrupted; place this after hook alongside the existing before to guarantee
teardown of PHYSICAL_NETWORK_TEST_NAME.

14-17: ⚡ Quick win

Test depends on previous test execution.

This test assumes the Physical network already exists from the previous 'create Physical network' test. If this test runs in isolation (e.g., via .only), it will fail. Cypress tests should be independent and runnable individually.

Consider adding a beforeEach hook that ensures the resource exists, or restructure the tests to use nested describe blocks with appropriate setup/teardown.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/physical.cy.ts` around lines 14 - 17, The test
'verify Physical network in list' depends on a prior test creating the network;
make it independent by adding setup that ensures the resource exists before
running: add a beforeEach (or move into a nested describe with setup) that calls
the creation helper used by the 'create Physical network' flow (or an API
utility) to create PHYSICAL_NETWORK_TEST_NAME, then call
cy.visitPhysicalNetworks() and assert presence; reference the test name 'verify
Physical network in list', the helper cy.visitPhysicalNetworks(), and the
constant PHYSICAL_NETWORK_TEST_NAME when locating where to add the
setup/creation logic.

21-26: ⚡ Quick win

Replace hard-coded wait with assertion-based waiting.

Line 26 uses cy.wait(2 * SECOND), which is a hard-coded time-based wait. This is a Cypress anti-pattern that adds unnecessary delay and can still be flaky if the DOM takes longer than 2 seconds to update.

Instead, wait for a specific DOM condition that indicates the row has expanded (e.g., presence of expanded content, an aria-expanded="true" attribute, or a specific class).

♻️ Suggested assertion-based wait
     cy.contains('td', PHYSICAL_NETWORK_TEST_NAME)
       .closest('tbody')
       .find('td:first-child button')
       .first()
       .click();
-    cy.wait(2 * SECOND);
 
     // Verify the NNCP name appears in the expanded content
     cy.contains('td', PHYSICAL_NETWORK_TEST_NAME)
       .closest('tbody')
-      .contains(PHYSICAL_NETWORK_TEST_NAME)
+      .contains(PHYSICAL_NETWORK_TEST_NAME, { timeout: MINUTE })
       .should('be.visible');

By adding a timeout to the assertion itself, Cypress will retry until the condition is met or the timeout expires.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/physical.cy.ts` around lines 21 - 26, Replace the
hard-coded cy.wait(2 * SECOND) after clicking the row action so the test waits
for a real DOM change: after clicking the button found via cy.contains('td',
PHYSICAL_NETWORK_TEST_NAME).closest('tbody').find('td:first-child
button').first().click(), assert the expected expanded state (for example, that
the clicked button or its container has aria-expanded="true" or that a known
expanded-content element/class appears) with an explicit timeout so Cypress will
retry until the row is expanded instead of sleeping.
ui-tests-cy/tests/nmstate/visit-pages.cy.ts (2)

14-17: 💤 Low value

Inconsistent assertion pattern.

This test uses URL assertion (cy.url().should('include', ...)) while the other navigation tests assert on the presence of an h1 element. This inconsistency may be intentional if the Node network configuration page lacks an h1 heading, but it's worth verifying.

For consistency and robustness, consider using the same assertion pattern (h1 check) unless there's a specific reason the page structure differs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/visit-pages.cy.ts` around lines 14 - 17, The test
"should navigate to Node network configuration" uses
cy.clickNavLink(['Networking', 'Node network configuration']) and then asserts
via cy.url(), which is inconsistent with other navigation tests that assert the
presence of an h1; update the test to assert the page heading instead (e.g.,
check that the page contains an h1 with the expected text) by replacing or
augmenting the cy.url().should(...) assertion with an h1 existence/text
assertion targeting the Node network configuration page; if the page truly lacks
an h1, add a brief inline comment in this test explaining why URL assertion is
kept and consider adding a more specific DOM selector to assert page load
consistency.

19-28: ⚡ Quick win

Conditional test based on DOM state may be flaky.

This test uses .then() to conditionally execute based on whether 'Virtualization' appears in the sidebar text. This pattern can be flaky if the sidebar hasn't fully loaded when the check executes.

Consider using a Cypress environment variable or feature flag to determine whether Virtualization is installed, rather than inspecting DOM content. Alternatively, add an explicit wait or assertion to ensure the sidebar is fully loaded before checking its text.

♻️ Alternative: use environment variable
   it('should navigate to Virtual machine networks (if Virtualization present)', () => {
-    cy.get('`#page-sidebar`').then(($sidebar) => {
-      if ($sidebar.text().includes('Virtualization')) {
+    if (Cypress.env('HAS_VIRTUALIZATION')) {
         cy.clickNavLink(['Virtualization', 'Virtual machine networks']);
         cy.contains('h1', 'Virtual machine networks', { timeout: MINUTE }).should('exist');
-      } else {
+    } else {
         cy.log('Virtualization section not present — skipping');
-      }
-    });
+    }
   });

This would require setting HAS_VIRTUALIZATION in your Cypress config or via environment variable, but provides more reliable conditional logic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/visit-pages.cy.ts` around lines 19 - 28, The
conditional DOM check in the test "should navigate to Virtual machine networks
(if Virtualization present)" using cy.get('`#page-sidebar`').then(...) is flaky;
either read a Cypress env var like HAS_VIRTUALIZATION
(Cypress.env('HAS_VIRTUALIZATION')) at the top of the test and branch to call
cy.clickNavLink(['Virtualization', 'Virtual machine networks']) and the
subsequent cy.contains('h1', 'Virtual machine networks', { timeout: MINUTE })
when true, or if you must detect via DOM, replace the immediate .then() check
with a robust wait/assertion (e.g.,
cy.get('`#page-sidebar`').should('exist').and('not.be.empty') before checking
.invoke('text') or use cy.contains('Virtualization', { timeout: MINUTE
}).then(...) ) so the sidebar is fully loaded before deciding to navigate or
skip.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui-tests-cy/support/selectors.ts`:
- Line 22: The TypeScript signature for clickNavLink is wrong: either make the
declaration return void or change the implementation to return the Cypress
Chainable so types match; recommended: update the declaration of
clickNavLink(path: [string, string?]) to return void (since the implementation
currently does not return the chain), or if chaining is required, modify the
implementation in clickNavLink to return the final Cypress command chain (ensure
the final expression inside .within(...) is returned) so the declared Chainable
type is satisfied.
- Line 21: The declaration for clickBtn in selectors.ts currently requires
btnTxt: string but the implementation accepts an optional parameter; update the
type signature for clickBtn to make btnTxt optional (btnTxt?: string) so it
matches the implementation (clickBtn) and any other declarations/overloads in
the same file that reference clickBtn to avoid the type mismatch.

In `@ui-tests-cy/tests/nmstate/physical.cy.ts`:
- Around line 21-25: The current selector uses cy.contains('td',
PHYSICAL_NETWORK_TEST_NAME).closest('tbody') which can select the wrong row's
expand button; instead scope to the specific row by using .closest('tr') from
the cell that contains PHYSICAL_NETWORK_TEST_NAME and then locate the expand
button within that row (e.g., the first cell's button) before clicking; update
the selector chain that references PHYSICAL_NETWORK_TEST_NAME to use
.closest('tr') and then .find(...) to ensure you target the row-scoped expand
button.

---

Duplicate comments:
In `@cleanup.sh`:
- Around line 7-12: The cleanup function uses a different default TEST_NS and
omits namespace scope when deleting resources; change the TEST_NS default to
match setup.sh (use TEST_NS="${TEST_NS:-cy-test-ns}") and update the oc delete
invocations inside cleanup (the commands in function cleanup and the second oc
delete line) to include -n "${TEST_NS}" so deletes target the intended
namespace; keep --ignore-not-found and timeouts as-is and preserve the
2>/dev/null || true behavior if desired.

In `@setup.sh`:
- Around line 7-11: The TEST_NS default expansion is wrong and the variable is
unquoted; change the parameter expansion to use the fallback operator and quote
usages: replace occurrences of TEST_NS definition `${TEST_NS:cy-test-ns}` with
`${TEST_NS:-cy-test-ns}` and wrap variable references in the setup function (the
oc get namespace and oc create namespace calls inside the setup() function) with
double quotes around `${TEST_NS}` to prevent globbing/word-splitting.

In `@test-cypress.sh`:
- Around line 3-40: The script currently uses set +e so failures from setup() or
the Cypress run can be ignored; ensure failures are propagated by enabling
strict exit handling and exiting with the Cypress status: enable errexit
(replace set +e with set -e or add set -euo pipefail) and after running Cypress
use the captured test_exit_code to exit the script (add a final exit
"${test_exit_code}" so CI sees failures); also check the return value of setup
and cleanup calls (call setup and immediately exit on non-zero) to ensure setup
failures don't get swallowed.

In `@ui-tests-cy/package.json`:
- Around line 13-23: The devDependencies in package.json currently use caret
ranges (e.g., "`@cypress/webpack-preprocessor`", "cypress",
"cypress-multi-reporters", "dotenv", "esbuild-loader", "mocha-junit-reporter",
"mochawesome", "mochawesome-merge", "mochawesome-report-generator",
"typescript", "webpack"); change each version string to an exact pinned version
(remove the leading '^' so entries become e.g. "cypress": "15.3.0") and then
regenerate the lockfile by running your package manager install command to
persist the pinned versions.

In `@ui-tests-cy/support/commands.ts`:
- Around line 12-24: The deleteResource command is vulnerable because it
interpolates user-controlled strings into a shell command; fix it by validating
and sanitizing the three parameters in the deleteResource function (kind, name,
namespace) before calling cy.exec: enforce strict allowlists/regexes (e.g., only
letters, numbers, '-', '.', and length limits) or map known resource kinds to an
enum, reject anything that doesn't match, and only then build the command;
update the cy.exec calls in deleteResource to use those validated values (or
fail fast) so no unvalidated input is ever interpolated into the shell string.

In `@ui-tests-cy/support/selectors.ts`:
- Around line 29-34: The custom Cypress command 'byTestID' currently calls
cy.get(`[data-test="${selector}"]`, options) but does not return it, which
breaks Cypress chaining; update the command implementation for 'byTestID' (the
Cypress.Commands.add call) to return the result of cy.get(...) so callers can
chain .click(), .should(), etc. normally.

---

Nitpick comments:
In `@ui-tests-cy/tests/nmstate/physical.cy.ts`:
- Around line 4-7: Add an after hook to ensure created PhysicalNetwork resources
are removed after the suite: in the adminOnlyDescribe block that contains the
before hook, add an after(() => { ... }) that calls
cy.deleteResource(K8S_KIND.NNCP, PHYSICAL_NETWORK_TEST_NAME) (matching the
before) so the resource is cleaned up even if tests fail or are interrupted;
place this after hook alongside the existing before to guarantee teardown of
PHYSICAL_NETWORK_TEST_NAME.
- Around line 14-17: The test 'verify Physical network in list' depends on a
prior test creating the network; make it independent by adding setup that
ensures the resource exists before running: add a beforeEach (or move into a
nested describe with setup) that calls the creation helper used by the 'create
Physical network' flow (or an API utility) to create PHYSICAL_NETWORK_TEST_NAME,
then call cy.visitPhysicalNetworks() and assert presence; reference the test
name 'verify Physical network in list', the helper cy.visitPhysicalNetworks(),
and the constant PHYSICAL_NETWORK_TEST_NAME when locating where to add the
setup/creation logic.
- Around line 21-26: Replace the hard-coded cy.wait(2 * SECOND) after clicking
the row action so the test waits for a real DOM change: after clicking the
button found via cy.contains('td',
PHYSICAL_NETWORK_TEST_NAME).closest('tbody').find('td:first-child
button').first().click(), assert the expected expanded state (for example, that
the clicked button or its container has aria-expanded="true" or that a known
expanded-content element/class appears) with an explicit timeout so Cypress will
retry until the row is expanded instead of sleeping.

In `@ui-tests-cy/tests/nmstate/visit-pages.cy.ts`:
- Around line 14-17: The test "should navigate to Node network configuration"
uses cy.clickNavLink(['Networking', 'Node network configuration']) and then
asserts via cy.url(), which is inconsistent with other navigation tests that
assert the presence of an h1; update the test to assert the page heading instead
(e.g., check that the page contains an h1 with the expected text) by replacing
or augmenting the cy.url().should(...) assertion with an h1 existence/text
assertion targeting the Node network configuration page; if the page truly lacks
an h1, add a brief inline comment in this test explaining why URL assertion is
kept and consider adding a more specific DOM selector to assert page load
consistency.
- Around line 19-28: The conditional DOM check in the test "should navigate to
Virtual machine networks (if Virtualization present)" using
cy.get('`#page-sidebar`').then(...) is flaky; either read a Cypress env var like
HAS_VIRTUALIZATION (Cypress.env('HAS_VIRTUALIZATION')) at the top of the test
and branch to call cy.clickNavLink(['Virtualization', 'Virtual machine
networks']) and the subsequent cy.contains('h1', 'Virtual machine networks', {
timeout: MINUTE }) when true, or if you must detect via DOM, replace the
immediate .then() check with a robust wait/assertion (e.g.,
cy.get('`#page-sidebar`').should('exist').and('not.be.empty') before checking
.invoke('text') or use cy.contains('Virtualization', { timeout: MINUTE
}).then(...) ) so the sidebar is fully loaded before deciding to navigate or
skip.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 417d9e56-2535-499c-b6e0-83c0f66d2113

📥 Commits

Reviewing files that changed from the base of the PR and between f93ba4f and f8d6c0a.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • ui-tests-cy/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • .env.example
  • .gitignore
  • cleanup.sh
  • research-flakiness.sh
  • setup.sh
  • test-cypress.sh
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/package.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/support/commands.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/views/vmNetwork.ts
✅ Files skipped from review due to trivial changes (2)
  • ui-tests-cy/views/selector-common.ts
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (17)
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/vmNetwork.ts
  • ui-tests-cy/tests/all.cy.ts
  • research-flakiness.sh
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/support/login.ts

Comment thread ui-tests-cy/support/selectors.ts Outdated
Comment thread ui-tests-cy/support/selectors.ts Outdated
Comment thread ui-tests-cy/tests/nmstate/physical.cy.ts
@lkladnit lkladnit force-pushed the qe-ui branch 3 times, most recently from b602f4f to cca7fc5 Compare June 10, 2026 06:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
setup.sh (1)

11-11: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Quote the second ${TEST_NS} reference for consistency.

The first reference is quoted ("${TEST_NS}"), but the second in oc create namespace ${TEST_NS} is not. While Kubernetes namespace names are restricted and unlikely to contain special characters, quoting ensures consistent defensive behavior and satisfies shellcheck.

🔧 Proposed fix
-  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace ${TEST_NS}
+  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace "${TEST_NS}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@setup.sh` at line 11, The second reference to the TEST_NS variable in the oc
create command is unquoted; update the oc create namespace ${TEST_NS} invocation
to use the same quoted form as the oc get namespace "${TEST_NS}" (i.e., wrap the
second ${TEST_NS} in double quotes) so both uses are consistent and safe against
special characters.

Source: Linters/SAST tools

cleanup.sh (1)

11-12: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add explicit namespace targeting to all oc delete commands.

Neither delete command specifies a namespace with -n "${TEST_NS}", so they will target the current kubectl context's default namespace rather than the test namespace. Resources created in TEST_NS by the test suite will not be cleaned up.

🔧 Proposed fix
-  oc delete nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network --ignore-not-found --wait=true --timeout=180s
+  oc delete nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network -n "${TEST_NS}" --ignore-not-found --wait=true --timeout=180s
-  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled --wait=true --timeout=60s 2>/dev/null || true
+  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled -n "${TEST_NS}" --wait=true --timeout=60s 2>/dev/null || true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` around lines 11 - 12, The oc delete commands in cleanup.sh (the
lines deleting nncp resources and virtualmachinenetworks) lack explicit
namespace targeting so they operate in the current kubectl context; update both
commands to include -n "${TEST_NS}" (e.g., oc delete nncp ... -n "${TEST_NS}"
--ignore-not-found --wait=... and oc delete --ignore-not-found=true
virtualmachinenetwork ... -n "${TEST_NS}" --wait=...) so the test namespace is
explicitly used when deleting test-form-nncp, test-vm-nncp, example,
test-nncp-physical-network, test-vm-physical-network, test-vmn-project and
test-vmn-labeled.
ui-tests-cy/support/commands.ts (1)

12-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unvalidated shell interpolation in deleteResource is still command-injection prone.

Line 14 and Line 21 interpolate kind, name, and namespace directly into cy.exec(...). This remains exploitable if any caller passes unexpected shell metacharacters.

🛡️ Minimal hardening diff (allow-list validation before exec)
 Cypress.Commands.add('deleteResource', (kind: string, name: string, namespace?: string) => {
+  const safeKind = /^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$/i;
+  const safeNameOrNamespace = /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/i;
+
+  if (!safeKind.test(kind) || !safeNameOrNamespace.test(name)) {
+    throw new Error('Invalid kind or name passed to deleteResource');
+  }
+  if (namespace && !safeNameOrNamespace.test(namespace)) {
+    throw new Error('Invalid namespace passed to deleteResource');
+  }
+
   if (!namespace) {
     cy.exec(`oc delete --ignore-not-found=true ${kind} ${name} --wait=true --timeout=300s`, {
       failOnNonZeroExit: false,
       timeout: 5 * MINUTE,
     });
     return;
   }

As per coding guidelines, "Command: no shell=True, os.system, or backtick exec with user input" and "Validate at trust boundaries with allow-lists, not deny-lists."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/support/commands.ts` around lines 12 - 23, The deleteResource
command is vulnerable to shell injection by interpolating unvalidated kind,
name, and namespace into cy.exec; update the deleteResource function to validate
inputs before building the command: enforce kind against an allow-list (e.g.,
allowedKinds array containing known resource types) and validate name and
namespace with a strict regex matching Kubernetes DNS-1123 label rules (only
lower-case alphanumerics and hyphens, no leading/trailing hyphen), fail the test
or throw if validation fails, then construct the oc delete command using the
validated/sanitized strings (kind, name, namespace) for the cy.exec calls;
reference deleteResource and the variables kind, name, namespace when making
these changes.

Sources: Coding guidelines, Linters/SAST tools

🧹 Nitpick comments (2)
test-cypress.sh (1)

8-14: ⚡ Quick win

Add a default case to handle invalid flags.

The getopts case statement lacks a *) default branch, so unrecognized flags are silently ignored. Adding a default case improves user experience by flagging typos or incorrect usage.

♻️ Proposed improvement
 while getopts g:s: flag
 do
   case "${flag}" in
     g) gui=${OPTARG};;
     s) spec=${OPTARG};;
+    *) echo "Invalid flag: -${OPTARG}" >&2; exit 1;;
   esac
 done
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` around lines 8 - 14, The case handling for getopts currently
only matches g and s and silently ignores unknown flags; update the case
statement that processes the getopts "flag" to add a default branch (*) that
prints a short usage/error message (mentioning expected flags like -g and -s),
optionally referencing OPTARG or "$flag" to show the invalid option, and exit
with a non-zero status so invalid flags (when parsing gui and spec) are surfaced
to the user.

Source: Linters/SAST tools

ui-tests-cy/tests/nmstate/nncp.cy.ts (1)

22-42: ⚡ Quick win

Reduce cross-test state coupling in this suite.

nodes summary, page controls, edit, and delete depend on artifacts created by earlier it cases. This makes isolated reruns brittle and increases flake risk; prefer per-test setup (beforeEach) or a single end-to-end scenario for dependent steps.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts` around lines 22 - 42, Tests in this
suite are coupling state across it blocks causing brittle runs; either create
the NNCP fixture in a beforeEach or collapse dependent steps into one end-to-end
it. Add a beforeEach that ensures NNCP_TEST_NAME exists (call whatever helper
creates the NNCP) and cleans up or resets filters before each test, then keep
the existing assertions that reference NNCP_TEST_NAME, itemFilter, editNNCP,
deleteNNCP and cy.visitNNCP; alternatively wrap the sequence of assertions and
actions (nodes summary, page controls, editNNCP + cy.visitNNCP, deleteNNCP) into
a single it so the setup/teardown are local to that scenario. Ensure the helpers
used for creation/cleanup are idempotent so individual tests can run in
isolation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cleanup.sh`:
- Line 7: Uncomment and restore the default TEST_NS assignment so the cleanup
function has a fallback namespace: remove the leading comment from the line that
sets TEST_NS using parameter expansion (TEST_NS="${TEST_NS:-cy-test-ns}") in
cleanup.sh, ensuring any references to TEST_NS inside the cleanup function (and
related logic) will use the provided env value or fall back to "cy-test-ns" when
.env does not supply it.

In `@test-cypress.sh`:
- Line 36: The conditional uses an unquoted variable `${test_exit_code}` which
can break under certain shell settings and triggers shellcheck; update the if
test that reads `if [ ${test_exit_code} -eq 0 ]; then` to quote the variable
reference (e.g., `if [ "${test_exit_code}" -eq 0 ]; then`) so `test_exit_code`
is safely handled; look for the `if` statement controlling the test exit path
and the `test_exit_code` variable in the script to make this change.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts`:
- Line 14: The test currently uses a global selector
cy.contains(NNCP_TEST_NAME).should('exist') which can match unrelated text;
change it to scope the lookup to the NNCP table row by using a row-scoped
contains call (e.g., cy.contains('tr', NNCP_TEST_NAME).should('exist')) so it
matches the NNCP table row consistently with the other row-scoped checks that
reference NNCP_TEST_NAME at lines below; update the assertion where
NNCP_TEST_NAME is used to use the 'tr' scoped contains call.

---

Duplicate comments:
In `@cleanup.sh`:
- Around line 11-12: The oc delete commands in cleanup.sh (the lines deleting
nncp resources and virtualmachinenetworks) lack explicit namespace targeting so
they operate in the current kubectl context; update both commands to include -n
"${TEST_NS}" (e.g., oc delete nncp ... -n "${TEST_NS}" --ignore-not-found
--wait=... and oc delete --ignore-not-found=true virtualmachinenetwork ... -n
"${TEST_NS}" --wait=...) so the test namespace is explicitly used when deleting
test-form-nncp, test-vm-nncp, example, test-nncp-physical-network,
test-vm-physical-network, test-vmn-project and test-vmn-labeled.

In `@setup.sh`:
- Line 11: The second reference to the TEST_NS variable in the oc create command
is unquoted; update the oc create namespace ${TEST_NS} invocation to use the
same quoted form as the oc get namespace "${TEST_NS}" (i.e., wrap the second
${TEST_NS} in double quotes) so both uses are consistent and safe against
special characters.

In `@ui-tests-cy/support/commands.ts`:
- Around line 12-23: The deleteResource command is vulnerable to shell injection
by interpolating unvalidated kind, name, and namespace into cy.exec; update the
deleteResource function to validate inputs before building the command: enforce
kind against an allow-list (e.g., allowedKinds array containing known resource
types) and validate name and namespace with a strict regex matching Kubernetes
DNS-1123 label rules (only lower-case alphanumerics and hyphens, no
leading/trailing hyphen), fail the test or throw if validation fails, then
construct the oc delete command using the validated/sanitized strings (kind,
name, namespace) for the cy.exec calls; reference deleteResource and the
variables kind, name, namespace when making these changes.

---

Nitpick comments:
In `@test-cypress.sh`:
- Around line 8-14: The case handling for getopts currently only matches g and s
and silently ignores unknown flags; update the case statement that processes the
getopts "flag" to add a default branch (*) that prints a short usage/error
message (mentioning expected flags like -g and -s), optionally referencing
OPTARG or "$flag" to show the invalid option, and exit with a non-zero status so
invalid flags (when parsing gui and spec) are surfaced to the user.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts`:
- Around line 22-42: Tests in this suite are coupling state across it blocks
causing brittle runs; either create the NNCP fixture in a beforeEach or collapse
dependent steps into one end-to-end it. Add a beforeEach that ensures
NNCP_TEST_NAME exists (call whatever helper creates the NNCP) and cleans up or
resets filters before each test, then keep the existing assertions that
reference NNCP_TEST_NAME, itemFilter, editNNCP, deleteNNCP and cy.visitNNCP;
alternatively wrap the sequence of assertions and actions (nodes summary, page
controls, editNNCP + cy.visitNNCP, deleteNNCP) into a single it so the
setup/teardown are local to that scenario. Ensure the helpers used for
creation/cleanup are idempotent so individual tests can run in isolation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5d910e36-26a9-4beb-af1a-553db738f1c1

📥 Commits

Reviewing files that changed from the base of the PR and between f8d6c0a and a3b61bf.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • ui-tests-cy/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • .env.example
  • .gitignore
  • cleanup.sh
  • research-flakiness.sh
  • setup.sh
  • test-cypress.sh
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/package.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/support/commands.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/views/vmNetwork.ts
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (21)
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/package.json
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • research-flakiness.sh
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/views/vmNetwork.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/plugins/index.ts

Comment thread cleanup.sh
# Sources .env for namespace names

source .env 2>/dev/null || true
#TEST_NS="${TEST_NS:-cy-test-ns}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Uncomment and use the TEST_NS default.

Line 7 is commented out, so TEST_NS has no fallback when .env doesn't provide it. Without this line, the cleanup function cannot reliably determine which namespace to target.

🔧 Proposed fix
-#TEST_NS="${TEST_NS:-cy-test-ns}"
+TEST_NS="${TEST_NS:-cy-test-ns}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#TEST_NS="${TEST_NS:-cy-test-ns}"
TEST_NS="${TEST_NS:-cy-test-ns}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` at line 7, Uncomment and restore the default TEST_NS assignment
so the cleanup function has a fallback namespace: remove the leading comment
from the line that sets TEST_NS using parameter expansion
(TEST_NS="${TEST_NS:-cy-test-ns}") in cleanup.sh, ensuring any references to
TEST_NS inside the cleanup function (and related logic) will use the provided
env value or fall back to "cy-test-ns" when .env does not supply it.

Comment thread test-cypress.sh Outdated
Comment thread ui-tests-cy/tests/nmstate/nncp.cy.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
cleanup.sh (2)

7-7: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Uncomment the TEST_NS default assignment.

Without this line, TEST_NS has no fallback when .env is missing or doesn't define it, causing the cleanup() function to operate in an undefined or incorrect namespace. This matches a previous review comment that remains unaddressed.

🔧 Proposed fix
-#TEST_NS="${TEST_NS:-cy-test-ns}"
+TEST_NS="${TEST_NS:-cy-test-ns}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` at line 7, Uncomment the default TEST_NS assignment so the
TEST_NS environment variable has a fallback; restore the line setting
TEST_NS="${TEST_NS:-cy-test-ns}" (or equivalent) so cleanup() uses a defined
namespace when .env is missing or doesn't define TEST_NS; ensure no other logic
overrides this default and that cleanup() references TEST_NS consistently.

11-12: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add explicit namespace scoping to all oc delete commands.

Both delete commands lack -n "${TEST_NS}" flags, so they target the current kubectl context namespace instead of the intended test namespace. This can leave test resources in ${TEST_NS} or accidentally delete resources in production namespaces.

🔧 Proposed fix
-  oc delete nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network --ignore-not-found --wait=true --timeout=180s
-  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled --wait=true --timeout=60s 2>/dev/null || true
+  oc delete nncp test-form-nncp test-vm-nncp example test-nncp-physical-network test-vm-physical-network -n "${TEST_NS}" --ignore-not-found --wait=true --timeout=180s
+  oc delete --ignore-not-found=true virtualmachinenetwork test-vmn-project test-vmn-labeled -n "${TEST_NS}" --wait=true --timeout=60s 2>/dev/null || true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` around lines 11 - 12, The oc delete commands (the lines invoking
oc delete nncp ... and oc delete --ignore-not-found=true virtualmachinenetwork
...) are missing explicit namespace scoping; update both commands to include -n
"${TEST_NS}" so they operate against the intended TEST_NS instead of the current
kubectl context namespace, ensuring each oc delete invocation (for resources
like nncp, virtualmachinenetwork, test-form-nncp, test-vm-nncp, etc.) is run
with -n "${TEST_NS}" and preserving the existing flags (--ignore-not-found,
--wait, --timeout, and redirection/|| true).
🧹 Nitpick comments (4)
setup.sh (1)

11-11: ⚡ Quick win

Quote the variable in oc create namespace.

The second ${TEST_NS} reference should be quoted to prevent globbing and word splitting, satisfying shellcheck SC2086 and matching the quoting used in the oc get command.

🔧 Proposed fix
-  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace ${TEST_NS}
+  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace "${TEST_NS}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@setup.sh` at line 11, The oc create command uses an unquoted variable; update
the second reference so both commands use the same quoted variable form by
changing oc create namespace ${TEST_NS} to use the quoted parameter for TEST_NS
(i.e., quote the ${TEST_NS} in the oc create namespace invocation) so the oc get
and oc create lines consistently use "${TEST_NS}".

Source: Linters/SAST tools

.env.example (1)

3-4: 💤 Low value

Consider reordering keys alphabetically.

The static analysis tool suggests placing HIDE_XHR before TEST_NS for consistency. While this doesn't affect functionality, alphabetical ordering can improve maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.env.example around lines 3 - 4, Reorder the environment variable keys in
.env.example so they are alphabetically sorted: place HIDE_XHR before TEST_NS;
update the file to list HIDE_XHR then TEST_NS to satisfy the static analysis
ordering preference.

Source: Linters/SAST tools

test-cypress.sh (2)

10-13: 💤 Low value

Add a default case to the getopts switch.

Shellcheck SC2220 suggests adding a *) case to handle invalid flags. While getopts itself handles unknown flags, an explicit default case improves error messaging and defensive coding.

🔧 Proposed fix
   case "${flag}" in
     g) gui=${OPTARG};;
     s) spec=${OPTARG};;
+    *) echo "Invalid option: -${OPTARG}" >&2; exit 1;;
   esac
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` around lines 10 - 13, The getopts case handling for variable
"flag" (case "${flag}" in with branches g) gui and s) spec) lacks a default
branch; add a *) default case to the case statement (alongside g) and s)) to
catch invalid flags, print a clear error/usage message (e.g., "Invalid option:
-${flag}") to stderr, and exit with a non-zero status so the script fails fast
when unknown options are provided; ensure this integrates with any existing
usage/help output if present.

Source: Linters/SAST tools


36-36: ⚡ Quick win

Quote test_exit_code in the conditional.

The variable should be quoted to satisfy shellcheck SC2086 and follow shell best practices. A previous review comment flagged this, but the code remains unquoted.

🔧 Proposed fix
-  if [ ${test_exit_code} -eq 0 ]; then
+  if [ "${test_exit_code}" -eq 0 ]; then
     cleanup
   fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` at line 36, The conditional uses an unquoted variable
expansion and should quote the test_exit_code variable to avoid word-splitting
and satisfy shellcheck SC2086; update the if test in test-cypress.sh to
reference test_exit_code as a quoted expansion (replace the unquoted
${test_exit_code} usage in the if [ ... -eq 0 ]; then conditional with a quoted
expansion) so the comparison is safe when the variable is empty or contains
spaces.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.env.example:
- Around line 1-4: Remove surrounding quotes from environment variable values in
.env.example so dotenv parsers don't include literal quotes; specifically change
BRIDGE_BASE_ADDRESS to an unquoted URL and BRIDGE_KUBEADMIN_PASSWORD to an empty
value (no quotes), and likewise remove quotes from TEST_NS and HIDE_XHR. This
will ensure config.baseUrl (used in ui-tests-cy/plugins/index.ts via
config.baseUrl) receives a proper URL string and empty-password checks work as
intended.

In `@setup.sh`:
- Line 7: The TEST_NS default in setup.sh ("TEST_NS") is mismatched with the
test default in ui-tests-cy/utils/const/base.ts (the default namespace constant
set to "nmstate-test-ns"); pick one consistent default and update the other so
both match—either change TEST_NS in setup.sh to "nmstate-test-ns" or change the
namespace default in base.ts to "cy-test-ns" so tests and setup use the same
namespace value.

In `@ui-tests-cy/support/nav.ts`:
- Line 17: The test contains a typo in the assertion: update the cy.contains
call in ui-tests-cy/support/nav.ts that currently looks for
'NodeNetworkConfigurationPolic' to the correct resource name
'NodeNetworkConfigurationPolicy' so the h1 lookup matches the expected title
(the statement to change is the cy.contains('h1',
'NodeNetworkConfigurationPolic', { timeout: MINUTE }).should('exist')
invocation).

In `@ui-tests-cy/support/selectors.ts`:
- Line 21: The TypeScript declaration for clickBtn is wrong: change its return
type from void to the Cypress Chainable type to match the implementation that
returns cy.contains(...).click(); update the declaration signature
clickBtn(btnTxt?: string): void to return Cypress.Chainable or
Chainable<JQuery<HTMLElement>> (consistent with other selector methods) so
callers can continue chaining; ensure the exported interface/type that contains
clickBtn reflects the new return type as well.
- Line 23: The TypeScript declaration for clickNextBtn is incorrect: it declares
clickNextBtn(): void but the implementation returns a Cypress Chainable; update
the function signature for clickNextBtn to return the appropriate Cypress type
(e.g., Cypress.Chainable<JQuery<HTMLElement>> or Cypress.Chainable<any>) to
match the implementation (or alternatively change the implementation to not
return the cy call), ensuring the declaration and the implementation for
clickNextBtn are consistent.

---

Duplicate comments:
In `@cleanup.sh`:
- Line 7: Uncomment the default TEST_NS assignment so the TEST_NS environment
variable has a fallback; restore the line setting
TEST_NS="${TEST_NS:-cy-test-ns}" (or equivalent) so cleanup() uses a defined
namespace when .env is missing or doesn't define TEST_NS; ensure no other logic
overrides this default and that cleanup() references TEST_NS consistently.
- Around line 11-12: The oc delete commands (the lines invoking oc delete nncp
... and oc delete --ignore-not-found=true virtualmachinenetwork ...) are missing
explicit namespace scoping; update both commands to include -n "${TEST_NS}" so
they operate against the intended TEST_NS instead of the current kubectl context
namespace, ensuring each oc delete invocation (for resources like nncp,
virtualmachinenetwork, test-form-nncp, test-vm-nncp, etc.) is run with -n
"${TEST_NS}" and preserving the existing flags (--ignore-not-found, --wait,
--timeout, and redirection/|| true).

---

Nitpick comments:
In @.env.example:
- Around line 3-4: Reorder the environment variable keys in .env.example so they
are alphabetically sorted: place HIDE_XHR before TEST_NS; update the file to
list HIDE_XHR then TEST_NS to satisfy the static analysis ordering preference.

In `@setup.sh`:
- Line 11: The oc create command uses an unquoted variable; update the second
reference so both commands use the same quoted variable form by changing oc
create namespace ${TEST_NS} to use the quoted parameter for TEST_NS (i.e., quote
the ${TEST_NS} in the oc create namespace invocation) so the oc get and oc
create lines consistently use "${TEST_NS}".

In `@test-cypress.sh`:
- Around line 10-13: The getopts case handling for variable "flag" (case
"${flag}" in with branches g) gui and s) spec) lacks a default branch; add a *)
default case to the case statement (alongside g) and s)) to catch invalid flags,
print a clear error/usage message (e.g., "Invalid option: -${flag}") to stderr,
and exit with a non-zero status so the script fails fast when unknown options
are provided; ensure this integrates with any existing usage/help output if
present.
- Line 36: The conditional uses an unquoted variable expansion and should quote
the test_exit_code variable to avoid word-splitting and satisfy shellcheck
SC2086; update the if test in test-cypress.sh to reference test_exit_code as a
quoted expansion (replace the unquoted ${test_exit_code} usage in the if [ ...
-eq 0 ]; then conditional with a quoted expansion) so the comparison is safe
when the variable is empty or contains spaces.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7bc3ecff-8478-4a24-847f-51ed10b901a2

📥 Commits

Reviewing files that changed from the base of the PR and between a3b61bf and ca14d3a.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • ui-tests-cy/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • .env.example
  • .gitignore
  • cleanup.sh
  • research-flakiness.sh
  • setup.sh
  • test-cypress.sh
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/package.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/support/commands.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/views/vmNetwork.ts
✅ Files skipped from review due to trivial changes (4)
  • ui-tests-cy/tsconfig.json
  • .gitignore
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/tests/all.cy.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/package.json
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/plugins/index.ts
  • research-flakiness.sh
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/vmNetwork.ts

Comment thread .env.example
Comment thread setup.sh
Comment thread ui-tests-cy/support/nav.ts Outdated
Comment thread ui-tests-cy/support/selectors.ts
Comment thread ui-tests-cy/support/selectors.ts Outdated
@lkladnit lkladnit force-pushed the qe-ui branch 3 times, most recently from 02f0305 to 6d5ac38 Compare June 11, 2026 08:20
@lkladnit

Copy link
Copy Markdown
Author

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (8)
ui-tests-cy/tests/nmstate/nns.cy.ts (2)

4-16: 💤 Low value

Consider more idiomatic Cypress selectors for button text matching.

Lines 12-14 use .filter(':contains("...")), which is jQuery syntax. Cypress provides more idiomatic alternatives:

  • Use cy.contains('td button', 'ethernet') to find buttons with specific text.
  • If available, use data-test attributes for more stable selectors.
♻️ Alternative approach
  cy.contains('table tbody tr', 'worker').first().within(() => {
    cy.get('td button').should('have.length.at.least', 3);
-   cy.get('td button').filter(':contains("ethernet")').should('exist');
-   cy.get('td button').filter(':contains("linux-bridge")').should('exist');
-   cy.get('td button').filter(':contains("ovs-bridge")').should('exist');
+   cy.contains('td button', 'ethernet').should('exist');
+   cy.contains('td button', 'linux-bridge').should('exist');
+   cy.contains('td button', 'ovs-bridge').should('exist');
  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nns.cy.ts` around lines 4 - 16, Replace the
jQuery-style .filter(':contains("...")') selectors in the "verify bridge on
NodeNetworkState" test with Cypress-native text selectors: use cy.contains('td
button', 'ethernet'), cy.contains('td button', 'linux-bridge'), and
cy.contains('td button', 'ovs-bridge') inside the same within() block (or, when
available, switch to stable data-test attributes on the buttons and use
cy.get('[data-test="..."]') for each button) so the test uses idiomatic Cypress
selectors and avoids jQuery-specific filtering.

18-31: 💤 Low value

Consider more stable selectors for expanded state.

Lines 24-25 and 29-30 use '[class*="expanded-true"], tbody.pf-m-expanded', which relies on PatternFly implementation details (class names and modifiers). These selectors are brittle and could break with PatternFly updates.

If possible, use data-test attributes or ARIA states ([aria-expanded="true"]) for more stable selectors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nns.cy.ts` around lines 18 - 31, The test "verify
expand all and collapse all" uses brittle selectors ('[class*="expanded-true"],
tbody.pf-m-expanded') to detect expanded rows; update the checks in that it
block to use stable attributes instead — prefer an explicit data-test attribute
like data-test="row-expanded" on expandable rows or use ARIA state selectors
such as [aria-expanded="true"] for the expand assertion and
[aria-expanded="false"] or absence for the collapse assertion; change the two
cy.get calls that currently reference the class-based selector to the chosen
stable selector so the test queries the semantic/data-test/ARIA state rather
than PatternFly class names.
ui-tests-cy/views/vmNetwork.ts (4)

63-63: ⚡ Quick win

Remove { force: true } from checkbox interaction.

Line 63 uses { force: true } to click the project checkbox, bypassing Cypress's actionability checks. This can hide real UI issues such as the checkbox being covered by another element or not actually clickable.

🔒 Recommended fix
-    cy.contains('li', projectName).find('input[type="checkbox"]').click({ force: true });
+    cy.contains('li', projectName).find('input[type="checkbox"]').should('be.visible').click();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` at line 63, Remove the bypass of Cypress
actionability checks on the project checkbox: replace the call to
cy.contains('li', projectName).find('input[type="checkbox"]').click({ force:
true }) with an actionable interaction such as cy.contains('li',
projectName).find('input[type="checkbox"]').should('be.visible').check() (or
.click() after the should('be.visible') assertion) so the test fails if the
checkbox is not interactable instead of forcing the click.

17-31: ⚡ Quick win

Remove { force: true } to respect Cypress actionability checks.

Line 26 uses { force: true } to click the "Create physical network" button, bypassing Cypress's built-in checks for visibility, enabled state, and coverage by other elements. This can hide real UI issues.

🔒 Recommended fix
-    cy.contains('button', 'Create physical network').click({ force: true });
+    cy.contains('button', 'Create physical network').should('be.visible').and('be.enabled').click();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 17 - 31, The click using {
force: true } in attemptToCreateVMNetwork should be replaced with an actionable
click that respects Cypress checks: locate the "Create physical network" button
via cy.contains('button', 'Create physical network') and ensure it's visible and
enabled (e.g., .should('be.visible').and('not.be.disabled')) and/or scroll into
view before calling .click(), so the flow in navigateToVMN →
cy.get(itemCreateBtn) → fillPhysicalNetworkWizard remains the same but without
bypassing actionability; adjust waits/timeouts around fillPhysicalNetworkWizard
and the subsequent navigateToVMN call if needed to make the button reliably
actionable.

41-80: ⚡ Quick win

Replace hardcoded waits with explicit assertions.

Lines 41, 51, 62, and 80 use cy.wait() with fixed time delays. This is a Cypress anti-pattern that makes tests slower and unreliable.

  • Line 41: Remove the 2-second wait; the input visibility check on line 43 is sufficient.
  • Lines 51, 62: Instead of waiting 1 second after typing, wait for the dropdown/combobox options to be visible.
  • Line 80: Instead of waiting 5 seconds after clicking "Create," wait for navigation or a success indicator.
⚡ Recommended fix
  cy.get(itemCreateBtn).click();
  cy.contains('h1', 'Create virtual machine network', { timeout: MINUTE }).should('exist');
- cy.wait(2 * SECOND);
  
  cy.get(vmnNameInput, { timeout: MINUTE })
  cy.get('input[role="combobox"]').first().click();
  cy.get('input[role="combobox"]').first().clear().type(physicalNetworkName);
- cy.wait(SECOND);
+ cy.get('button[role="option"]').should('be.visible');
  cy.get('button[role="option"]').contains(physicalNetworkName).click();
  cy.get('input[role="combobox"][aria-label="Type to filter"]').first().click();
  cy.get('input[role="combobox"][aria-label="Type to filter"]').first().clear().type(projectName);
- cy.wait(SECOND);
+ cy.contains('li', projectName).should('be.visible');
  cy.contains('li', projectName).find('input[type="checkbox"]').click({ force: true });
  cy.contains(submitBtn, 'Create').click();
- cy.wait(5 * SECOND);
+ // Wait for success/error state or navigation
  cy.get('body').then(($body) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 41 - 80, Remove hardcoded
cy.waits and replace them with explicit assertions: drop the initial cy.wait(2 *
SECOND) before interacting with vmnNameInput because the existing
cy.get(vmnNameInput).should('be.visible') is sufficient; after typing into the
physical network combobox (the first 'input[role="combobox"]') replace
cy.wait(SECOND) with an assertion that the expected option/button[role="option"]
containing physicalNetworkName is visible (e.g.,
cy.get('button[role="option"]').contains(physicalNetworkName).should('be.visible')
before clicking); similarly after typing into the project combobox
(input[role="combobox"][aria-label="Type to filter"]) assert that the matching
li or checkbox option for projectName is visible before clicking it; and after
clicking cy.contains(submitBtn, 'Create') remove cy.wait(5 * SECOND) and instead
wait for the post-submit success indicator or navigation (e.g., assert
visibility of a toast, a "1 project selected" update, or a unique page element)
to confirm completion.

93-97: ⚡ Quick win

Replace hardcoded waits in delete flow.

Lines 93, 95, and 97 use fixed time delays. Consider replacing these with explicit assertions:

  • Line 93: Wait for the modal to be visible instead of a fixed 2-second delay.
  • Line 95: Wait for the checkbox to be checked instead of a fixed 1-second delay.
  • Line 97: Wait for the modal to close or the row to disappear instead of a fixed 3-second delay.
⚡ Recommended fix
  cy.contains('button', 'Delete').click();
- cy.wait(2 * SECOND);
+ cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible');
  cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').click({ force: true });
- cy.wait(SECOND);
+ cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.checked');
  cy.get('button').contains('Delete').last().click({ force: true });
- cy.wait(3 * SECOND);
+ cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('not.exist');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 93 - 97, The three hardcoded
cy.waits should be replaced with explicit assertions: wait for the delete modal
to appear (use an assertion that the modal is visible before interacting instead
of cy.wait(2 * SECOND)), replace the post-click wait for
'`#delete-vm-network-modal-acknowledge-checkbox`' with an assertion that the
checkbox is checked (e.g., assert checked after .click({ force: true })), and
replace the final cy.wait(3 * SECOND) with an assertion that the modal has
closed or the deleted VM row is gone (e.g., assert the modal is not visible or
the row representing the VM no longer exists after clicking the 'Delete'
button). Use the existing selectors
'`#delete-vm-network-modal-acknowledge-checkbox`' and the button containing
'Delete' to locate elements and rely on visibility/checked/existence assertions
instead of fixed delays.
ui-tests-cy/views/physicalNetwork.ts (1)

11-44: ⚡ Quick win

Replace hardcoded waits with explicit assertions.

Lines 19 and 43 use cy.wait() with fixed time delays. This is a Cypress anti-pattern that makes tests slower and still prone to timing issues.

  • Line 19: Instead of waiting 2 seconds for the "auto-generated name to settle," assert that the input has a non-empty value before clearing: cy.get(physicalNetworkNameInput).should('have.value').and('not.be.empty').
  • Line 43: Instead of waiting 3 seconds after clicking "Create network," wait for a success indicator such as navigation to the policy details page or a success alert.
⚡ Recommended fix
  // Step 1: Network identity
  cy.get(physicalNetworkNameInput, { timeout: MINUTE }).should('be.visible');
- // Wait for form auto-generated name to settle before clearing
- cy.wait(2 * SECOND);
+ cy.get(physicalNetworkNameInput).should('have.value').and('not.be.empty');
  cy.get(physicalNetworkNameInput).clear();
  // Step 5: Review and Create
  cy.contains('button', 'Create network', { timeout: MINUTE }).should('be.visible');
  cy.contains('button', 'Create network').click();
- cy.wait(3 * SECOND);
+ // Wait for navigation or success indicator instead of fixed delay
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/physicalNetwork.ts` around lines 11 - 44, In
fillPhysicalNetworkWizard replace the two hard waits with explicit assertions:
for the initial wait, before clearing physicalNetworkNameInput assert the input
has a non-empty value (e.g.,
cy.get(physicalNetworkNameInput).should('have.value').and('not.be.empty')) then
clear/type as before; for the post-create wait, after clicking the Create
network button remove cy.wait(3 * SECOND) and instead wait for a deterministic
success indicator such as a success toast or navigation to the new
network/policy details (e.g., assert a success alert is visible or the details
header/route for the created network appears) so the flow uses
physicalNetworkNameInput, submitBtn and the success selector instead of fixed
time delays.
ui-tests-cy/tests/nmstate/vmn.cy.ts (1)

28-32: 💤 Low value

Consider extracting hardcoded label to a constant.

Line 29 contains a hardcoded label string 'kubernetes.io/metadata.name=default'. Consider extracting this to a named constant (e.g., VM_NETWORK_LABEL) at the top of the file or in the view helper for better maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/vmn.cy.ts` around lines 28 - 32, Extract the
hardcoded label string 'kubernetes.io/metadata.name=default' into a descriptive
constant (e.g., VM_NETWORK_LABEL) and use that constant in the createVMNetwork
call; update the top of the test file (or the shared view helper) to export the
new VM_NETWORK_LABEL constant and replace occurrences in this file where
createVMNetwork is invoked (reference symbols: createVMNetwork,
VM_NETWORK_LABELED_NAME, REQ_PHYSICAL_NETWORK_NAME) so the label is maintained
in one place for reuse and easier modification.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test-cypress.sh`:
- Around line 3-7: The script currently enables xtrace with "set -x" before
sourcing "./cleanup.sh" and "./setup.sh", which may echo secrets; change flow to
disable tracing around those sources: call "set +x" immediately before "source
./cleanup.sh" and "source ./setup.sh", then restore tracing with "set -x"
afterwards (or move the initial "set -x" to after the two source lines). Ensure
you still preserve "set +e" behavior and reference the existing tokens "set -x",
"set +e", "source ./cleanup.sh", and "source ./setup.sh" when making the change.

---

Nitpick comments:
In `@ui-tests-cy/tests/nmstate/nns.cy.ts`:
- Around line 4-16: Replace the jQuery-style .filter(':contains("...")')
selectors in the "verify bridge on NodeNetworkState" test with Cypress-native
text selectors: use cy.contains('td button', 'ethernet'), cy.contains('td
button', 'linux-bridge'), and cy.contains('td button', 'ovs-bridge') inside the
same within() block (or, when available, switch to stable data-test attributes
on the buttons and use cy.get('[data-test="..."]') for each button) so the test
uses idiomatic Cypress selectors and avoids jQuery-specific filtering.
- Around line 18-31: The test "verify expand all and collapse all" uses brittle
selectors ('[class*="expanded-true"], tbody.pf-m-expanded') to detect expanded
rows; update the checks in that it block to use stable attributes instead —
prefer an explicit data-test attribute like data-test="row-expanded" on
expandable rows or use ARIA state selectors such as [aria-expanded="true"] for
the expand assertion and [aria-expanded="false"] or absence for the collapse
assertion; change the two cy.get calls that currently reference the class-based
selector to the chosen stable selector so the test queries the
semantic/data-test/ARIA state rather than PatternFly class names.

In `@ui-tests-cy/tests/nmstate/vmn.cy.ts`:
- Around line 28-32: Extract the hardcoded label string
'kubernetes.io/metadata.name=default' into a descriptive constant (e.g.,
VM_NETWORK_LABEL) and use that constant in the createVMNetwork call; update the
top of the test file (or the shared view helper) to export the new
VM_NETWORK_LABEL constant and replace occurrences in this file where
createVMNetwork is invoked (reference symbols: createVMNetwork,
VM_NETWORK_LABELED_NAME, REQ_PHYSICAL_NETWORK_NAME) so the label is maintained
in one place for reuse and easier modification.

In `@ui-tests-cy/views/physicalNetwork.ts`:
- Around line 11-44: In fillPhysicalNetworkWizard replace the two hard waits
with explicit assertions: for the initial wait, before clearing
physicalNetworkNameInput assert the input has a non-empty value (e.g.,
cy.get(physicalNetworkNameInput).should('have.value').and('not.be.empty')) then
clear/type as before; for the post-create wait, after clicking the Create
network button remove cy.wait(3 * SECOND) and instead wait for a deterministic
success indicator such as a success toast or navigation to the new
network/policy details (e.g., assert a success alert is visible or the details
header/route for the created network appears) so the flow uses
physicalNetworkNameInput, submitBtn and the success selector instead of fixed
time delays.

In `@ui-tests-cy/views/vmNetwork.ts`:
- Line 63: Remove the bypass of Cypress actionability checks on the project
checkbox: replace the call to cy.contains('li',
projectName).find('input[type="checkbox"]').click({ force: true }) with an
actionable interaction such as cy.contains('li',
projectName).find('input[type="checkbox"]').should('be.visible').check() (or
.click() after the should('be.visible') assertion) so the test fails if the
checkbox is not interactable instead of forcing the click.
- Around line 17-31: The click using { force: true } in attemptToCreateVMNetwork
should be replaced with an actionable click that respects Cypress checks: locate
the "Create physical network" button via cy.contains('button', 'Create physical
network') and ensure it's visible and enabled (e.g.,
.should('be.visible').and('not.be.disabled')) and/or scroll into view before
calling .click(), so the flow in navigateToVMN → cy.get(itemCreateBtn) →
fillPhysicalNetworkWizard remains the same but without bypassing actionability;
adjust waits/timeouts around fillPhysicalNetworkWizard and the subsequent
navigateToVMN call if needed to make the button reliably actionable.
- Around line 41-80: Remove hardcoded cy.waits and replace them with explicit
assertions: drop the initial cy.wait(2 * SECOND) before interacting with
vmnNameInput because the existing cy.get(vmnNameInput).should('be.visible') is
sufficient; after typing into the physical network combobox (the first
'input[role="combobox"]') replace cy.wait(SECOND) with an assertion that the
expected option/button[role="option"] containing physicalNetworkName is visible
(e.g.,
cy.get('button[role="option"]').contains(physicalNetworkName).should('be.visible')
before clicking); similarly after typing into the project combobox
(input[role="combobox"][aria-label="Type to filter"]) assert that the matching
li or checkbox option for projectName is visible before clicking it; and after
clicking cy.contains(submitBtn, 'Create') remove cy.wait(5 * SECOND) and instead
wait for the post-submit success indicator or navigation (e.g., assert
visibility of a toast, a "1 project selected" update, or a unique page element)
to confirm completion.
- Around line 93-97: The three hardcoded cy.waits should be replaced with
explicit assertions: wait for the delete modal to appear (use an assertion that
the modal is visible before interacting instead of cy.wait(2 * SECOND)), replace
the post-click wait for '`#delete-vm-network-modal-acknowledge-checkbox`' with an
assertion that the checkbox is checked (e.g., assert checked after .click({
force: true })), and replace the final cy.wait(3 * SECOND) with an assertion
that the modal has closed or the deleted VM row is gone (e.g., assert the modal
is not visible or the row representing the VM no longer exists after clicking
the 'Delete' button). Use the existing selectors
'`#delete-vm-network-modal-acknowledge-checkbox`' and the button containing
'Delete' to locate elements and rely on visibility/checked/existence assertions
instead of fixed delays.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d462aef1-c158-4072-99c6-353246832e86

📥 Commits

Reviewing files that changed from the base of the PR and between ca14d3a and 9d26b8c.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • ui-tests-cy/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • .env.example
  • .gitignore
  • cleanup.sh
  • research-flakiness.sh
  • setup.sh
  • test-cypress.sh
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/package.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/support/commands.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/views/vmNetwork.ts
✅ Files skipped from review due to trivial changes (2)
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/.eslintrc
🚧 Files skipped from review as they are similar to previous changes (16)
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/package.json
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/utils/const/base.ts
  • research-flakiness.sh
  • .gitignore
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/views/nncp.ts

Comment thread test-cypress.sh Outdated
@lkladnit lkladnit changed the title WIP: CNV-87995 Add Cypress E2E tests for NNCP, Physical networks, VM networks, and NNS CNV-87995 Add Cypress E2E tests for NNCP, Physical networks, VM networks, and NNS Jun 11, 2026
@lkladnit lkladnit marked this pull request as ready for review June 11, 2026 11:33
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 11, 2026
@lkladnit

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@openshift-ci openshift-ci Bot requested review from avivtur and upalatucci June 11, 2026 11:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (7)
setup.sh (1)

11-11: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Quote the variable in the oc create command.

The second ${TEST_NS} on line 11 is unquoted, which can cause word splitting or globbing if the value contains spaces or special characters.

🔧 Proposed fix
-  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace ${TEST_NS}
+  oc get namespace "${TEST_NS}" 2>/dev/null || oc create namespace "${TEST_NS}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@setup.sh` at line 11, The oc create command uses an unquoted variable; update
the command that runs when creating the namespace (the oc create namespace
${TEST_NS} invocation) to quote the variable (oc create namespace "${TEST_NS}")
to prevent word-splitting and globbing when TEST_NS contains spaces or special
characters.
test-cypress.sh (1)

3-7: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Disable xtrace while sourcing scripts that load secrets.

Line 3 enables command tracing (set -x) before lines 6-7 source cleanup.sh and setup.sh, which themselves source .env containing BRIDGE_KUBEADMIN_PASSWORD. This can echo the password to CI logs.

🔒 Proposed fix
-set -x
 set +e
 
 source ./cleanup.sh
 source ./setup.sh
+
+set -x

As per coding guidelines, logging must not expose passwords, tokens, or API keys.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` around lines 3 - 7, The script enables xtrace with `set -x`
before sourcing `./cleanup.sh` and `./setup.sh`, which can expose secrets from
their `.env` (e.g., BRIDGE_KUBEADMIN_PASSWORD); modify the script to temporarily
disable xtrace around the sensitive sources: call `set +x` (or otherwise disable
tracing) immediately before `source ./cleanup.sh` and `source ./setup.sh`, then
restore tracing afterwards if needed (e.g., `set -x`) and keep the existing `set
+e` behavior; ensure you reference the `set -x`, `set +e`, `source
./cleanup.sh`, and `source ./setup.sh` commands when making the change.

Source: Coding guidelines

cleanup.sh (1)

11-12: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Cleanup commands ignore the test namespace.

Lines 11-12 delete resources without specifying -n "${TEST_NS}", so they operate in the current context namespace instead of the test namespace created by setup.sh. This can leave test resources behind or delete unrelated resources.

Additionally, line 7 is commented out, so TEST_NS has no fallback when .env doesn't provide it.

🔧 Proposed fix
-#TEST_NS="${TEST_NS:-cy-test-ns}"
+TEST_NS="${TEST_NS:-cy-test-ns}"
@@
   echo "Cleaning up nmstate ui test resources..."
-  oc delete nncp test-form-nncp test-req-nncp example test-nncp-physical-network --ignore-not-found --wait=true --timeout=180s
-  oc delete --ignore-not-found=true virtualmachinenetwork test-project-vmn test-labeled-vmn --wait=true --timeout=60s 2>/dev/null || true
+  oc delete nncp test-form-nncp test-req-nncp example test-nncp-physical-network -n "${TEST_NS}" --ignore-not-found --wait=true --timeout=180s
+  oc delete --ignore-not-found=true virtualmachinenetwork test-project-vmn test-labeled-vmn -n "${TEST_NS}" --wait=true --timeout=60s 2>/dev/null || true
   echo "Cleanup done."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cleanup.sh` around lines 11 - 12, The oc delete invocations (the lines
invoking oc delete nncp ... and oc delete --ignore-not-found=true
virtualmachinenetwork ...) are missing the namespace flag and thus act in the
current kubectl context; update those commands to include -n "${TEST_NS}" so
they explicitly target the test namespace, and ensure TEST_NS is defined
(uncomment or add a fallback default assignment for TEST_NS near where .env is
sourced or in setup.sh) so the cleanup always has a valid namespace to operate
against.
ui-tests-cy/tests/nmstate/nncp.cy.ts (1)

14-14: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Scope the create assertion to the NNCP table row.

Line 14 uses cy.contains(NNCP_TEST_NAME) which can match any page text. Use a row-scoped assertion like cy.contains('tr', NNCP_TEST_NAME) to be consistent with lines 24 and 32.

♻️ Recommended fix
-    cy.contains(NNCP_TEST_NAME).should('exist');
+    cy.contains('tr', NNCP_TEST_NAME).should('exist');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts` at line 14, The assertion using
cy.contains(NNCP_TEST_NAME) is too broad and can match any page text; update the
check to scope it to the NNCP table row by changing the selector to
cy.contains('tr', NNCP_TEST_NAME) so it matches the specific table row (the
existing NNCP_TEST_NAME usage on the create assertion should be replaced to
mirror the row-scoped checks used at lines with similar checks).
ui-tests-cy/views/vmNetwork.ts (2)

94-96: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove { force: true } from modal checkbox and delete button clicks.

Lines 94 and 96 use { force: true } to click the modal checkbox and delete button. This bypasses Cypress's actionability checks and can hide real UI issues such as overlapping modals or elements not actually visible to users.

♻️ Recommended fix
-  cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').click({ force: true });
+  cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').click();
   cy.wait(SECOND);
-  cy.get('button').contains('Delete').last().click({ force: true });
+  cy.get('button').contains('Delete').last().should('be.enabled').click();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` around lines 94 - 96, The test is bypassing
Cypress actionability checks by using { force: true } on the modal checkbox
(`#delete-vm-network-modal-acknowledge-checkbox`) and the Delete button
(cy.get('button').contains('Delete').last()); remove the { force: true } options
and instead wait/assert the modal and controls are visible before clicking
(e.g., use
cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').click()
and cy.get('button').contains('Delete').last().should('be.visible').click()), or
add a targeted visibility/wait assertion for the delete modal prior to these
clicks so real UI issues aren’t masked.

63-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove { force: true } from checkbox click.

Line 63 uses { force: true } to click the checkbox, bypassing Cypress's visibility and actionability checks. Tests should fail if the checkbox is not genuinely clickable.

♻️ Recommended fix
-    cy.contains('li', projectName).find('input[type="checkbox"]').click({ force: true });
+    cy.contains('li', projectName).find('input[type="checkbox"]').should('be.visible').click();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` at line 63, The test currently forces a click
on the checkbox using cy.contains('li',
projectName).find('input[type="checkbox"]').click({ force: true }) which
bypasses Cypress actionability checks; remove the { force: true } option and
instead ensure the checkbox is actionable before interacting (for example, chain
.scrollIntoView() or .should('be.visible') and then call .click() or use
.check() on the input). Update the statement using the same selector
(cy.contains('li', projectName).find('input[type="checkbox"]')) to perform a
normal click/check without force so failures surface when the checkbox isn't
genuinely clickable.
ui-tests-cy/support/commands.ts (1)

12-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Command injection vulnerability via string interpolation.

The deleteResource command constructs shell commands by directly interpolating kind, name, and namespace into command strings without validation. This violates the coding guideline: "Command: no shell=True, os.system, or backtick exec with user input."

🛡️ Proposed fix using input validation
 Cypress.Commands.add('deleteResource', (kind: string, name: string, namespace?: string) => {
+  // Validate inputs contain only alphanumeric, dash, underscore, and dot
+  const safePattern = /^[a-zA-Z0-9._-]+$/;
+  if (!safePattern.test(kind) || !safePattern.test(name)) {
+    throw new Error('Invalid resource kind or name');
+  }
+  if (namespace && !safePattern.test(namespace)) {
+    throw new Error('Invalid namespace');
+  }
+
   if (!namespace) {
     cy.exec(`oc delete --ignore-not-found=true ${kind} ${name} --wait=true --timeout=300s`, {
       failOnNonZeroExit: false,
       timeout: 5 * MINUTE,
     });
     return;
   }
   cy.exec(
     `oc delete --ignore-not-found=true -n ${namespace} ${kind} ${name} --wait=true --timeout=300s`,
     { failOnNonZeroExit: false, timeout: 5 * MINUTE },
   );
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/support/commands.ts` around lines 12 - 24, In deleteResource
(ui-tests-cy/support/commands.ts) avoid command injection by validating and
whitelisting the inputs before interpolating into cy.exec: enforce that kind,
name, and namespace match a safe regex (e.g.
/^[a-z0-9A-Z.-]+(?:-[a-z0-9A-Z.-]+)*$/ or a stricter cluster resource/name
pattern) or check against an explicit allowed-kinds list; if validation fails,
throw or reject the command rather than running cy.exec; then build the oc
delete string only from validated values (or map kind to a known literal) so no
untrusted characters can inject shell operators.

Source: Coding guidelines

🧹 Nitpick comments (2)
test-cypress.sh (2)

11-14: 💤 Low value

Add a default case to handle invalid flags.

The getopts case statement doesn't handle invalid flags. While getopts itself will print an error, adding a *) case documents the expected behavior and follows shell scripting best practices.

♻️ Proposed fix
   case "${flag}" in
     g) gui=${OPTARG};;
     s) spec=${OPTARG};;
+    *) ;;
   esac
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` around lines 11 - 14, Add a default branch to the getopts
case statement to handle invalid flags: in the existing case handling for g)
gui=${OPTARG};; and s) spec=${OPTARG};; add a *) branch that prints a helpful
usage/error message (e.g., to stderr) and exits with non‑zero status; update the
case block around getopts so unknown options are explicitly handled and
documented, referencing the case statement and the variables gui and spec.

34-35: 💤 Low value

Remove redundant directory change.

Line 34 changes to the parent directory, but line 35 immediately changes back to ui-tests-cy. The cd .. on line 34 serves no purpose and can be removed.

♻️ Proposed fix
   node --max-old-space-size=4096 ./node_modules/.bin/cypress run --env openshift=true --browser "${BRIDGE_E2E_BROWSER_NAME:=electron}" --spec "$spec" | tee ./gui-test-screenshots/build.log
      test_exit_code=${PIPESTATUS[0]}
-  cd ..
-  cd ui-tests-cy && npm run cypress-postreport && cd ..
+  npm run cypress-postreport
+  cd ..
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` around lines 34 - 35, The script contains a redundant
directory change: the "cd .." immediately before "cd ui-tests-cy && npm run
cypress-postreport && cd .." is unnecessary; open test-cypress.sh and remove the
standalone "cd .." so the script directly runs the existing "cd ui-tests-cy &&
npm run cypress-postreport && cd .." sequence (or alternatively run npm in the
subdirectory without changing directories), ensuring the surrounding flow
remains correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test-cypress.sh`:
- Line 25: The script uses a bare "cd ui-tests-cy" which can fail and cause
subsequent "npm ci" and "mkdir" to run in the wrong directory; after the cd
command (referencing the literal cd ui-tests-cy) add explicit error handling to
detect failure and abort the script (e.g., check the exit status and print an
error before exit) so that npm ci and mkdir only run when the directory change
succeeds.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts`:
- Around line 36-38: The tests call editNNCP(NNCP_TEST_NAME) and deleteNNCP(...)
but lack outcome assertions; after editNNCP(NNCP_TEST_NAME) add a verification
that the NNCP row for NNCP_TEST_NAME reflects the expected changes (e.g., use
the same identifier NNCP_TEST_NAME to cy.get the table/row and assert the edited
field/text/value), and after deleteNNCP(...) assert the NNCP row is removed by
asserting the selector for NNCP_TEST_NAME does not exist or is not visible;
reference the helper calls editNNCP, deleteNNCP and the NNCP_TEST_NAME constant
to place these assertions immediately after those calls.

In `@ui-tests-cy/views/vmNetwork.ts`:
- Line 26: Remove the explicit force click on the "Create physical network"
button in ui-tests-cy/views/vmNetwork.ts by modifying the cy.contains('button',
'Create physical network').click({ force: true }) call to use a normal
actionability-checked click (e.g., cy.contains('button', 'Create physical
network').click()), and if flakiness occurs, add an explicit assertion or wait
(visible/should('be.visible') or cy.wait) before clicking to ensure the button
is interactable rather than bypassing Cypress checks.

---

Duplicate comments:
In `@cleanup.sh`:
- Around line 11-12: The oc delete invocations (the lines invoking oc delete
nncp ... and oc delete --ignore-not-found=true virtualmachinenetwork ...) are
missing the namespace flag and thus act in the current kubectl context; update
those commands to include -n "${TEST_NS}" so they explicitly target the test
namespace, and ensure TEST_NS is defined (uncomment or add a fallback default
assignment for TEST_NS near where .env is sourced or in setup.sh) so the cleanup
always has a valid namespace to operate against.

In `@setup.sh`:
- Line 11: The oc create command uses an unquoted variable; update the command
that runs when creating the namespace (the oc create namespace ${TEST_NS}
invocation) to quote the variable (oc create namespace "${TEST_NS}") to prevent
word-splitting and globbing when TEST_NS contains spaces or special characters.

In `@test-cypress.sh`:
- Around line 3-7: The script enables xtrace with `set -x` before sourcing
`./cleanup.sh` and `./setup.sh`, which can expose secrets from their `.env`
(e.g., BRIDGE_KUBEADMIN_PASSWORD); modify the script to temporarily disable
xtrace around the sensitive sources: call `set +x` (or otherwise disable
tracing) immediately before `source ./cleanup.sh` and `source ./setup.sh`, then
restore tracing afterwards if needed (e.g., `set -x`) and keep the existing `set
+e` behavior; ensure you reference the `set -x`, `set +e`, `source
./cleanup.sh`, and `source ./setup.sh` commands when making the change.

In `@ui-tests-cy/support/commands.ts`:
- Around line 12-24: In deleteResource (ui-tests-cy/support/commands.ts) avoid
command injection by validating and whitelisting the inputs before interpolating
into cy.exec: enforce that kind, name, and namespace match a safe regex (e.g.
/^[a-z0-9A-Z.-]+(?:-[a-z0-9A-Z.-]+)*$/ or a stricter cluster resource/name
pattern) or check against an explicit allowed-kinds list; if validation fails,
throw or reject the command rather than running cy.exec; then build the oc
delete string only from validated values (or map kind to a known literal) so no
untrusted characters can inject shell operators.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts`:
- Line 14: The assertion using cy.contains(NNCP_TEST_NAME) is too broad and can
match any page text; update the check to scope it to the NNCP table row by
changing the selector to cy.contains('tr', NNCP_TEST_NAME) so it matches the
specific table row (the existing NNCP_TEST_NAME usage on the create assertion
should be replaced to mirror the row-scoped checks used at lines with similar
checks).

In `@ui-tests-cy/views/vmNetwork.ts`:
- Around line 94-96: The test is bypassing Cypress actionability checks by using
{ force: true } on the modal checkbox
(`#delete-vm-network-modal-acknowledge-checkbox`) and the Delete button
(cy.get('button').contains('Delete').last()); remove the { force: true } options
and instead wait/assert the modal and controls are visible before clicking
(e.g., use
cy.get('`#delete-vm-network-modal-acknowledge-checkbox`').should('be.visible').click()
and cy.get('button').contains('Delete').last().should('be.visible').click()), or
add a targeted visibility/wait assertion for the delete modal prior to these
clicks so real UI issues aren’t masked.
- Line 63: The test currently forces a click on the checkbox using
cy.contains('li', projectName).find('input[type="checkbox"]').click({ force:
true }) which bypasses Cypress actionability checks; remove the { force: true }
option and instead ensure the checkbox is actionable before interacting (for
example, chain .scrollIntoView() or .should('be.visible') and then call .click()
or use .check() on the input). Update the statement using the same selector
(cy.contains('li', projectName).find('input[type="checkbox"]')) to perform a
normal click/check without force so failures surface when the checkbox isn't
genuinely clickable.

---

Nitpick comments:
In `@test-cypress.sh`:
- Around line 11-14: Add a default branch to the getopts case statement to
handle invalid flags: in the existing case handling for g) gui=${OPTARG};; and
s) spec=${OPTARG};; add a *) branch that prints a helpful usage/error message
(e.g., to stderr) and exits with non‑zero status; update the case block around
getopts so unknown options are explicitly handled and documented, referencing
the case statement and the variables gui and spec.
- Around line 34-35: The script contains a redundant directory change: the "cd
.." immediately before "cd ui-tests-cy && npm run cypress-postreport && cd .."
is unnecessary; open test-cypress.sh and remove the standalone "cd .." so the
script directly runs the existing "cd ui-tests-cy && npm run cypress-postreport
&& cd .." sequence (or alternatively run npm in the subdirectory without
changing directories), ensuring the surrounding flow remains correct.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9dfb809c-c099-482b-a3e2-0d64c4f601cc

📥 Commits

Reviewing files that changed from the base of the PR and between ca14d3a and 209cda6.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • ui-tests-cy/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (28)
  • .env.example
  • .gitignore
  • cleanup.sh
  • setup.sh
  • test-cypress.sh
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/package.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/reporter-config.json
  • ui-tests-cy/support/commands.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/support/selectors.ts
  • ui-tests-cy/tests/all.cy.ts
  • ui-tests-cy/tests/nmstate/nncp.cy.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/views/vmNetwork.ts
✅ Files skipped from review due to trivial changes (4)
  • ui-tests-cy/tests/setup/login.cy.ts
  • ui-tests-cy/.eslintrc
  • ui-tests-cy/package.json
  • ui-tests-cy/reporter-config.json
🚧 Files skipped from review as they are similar to previous changes (16)
  • .gitignore
  • ui-tests-cy/tsconfig.json
  • ui-tests-cy/plugins/index.ts
  • ui-tests-cy/support/login.ts
  • ui-tests-cy/support/nav.ts
  • ui-tests-cy/tests/nmstate/nns.cy.ts
  • ui-tests-cy/tests/nmstate/vmn.cy.ts
  • ui-tests-cy/tests/nmstate/visit-pages.cy.ts
  • ui-tests-cy/cypress.config.js
  • ui-tests-cy/views/selector-common.ts
  • ui-tests-cy/support/index.ts
  • ui-tests-cy/views/physicalNetwork.ts
  • ui-tests-cy/utils/const/base.ts
  • ui-tests-cy/views/nncp.ts
  • ui-tests-cy/tests/nmstate/physical.cy.ts
  • ui-tests-cy/support/selectors.ts

Comment thread test-cypress.sh
cleanup
setup

cd ui-tests-cy

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add error handling to the cd command.

If cd ui-tests-cy fails (directory missing or inaccessible), the script continues in the wrong directory. Lines 26-27 then run npm ci and mkdir in an unintended location, corrupting the environment or producing confusing failures.

🛡️ Proposed fix
-cd ui-tests-cy
+cd ui-tests-cy || exit 1
 npm ci
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cd ui-tests-cy
cd ui-tests-cy || exit 1
npm ci
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 25-25: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-cypress.sh` at line 25, The script uses a bare "cd ui-tests-cy" which
can fail and cause subsequent "npm ci" and "mkdir" to run in the wrong
directory; after the cd command (referencing the literal cd ui-tests-cy) add
explicit error handling to detect failure and abort the script (e.g., check the
exit status and print an error before exit) so that npm ci and mkdir only run
when the directory change succeeds.

Comment on lines +36 to +38
it('test Edit NNCP modal', () => {
editNNCP(NNCP_TEST_NAME);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add outcome assertions for edit and delete flows.

The edit test (lines 36-38) and delete test (lines 40-43) perform actions without asserting final state. Tests should verify that the edit succeeded and that the NNCP row is removed after deletion.

🧪 Recommended fix

For the edit test:

   it('test Edit NNCP modal', () => {
     editNNCP(NNCP_TEST_NAME);
+    cy.visitNNCP();
+    cy.contains('tr', NNCP_TEST_NAME).should('exist');
   });

For the delete test:

   it('delete NNCP', () => {
     cy.visitNNCP();
     deleteNNCP(NNCP_TEST_NAME);
+    cy.contains('tr', NNCP_TEST_NAME).should('not.exist');
   });

Also applies to: 40-43

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/tests/nmstate/nncp.cy.ts` around lines 36 - 38, The tests call
editNNCP(NNCP_TEST_NAME) and deleteNNCP(...) but lack outcome assertions; after
editNNCP(NNCP_TEST_NAME) add a verification that the NNCP row for NNCP_TEST_NAME
reflects the expected changes (e.g., use the same identifier NNCP_TEST_NAME to
cy.get the table/row and assert the edited field/text/value), and after
deleteNNCP(...) assert the NNCP row is removed by asserting the selector for
NNCP_TEST_NAME does not exist or is not visible; reference the helper calls
editNNCP, deleteNNCP and the NNCP_TEST_NAME constant to place these assertions
immediately after those calls.

return;
}
// Button is disabled — click "Create physical network" to create prerequisite
cy.contains('button', 'Create physical network').click({ force: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove { force: true } from "Create physical network" button click.

Line 26 uses { force: true } to click the button, bypassing Cypress's actionability checks. This can hide real UI issues such as the button being covered by another element or not actually visible to users.

♻️ Recommended fix
-    cy.contains('button', 'Create physical network').click({ force: true });
+    cy.contains('button', 'Create physical network').should('be.visible').click();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui-tests-cy/views/vmNetwork.ts` at line 26, Remove the explicit force click
on the "Create physical network" button in ui-tests-cy/views/vmNetwork.ts by
modifying the cy.contains('button', 'Create physical network').click({ force:
true }) call to use a normal actionability-checked click (e.g.,
cy.contains('button', 'Create physical network').click()), and if flakiness
occurs, add an explicit assertion or wait (visible/should('be.visible') or
cy.wait) before clicking to ensure the button is interactable rather than
bypassing Cypress checks.

Migrates tests from kubevirt-ui to a standalone ui-tests-cy/ folder with
its own package.json (Cypress 15). Covers NNCP CRUD, Physical network
wizard, Virtual machine network lifecycle, NNS list, and topology view.

Jira: CNV-87983
Co-authored-by: Cursor <cursoragent@cursor.com>
@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown

@lkladnit: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-tests b4ff8e1 link true /test e2e-tests

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant