Skip to content

Conversation

Katka92
Copy link
Collaborator

@Katka92 Katka92 commented Aug 20, 2025

Test dependencies tab.
Add screenshots and videos to artifacts if a test fails.
Create a common waitForPageLoad method and use it across all UI tests when a page is loaded (page.goto()).

Summary by CodeRabbit

  • Tests

    • Added E2E coverage for the Dependencies tab: verifies sections, nodes, relations, and navigation to a GitOps dependency; expanded Docs/GitOps checks and unified page-readiness handling via reusable page-load and tab helpers.
    • Introduced a Dependencies UI plugin to encapsulate dependency interactions.
  • Chores

    • Test runner now captures screenshots and retains videos on failures to aid debugging.
  • Style

    • Minor whitespace/comment formatting tweaks in UI test utilities.

@Katka92 Katka92 requested a review from xinredhat as a code owner August 20, 2025 10:16
Copy link

coderabbitai bot commented Aug 20, 2025

Walkthrough

Adds a global Playwright use block for screenshots/videos; introduces UI helpers waitForPageLoad and openTab; adds a Dependencies page-object and DependenciesUiPlugin; wires the plugin into UiComponent with getDependencies(); and updates UI tests to use the new helpers and test the dependencies tab and GitOps dependency.

Changes

Cohort / File(s) Summary
Playwright config
playwright.config.ts
Adds top-level use defaults: screenshot: 'only-on-failure' and video: 'retain-on-failure' (inserted after globalSetup).
UI utilities
src/ui/common.ts
Adds exported helpers waitForPageLoad(page: Page, name: string) and openTab(page: Page, tabName: string); minor comment/whitespace tweak.
Dependencies page object
src/ui/page-objects/dependencies_po.ts
New exported DependenciesPO with titles: string[] and relationsTitle: string.
Dependencies UI plugin
src/ui/plugins/dependencies/dependenciesUiPlugin.ts
New exported DependenciesUiPlugin class (constructed with componentName) with methods: checkAllBoxesPresent, checkRelationsTitle, checkNodesPresent, goToGitopsDependency.
UI component wiring
src/ui/uiComponent.ts
Wires DependenciesUiPlugin into UiComponent: accepts plugin in constructor, stores it, and exposes getDependencies(): DependenciesUiPlugin.
UI tests
tests/ui/ui.test.ts
Replaces ad-hoc navigation/waits with getComponentUrl() and waitForPageLoad; uses openTab for Docs navigation; adds "Check dependencies tab and gitops dependency" suite using DependenciesUiPlugin; minor formatting tweaks.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Test as Test
  participant Page as Playwright Page
  participant Helper as waitForPageLoad
  rect rgba(200,230,255,0.35)
  Test->>Page: goto(component URL)
  Test->>Helper: waitForPageLoad(Page, componentName)
  activate Helper
  Helper->>Page: wait for progress bars hidden (per-bar timeout)
  Helper->>Page: wait for #sidebar-root attached
  Helper->>Page: wait for heading(componentName) visible
  Helper->>Page: wait for load state 'load'
  Helper-->>Test: resolved
  deactivate Helper
  end
Loading
sequenceDiagram
  autonumber
  participant Test as Test
  participant Ui as UiComponent
  participant Plugin as DependenciesUiPlugin
  participant Page as Playwright Page
  rect rgba(220,255,220,0.25)
  Test->>Ui: getDependencies()
  Ui-->>Test: DependenciesUiPlugin
  Test->>Page: goto(component dependencies URL)
  Test->>Plugin: checkAllBoxesPresent(Page)
  Plugin->>Page: assert titles visible
  Test->>Plugin: checkRelationsTitle(Page)
  Plugin->>Page: assert "Relations" visible
  Test->>Plugin: checkNodesPresent(Page)
  Plugin->>Page: assert component & gitops nodes present
  Test->>Plugin: goToGitopsDependency(Page)
  Plugin->>Page: click gitops node -> waitForPageLoad(Page, componentName-gitops)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • xinredhat
  • jsmid1

Provide constructive feedback focused on testing reliability, security, and maintainability: ensure waitForPageLoad timeouts and selectors are resilient to avoid flakiness, validate that video/screenshot defaults do not capture or retain sensitive data, centralize page-object strings to ease maintenance, prefer explicit selector timeouts where navigation assumptions are critical, and add unit/IT-level assertions around plugin wiring to catch injection regressions.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7e5eee2 and 340f952.

📒 Files selected for processing (1)
  • tests/ui/ui.test.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
tests/**/*.test.ts

📄 CodeRabbit inference engine (README.md)

Never print secrets in test logs

Files:

  • tests/ui/ui.test.ts
{tests/ui/**/*.ts,src/ui/**/*.ts}

📄 CodeRabbit inference engine (README.md)

When entering secrets in UI flows, blur the input fields before typing to avoid exposing values in screenshots

Files:

  • tests/ui/ui.test.ts
tests/**

⚙️ CodeRabbit configuration file

Focus on test coverage, maintainability, proper test structure, test isolation, mock usage, async test patterns, and test stability. Ensure tests are deterministic and properly clean up after themselves.

Files:

  • tests/ui/ui.test.ts
**/*.test.ts

⚙️ CodeRabbit configuration file

Ensure comprehensive test coverage, proper assertions, test isolation, async pattern correctness, mock usage, and test maintainability. Review for potential flaky tests and race conditions.

Files:

  • tests/ui/ui.test.ts
🧠 Learnings (1)
📚 Learning: 2025-07-31T07:43:28.355Z
Learnt from: rhopp
PR: redhat-appstudio/tssc-test#72
File: package.json:15-15
Timestamp: 2025-07-31T07:43:28.355Z
Learning: In the tssc-test project, the `test:ui` script intentionally does not include the `generate-config` step. This is expected behavior because UI tests are designed to run in scenarios where the project-configs.json file already exists - either from prior E2E test execution or from manual template creation in RHDH.

Applied to files:

  • tests/ui/ui.test.ts
🧬 Code graph analysis (1)
tests/ui/ui.test.ts (2)
src/ui/uiComponent.ts (1)
  • UiComponent (24-136)
src/ui/common.ts (3)
  • waitForPageLoad (41-54)
  • hideQuickStartIfVisible (22-39)
  • openTab (56-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Red Hat Konflux / tssc-test-on-pull-request
🔇 Additional comments (6)
tests/ui/ui.test.ts (6)

59-61: LGTM: stable navigation with waitForPageLoad

This reduces race conditions before checking the Git link.


81-81: LGTM: added waitForPageLoad to harden Docs navigation

This should reduce flakiness.


89-96: LGTM: scoped steps with explicit timeouts

Clear steps and reasonable timeouts improve test diagnostics and stability.


158-167: LGTM: dependencies graph validations are well-scoped

Good coverage on checkboxes, relations, nodes, and GitOps navigation.


168-175: LGTM: guarded Git check avoids mid-test skip and keeps signal strong

Conditional step with a warning is appropriate here.


187-193: LGTM: GitOps Docs flow with page readiness

Consistent use of helpers; timeout is appropriate for content load.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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: 17

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/ui/ui.test.ts (1)

29-37: beforeAll signature is invalid; remove the stray title argument

Playwright’s test.beforeAll expects a function (and optional timeout). Passing an empty string will cause a type/runtime error.

Apply this diff:

-  test.beforeAll('', async ({ testItem }) => {
+  test.beforeAll(async ({ testItem }) => {
     console.log('Running UI test for:', testItem);
     const componentName = testItem.getName();
     const imageName = `${componentName}`;
     console.log(`Creating component: ${componentName}`);

     // Assign the already created component
     component = await UiComponent.new(componentName, testItem, imageName);
   });
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0a7259e and ad239f8.

📒 Files selected for processing (6)
  • playwright.config.ts (2 hunks)
  • src/ui/common.ts (1 hunks)
  • src/ui/page-objects/dependencies_po.ts (1 hunks)
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1 hunks)
  • src/ui/uiComponent.ts (6 hunks)
  • tests/ui/ui.test.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
{src,tests}/ui/**

📄 CodeRabbit Inference Engine (README.md)

Place all UI-related files under either src/ui or tests/ui directories

Files:

  • src/ui/uiComponent.ts
  • src/ui/page-objects/dependencies_po.ts
  • src/ui/common.ts
  • tests/ui/ui.test.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
src/ui/**

⚙️ CodeRabbit Configuration File

Focus on page object pattern implementation, element selection strategies, UI test stability, maintainability, proper wait conditions, error handling, and flaky test prevention. Ensure tests are resilient to UI changes.

Files:

  • src/ui/uiComponent.ts
  • src/ui/page-objects/dependencies_po.ts
  • src/ui/common.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
src/ui/page-objects/**/*.ts

📄 CodeRabbit Inference Engine (README.md)

Store all Page Object Model files under src/ui/page-objects

Files:

  • src/ui/page-objects/dependencies_po.ts
src/ui/page-objects/**/*_po.ts

📄 CodeRabbit Inference Engine (README.md)

Name each Page Object file with a _po.ts suffix

Files:

  • src/ui/page-objects/dependencies_po.ts
playwright.config.ts

⚙️ CodeRabbit Configuration File

Review test configuration for optimal performance, browser configurations, device settings, reporter configurations, artifact management, and parallelization settings.

Files:

  • playwright.config.ts
tests/ui/ui.test.ts

📄 CodeRabbit Inference Engine (README.md)

Keep the main UI automation test file at tests/ui/ui.test.ts

Files:

  • tests/ui/ui.test.ts
tests/**

⚙️ CodeRabbit Configuration File

Focus on test coverage, maintainability, proper test structure, test isolation, mock usage, async test patterns, and test stability. Ensure tests are deterministic and properly clean up after themselves.

Files:

  • tests/ui/ui.test.ts
**/*.test.ts

⚙️ CodeRabbit Configuration File

Ensure comprehensive test coverage, proper assertions, test isolation, async pattern correctness, mock usage, and test maintainability. Review for potential flaky tests and race conditions.

Files:

  • tests/ui/ui.test.ts
src/ui/plugins/**/*.ts

📄 CodeRabbit Inference Engine (README.md)

src/ui/plugins/**/*.ts: Store plugin-related UI functionality under src/ui/plugins, organized by plugin type (e.g., git, ci); file name should match the plugin’s short name
Classes defined in src/ui/plugins must include either Ui or plugin in their class names

Files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
🧠 Learnings (5)
📚 Learning: 2025-08-18T07:39:58.810Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.810Z
Learning: Applies to src/ui/plugins/**/*.ts : Classes defined in src/ui/plugins must include either Ui or plugin in their class names

Applied to files:

  • src/ui/uiComponent.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-18T07:39:58.810Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.810Z
Learning: Applies to src/ui/plugins/**/*.ts : Store plugin-related UI functionality under src/ui/plugins, organized by plugin type (e.g., git, ci); file name should match the plugin’s short name

Applied to files:

  • src/ui/uiComponent.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-18T07:39:58.810Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.810Z
Learning: Applies to src/ui/page-objects/**/*_po.ts : Name each Page Object file with a _po.ts suffix

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
📚 Learning: 2025-08-18T07:39:58.810Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.810Z
Learning: Applies to tests/ui/ui.test.ts : Keep the main UI automation test file at tests/ui/ui.test.ts

Applied to files:

  • tests/ui/ui.test.ts
📚 Learning: 2025-07-31T07:43:28.355Z
Learnt from: rhopp
PR: redhat-appstudio/tssc-test#72
File: package.json:15-15
Timestamp: 2025-07-31T07:43:28.355Z
Learning: In the tssc-test project, the `test:ui` script intentionally does not include the `generate-config` step. This is expected behavior because UI tests are designed to run in scenarios where the project-configs.json file already exists - either from prior E2E test execution or from manual template creation in RHDH.

Applied to files:

  • tests/ui/ui.test.ts
🧬 Code Graph Analysis (3)
src/ui/uiComponent.ts (2)
src/rhtap/core/component.ts (1)
  • Component (14-253)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-42)
tests/ui/ui.test.ts (2)
src/ui/common.ts (1)
  • waitForPageLoad (18-27)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-42)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
src/ui/page-objects/dependencies_po.ts (1)
  • DependenciesPO (6-9)
🔇 Additional comments (1)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)

5-18: Plugin placement & naming compliant with guidelines

Class name and file path follow the src/ui/plugins conventions; includes "Ui" and "Plugin" in the class name and is organized under the plugin short name.

Copy link

@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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/ui/ui.test.ts (1)

16-24: Fix the suite comment for clarity

"This test should not" reads incomplete. Tighten phrasing to avoid confusion for future maintainers.

- * This test should not
- * 1. Login to the UI
- * TODO:
- * 2. Find a component in the UI
+ * Notes:
+ * 1) This suite does not perform UI login (auth is handled by storageState).
+ * 2) TODO: Add step to locate component in UI when navigation patterns stabilize.
♻️ Duplicate comments (7)
src/ui/page-objects/dependencies_po.ts (1)

6-9: Centralize remaining literals (node testId and gitops suffix) in the PO

Move the 'node' testId and '-gitops' suffix from the plugin into this PO to reduce brittleness and ease future UI changes.

 export const DependenciesPO = {
     titles: ['Depends on components', 'Depends on resources', 'Has subcomponents', 'Provided APIs', 'Consumed APIs'],
     relationsTitle: 'Relations',
+    nodeTestId: 'node',
+    gitopsSuffix: '-gitops',
 } as const;
src/ui/uiComponent.ts (1)

64-66: Decoupling: passing only componentName is the right call

Dropping unused repo URLs reduces coupling and keeps the plugin focused on UI concerns. Nice.

tests/ui/ui.test.ts (2)

118-123: Relations title check uses text — correct, since it’s not a heading

Good alignment with the UI reality (Relations isn’t a heading element).


4-6: Use a type-only import for the plugin to avoid unnecessary runtime dependency

This import is only used for typing the variable. Switch to a type-only import to keep the runtime graph lean and prevent accidental cycles.

-import { DependenciesUiPlugin } from '../../src/ui/plugins/dependencies/dependenciesUiPlugin';
+import type { DependenciesUiPlugin } from '../../src/ui/plugins/dependencies/dependenciesUiPlugin';
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (3)

14-18: Tighten heading match and add explicit return type to reduce flakiness

Use exact matching for headings and declare Promise for clarity and consistency.

Apply this diff:

-    async checkAllBoxesPresent(page: Page) {
+    async checkAllBoxesPresent(page: Page): Promise<void> {
         for (const title of DependenciesPO.titles) {
-            await expect(page.getByRole('heading', { name: title })).toBeVisible();
+            await expect(page.getByRole('heading', { name: title, exact: true })).toBeVisible();
         }
     }

24-28: Make node locators stricter, consistent, and DRY; add explicit return type

Unify on has + getByText({ exact: true }) instead of hasText to avoid substring matches; reuse a helper to reduce duplication; optionally assert uniqueness to catch duplicates early.

Apply this diff:

-    async checkNodesPresent(page: Page) {
-        const componentNode = page.getByTestId('node').filter({ has: page.getByText(this.componentName, { exact: true }) });
-        await expect(componentNode).toBeVisible();
-        await expect(page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` })).toBeVisible();
-    }
+    async checkNodesPresent(page: Page): Promise<void> {
+        const componentNode = this.nodeByName(page, this.componentName);
+        await expect(componentNode).toBeVisible();
+        // Optionally ensure uniqueness:
+        // await expect(componentNode).toHaveCount(1);
+
+        const gitopsNode = this.nodeByName(page, `${this.componentName}-gitops`);
+        await expect(gitopsNode).toBeVisible();
+        // Optionally ensure uniqueness:
+        // await expect(gitopsNode).toHaveCount(1);
+    }

To support the above, add a small helper inside this class and import Locator:

- import { expect, Page } from '@playwright/test';
+ import { expect, Page, Locator } from '@playwright/test';
@@
 export class DependenciesUiPlugin {
     private readonly componentName: string;
@@
     constructor(
         componentName: string,
     ) {
         this.componentName = componentName;
     }
+
+    private nodeByName(page: Page, name: string): Locator {
+        return page
+            .getByTestId('node')
+            .filter({ has: page.getByText(name, { exact: true }) });
+    }

Optional follow-up (outside this file) to centralize test IDs and avoid hard-coding:

// src/ui/page-objects/dependencies_po.ts
export const DependenciesPO = {
  titles: ['Depends on components', 'Depends on resources', 'Has subcomponents', 'Provided APIs', 'Consumed APIs'],
  relationsTitle: 'Relations',
  testIds: { node: 'node' },
};

Then use page.getByTestId(DependenciesPO.testIds.node) here.


30-35: Stabilize post-click flow; reuse the strict locator and declare return type

Reuse the helper for consistency and avoid hasText; keep the deterministic wait via waitForPageLoad. If the click triggers an in-page update (not navigation), this still works because waitForPageLoad waits on spinners and a heading; verify the expected heading matches ${componentName}-gitops.

Apply this diff:

-    async goToGitopsDependency(page: Page) {
-        const nodeLocator = page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` });
-        await expect(nodeLocator).toBeVisible();
-        await nodeLocator.click();
-        await waitForPageLoad(page, `${this.componentName}-gitops`);
-    }
+    async goToGitopsDependency(page: Page): Promise<void> {
+        const nodeLocator = this.nodeByName(page, `${this.componentName}-gitops`);
+        await expect(nodeLocator).toBeVisible();
+        await nodeLocator.click();
+        await waitForPageLoad(page, `${this.componentName}-gitops`);
+    }

Run this quick audit to standardize selectors and confirm navigation waits after page.goto are consistently applied across UI tests:

#!/bin/bash
set -euo pipefail

echo "Occurrences of hasText: (prefer has + getByText(..., { exact: true }))"
rg -nP --glob '{src,tests}/ui/**' '\bhasText\s*:'

echo
echo "Heading assertions missing exact: true:"
rg -nP --glob '{src,tests}/ui/**' "getByRole\(\s*'heading'\s*,\s*\{\s*name\s*:\s*[^}]*\}\s*\)" -C2

echo
echo "Calls to page.goto() with surrounding context (verify waitForPageLoad is used right after):"
rg -nP --glob '{src,tests}/ui/**' -C3 "page\.goto\s*\("
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ad239f8 and 45af072.

📒 Files selected for processing (6)
  • playwright.config.ts (1 hunks)
  • src/ui/common.ts (1 hunks)
  • src/ui/page-objects/dependencies_po.ts (1 hunks)
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1 hunks)
  • src/ui/uiComponent.ts (6 hunks)
  • tests/ui/ui.test.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
{src,tests}/ui/**

📄 CodeRabbit inference engine (README.md)

Place all UI-related files under either src/ui or tests/ui directories

Files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
  • tests/ui/ui.test.ts
  • src/ui/common.ts
src/ui/page-objects/**/*.ts

📄 CodeRabbit inference engine (README.md)

Store all Page Object Model files under src/ui/page-objects

Files:

  • src/ui/page-objects/dependencies_po.ts
src/ui/page-objects/**/*_po.ts

📄 CodeRabbit inference engine (README.md)

Name each Page Object file with a _po.ts suffix

Files:

  • src/ui/page-objects/dependencies_po.ts
src/ui/**

⚙️ CodeRabbit configuration file

Focus on page object pattern implementation, element selection strategies, UI test stability, maintainability, proper wait conditions, error handling, and flaky test prevention. Ensure tests are resilient to UI changes.

Files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
  • src/ui/common.ts
src/ui/plugins/**/*.ts

📄 CodeRabbit inference engine (README.md)

src/ui/plugins/**/*.ts: Store plugin-related UI functionality under src/ui/plugins, organized by plugin type (e.g., git, ci); file name should match the plugin’s short name
Classes defined in src/ui/plugins must include either Ui or plugin in their class names

Files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
playwright.config.ts

⚙️ CodeRabbit configuration file

Review test configuration for optimal performance, browser configurations, device settings, reporter configurations, artifact management, and parallelization settings.

Files:

  • playwright.config.ts
tests/ui/ui.test.ts

📄 CodeRabbit inference engine (README.md)

Keep the main UI automation test file at tests/ui/ui.test.ts

Files:

  • tests/ui/ui.test.ts
tests/**

⚙️ CodeRabbit configuration file

Focus on test coverage, maintainability, proper test structure, test isolation, mock usage, async test patterns, and test stability. Ensure tests are deterministic and properly clean up after themselves.

Files:

  • tests/ui/ui.test.ts
**/*.test.ts

⚙️ CodeRabbit configuration file

Ensure comprehensive test coverage, proper assertions, test isolation, async pattern correctness, mock usage, and test maintainability. Review for potential flaky tests and race conditions.

Files:

  • tests/ui/ui.test.ts
🧠 Learnings (8)
📚 Learning: 2025-08-18T07:39:58.821Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.821Z
Learning: Applies to src/ui/page-objects/**/*_po.ts : Name each Page Object file with a _po.ts suffix

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-21T09:14:32.201Z
Learnt from: Katka92
PR: redhat-appstudio/tssc-test#119
File: src/ui/plugins/dependencies/dependenciesUiPlugin.ts:26-28
Timestamp: 2025-08-21T09:14:32.201Z
Learning: In the dependencies UI page object for TSSC E2E testing framework, the Relations title (DependenciesPO.relationsTitle) is not a heading element, so getByRole('heading') should not be used for this element.

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-18T07:39:58.821Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.821Z
Learning: Applies to src/ui/plugins/**/*.ts : Store plugin-related UI functionality under src/ui/plugins, organized by plugin type (e.g., git, ci); file name should match the plugin’s short name

Applied to files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
  • tests/ui/ui.test.ts
📚 Learning: 2025-08-18T07:39:58.821Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.821Z
Learning: Applies to src/ui/plugins/**/*.ts : Classes defined in src/ui/plugins must include either Ui or plugin in their class names

Applied to files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
📚 Learning: 2025-08-19T11:28:24.837Z
Learnt from: jsmid1
PR: redhat-appstudio/tssc-test#101
File: src/ui/plugins/docs/docsUiPlugin.ts:26-28
Timestamp: 2025-08-19T11:28:24.837Z
Learning: The HTML `<strong>` element has an implicit ARIA role of `strong`, making `page.getByRole('strong')` a valid selector in Playwright tests for TSSC E2E testing framework.

Applied to files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-21T08:57:44.934Z
Learnt from: Katka92
PR: redhat-appstudio/tssc-test#119
File: playwright.config.ts:109-112
Timestamp: 2025-08-21T08:57:44.934Z
Learning: In the TSSC E2E testing framework, trace retention should not be enabled in Playwright configuration for CI jobs due to security concerns, as traces may leak sensitive information.

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-08-18T07:39:58.821Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-18T07:39:58.821Z
Learning: Applies to tests/ui/ui.test.ts : Keep the main UI automation test file at tests/ui/ui.test.ts

Applied to files:

  • tests/ui/ui.test.ts
📚 Learning: 2025-07-31T07:43:28.355Z
Learnt from: rhopp
PR: redhat-appstudio/tssc-test#72
File: package.json:15-15
Timestamp: 2025-07-31T07:43:28.355Z
Learning: In the tssc-test project, the `test:ui` script intentionally does not include the `generate-config` step. This is expected behavior because UI tests are designed to run in scenarios where the project-configs.json file already exists - either from prior E2E test execution or from manual template creation in RHDH.

Applied to files:

  • tests/ui/ui.test.ts
🧬 Code graph analysis (3)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (2)
src/ui/page-objects/dependencies_po.ts (1)
  • DependenciesPO (6-9)
src/ui/common.ts (1)
  • waitForPageLoad (18-31)
src/ui/uiComponent.ts (2)
src/rhtap/core/component.ts (1)
  • Component (14-253)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-36)
tests/ui/ui.test.ts (3)
src/ui/uiComponent.ts (1)
  • UiComponent (22-118)
src/ui/common.ts (2)
  • waitForPageLoad (18-31)
  • openTab (33-36)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-36)
🔇 Additional comments (9)
src/ui/page-objects/dependencies_po.ts (1)

1-9: Good PO extraction; selectors are readable and colocated

The PO name and placement follow the conventions; titles and relations label centralized here keep tests maintainable.

playwright.config.ts (1)

107-110: Global artifacts on failure configured correctly; aligns with CI security stance

Setting screenshot: 'only-on-failure' and video: 'retain-on-failure' at the global use level is correct and will apply to all projects. Thanks for keeping trace disabled per CI security guidance.

src/ui/uiComponent.ts (2)

20-33: Constructor injection for DependenciesUiPlugin improves testability and cohesion

Importing and wiring the DependenciesUiPlugin via constructor aligns with the existing pattern for Docs/Git and keeps responsibilities clean.


109-117: Getter matches existing style and docs are clear

Explicit public modifier and JSDoc keep the API consistent.

tests/ui/ui.test.ts (4)

59-61: Good use of waitForPageLoad after navigation

This reduces flakiness when checking the Git "View Source" link.


81-89: Docs checks are now guarded by waitForPageLoad — good

This should mitigate rendering races on slower clusters.


124-132: Explicit skip path for unsupported Git providers is clear

Good defensive guard; avoids false failures when the Git UI plugin is not available.


138-143: Great: reusing openTab and waitForPageLoad for GitOps Docs

Once openTab is updated to target role=tab and assert selection (see common.ts), this step becomes even more robust.

src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)

5-12: Plugin naming and placement align with guidelines

Class name includes “Ui”/“Plugin” and file path matches the plugin’s short name. Good adherence to repo conventions.

Copy link

@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: 4

♻️ Duplicate comments (13)
src/ui/page-objects/dependencies_po.ts (1)

6-9: Centralize commonly used identifiers (testId/suffix) in the PO

Move hard-coded literals from the plugin into the PO to reduce brittleness and improve maintainability. This also makes selector updates cheaper if the UI changes.

 export const DependenciesPO = {
     titles: ['Depends on components', 'Depends on resources', 'Has subcomponents', 'Provided APIs', 'Consumed APIs'],
     relationsTitle: 'Relations',
-}
+    nodeTestId: 'node',
+    gitopsSuffix: '-gitops',
+} as const

Follow-up: update plugin usages to reference DependenciesPO.nodeTestId and DependenciesPO.gitopsSuffix.

src/ui/common.ts (2)

18-31: Make waitForPageLoad deterministic; avoid snapshot waits

Snapshotting progress bars with .all() can miss spinners that appear slightly later. Prefer dynamic absence assertions and unify waits. Also assert heading exactness and wait for networkidle to reduce flakes.

 export async function waitForPageLoad(page: Page, name: string) {
-    const progressBars = page.getByRole('progressbar');
-    // Get all progressbar elements and wait until all are hidden
-    const bars = await progressBars.all();
-    if (bars.length > 0) {
-        await Promise.all(
-            bars.map(bar => expect(bar).toBeHidden({ timeout: 10000 }))
-        );
-    }
-
-    await expect(page.getByTestId('sidebar-root')).toBeAttached({ timeout: 5000 });
-    await expect(page.getByRole('heading', { name: name })).toBeVisible({ timeout: 20000 });
-    await page.waitForLoadState();
+    const progressBars = page.getByRole('progressbar');
+    // Wait until no progress bars remain (handles appear/disappear cycles)
+    await expect(progressBars).toHaveCount(0, { timeout: 20000 });
+
+    await expect(page.getByTestId('sidebar-root')).toBeVisible({ timeout: 20000 });
+    await expect(page.getByRole('heading', { name, exact: true })).toBeVisible({ timeout: 20000 });
+    await page.waitForLoadState('networkidle');
 }

33-36: Select tabs by role and assert activation

Target the tab role directly and assert aria-selected to confirm the click actually activated the tab. This reduces misclicks and improves reliability.

 export async function openTab(page: Page, tabName: string) {
-    const tab = page.getByRole('tablist').getByText(tabName);
-    await tab.click();
+    const tab = page.getByRole('tablist').getByRole('tab', { name: tabName, exact: true });
+    await tab.click();
+    await expect(tab).toHaveAttribute('aria-selected', 'true');
 }
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (4)

14-18: Tighten heading match and add explicit return type

Exact matching prevents accidental partial matches; explicit return types improve clarity.

-    async checkAllBoxesPresent(page: Page) {
-        for (const title of DependenciesPO.titles) {
-            await expect(page.getByRole('heading', { name: title })).toBeVisible();
-        }
-    }
+    async checkAllBoxesPresent(page: Page): Promise<void> {
+        for (const title of DependenciesPO.titles) {
+            await expect(page.getByRole('heading', { name: title, exact: true })).toBeVisible();
+        }
+    }

20-22: Non-heading “Relations”: use exact text and return type

Keep using getByText (since it's not a heading), but add exactness and an explicit return type.

-    async checkRelationsTitle(page: Page) {
-        await expect(page.getByText( DependenciesPO.relationsTitle )).toBeVisible();
-      }
+    async checkRelationsTitle(page: Page): Promise<void> {
+        await expect(page.getByText(DependenciesPO.relationsTitle, { exact: true })).toBeVisible();
+    }

24-28: Harden node locators; avoid hasText substring matches

Use the page object constants and exact text matching to minimize false positives. Add an explicit return type.

-    async checkNodesPresent(page: Page) {
-        const componentNode = page.getByTestId('node').filter({ has: page.getByText(this.componentName, { exact: true }) });
-        await expect(componentNode).toBeVisible();
-        await expect(page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` })).toBeVisible();
-    }
+    async checkNodesPresent(page: Page): Promise<void> {
+        const componentNode = page
+            .getByTestId(DependenciesPO.nodeTestId)
+            .filter({ has: page.getByText(this.componentName, { exact: true }) });
+        await expect(componentNode).toBeVisible();
+        // Optionally enforce uniqueness:
+        // await expect(componentNode).toHaveCount(1);
+
+        const gitopsNode = page
+            .getByTestId(DependenciesPO.nodeTestId)
+            .filter({ has: page.getByText(`${this.componentName}${DependenciesPO.gitopsSuffix}`, { exact: true }) });
+        await expect(gitopsNode).toBeVisible();
+        // Optionally enforce uniqueness:
+        // await expect(gitopsNode).toHaveCount(1);
+    }

30-35: Stabilize navigation to GitOps dependency and align with PO constants

Use exact text via has + getByText, return type, and PO constants. Keeping waitForPageLoad is good for determinism.

-    async goToGitopsDependency(page: Page) {
-        const nodeLocator = page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` });
-        await expect(nodeLocator).toBeVisible();
-        await nodeLocator.click();
-        await waitForPageLoad(page, `${this.componentName}-gitops`);
-    }
+    async goToGitopsDependency(page: Page): Promise<void> {
+        const nodeLocator = page
+            .getByTestId(DependenciesPO.nodeTestId)
+            .filter({ has: page.getByText(`${this.componentName}${DependenciesPO.gitopsSuffix}`, { exact: true }) });
+        await expect(nodeLocator).toBeVisible();
+        await nodeLocator.click();
+        await waitForPageLoad(page, `${this.componentName}${DependenciesPO.gitopsSuffix}`);
+    }
tests/ui/ui.test.ts (6)

4-5: Use a type-only import for DependenciesUiPlugin to keep the test runtime lean

You only use DependenciesUiPlugin as a type. Make it a type-only import to avoid pulling the module at runtime and reduce the risk of circular imports.

Apply this diff:

-import { DependenciesUiPlugin } from '../../src/ui/plugins/dependencies/dependenciesUiPlugin';
+import type { DependenciesUiPlugin } from '../../src/ui/plugins/dependencies/dependenciesUiPlugin';

If you adopt the attribute-based assertions suggested below, ensure expect is in scope. If the fixtures don’t re-export it, import it explicitly:

+import { expect } from '@playwright/test';

67-69: Add a concrete CI assertion to avoid false positives

Right now the test only navigates. Assert the CI tab is active (or a known CI widget is present) so failures are actionable.

Apply this diff:

   test('verify CI provider on CI tab', async ({ page }) => {
       await page.goto(`${component.getComponentUrl()}/ci`, { timeout: 20000 });
       await waitForPageLoad(page, component.getCoreComponent().getName());
+      await test.step('Assert CI tab is active', async () => {
+        const ciTab = page.getByRole('tab', { name: 'CI' });
+        await expect(ciTab).toHaveAttribute('aria-selected', 'true');
+      });
   });

Note: If expect is not already available via fixtures, add import { expect } from '@playwright/test' to the imports.


145-147: Drop unnecessary await; getDependencies() is synchronous

getDependencies() returns a value, not a Promise. Make the hook synchronous for simplicity and slight speedup.

Apply this diff:

-    test.beforeAll(async () => {
-      dependencies = await component.getDependencies();
-    });
+    test.beforeAll(() => {
+      dependencies = component.getDependencies();
+    });

149-154: Fast-fail: assert Dependencies tab is active after navigation

Catches routing issues early and makes failures more diagnosable.

Apply this diff:

     test('test dependency', async ({ page }) => {
       await page.goto(`${component.getComponentUrl()}/dependencies`, {
         timeout: 20000,
       });
       await waitForPageLoad(page, component.getCoreComponent().getName());
+      await test.step('Assert Dependencies tab is active', async () => {
+        const depTab = page.getByRole('tab', { name: 'Dependencies' });
+        await expect(depTab).toHaveAttribute('aria-selected', 'true');
+      });

155-164: Add a quick page-heading assertion before deep checks

Fail fast if navigation landed on the wrong subpage.

Apply this diff:

-      await test.step('Check all boxes', async () => {
+      await test.step('Assert Dependencies heading', async () => {
+        await page.getByRole('heading', { name: 'Dependencies' })
+          .waitFor({ state: 'visible', timeout: 20000 });
+      });
+      await test.step('Check all boxes', async () => {
         await dependencies.checkAllBoxesPresent(page);
       }, {timeout: 30000});

This version uses locator.waitFor to avoid introducing a new expect import.


175-177: Replace placeholder with a real GitOps CI assertion

Placeholders mask missing coverage. Either remove or implement a minimal, stable check.

Apply this diff:

-      await test.step('Check Gitops CI tab', async () => {
-        // TBD
-      });
+      await test.step('Check GitOps CI tab is active', async () => {
+        await openTab(page, 'CI');
+        await waitForPageLoad(page, `${component.getCoreComponent().getName()}-gitops`);
+        const ciTab = page.getByRole('tab', { name: 'CI' });
+        await expect(ciTab).toHaveAttribute('aria-selected', 'true');
+      });

Note: Add import { expect } from '@playwright/test' to the imports if not already available via fixtures.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 45af072 and 7d05a4e.

📒 Files selected for processing (6)
  • playwright.config.ts (1 hunks)
  • src/ui/common.ts (1 hunks)
  • src/ui/page-objects/dependencies_po.ts (1 hunks)
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1 hunks)
  • src/ui/uiComponent.ts (7 hunks)
  • tests/ui/ui.test.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/ui/**/*.ts

📄 CodeRabbit inference engine (README.md)

UI entity class names should include 'Ui' or 'plugin' to distinguish them from backend entities

Files:

  • src/ui/common.ts
  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
{tests/ui/**/*.ts,src/ui/**/*.ts}

📄 CodeRabbit inference engine (README.md)

When entering secrets in UI flows, blur the input fields before typing to avoid exposing values in screenshots

Files:

  • src/ui/common.ts
  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
  • tests/ui/ui.test.ts
src/ui/**

⚙️ CodeRabbit configuration file

Focus on page object pattern implementation, element selection strategies, UI test stability, maintainability, proper wait conditions, error handling, and flaky test prevention. Ensure tests are resilient to UI changes.

Files:

  • src/ui/common.ts
  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
src/ui/page-objects/**/*_po.ts

📄 CodeRabbit inference engine (README.md)

Each page object identifier file must be placed under src/ui/page-objects and have a _po.ts suffix

Files:

  • src/ui/page-objects/dependencies_po.ts
src/ui/plugins/**/*.ts

📄 CodeRabbit inference engine (README.md)

src/ui/plugins/**/*.ts: Classes in src/ui/plugins must include either 'Ui' or 'plugin' in their class names
Plugin file names in src/ui/plugins should match the short name of the plugin

Files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
playwright.config.ts

⚙️ CodeRabbit configuration file

Review test configuration for optimal performance, browser configurations, device settings, reporter configurations, artifact management, and parallelization settings.

Files:

  • playwright.config.ts
tests/**/*.test.ts

📄 CodeRabbit inference engine (README.md)

Never print secrets in test logs

Files:

  • tests/ui/ui.test.ts
tests/**

⚙️ CodeRabbit configuration file

Focus on test coverage, maintainability, proper test structure, test isolation, mock usage, async test patterns, and test stability. Ensure tests are deterministic and properly clean up after themselves.

Files:

  • tests/ui/ui.test.ts
**/*.test.ts

⚙️ CodeRabbit configuration file

Ensure comprehensive test coverage, proper assertions, test isolation, async pattern correctness, mock usage, and test maintainability. Review for potential flaky tests and race conditions.

Files:

  • tests/ui/ui.test.ts
🧠 Learnings (8)
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Applies to src/ui/page-objects/**/*_po.ts : Each page object identifier file must be placed under src/ui/page-objects and have a _po.ts suffix

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-21T09:14:32.201Z
Learnt from: Katka92
PR: redhat-appstudio/tssc-test#119
File: src/ui/plugins/dependencies/dependenciesUiPlugin.ts:26-28
Timestamp: 2025-08-21T09:14:32.201Z
Learning: In the dependencies UI page object for TSSC E2E testing framework, the Relations title (DependenciesPO.relationsTitle) is not a heading element, so getByRole('heading') should not be used for this element.

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Applies to src/ui/plugins/**/*.ts : Classes in src/ui/plugins must include either 'Ui' or 'plugin' in their class names

Applied to files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • src/ui/uiComponent.ts
📚 Learning: 2025-08-19T11:28:24.837Z
Learnt from: jsmid1
PR: redhat-appstudio/tssc-test#101
File: src/ui/plugins/docs/docsUiPlugin.ts:26-28
Timestamp: 2025-08-19T11:28:24.837Z
Learning: The HTML `<strong>` element has an implicit ARIA role of `strong`, making `page.getByRole('strong')` a valid selector in Playwright tests for TSSC E2E testing framework.

Applied to files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-21T08:57:44.934Z
Learnt from: Katka92
PR: redhat-appstudio/tssc-test#119
File: playwright.config.ts:109-112
Timestamp: 2025-08-21T08:57:44.934Z
Learning: In the TSSC E2E testing framework, trace retention should not be enabled in Playwright configuration for CI jobs due to security concerns, as traces may leak sensitive information.

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Set logging level lower than TRACE during tests to avoid capturing sensitive data (e.g., in network requests)

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Applies to tests/**/*.test.ts : Never print secrets in test logs

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-07-31T07:43:28.355Z
Learnt from: rhopp
PR: redhat-appstudio/tssc-test#72
File: package.json:15-15
Timestamp: 2025-07-31T07:43:28.355Z
Learning: In the tssc-test project, the `test:ui` script intentionally does not include the `generate-config` step. This is expected behavior because UI tests are designed to run in scenarios where the project-configs.json file already exists - either from prior E2E test execution or from manual template creation in RHDH.

Applied to files:

  • tests/ui/ui.test.ts
🧬 Code graph analysis (3)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (2)
src/ui/page-objects/dependencies_po.ts (1)
  • DependenciesPO (6-9)
src/ui/common.ts (1)
  • waitForPageLoad (18-31)
src/ui/uiComponent.ts (2)
src/rhtap/core/component.ts (1)
  • Component (14-253)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-36)
tests/ui/ui.test.ts (3)
src/ui/uiComponent.ts (1)
  • UiComponent (24-136)
src/ui/common.ts (2)
  • waitForPageLoad (18-31)
  • openTab (33-36)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Red Hat Konflux / tssc-test-on-pull-request
🔇 Additional comments (8)
playwright.config.ts (1)

107-110: Global artifacts-on-failure: LGTM and aligned with security stance

Good call setting screenshots/videos only on failure at the global use level. This also respects the no-trace-in-CI guidance to avoid leaking sensitive information in traces.

src/ui/uiComponent.ts (3)

29-37: Wiring DependenciesUiPlugin into UiComponent: looks good

The new private field, constructor injection, and assignment are consistent with existing plugin patterns and keep concerns separated.


72-74: Factory integration of DependenciesUiPlugin: good instantiation point

Constructing DependenciesUiPlugin in UiComponent.new mirrors how other UI plugins are created. Keeps composition centralized and predictable.


133-135: Getter for Dependencies plugin is consistent and documented

Public accessor matches style of other getters and the JSDoc clarifies its purpose. No issues.

tests/ui/ui.test.ts (4)

58-60: Good: standardized on waitForPageLoad after navigation

This reduces flakiness by relying on a single readiness heuristic across tests.


80-89: Docs flow readiness looks solid

Adding waitForPageLoad and splitting assertions into scoped test.steps improves stability and debuggability.


179-184: Good: GitOps Docs flow uses tab navigation plus readiness wait

Consistent with the rest of the suite and lowers flake risk.


30-33: Redact full object logging in UI tests

I’ve verified that the only place we’re printing a full fixture object is in tests/ui/ui.test.ts. Please update that call to log only the component name:

  • Location: tests/ui/ui.test.ts:30
    -    console.log('Running UI test for:', testItem);
    +    // Avoid logging the full fixture object to prevent secret leakage
    +    console.log(`Running UI test for: ${testItem.getName()}`);

I ran a scan across the codebase for console statements containing sensitive keywords; no other test files log full objects or secret values. The remaining logs in src/api/… only emit literal messages or resource names (not secret contents), so they don’t pose a leakage risk.

Comment on lines +107 to +110
use: {
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Be explicit about disabling Playwright traces

To guard against accidental trace enablement via overrides, explicitly set trace to 'off'. This keeps CI safe while still allowing local devs to override via CLI when needed.

   use: {
     screenshot: 'only-on-failure',
     video: 'retain-on-failure',
+    trace: 'off',
   },
📝 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
use: {
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
use: {
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'off',
},
🤖 Prompt for AI Agents
In playwright.config.ts around lines 107 to 110, the Playwright "use"
configuration sets screenshot and video options but does not explicitly disable
traces; add trace: 'off' to the use block to ensure traces are disabled by
default (preventing accidental CI trace collection) while still allowing local
overrides via CLI.

Comment on lines +5 to +12
export class DependenciesUiPlugin {
private readonly componentName: string;

constructor(
componentName: string,
) {
this.componentName = componentName;
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Use parameter property to reduce boilerplate

You can declare and assign componentName in the constructor signature to simplify the class.

-export class DependenciesUiPlugin {
-    private readonly componentName: string;
-
-    constructor(
-        componentName: string,
-    ) {
-        this.componentName = componentName;
-    }
+export class DependenciesUiPlugin {
+    constructor(private readonly componentName: string) {}
📝 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
export class DependenciesUiPlugin {
private readonly componentName: string;
constructor(
componentName: string,
) {
this.componentName = componentName;
}
export class DependenciesUiPlugin {
constructor(private readonly componentName: string) {}
// …rest of class methods…
}
🤖 Prompt for AI Agents
In src/ui/plugins/dependencies/dependenciesUiPlugin.ts around lines 5 to 12, the
class declares a private readonly componentName field and then assigns it in the
constructor; replace that boilerplate by using a TypeScript parameter property:
remove the explicit field declaration and change the constructor signature to
take the parameter as private readonly componentName: string so the property is
declared and assigned automatically (ensure any references continue to work).

@@ -11,7 +13,7 @@ const test = createBasicFixture();
* A complete test scenario for RHTAP UI plugins test:
*
* This test suite check the plugin in the UI and uses the component from backend e2e test.
* This test should not
* This test should not
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Fix incomplete doc sentence for clarity

The comment reads as unfinished. Make the intent explicit.

Apply this diff:

- * This test should not
+ * This test intentionally does not:
📝 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
* This test should not
* This test intentionally does not:
🤖 Prompt for AI Agents
In tests/ui/ui.test.ts around line 16, the inline comment "This test should not"
is an incomplete sentence; replace it with a complete, explicit sentence that
clearly states the test's intent (for example: "This test should not modify
global state and must run in isolation" or "This test should not perform network
requests"), choosing wording that accurately reflects what the test must avoid;
update the comment to that full sentence so the intent is unambiguous.

Comment on lines 165 to 181
await test.step('Check gitops git link', async () => {
// Skip test for not yet supported git providers
if (component.getGit() === undefined) {
console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
test.skip();
return;
}
await component.getGit()!.checkViewSourceLink(page);
});

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid test.skip inside a nested step; guard the step instead

Calling test.skip mid-test marks the entire test as skipped after work has already run, which skews reporting. Guard the step and proceed without skipping the whole test.

Apply this diff:

-      await test.step('Check gitops git link', async () => {
-        // Skip test for not yet supported git providers
-        if (component.getGit() === undefined) {
-          console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
-          test.skip();
-          return;
-        }
-        await component.getGit()!.checkViewSourceLink(page);
-      });
+      if (component.getGit()) {
+        await test.step('Check gitops "View Source" link', async () => {
+          await component.getGit()!.checkViewSourceLink(page);
+        });
+      } else {
+        console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
+      }
📝 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
await test.step('Check gitops git link', async () => {
// Skip test for not yet supported git providers
if (component.getGit() === undefined) {
console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
test.skip();
return;
}
await component.getGit()!.checkViewSourceLink(page);
});
if (component.getGit()) {
await test.step('Check gitops "View Source" link', async () => {
await component.getGit()!.checkViewSourceLink(page);
});
} else {
console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
}

Copy link

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/ui/common.ts (1)

27-39: Tighten Quick Start dismissal and avoid false clicks

Minor stability improvement: ensure the Hide button is matched exactly before clicking to avoid text collisions.

Apply this diff:

-    const hideButton = page.getByRole('button', { name: 'Hide' });
+    const hideButton = page.getByRole('button', { name: 'Hide', exact: true });
tests/ui/ui.test.ts (2)

40-47: Prefer waitForPageLoad for home page readiness to standardize load checks

Unifies page-load behavior and reduces flakiness by using the shared helper.

   test('open developer hub', async ({ page }) => {
     await page.goto(component.getCoreComponent().getDeveloperHub().getUrl(), {
       timeout: 20000,
     });
-    await page
-      .getByRole('heading', { name: CommonPO.welcomeTitle })
-      .waitFor({ state: 'visible', timeout: 20000 });
+    await waitForPageLoad(page, CommonPO.welcomeTitle);
   });

31-37: Remove sensitive logging and clarify setup comment in UI tests

The grep scan confirms there are two places in tests/ui/ui.test.ts where we log the full testItem object (which can expose secrets) and a generic comment that could be clearer about what’s happening. Let’s update both to improve security, clarity, and maintainability.

Affected location:

  • tests/ui/ui.test.ts, around lines 31–37

Suggested changes:

-    console.log('Running UI test for:', testItem);
     const componentName = testItem.getName();
-    console.log(`Creating component: ${componentName}`);
+    console.log(`Starting UI test for component: ${componentName}`);
 
-    // Assign the already created component
+    // Initialize the UiComponent wrapper for the existing backend component (we’re not creating a new backend here)
     component = await UiComponent.new(componentName, testItem, componentName);

• We've removed the first log that prints out testItem to avoid leaking any sensitive fields.
• We’ve updated the second log to reference only componentName for clearer, non-sensitive output.
• The comment now explicitly states that we’re wrapping an existing backend component, improving onboarding clarity.

♻️ Duplicate comments (15)
playwright.config.ts (1)

107-110: Explicitly disable Playwright traces to avoid accidental leakage in CI

Given prior guidance not to retain traces in CI, set trace: 'off' to guard against overrides in child projects or env-based merges.

Apply this diff:

   use: {
     screenshot: 'only-on-failure',
     video: 'retain-on-failure',
+    trace: 'off',
   },
src/ui/page-objects/dependencies_po.ts (1)

6-9: Centralize frequently used selectors and suffixes to reduce brittleness

The plugin hard-codes testId 'node' and the '-gitops' suffix. Exporting them here improves maintainability and keeps selector drift in one place.

Apply this diff:

 export const DependenciesPO = {
     titles: ['Depends on components', 'Depends on resources', 'Has subcomponents', 'Provided APIs', 'Consumed APIs'],
     relationsTitle: 'Relations',
+    nodeTestId: 'node',
+    gitopsSuffix: '-gitops',
 }
src/ui/common.ts (2)

41-54: Avoid snapshotting progress bars; wait for dynamic absence and network idle

Snapshotting locators with .all() can miss late-appearing spinners. Prefer dynamic absence and a deterministic networkidle wait.

Apply this diff:

 export async function waitForPageLoad(page: Page, name: string) {
-    const progressBars = page.getByRole('progressbar');
-    // Get all progressbar elements and wait until all are hidden
-    const bars = await progressBars.all();
-    if (bars.length > 0) {
-        await Promise.all(
-            bars.map(bar => expect(bar).toBeHidden({ timeout: 10000 }))
-        );
-    }
-
-    await expect(page.getByTestId('sidebar-root')).toBeAttached({ timeout: 5000 });
-    await expect(page.getByRole('heading', { name: name })).toBeVisible({ timeout: 20000 });
-    await page.waitForLoadState();
+    const progressBars = page.getByRole('progressbar');
+    // Wait until no progress bars remain (handles appear/disappear cycles)
+    await expect(progressBars).toHaveCount(0, { timeout: 20000 });
+
+    await expect(page.getByTestId('sidebar-root')).toBeVisible({ timeout: 20000 });
+    await expect(page.getByRole('heading', { name, exact: true })).toBeVisible({ timeout: 20000 });
+    await page.waitForLoadState('networkidle');
 }

56-59: Select tabs by role and assert activation to prevent misclicks

Target role='tab' with an exact name and verify aria-selected after the click to reduce flakiness.

Apply this diff:

-export async function openTab(page: Page, tabName: string) {
-    const tab = page.getByRole('tablist').getByText(tabName);
-    await tab.click();
-}
+export async function openTab(page: Page, tabName: string): Promise<void> {
+    const tab = page.getByRole('tablist').getByRole('tab', { name: tabName, exact: true });
+    await tab.click();
+    await expect(tab).toHaveAttribute('aria-selected', 'true');
+}
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (4)

20-22: Relations title is not a heading; ensure exact text match and add return type

Avoid role-based selection here, and prefer exact text matching.

Apply this diff:

-    async checkRelationsTitle(page: Page) {
-        await expect(page.getByText( DependenciesPO.relationsTitle )).toBeVisible();
-      }
+    async checkRelationsTitle(page: Page): Promise<void> {
+        await expect(page.getByText(DependenciesPO.relationsTitle, { exact: true })).toBeVisible();
+    }

5-12: Use a parameter property to reduce boilerplate

Simplify by declaring componentName in the constructor parameter list.

Apply this diff:

-export class DependenciesUiPlugin {
-    private readonly componentName: string;
-
-    constructor(
-        componentName: string,
-    ) {
-        this.componentName = componentName;
-    }
+export class DependenciesUiPlugin {
+    constructor(private readonly componentName: string) {}

14-18: Make heading matches exact and declare return type

Exact heading matching reduces accidental partial matches; explicit return type aids readability.

Apply this diff:

-    async checkAllBoxesPresent(page: Page) {
+    async checkAllBoxesPresent(page: Page): Promise<void> {
         for (const title of DependenciesPO.titles) {
-            await expect(page.getByRole('heading', { name: title })).toBeVisible();
+            await expect(page.getByRole('heading', { name: title, exact: true })).toBeVisible();
         }
     }

24-28: Tighten node locators and avoid hasText; reference selectors from the PO

Use has: getByText(..., { exact: true }) for precision and centralize 'node' and '-gitops' via DependenciesPO. Also unify quotes.

Apply this diff:

-    async checkNodesPresent(page: Page) {
-        const componentNode = page.getByTestId('node').filter({ has: page.getByText(this.componentName, { exact: true }) });
-        await expect(componentNode).toBeVisible();
-        await expect(page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` })).toBeVisible();
-    }
+    async checkNodesPresent(page: Page): Promise<void> {
+        const componentNode = page
+            .getByTestId(DependenciesPO.nodeTestId)
+            .filter({ has: page.getByText(this.componentName, { exact: true }) });
+        await expect(componentNode).toBeVisible();
+
+        const gitopsNode = page
+            .getByTestId(DependenciesPO.nodeTestId)
+            .filter({ has: page.getByText(`${this.componentName}${DependenciesPO.gitopsSuffix}`, { exact: true }) });
+        await expect(gitopsNode).toBeVisible();
+    }
tests/ui/ui.test.ts (7)

17-17: Fix incomplete doc sentence for clarity

Make the intent explicit to keep the suite’s contract unambiguous.

- * This test should not
+ * This test intentionally does not:

4-6: Consolidate common imports; use a type-only import for DependenciesUiPlugin

Reduce runtime deps and circular import risk by erasing the plugin symbol at compile time; also merge the two common imports for maintainability.

-import { hideQuickStartIfVisible, openTab } from '../../src/ui/common';
-import { waitForPageLoad } from '../../src/ui/common';
-import { DependenciesUiPlugin } from '../../src/ui/plugins/dependencies/dependenciesUiPlugin';
+import { hideQuickStartIfVisible, openTab, waitForPageLoad } from '../../src/ui/common';
+import type { DependenciesUiPlugin } from '../../src/ui/plugins/dependencies/dependenciesUiPlugin';

68-70: Add a concrete assertion on the CI page to avoid false positives

Right now the test only navigates. Assert the CI tab is active (or a known CI widget is visible) to validate rendering.

   test('verify CI provider on CI tab', async ({ page }) => {
     await page.goto(`${component.getComponentUrl()}/ci`, { timeout: 20000 });
     await waitForPageLoad(page, component.getCoreComponent().getName());
+    await test.step('Assert CI tab is active', async () => {
+      const ciTab = page.getByRole('tab', { name: 'CI' });
+      await expect(ciTab).toHaveAttribute('aria-selected', 'true');
+    });
   });

149-155: Drop unnecessary await and async in beforeAll when fetching Dependencies plugin

getDependencies() returns a value, not a Promise. Keep the hook synchronous.

-    test.beforeAll(async () => {
-      dependencies = await component.getDependencies();
-    });
+    test.beforeAll(() => {
+      dependencies = component.getDependencies();
+    });

156-161: Fast-fail by asserting the Dependencies tab is active after navigation

Catches routing issues early and tightens the signal.

   test('test dependency', async ({ page }) => {
     await page.goto(`${component.getComponentUrl()}/dependencies`, {
       timeout: 20000,
     });
     await waitForPageLoad(page, component.getCoreComponent().getName());
+    await test.step('Assert Dependencies tab is active', async () => {
+      const depTab = page.getByRole('tab', { name: 'Dependencies' });
+      await expect(depTab).toHaveAttribute('aria-selected', 'true');
+    });

172-181: Avoid test.skip inside a nested step; guard the step instead

Skipping mid-test after prior work skews reporting and can hide partial execution. Guard the step with an if and only run it when supported.

-      await test.step('Check gitops git link', async () => {
-        // Skip test for not yet supported git providers
-        if (component.getGit() === undefined) {
-          console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
-          test.skip();
-          return;
-        }
-        await component.getGit()!.checkViewSourceLink(page);
-      });
+      if (component.getGit()) {
+        await test.step('Check gitops "View Source" link', async () => {
+          await component.getGit()!.checkViewSourceLink(page);
+        });
+      } else {
+        console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
+      }

182-185: Replace placeholder with a real CI assertion (or remove it)

A no-op step always passes and weakens coverage.

-      await test.step('Check Gitops CI tab', async () => {
-        // TBD
-      });
+      await test.step('Check GitOps CI tab is active', async () => {
+        await openTab(page, 'CI');
+        const ciTab = page.getByRole('tab', { name: 'CI' });
+        await expect(ciTab).toHaveAttribute('aria-selected', 'true');
+      });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7d05a4e and 4bd3d7d.

📒 Files selected for processing (6)
  • playwright.config.ts (1 hunks)
  • src/ui/common.ts (2 hunks)
  • src/ui/page-objects/dependencies_po.ts (1 hunks)
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1 hunks)
  • src/ui/uiComponent.ts (7 hunks)
  • tests/ui/ui.test.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/ui/page-objects/**/*_po.ts

📄 CodeRabbit inference engine (README.md)

Each page object identifier file must be placed under src/ui/page-objects and have a _po.ts suffix

Files:

  • src/ui/page-objects/dependencies_po.ts
src/ui/**/*.ts

📄 CodeRabbit inference engine (README.md)

UI entity class names should include 'Ui' or 'plugin' to distinguish them from backend entities

Files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/common.ts
  • src/ui/uiComponent.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
{tests/ui/**/*.ts,src/ui/**/*.ts}

📄 CodeRabbit inference engine (README.md)

When entering secrets in UI flows, blur the input fields before typing to avoid exposing values in screenshots

Files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/common.ts
  • src/ui/uiComponent.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
  • tests/ui/ui.test.ts
src/ui/**

⚙️ CodeRabbit configuration file

Focus on page object pattern implementation, element selection strategies, UI test stability, maintainability, proper wait conditions, error handling, and flaky test prevention. Ensure tests are resilient to UI changes.

Files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/common.ts
  • src/ui/uiComponent.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
playwright.config.ts

⚙️ CodeRabbit configuration file

Review test configuration for optimal performance, browser configurations, device settings, reporter configurations, artifact management, and parallelization settings.

Files:

  • playwright.config.ts
src/ui/plugins/**/*.ts

📄 CodeRabbit inference engine (README.md)

src/ui/plugins/**/*.ts: Classes in src/ui/plugins must include either 'Ui' or 'plugin' in their class names
Plugin file names in src/ui/plugins should match the short name of the plugin

Files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
tests/**/*.test.ts

📄 CodeRabbit inference engine (README.md)

Never print secrets in test logs

Files:

  • tests/ui/ui.test.ts
tests/**

⚙️ CodeRabbit configuration file

Focus on test coverage, maintainability, proper test structure, test isolation, mock usage, async test patterns, and test stability. Ensure tests are deterministic and properly clean up after themselves.

Files:

  • tests/ui/ui.test.ts
**/*.test.ts

⚙️ CodeRabbit configuration file

Ensure comprehensive test coverage, proper assertions, test isolation, async pattern correctness, mock usage, and test maintainability. Review for potential flaky tests and race conditions.

Files:

  • tests/ui/ui.test.ts
🧠 Learnings (8)
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Applies to src/ui/page-objects/**/*_po.ts : Each page object identifier file must be placed under src/ui/page-objects and have a _po.ts suffix

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-21T09:14:32.201Z
Learnt from: Katka92
PR: redhat-appstudio/tssc-test#119
File: src/ui/plugins/dependencies/dependenciesUiPlugin.ts:26-28
Timestamp: 2025-08-21T09:14:32.201Z
Learning: In the dependencies UI page object for TSSC E2E testing framework, the Relations title (DependenciesPO.relationsTitle) is not a heading element, so getByRole('heading') should not be used for this element.

Applied to files:

  • src/ui/page-objects/dependencies_po.ts
  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-08-21T08:57:44.934Z
Learnt from: Katka92
PR: redhat-appstudio/tssc-test#119
File: playwright.config.ts:109-112
Timestamp: 2025-08-21T08:57:44.934Z
Learning: In the TSSC E2E testing framework, trace retention should not be enabled in Playwright configuration for CI jobs due to security concerns, as traces may leak sensitive information.

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Set logging level lower than TRACE during tests to avoid capturing sensitive data (e.g., in network requests)

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Applies to tests/**/*.test.ts : Never print secrets in test logs

Applied to files:

  • playwright.config.ts
📚 Learning: 2025-08-25T11:24:45.518Z
Learnt from: CR
PR: redhat-appstudio/tssc-test#0
File: README.md:0-0
Timestamp: 2025-08-25T11:24:45.518Z
Learning: Applies to src/ui/plugins/**/*.ts : Classes in src/ui/plugins must include either 'Ui' or 'plugin' in their class names

Applied to files:

  • src/ui/uiComponent.ts
📚 Learning: 2025-08-19T11:28:24.837Z
Learnt from: jsmid1
PR: redhat-appstudio/tssc-test#101
File: src/ui/plugins/docs/docsUiPlugin.ts:26-28
Timestamp: 2025-08-19T11:28:24.837Z
Learning: The HTML `<strong>` element has an implicit ARIA role of `strong`, making `page.getByRole('strong')` a valid selector in Playwright tests for TSSC E2E testing framework.

Applied to files:

  • src/ui/plugins/dependencies/dependenciesUiPlugin.ts
📚 Learning: 2025-07-31T07:43:28.355Z
Learnt from: rhopp
PR: redhat-appstudio/tssc-test#72
File: package.json:15-15
Timestamp: 2025-07-31T07:43:28.355Z
Learning: In the tssc-test project, the `test:ui` script intentionally does not include the `generate-config` step. This is expected behavior because UI tests are designed to run in scenarios where the project-configs.json file already exists - either from prior E2E test execution or from manual template creation in RHDH.

Applied to files:

  • tests/ui/ui.test.ts
🧬 Code graph analysis (3)
src/ui/uiComponent.ts (2)
src/rhtap/core/component.ts (1)
  • Component (14-253)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-36)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (2)
src/ui/page-objects/dependencies_po.ts (1)
  • DependenciesPO (6-9)
src/ui/common.ts (1)
  • waitForPageLoad (41-54)
tests/ui/ui.test.ts (3)
src/ui/uiComponent.ts (1)
  • UiComponent (24-136)
src/ui/common.ts (3)
  • waitForPageLoad (41-54)
  • hideQuickStartIfVisible (22-39)
  • openTab (56-59)
src/ui/plugins/dependencies/dependenciesUiPlugin.ts (1)
  • DependenciesUiPlugin (5-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Red Hat Konflux / tssc-test-on-pull-request
🔇 Additional comments (6)
playwright.config.ts (1)

107-110: Correct placement for artifacts configuration under use

Good move centralizing screenshot/video defaults at the global use level. This ensures consistent artifact retention across all projects without duplications or ignored keys.

src/ui/uiComponent.ts (2)

133-135: Getter for Dependencies plugin looks good

Public getter is consistent with other accessors and supports the new workflow cleanly.


72-74: Factory wiring is sound

Instantiating DependenciesUiPlugin with the component name and threading it through the UiComponent constructor is straightforward and low-coupling.

tests/ui/ui.test.ts (3)

59-61: LGTM: Consistent use of waitForPageLoad on Overview navigation

This aligns with the unified page-load strategy and should reduce flakiness.


81-82: LGTM: Added waitForPageLoad before Docs assertions

Good call; this will mitigate race conditions with Docs rendering.


186-191: LGTM: GitOps docs validation is robust

Opening the Docs tab, waiting for page readiness with the GitOps name, and asserting content via the plugin is a stable pattern.

Comment on lines +30 to +35
async goToGitopsDependency(page: Page) {
const nodeLocator = page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` });
await expect(nodeLocator).toBeVisible();
await nodeLocator.click();
await waitForPageLoad(page, `${this.componentName}-gitops`);
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Stabilize navigation to GitOps dependency and reuse centralized selectors

Reuse the stricter locator and page-object constants; keep the deterministic wait you added.

Apply this diff:

-    async goToGitopsDependency(page: Page) {
-        const nodeLocator = page.getByTestId("node").filter({ hasText: `${this.componentName}-gitops` });
-        await expect(nodeLocator).toBeVisible();
-        await nodeLocator.click();
-        await waitForPageLoad(page, `${this.componentName}-gitops`);
-    }
+    async goToGitopsDependency(page: Page): Promise<void> {
+        const nodeLocator = page
+            .getByTestId(DependenciesPO.nodeTestId)
+            .filter({ has: page.getByText(`${this.componentName}${DependenciesPO.gitopsSuffix}`, { exact: true }) });
+        await expect(nodeLocator).toBeVisible();
+        await nodeLocator.click();
+        await waitForPageLoad(page, `${this.componentName}${DependenciesPO.gitopsSuffix}`);
+    }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/ui/plugins/dependencies/dependenciesUiPlugin.ts around lines 30 to 35,
replace the ad-hoc locator with the centralized, stricter page-object selector
constant (use the shared node test-id/selector from the page object module and a
dedicated "gitops" item text constant) so the locator is deterministic and
reusable; keep the await expect(...).toBeVisible(), await click(), and the
existing waitForPageLoad(page, `${this.componentName}-gitops`) call to maintain
the deterministic wait behavior; ensure you import the selector/constant from
the page-object module and update the locator usage to reference those constants
instead of building the selector inline.

Comment on lines +29 to 37
private dependencies!: DependenciesUiPlugin;

private constructor(component: Component, git: GitPlugin | undefined, docs: DocsUiPlugin, registry: RegistryPlugin | undefined) {
private constructor(component: Component, git: GitPlugin | undefined, docs: DocsUiPlugin, registry: RegistryPlugin | undefined, dependencies: DependenciesUiPlugin) {
this.component = component;
this.git = git;
this.docs = docs;
this.registry = registry;
this.dependencies = dependencies;
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Drop definite assignment (!) and make dependency field readonly

The field is always initialized via the constructor. Prefer a readonly declaration and remove the definite assignment assertion for stronger typing.

Apply this diff:

-  private dependencies!: DependenciesUiPlugin;
+  private readonly dependencies: DependenciesUiPlugin;
📝 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
private dependencies!: DependenciesUiPlugin;
private constructor(component: Component, git: GitPlugin | undefined, docs: DocsUiPlugin, registry: RegistryPlugin | undefined) {
private constructor(component: Component, git: GitPlugin | undefined, docs: DocsUiPlugin, registry: RegistryPlugin | undefined, dependencies: DependenciesUiPlugin) {
this.component = component;
this.git = git;
this.docs = docs;
this.registry = registry;
this.dependencies = dependencies;
}
private readonly dependencies: DependenciesUiPlugin;
private constructor(
component: Component,
git: GitPlugin | undefined,
docs: DocsUiPlugin,
registry: RegistryPlugin | undefined,
dependencies: DependenciesUiPlugin
) {
this.component = component;
this.git = git;
this.docs = docs;
this.registry = registry;
this.dependencies = dependencies;
}
🤖 Prompt for AI Agents
In src/ui/uiComponent.ts around lines 29 to 37, the private field dependencies
uses a definite assignment assertion (!) but is always set in the constructor;
remove the '!' and mark the field as readonly (private readonly dependencies:
DependenciesUiPlugin) so the compiler knows it is initialized and immutable, and
keep the constructor assignment as-is to satisfy initialization.

Comment on lines 121 to 125
public getComponentUrl(): string {
const developerHubUrl = this.component.getDeveloperHub().getUrl();
const componentName = this.component.getName();
return `${developerHubUrl}/catalog/default/component/${componentName}`;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

URL-encode component names to handle special characters

If component names contain spaces or special characters, the current URL can break. Encode the segment.

Apply this diff:

   public getComponentUrl(): string {
     const developerHubUrl = this.component.getDeveloperHub().getUrl();
     const componentName = this.component.getName();
-    return `${developerHubUrl}/catalog/default/component/${componentName}`;
+    return `${developerHubUrl}/catalog/default/component/${encodeURIComponent(componentName)}`;
   }
📝 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
public getComponentUrl(): string {
const developerHubUrl = this.component.getDeveloperHub().getUrl();
const componentName = this.component.getName();
return `${developerHubUrl}/catalog/default/component/${componentName}`;
}
public getComponentUrl(): string {
const developerHubUrl = this.component.getDeveloperHub().getUrl();
const componentName = this.component.getName();
return `${developerHubUrl}/catalog/default/component/${encodeURIComponent(componentName)}`;
}
🤖 Prompt for AI Agents
In src/ui/uiComponent.ts around lines 121 to 125, the component name is inserted
into the URL without encoding which breaks URLs when names contain spaces or
special characters; update the method to URL-encode the componentName (e.g. use
encodeURIComponent on the name) before composing the URL so the returned string
safely encodes any unsafe characters, keeping the rest of the path unchanged.

@jsmid1
Copy link
Collaborator

jsmid1 commented Aug 27, 2025

/retest

Comment on lines 172 to 180
await test.step('Check gitops git link', async () => {
// Skip test for not yet supported git providers
if (component.getGit() === undefined) {
console.warn(`Skipping Git test as testing ${component.getCoreComponent().getGit().getGitType()} is not supported`);
test.skip();
return;
}
await component.getGit()!.checkViewSourceLink(page);
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we move this step under Verify Git describe section?

@konflux-ci-qe-bot
Copy link

@Katka92: The following test has Failed, say /retest to rerun failed tests.

PipelineRun Name Status Rerun command Build Log Test Log
e2e-4.19-rcpb7 Failed /retest View Pipeline Log View Test Logs

Inspecting Test Artifacts

To inspect your test artifacts, follow these steps:

  1. Install ORAS (see the ORAS installation guide).
  2. Download artifacts with the following commands:
mkdir -p oras-artifacts
cd oras-artifacts
oras pull quay.io/konflux-test-storage/rhtap-team/rhtap-cli:e2e-4.19-rcpb7

Test results analysis

<not enabled>

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.

3 participants