Skip to content

Add Gen AI navigation tests#6944

Draft
toklumpp wants to merge 12 commits intoopendatahub-io:mainfrom
toklumpp:RHOAIENG-37588
Draft

Add Gen AI navigation tests#6944
toklumpp wants to merge 12 commits intoopendatahub-io:mainfrom
toklumpp:RHOAIENG-37588

Conversation

@toklumpp
Copy link
Copy Markdown
Contributor

@toklumpp toklumpp commented Mar 27, 2026

https://redhat.atlassian.net/browse/RHOAIENG-37588

Description

Implements 8 E2E tests for Gen AI navigation:

  • Administrator navigates between Gen AI sections
  • Data scientist accesses resources via direct URLs
  • User gets automatic redirect to default page
  • User redirected when accessing without namespace
  • User receives clear guidance for broken links
  • User understands current location while navigating
  • Developer shares direct links for team collaboration
  • User receives feedback for invalid namespace

Tests follow user-story focused pattern, representing real user workflows rather than technical UI checks.

How Has This Been Tested?

test working

Test Impact

Tests

Request review criteria:

Self checklist (all need to be checked):

  • The developer has manually tested the changes and verified that the changes work
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has added tests or explained why testing cannot be added (unit or cypress tests for related changes)
  • The code follows our Best Practices (React coding standards, PatternFly usage, performance considerations)

If you have UI changes:

  • [ ] Included any necessary screenshots or gifs if it was a UI change.
  • [ ] Included tags to the UX team if it was a UI/UX change.

After the PR is posted & before it merges:

  • The developer has tested their solution on a cluster by using the image produced by the PR to main

Summary by CodeRabbit

  • Tests
    • Added end-to-end Gen AI navigation coverage including reusable page helpers for Playground and AI Assets.
    • Validates in-app navigation, direct links, redirects to Playground, cross-session/shared-link behavior, 404 and "Project not found" recovery flows, namespace handling, and environment-aware skip logic.

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress This PR is in WIP state label Mar 27, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 27, 2026

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
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 27, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 457e2c66-abbc-47ee-b488-3843028e1a4c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Walkthrough

Adds a new Cypress page object module packages/cypress/cypress/pages/aiAssets.ts exporting an AiAssets class and singleton aiAssets for interacting with the Gen AI "AI asset endpoints" UI. Adds a findPageTitle() method to packages/cypress/cypress/pages/genAiPlayground.ts. Introduces a comprehensive end-to-end spec packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts covering navigation, redirects, namespace handling, broken-route checks, cross-session shared-link validation, project lifecycle setup/teardown, and conditional test skipping.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Actionable Issues

  1. Broad uncaught-exception suppression — CWE-703 (Improper Check or Handling of Exceptional Conditions)
  • Location: packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts (global uncaught:exception handler)
  • Problem: The handler suppresses errors using a substring match on err.message ("Failed to parse module script"), which can hide legitimate parse/runtime failures and obscure test failures.
  • Fix: Restrict suppression to a narrowly-scoped, verifiable condition (e.g., exact error message plus source file/origin or error code). Prefer stubbing or isolating the federated module load in the test environment rather than globally swallowing errors.
  1. Cross-session shared-URL test lacks explicit authorization assertions — CWE-639 (Authorization Bypass Through User-Controlled Key)
  • Location: packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts (cross-session/shared-link scenario)
  • Problem: The test assumes visiting a captured AI Assets URL from another session is valid without asserting server-side access control or indicating sharing metadata, risking false confidence about access controls or exposing IDOR.
  • Fix: Assert HTTP status codes (200 vs 403/404) and presence/absence of sharing metadata or access indicators. If sharing should be restricted, verify access is denied for non-members; if public, verify sensitive fields are redacted.
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning PR description is incomplete: lacks detailed testing methodology, vague test impact statement, and omits cluster validation before merge. Add specific testing steps, clarify which tests were executed, and check the final checkbox confirming cluster deployment testing with the PR-built image.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title "Add Gen AI navigation tests" directly and clearly describes the main change: introducing new end-to-end navigation tests for the Gen AI feature.

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


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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.99%. Comparing base (4dbfc83) to head (b32825b).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #6944      +/-   ##
==========================================
+ Coverage   64.98%   64.99%   +0.01%     
==========================================
  Files        2446     2446              
  Lines       76161    76161              
  Branches    19213    19213              
==========================================
+ Hits        49490    49502      +12     
+ Misses      26671    26659      -12     

see 10 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4dbfc83...b32825b. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@toklumpp toklumpp force-pushed the RHOAIENG-37588 branch 3 times, most recently from 1ec4635 to 4a2811a Compare March 30, 2026 15:57
@toklumpp toklumpp force-pushed the RHOAIENG-37588 branch 4 times, most recently from ba72c1e to a3c000a Compare March 31, 2026 13:21
@toklumpp toklumpp marked this pull request as ready for review March 31, 2026 13:25
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress This PR is in WIP state label Mar 31, 2026
@openshift-ci openshift-ci Bot requested review from ConorOM1 and sridarna March 31, 2026 13:25
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
packages/cypress/cypress/pages/aiAssets.ts (1)

11-13: Use a stable locator for the description.

cy.contains('Browse endpoints for models and MCP servers') is unscoped and tied to product copy, so a text tweak elsewhere on the page can make this pass or fail for the wrong reason. Prefer a dedicated data-testid, or at least scope the assertion under a stable page-header container.

As per coding guidelines, "Use data-testid selectors, not CSS classes (resilient to style changes)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/pages/aiAssets.ts` around lines 11 - 13, The
findPageDescription() method uses an unscoped text matcher (cy.contains(...))
which is brittle; update findPageDescription() to use a stable selector
instead—prefer a dedicated data-testid on the page header (e.g.
data-testid="ai-assets-page-description") and change the locator to
cy.get('[data-testid="ai-assets-page-description"]'), or at minimum scope the
contains() call under the page header container (e.g.
cy.get('[data-testid="ai-assets-page-header"]').contains(...)); modify the app
markup to include the new data-testid if needed and update the test to reference
the new attribute.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts`:
- Around line 16-57: The suite setup in retryableBefore() must early-exit when
running as a non-admin to avoid leaving projectName undefined or flip skipTest
incorrectly; add a guard that checks Cypress.env('IS_NON_ADMIN_RUN') at the top
of the hook and set skipTest = true (or return) before any logic that assigns
projectName or calls createCleanProject/enableGenAiFeatures; ensure the guard
runs prior to the getCustomResource(...) and project creation steps so
createCleanProject and enableGenAiFeatures are never invoked when
IS_NON_ADMIN_RUN is truthy.
- Around line 59-69: The after() hook currently calls disableGenAiFeatures()
which only patches resources but does not wait for the UI/feature flag to
actually clear; update the teardown to wait until Gen AI is fully disabled
before finishing the suite by adding a polling/wait step after
disableGenAiFeatures() that verifies the sidebar/feature flag is gone (e.g.,
implement or call a helper like
waitForGenAiDisabled()/waitForGenAiFeatureToggleToClear that polls the API or
checks the UI element disappears), then proceed to
deleteOpenShiftProject(projectName, { wait: false, ignoreNotFound: true }) —
ensure the new wait targets the same signals disableGenAiFeatures() modifies so
subsequent specs start with Gen AI disabled.
- Around line 304-305: The test currently uses a hard-coded invalidNamespace
('non-existent-project-12345') which can collide on shared clusters; change the
testGenAiNavigation.cy.ts code that sets invalidNamespace to instead generate a
unique value at runtime (e.g., use a uuid/UUID generator to build the string) so
the value used in cy.visit(`/gen-ai-studio/playground/${invalidNamespace}`) is
unique per run; update the variable named invalidNamespace and any related
usages in that test to use the generated UUID-based name.
- Around line 109-120: The tests labeled "Data scientist accesses Gen AI
resources via direct URL links" and the "Developer shares direct link" journey
are both reusing HTPASSWD_CLUSTER_ADMIN_USER and the same browser session, so
update the authentication to use the intended persona constants (e.g.,
DATASCIENTIST_USER, DEVELOPER_USER, COLLEAGUE_USER) instead of
HTPASSWD_CLUSTER_ADMIN_USER, and ensure each persona uses a fresh session (use
cy.session or clear cookies/localStorage between logins and call
cy.visitWithLogin for each distinct user) so RBAC and cross-user link access are
actually exercised; update occurrences of cy.visitWithLogin, the test titles in
testGenAiNavigation.cy.ts, and any related setup that currently references
HTPASSWD_CLUSTER_ADMIN_USER or reuses the same session.
- Around line 16-24: The uncaught exception handler inside retryableBefore that
currently checks err.message.includes('expected expression') ||
includes('Unexpected token') is too broad; update the
Cypress.on('uncaught:exception') predicate to only ignore the specific
federation/dev-server parse errors (e.g., check for exact substrings like
"Unexpected token '<'", "Unexpected token ':'", or known remote entry
URLs/module federation identifiers or module names appearing in err.message or
err.stack) and ensure other syntax errors still bubble up; apply the same
narrower check to the other occurrence in testGenAi.cy.ts so both handlers only
suppress the targeted federation/dev-server fallback errors.
- Around line 77-80: In testGenAiNavigation.cy.ts the current arrow-function
it() callbacks return early when skipTest is true which marks tests as passed
instead of skipped; change each affected it(...) callback from an arrow function
to a function() { ... } form and, at the top of the body before any Cypress
commands, call this.skip() when skipTest is true (e.g., if (skipTest) {
this.skip(); }), applying this change to the similar blocks referenced (around
the current branches at lines ~77, 114, 147, 172, 198, 223, 256, 295) so tests
are properly marked skipped instead of passing.

---

Nitpick comments:
In `@packages/cypress/cypress/pages/aiAssets.ts`:
- Around line 11-13: The findPageDescription() method uses an unscoped text
matcher (cy.contains(...)) which is brittle; update findPageDescription() to use
a stable selector instead—prefer a dedicated data-testid on the page header
(e.g. data-testid="ai-assets-page-description") and change the locator to
cy.get('[data-testid="ai-assets-page-description"]'), or at minimum scope the
contains() call under the page header container (e.g.
cy.get('[data-testid="ai-assets-page-header"]').contains(...)); modify the app
markup to include the new data-testid if needed and update the test to reference
the new attribute.
🪄 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 YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: d8e4beab-f2fc-410c-a3b7-1e0cd30bf93c

📥 Commits

Reviewing files that changed from the base of the PR and between 55a7893 and a3c000adb9a2aee75c3f44070533ca787214ecd7.

📒 Files selected for processing (3)
  • packages/cypress/cypress/pages/aiAssets.ts
  • packages/cypress/cypress/pages/genAiPlayground.ts
  • packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts

Comment thread packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts
Comment thread packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts Outdated
Comment thread packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts
Comment thread packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts Outdated
Comment on lines +109 to +120
'Data scientist accesses Gen AI resources via direct URL links',
{
tags: ['@Sanity', '@GenAI', '@Navigation'],
},
() => {
if (skipTest) {
cy.log('Skipping test - Gen AI is RHOAI-specific and not available on ODH.');
return;
}

cy.step('Log into the application as Data scientist');
cy.visitWithLogin('/', HTPASSWD_CLUSTER_ADMIN_USER);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

These persona stories never leave the admin session.

Both the "Data scientist" journey and the "Developer shares direct link" journey authenticate as HTPASSWD_CLUSTER_ADMIN_USER, and the "colleague" step just revisits the URL in the same browser session. That leaves RBAC and cross-user link access completely untested unless these cases use the intended personas and a fresh session.

Also applies to: 251-275

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 109 - 120, The tests labeled "Data scientist accesses Gen AI resources via
direct URL links" and the "Developer shares direct link" journey are both
reusing HTPASSWD_CLUSTER_ADMIN_USER and the same browser session, so update the
authentication to use the intended persona constants (e.g., DATASCIENTIST_USER,
DEVELOPER_USER, COLLEAGUE_USER) instead of HTPASSWD_CLUSTER_ADMIN_USER, and
ensure each persona uses a fresh session (use cy.session or clear
cookies/localStorage between logins and call cy.visitWithLogin for each distinct
user) so RBAC and cross-user link access are actually exercised; update
occurrences of cy.visitWithLogin, the test titles in testGenAiNavigation.cy.ts,
and any related setup that currently references HTPASSWD_CLUSTER_ADMIN_USER or
reuses the same session.

Comment thread packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (4)
packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts (4)

60-69: ⚠️ Potential issue | 🟠 Major

Wait for Gen AI disablement to converge before finishing teardown.

disableGenAiFeatures() is invoked, but teardown does not wait for the feature state to fully clear, so following specs can start against stale enabled state.

As per coding guidelines, "Test data cleanup: delete resources created during tests in after() hooks." and "Tests must be idempotent: runnable in any order without shared state."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 60 - 69, Teardown calls disableGenAiFeatures() but does not wait for the
feature state to actually clear, causing flakiness; update the after() to await
disableGenAiFeatures() completion and then poll the feature state (e.g., via a
new helper waitForGenAiDisabled() that repeatedly calls getGenAiFeatureState()
or your existing status API until it returns "disabled") before proceeding to
deleteOpenShiftProject(projectName, ...); ensure the after() returns a Promise
(or uses Cypress commands properly) so teardown waits for the disablement to
converge.

112-118: ⚠️ Potential issue | 🟠 Major

Persona stories are still executed as admin and in one session.

The “Data scientist” and “Developer shares direct link” journeys both log in as HTPASSWD_CLUSTER_ADMIN_USER, and the “colleague” step reuses the same authenticated session. This does not validate RBAC or cross-user link access.

Also applies to: 229-248

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 112 - 118, The tests "Data scientist accesses Gen AI resources via direct
URL links" and the "Developer shares direct link" flow currently both call
cy.visitWithLogin with HTPASSWD_CLUSTER_ADMIN_USER and reuse the same
authenticated session (e.g., the "colleague" step), which fails to validate
RBAC/cross-user access; update the tests to log in as distinct personas by
replacing the second and subsequent cy.visitWithLogin/visit steps to use the
correct non-admin credential constants (e.g., a DATA_SCIENTIST_USER and a
DEVELOPER_USER) and ensure you start a fresh session between personas (use
cy.clearCookies()/cy.clearLocalStorage() or a distinct cy.session call) so each
journey runs under the intended user identity (look for uses of
cy.visitWithLogin, HTPASSWD_CLUSTER_ADMIN_USER, and the "colleague" step to
modify).

19-24: ⚠️ Potential issue | 🟠 Major

Narrow exception suppression to federation-specific signatures only.

The current filter ignores any "expected expression" / "Unexpected token" parse error, which can hide real regressions unrelated to missing federated modules.

Proposed patch
 Cypress.on('uncaught:exception', (err) => {
-  // Ignore SyntaxError from missing federated modules
-  if (err.message.includes('expected expression') || err.message.includes('Unexpected token')) {
+  const message = err.message ?? '';
+  const stack = err.stack ?? '';
+  const isKnownFederationFallback =
+    message.includes("Unexpected token '<'") ||
+    message.includes("Unexpected token ':'") ||
+    stack.includes('remoteEntry') ||
+    stack.includes('module federation');
+
+  if (isKnownFederationFallback) {
     return false;
   }
   return true;
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 19 - 24, The uncaught exception handler currently suppresses any parse
errors containing "expected expression" or "Unexpected token"; change this to
only suppress errors that match those messages AND also indicate a
federated-module failure (e.g., the error message or stack contains
federation-specific signatures like "remoteEntry", "federation", "federated",
"__webpack_require__", or a remote URL pattern). Update the
Cypress.on('uncaught:exception', (err) => ...) predicate to use a combined check
(regex or chained includes) so only federation-related parse errors are returned
false while all other parse errors are allowed to bubble.

17-37: ⚠️ Potential issue | 🟠 Major

Add an explicit non-admin early skip guard before any setup commands.

This hook still proceeds without checking Cypress.env('IS_NON_ADMIN_RUN'), so restricted runs can enter partial setup paths before being skipped.

Proposed patch
 retryableBefore(() => {
+  if (Cypress.env('IS_NON_ADMIN_RUN')) {
+    skipTest = true;
+    cy.log('Non-admin run detected; skipping Gen AI navigation suite.');
+    return;
+  }
+
   // Ignore module federation loading errors (for clusters without Gen AI modules deployed)
   Cypress.on('uncaught:exception', (err) => {

As per coding guidelines, "Tests must be idempotent: runnable in any order without shared state."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 17 - 37, Add an explicit early non-admin guard at the top of the
retryableBefore hook: check Cypress.env('IS_NON_ADMIN_RUN') immediately inside
retryableBefore and, if true, set skipTest = true and short-circuit the rest of
the setup (return early) so no further Cypress commands (Cypress.on,
getCustomResource, etc.) run for non-admin runs; update references to
retryableBefore, Cypress.env('IS_NON_ADMIN_RUN'), and skipTest to ensure the
guard runs before any other setup logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts`:
- Around line 60-69: Teardown calls disableGenAiFeatures() but does not wait for
the feature state to actually clear, causing flakiness; update the after() to
await disableGenAiFeatures() completion and then poll the feature state (e.g.,
via a new helper waitForGenAiDisabled() that repeatedly calls
getGenAiFeatureState() or your existing status API until it returns "disabled")
before proceeding to deleteOpenShiftProject(projectName, ...); ensure the
after() returns a Promise (or uses Cypress commands properly) so teardown waits
for the disablement to converge.
- Around line 112-118: The tests "Data scientist accesses Gen AI resources via
direct URL links" and the "Developer shares direct link" flow currently both
call cy.visitWithLogin with HTPASSWD_CLUSTER_ADMIN_USER and reuse the same
authenticated session (e.g., the "colleague" step), which fails to validate
RBAC/cross-user access; update the tests to log in as distinct personas by
replacing the second and subsequent cy.visitWithLogin/visit steps to use the
correct non-admin credential constants (e.g., a DATA_SCIENTIST_USER and a
DEVELOPER_USER) and ensure you start a fresh session between personas (use
cy.clearCookies()/cy.clearLocalStorage() or a distinct cy.session call) so each
journey runs under the intended user identity (look for uses of
cy.visitWithLogin, HTPASSWD_CLUSTER_ADMIN_USER, and the "colleague" step to
modify).
- Around line 19-24: The uncaught exception handler currently suppresses any
parse errors containing "expected expression" or "Unexpected token"; change this
to only suppress errors that match those messages AND also indicate a
federated-module failure (e.g., the error message or stack contains
federation-specific signatures like "remoteEntry", "federation", "federated",
"__webpack_require__", or a remote URL pattern). Update the
Cypress.on('uncaught:exception', (err) => ...) predicate to use a combined check
(regex or chained includes) so only federation-related parse errors are returned
false while all other parse errors are allowed to bubble.
- Around line 17-37: Add an explicit early non-admin guard at the top of the
retryableBefore hook: check Cypress.env('IS_NON_ADMIN_RUN') immediately inside
retryableBefore and, if true, set skipTest = true and short-circuit the rest of
the setup (return early) so no further Cypress commands (Cypress.on,
getCustomResource, etc.) run for non-admin runs; update references to
retryableBefore, Cypress.env('IS_NON_ADMIN_RUN'), and skipTest to ensure the
guard runs before any other setup logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1130552b-4fb6-45b5-9b53-f7303b7715ef

📥 Commits

Reviewing files that changed from the base of the PR and between a3c000adb9a2aee75c3f44070533ca787214ecd7 and 7de3756facaf959fd37a5905413c52475d5c25e7.

📒 Files selected for processing (1)
  • packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts

@toklumpp toklumpp force-pushed the RHOAIENG-37588 branch 2 times, most recently from 14dc955 to dfc557f Compare March 31, 2026 16:04
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (3)
packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts (3)

65-75: ⚠️ Potential issue | 🟠 Major

Teardown is non-deterministic and can leak state into following specs.

Lines 70-74 disable features and delete the project without waiting (wait: false), so subsequent suites can start before cleanup is complete.

Proposed fix
 after(() => {
   if (skipTest) {
     return;
   }
 
-  disableGenAiFeatures();
+  disableGenAiFeatures();
 
   if (projectName) {
-    deleteOpenShiftProject(projectName, { wait: false, ignoreNotFound: true });
+    deleteOpenShiftProject(projectName, { wait: true, ignoreNotFound: true });
   }
 });

As per coding guidelines, "Test data cleanup: delete resources created during tests in after() hooks." and "Tests must be idempotent: runnable in any order without shared state."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 65 - 75, The after() teardown is non-deterministic: make the hook async
and ensure deterministic cleanup by awaiting disableGenAiFeatures() (if it is
async) and awaiting deleteOpenShiftProject(projectName, { wait: true,
ignoreNotFound: true }) instead of using wait: false; also keep the existing
skipTest guard and only call deleteOpenShiftProject when projectName is set so
the hook reliably completes before the next spec runs.

117-124: ⚠️ Potential issue | 🟠 Major

Persona journeys are not exercising persona behavior.

Line 123 and Line 240 log in as HTPASSWD_CLUSTER_ADMIN_USER for stories labeled "Data scientist" and "Developer/Colleague", and Lines 250-253 reuse the same session. This does not validate role-specific or cross-user link behavior.

Proposed fix
-      cy.step('Log into the application as Data scientist');
-      cy.visitWithLogin('/', HTPASSWD_CLUSTER_ADMIN_USER);
+      cy.step('Log into the application as Data scientist');
+      cy.visitWithLogin('/', DATASCIENTIST_USER);
...
-      cy.step('Log into the application as first user (Developer)');
-      cy.visitWithLogin('/', HTPASSWD_CLUSTER_ADMIN_USER);
+      cy.step('Log into the application as first user (Developer)');
+      cy.visitWithLogin('/', DEVELOPER_USER);
...
       cy.step('Colleague accesses the shared link');
       cy.then(() => {
+        cy.clearCookies();
+        cy.clearLocalStorage();
+        cy.visitWithLogin('/', COLLEAGUE_USER);
         cy.visit(sharedUrl);
       });

Also applies to: 234-253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 117 - 124, The tests labeled for different personas are all logging in
with HTPASSWD_CLUSTER_ADMIN_USER and reusing the same session (via
cy.visitWithLogin and the shared session block), so update the persona-specific
tests (e.g., the test titled 'Data scientist accesses Gen AI resources via
direct URL links' and the Developer/Colleague story) to log in with distinct
test accounts that reflect their roles instead of HTPASSWD_CLUSTER_ADMIN_USER,
and stop reusing the single session for cross-user validation by creating
separate cy.visitWithLogin/cy.session calls per persona; locate usages of
cy.visitWithLogin and any shared session helper in this spec and replace the
admin user with role-specific constants (e.g., HTPASSWD_DATA_SCIENTIST_USER,
HTPASSWD_DEVELOPER_USER) and ensure each persona test creates its own session.

24-30: ⚠️ Potential issue | 🟠 Major

Uncaught-exception suppression is too broad and can hide real regressions.

Line 26 ignores any parse error containing generic text (expected expression / Unexpected token), which can suppress unrelated app failures. Narrow this to known federation/dev-server signatures only.

Proposed fix
-    Cypress.on('uncaught:exception', (err) => {
-      // Ignore SyntaxError from missing federated modules
-      if (err.message.includes('expected expression') || err.message.includes('Unexpected token')) {
-        return false;
-      }
-      return true;
-    });
+    Cypress.on('uncaught:exception', (err) => {
+      const message = err.message ?? '';
+      const stack = err.stack ?? '';
+      const knownFederationParseError =
+        message.includes("Unexpected token '<'") ||
+        message.includes("Unexpected token ':'") ||
+        /remoteEntry|module federation|federated/i.test(`${message}\n${stack}`);
+
+      if (knownFederationParseError) {
+        return false;
+      }
+      return true;
+    });
#!/bin/bash
set -euo pipefail
# Compare exception-ignore patterns used in Gen AI specs and global Cypress support config.
rg -n --type ts -C3 "uncaught:exception|Unexpected token|expected expression|remoteEntry|module federation" \
  packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts \
  packages/cypress/cypress/tests/e2e/gen-ai/testGenAi.cy.ts \
  packages/cypress/cypress/support/e2e.ts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts` around
lines 24 - 30, The uncaught-exception handler registered via
Cypress.on('uncaught:exception', (err) => ...) is too broad — replace the
generic string checks for 'expected expression' / 'Unexpected token' with
narrowly targeted patterns that match known federation/dev-server failure
signatures (e.g., 'remoteEntry', 'module federation', a dev-server URL fragment
or the exact error message emitted by the federated module loader) so only those
known, benign parse errors are suppressed; update the handler to check
err.message for those specific identifiers and return false only when they
match, otherwise rethrow/return true to allow real regressions to surface.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts`:
- Around line 65-75: The after() teardown is non-deterministic: make the hook
async and ensure deterministic cleanup by awaiting disableGenAiFeatures() (if it
is async) and awaiting deleteOpenShiftProject(projectName, { wait: true,
ignoreNotFound: true }) instead of using wait: false; also keep the existing
skipTest guard and only call deleteOpenShiftProject when projectName is set so
the hook reliably completes before the next spec runs.
- Around line 117-124: The tests labeled for different personas are all logging
in with HTPASSWD_CLUSTER_ADMIN_USER and reusing the same session (via
cy.visitWithLogin and the shared session block), so update the persona-specific
tests (e.g., the test titled 'Data scientist accesses Gen AI resources via
direct URL links' and the Developer/Colleague story) to log in with distinct
test accounts that reflect their roles instead of HTPASSWD_CLUSTER_ADMIN_USER,
and stop reusing the single session for cross-user validation by creating
separate cy.visitWithLogin/cy.session calls per persona; locate usages of
cy.visitWithLogin and any shared session helper in this spec and replace the
admin user with role-specific constants (e.g., HTPASSWD_DATA_SCIENTIST_USER,
HTPASSWD_DEVELOPER_USER) and ensure each persona test creates its own session.
- Around line 24-30: The uncaught-exception handler registered via
Cypress.on('uncaught:exception', (err) => ...) is too broad — replace the
generic string checks for 'expected expression' / 'Unexpected token' with
narrowly targeted patterns that match known federation/dev-server failure
signatures (e.g., 'remoteEntry', 'module federation', a dev-server URL fragment
or the exact error message emitted by the federated module loader) so only those
known, benign parse errors are suppressed; update the handler to check
err.message for those specific identifiers and return false only when they
match, otherwise rethrow/return true to allow real regressions to surface.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 8401546d-df58-41ef-9e95-7804154010fd

📥 Commits

Reviewing files that changed from the base of the PR and between 14dc95579c81292932ab540bf8348a542e5596f4 and dfc557f54d1cba2a2e41793823fd84a00978fa49.

📒 Files selected for processing (3)
  • packages/cypress/cypress/pages/aiAssets.ts
  • packages/cypress/cypress/pages/genAiPlayground.ts
  • packages/cypress/cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/cypress/cypress/pages/aiAssets.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cypress/cypress/pages/genAiPlayground.ts

@toklumpp toklumpp force-pushed the RHOAIENG-37588 branch 6 times, most recently from 44e6024 to 7406dfd Compare April 1, 2026 13:10
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 2, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign christianvogt 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

@toklumpp toklumpp changed the title Add user-journey focused Gen AI navigation tests Add Gen AI navigation tests Apr 2, 2026
@openshift-ci openshift-ci Bot added needs-rebase PR needs to be rebased and removed needs-rebase PR needs to be rebased labels Apr 9, 2026
@toklumpp toklumpp force-pushed the RHOAIENG-37588 branch 5 times, most recently from b42c06c to b32825b Compare April 20, 2026 09:28
toklumpp and others added 7 commits April 21, 2026 10:39
Implements 8 user-story focused E2E tests for Gen AI navigation:
- Administrator navigates between Gen AI sections
- Data scientist accesses resources via direct URLs
- User gets automatic redirect to default page
- User redirected when accessing without namespace
- User receives clear guidance for broken links
- User understands current location while navigating
- Developer shares direct links for team collaboration
- User receives feedback for invalid namespace

New files:
- cypress/pages/aiAssets.ts - AI Assets page object
- cypress/tests/e2e/gen-ai/testGenAiNavigation.cy.ts - Navigation tests

Updated:
- cypress/pages/genAiPlayground.ts - Added findPageTitle() method

Tests follow user-story focused pattern, representing real user
workflows rather than technical UI checks. Tagged with @sanity,
@genai, @Navigation. RHOAI-only with proper skip handling for ODH.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes "Property 'then' does not exist on type 'void'" error.

createCleanProject returns void, not a Chainable, so it cannot be
chained with .then(). Split the logic into separate .then() blocks
to match the pattern used in testGenAi.cy.ts.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use unique UUID for invalidNamespace to prevent collisions on shared clusters
- Implement proper test skipping with beforeEach hook using this.skip()
- Remove redundant skipTest checks from individual test cases
- Tests now correctly report as skipped instead of passed when Gen AI is unavailable

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add early guard to set skipTest=true when running in non-admin mode
- Prevents undefined projectName errors when retryableBefore skips setup
- Ensures tests properly skip in non-admin CI runs instead of failing

The retryableHooks framework returns early when IS_NON_ADMIN_RUN=true,
preventing the test setup callback from executing. This guard ensures
skipTest is set before retryableBefore runs.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Improve test determinism and accuracy in Gen AI navigation E2E tests:

1. **Deterministic cleanup**: Make after() hook async and await cleanup
   - Changed deleteOpenShiftProject to use wait: true for reliable teardown
   - Added await for disableGenAiFeatures() to ensure complete cleanup

2. **Correct persona validation**: Use role-appropriate user accounts
   - Data scientist test now uses LDAP_CONTRIBUTOR_USER
   - Developer collaboration test now uses LDAP_CONTRIBUTOR_USER
   - Validates actual role-based access instead of all admin users

3. **Narrow exception suppression**: Target federation-specific errors only
   - Replace generic syntax error patterns with federation identifiers
   - Only suppress 'remoteEntry', 'module federation', and dynamic import errors
   - Allow other parse errors to surface as real regressions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…istener accumulation

Move Cypress.on('uncaught:exception') registration from inside retryableBefore()
to describe block level to avoid accumulating multiple event listeners on retries.

Problem: Registering the handler inside retryableBefore causes multiple
identical listeners to be created on each retry attempt, leading to:
- Memory leaks from accumulated event handlers
- Potential race conditions or unexpected behavior
- Violation of Cypress best practices

Solution: Register the handler once at the describe block level, ensuring
it is only created once for the entire test suite.

Based on review feedback from PR opendatahub-io#6229 by andrewballantyne.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove emoji character from cy.log statement to maintain consistent
code style without decorative characters.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@toklumpp toklumpp marked this pull request as draft April 21, 2026 16:28
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress This PR is in WIP state label Apr 21, 2026
toklumpp and others added 3 commits April 23, 2026 10:27
The Gen AI playground test was failing with a timeout waiting for a
tabpanel element. Root cause was a race condition where the test
navigated to the assets page before the project selector finished
loading.

The assets page requires a loaded project context to render its
content. Without waiting for the project selector, the page would
get stuck in a loading state with the selector showing "Loading...
No projects", preventing the Gen AI module from rendering the
tabpanel.

Changes:
- Added explicit wait for project-selector-toggle in waitForAssetsPageLoad()
- Ensures the selector is not disabled and not showing "Loading..."
- This wait happens between the page title check and tabpanel check

This fix applies to all tests using navigateToAssets(), making them
more robust against timing issues.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Dashboard requires status.components.llamastackoperator.managementState
to be 'Managed', not just the LlamaStackOperatorReady condition. Added
polling to wait for the status field to reconcile after patching the spec.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant