Skip to content

RHDHBUGS-3057: Refactor e2e tests for the scorecard plugin#3245

Merged
dzemanov merged 7 commits into
redhat-developer:mainfrom
imykhno:scorecard/implement-e2e-tests
Jun 10, 2026
Merged

RHDHBUGS-3057: Refactor e2e tests for the scorecard plugin#3245
dzemanov merged 7 commits into
redhat-developer:mainfrom
imykhno:scorecard/implement-e2e-tests

Conversation

@imykhno

@imykhno imykhno commented May 27, 2026

Copy link
Copy Markdown
Contributor

Hey, I just made a Pull Request!

This refactoring follows the merge of #2923. The expectation was that tests will be reviewed and added those tests that are missing to test scorecard aggregation card customization. Additionally, this PR incorporates the feedback and comments raised during the review of #2923.

PR is for:

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

…functions

Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@rhdh-qodo-merge

rhdh-qodo-merge Bot commented May 27, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0)

Grey Divider


Action required

1. Aggregation wait logic inverted ✓ Resolved 🐞 Bug ≡ Correctness
Description
waitForAggregationResponse treats mismatches as “valid” (uses !==) and then rejects matching
responses, so any use with options.expectedResult will hang until timeout. This makes the helper
unusable for value-based waiting and will cause future tests to intermittently stall or always fail
when they start using expectedResult.
Code

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts[R86-94]

+        const isAverageScoreValid =
+          expected.averageScore !== undefined &&
+          result?.averageScore !== expected.averageScore;
+        const isTotalValid =
+          expected.total !== undefined && result?.total !== expected.total;
+
+        if (!isAverageScoreValid || !isTotalValid) {
+          return false;
+        }
Relevance

⭐⭐⭐ High

Team fixes e2e race/flakiness; similar stabilization changes merged (race fix #2558; e2e hardening
#2703).

PR-#2558
PR-#2703

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The predicate marks a response as valid only when the returned values differ from the expected ones,
and then returns false when either check is not "valid", which rejects the matching response and
causes an eventual timeout.

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts[50-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`waitForAggregationResponse` currently rejects responses that match the provided `expectedResult` because it checks `result != expected` and requires those checks to be "valid". This makes the predicate unsatisfiable when `expectedResult` is provided.

### Issue Context
This helper is exported and intended for synchronizing tests on specific aggregation payloads. With the current logic, any future test that passes `expectedResult` will time out.

### Fix Focus Areas
- workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts[50-103]

### Suggested change
Rewrite the checks as:
- `averageOk = expected.averageScore === undefined || result?.averageScore === expected.averageScore`
- `totalOk = expected.total === undefined || result?.total === expected.total`
- `return averageOk && totalOk`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Homepage waits can resolve early ✓ Resolved 🐞 Bug ☼ Reliability
Description
setupHomepageAllCardsNoData creates waitForAggregationResponse promises before adding/saving
widgets, so those waits can be satisfied by pre-reload requests and not guarantee that the
post-page.reload() fetches finished. This undermines the purpose of waiting for homepage cards to
finish loading and can introduce test flakiness during reload-dependent assertions.
Code

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts[R74-83]

+  await mockAggregationNoDataFound(page);
+
+  const responseWaits = Object.values(AGGREGATED_CARDS_METRIC_IDS).map(id =>
+    waitForAggregationResponse(page, id),
+  );
+
+  await addAggregatedScorecardWidgets(homePage);
+  await page.reload();
+  await Promise.all(responseWaits);
+}
Relevance

⭐⭐⭐ High

E2E reliability issues around timing/reload are historically addressed and merged (#2144, #2558,
#2703).

PR-#2144
PR-#2558
PR-#2703

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The code constructs the wait promises before the actions that can already trigger aggregation
fetches (navigate/edit/save). Because the waits are not tied to the reload call, they can resolve
before the reload-triggered requests complete.

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts[70-83]
workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts[57-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`setupHomepageAllCardsNoData` sets up response waits too early, so `Promise.all(responseWaits)` may complete without actually waiting for the requests triggered by the subsequent `page.reload()`.

### Issue Context
The helper intends to stabilize the test by waiting for aggregation responses after a reload (to clear React Query cache). If the waits resolve due to earlier requests (during navigation/edit/save), the reload-triggered network activity may still be in flight when assertions run.

### Fix Focus Areas
- workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts[70-83]

### Suggested change
Create waits immediately before calling `page.reload()` (after widgets are added/saved), e.g.:
1) `await addAggregatedScorecardWidgets(homePage)`
2) create `responseWaits`
3) `await Promise.all([page.reload(), ...responseWaits])`

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@rhdh-gh-app

rhdh-gh-app Bot commented May 27, 2026

Copy link
Copy Markdown

Changed Packages

Package Name Package Path Changeset Bump Current Version
app-legacy workspaces/scorecard/packages/app-legacy none v0.0.0

@codecov

codecov Bot commented May 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 53.24%. Comparing base (dda0303) to head (ffe1cd3).
⚠️ Report is 51 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3245   +/-   ##
=======================================
  Coverage   53.23%   53.24%           
=======================================
  Files        2413     2414    +1     
  Lines       86358    86367    +9     
  Branches    23912    23907    -5     
=======================================
+ Hits        45974    45982    +8     
- Misses      38907    38908    +1     
  Partials     1477     1477           
Flag Coverage Δ *Carryforward flag
adoption-insights 83.58% <ø> (ø) Carriedforward from 78d6614
ai-integrations 70.03% <ø> (ø) Carriedforward from 78d6614
app-defaults 69.60% <ø> (ø) Carriedforward from 78d6614
augment 46.39% <ø> (ø) Carriedforward from 78d6614
bulk-import 72.86% <ø> (ø) Carriedforward from 78d6614
cost-management 16.49% <ø> (ø) Carriedforward from 78d6614
dcm 32.85% <ø> (ø) Carriedforward from 78d6614
extensions 61.79% <ø> (ø) Carriedforward from 78d6614
global-floating-action-button 74.30% <ø> (ø) Carriedforward from 78d6614
global-header 61.68% <ø> (ø) Carriedforward from 78d6614
homepage 51.52% <ø> (ø) Carriedforward from 78d6614
konflux 91.01% <ø> (ø) Carriedforward from 78d6614
lightspeed 68.33% <ø> (ø) Carriedforward from 78d6614
mcp-integrations 81.59% <ø> (ø) Carriedforward from 78d6614
orchestrator 36.36% <ø> (ø) Carriedforward from 78d6614
quickstart 62.88% <ø> (ø) Carriedforward from 78d6614
sandbox 79.49% <ø> (ø) Carriedforward from 78d6614
scorecard 83.86% <ø> (+0.01%) ⬆️
theme 64.54% <ø> (ø) Carriedforward from 78d6614
translations 8.49% <ø> (ø) Carriedforward from 78d6614
x2a 78.47% <ø> (ø) Carriedforward from 78d6614

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

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

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…nts and improve widget handling

Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@rhdh-qodo-merge

Copy link
Copy Markdown

Review Summary by Qodo

Refactor scorecard e2e tests with aggregation utilities and improved test structure

🧪 Tests ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Refactored e2e test structure with new aggregation constants and utility functions
• Reorganized constants from homepageWidgetTitles.ts to aggregations.ts with improved naming
• Extracted common test setup logic into reusable homepageWidgetUtils.ts helper functions
• Enhanced API utilities with aggregation response waiting and validation capabilities
• Improved test organization by grouping related aggregation tests with shared setup
Diagram
flowchart LR
  A["Old Constants<br/>homepageWidgetTitles.ts"] -->|Migrate & Rename| B["New Constants<br/>aggregations.ts"]
  C["Scattered Test Setup<br/>Code"] -->|Extract| D["Utility Functions<br/>homepageWidgetUtils.ts"]
  E["Basic API Utils<br/>apiUtils.ts"] -->|Enhance| F["Aggregation Response<br/>Waiting & Validation"]
  B --> G["Cleaner Test Code<br/>scorecard.test.ts"]
  D --> G
  F --> G

Loading

Grey Divider

File Changes

1. workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts ⚙️ Configuration changes +60/-0

New aggregation constants file with metadata

• New file consolidating aggregation-related constants previously scattered across files
• Defines AGGREGATED_CARDS_METRIC_IDS with metric and KPI identifiers
• Defines AGGREGATED_CARDS_WIDGET_TITLES mapping widget titles for UI interactions
• Defines AGGREGATED_CARDS_METADATA with complete aggregation configuration including id, title,
 and metricId

workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts


2. workspaces/scorecard/packages/app-legacy/e2e-tests/constants/homepageWidgetTitles.ts Refactoring +0/-32

Removed in favor of aggregations.ts

• File deleted and replaced by aggregations.ts
• Constants migrated with improved naming conventions
• Old naming (e.g., withDeprecatedMetricId) replaced with clearer names (e.g., jiraMetricId)

workspaces/scorecard/packages/app-legacy/e2e-tests/constants/homepageWidgetTitles.ts


3. workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts Refactoring +2/-4

Updated imports and constant references

• Updated import to use new aggregations.ts constants file
• Updated widget title reference from withOpenPrsWeightedKpi to openPrsWeightedKpi
• Simplified constant naming in card pattern matching logic

workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts


View more (4)
4. workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts 🧪 Tests +219/-489

Major test refactoring with utility extraction

• Extracted common test setup functions (addWidgets, addAggregatedScorecardWidgets) to
 homepageWidgetUtils.ts
• Removed test.afterEach hook that was unrouting API responses
• Reorganized test structure using test.beforeAll and test.afterAll for aggregation card setup
• Refactored test groups to use shared setupHomepageAggregationCard utility function
• Updated all constant references from old naming to new AGGREGATED_CARDS_METADATA structure
• Consolidated duplicate test logic and improved test readability with metadata-driven approach
• Added new test for empty aggregated response across all default homepage cards

workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts


5. workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts ✨ Enhancement +65/-0

Enhanced API utilities for aggregation responses

• Added Response type import from @playwright/test
• Created WaitForAggregationResponseOptions type for aggregation response validation
• Added isAggregationDataUrl helper function to identify aggregation data endpoints
• Implemented waitForAggregationResponse function to wait for specific aggregation responses with
 optional result validation

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts


6. workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts ✨ Enhancement +83/-0

New homepage widget utility functions

• New utility file extracting common test setup functions
• Provides addWidgets function for adding single widget to homepage
• Provides addAggregatedScorecardWidgets function for adding all aggregation widgets
• Provides setupHomepageAggregationCard function for complete card setup with mocking and reload
• Provides setupHomepageAllCardsNoData function for testing empty data scenarios across all cards

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts


7. workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts ✨ Enhancement +47/-0

Added mock function for empty aggregation responses

• Added imports for empty response constants (emptyGithubAggregatedResponse,
 emptyJiraAggregatedResponse, emptyOpenPrsWeightedAggregatedResponse)
• Implemented mockAggregationNoDataFound function to mock all aggregation endpoints with empty
 responses
• Function intelligently routes requests based on aggregation ID to appropriate empty response

workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts


Grey Divider

Qodo Logo

@rhdh-qodo-merge rhdh-qodo-merge Bot added enhancement New feature or request Tests labels May 27, 2026
Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@imykhno imykhno force-pushed the scorecard/implement-e2e-tests branch from ca1706a to 1d79f52 Compare May 27, 2026 09:13
@dzemanov

dzemanov commented Jun 1, 2026

Copy link
Copy Markdown
Member

/publish

@durandom

durandom commented Jun 2, 2026

Copy link
Copy Markdown
Member

/fs-review

2 similar comments
@durandom

durandom commented Jun 2, 2026

Copy link
Copy Markdown
Member

/fs-review

@durandom

durandom commented Jun 2, 2026

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review

Findings

High

  • [logic-error] workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts:66 — Property AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi does not exist on the new AGGREGATED_CARDS_WIDGET_TITLES object defined in aggregations.ts. The new object uses key gitHubOpenPrsWeightedKpi. Accessing .openPrsWeightedKpi evaluates to undefined, so the else if branch will never match, and the weighted KPI card name will fall through to the generic else branch using escapeRegex(cardName). While the fallback still produces a working regex for the literal title string, the specialized branch (which also matches the ScorecardOpenPrsWeightedKpi pattern) is bypassed, reducing robustness. With as const, TypeScript should flag this at compile time.
    Remediation: Change AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi to AGGREGATED_CARDS_WIDGET_TITLES.gitHubOpenPrsWeightedKpi.

Low

  • [test-isolation] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts:114 — The test.afterEach that called page.unroute() for metrics and aggregations routes was removed. setupHomepageAggregationCard registers new Playwright route handlers on every invocation without unrouting previous ones. Playwright evaluates routes LIFO so the latest handler wins, but stale handlers accumulate. While not a correctness bug for the current test flow, it makes the test suite slightly fragile.
    Remediation: Consider calling page.unroute(route) before page.route(route, ...) inside mockApiResponse, or restore the afterEach cleanup.

  • [naming-convention] workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts:29 — Inconsistent casing for the GitHub prefix across property names: githubMetricId, githubOpenPrsKpi use all-lowercase github, while gitHubOpenPrsWeightedKpi uses camelCase gitHub. This inconsistency also appears in scorecardResponseUtils.ts with gitHubWeightedPartiallyAggregatedResponse and gitHubPartiallyAggregatedResponse. The gitHub casing may reflect an upstream config key name, but it breaks the local naming pattern.
    Remediation: Standardize to github (lowercase) prefix across all new identifiers to match the established convention.

  • [coverage-reduced] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts:441 — The old 'GitHub weighted KPI: drill-down, average card, and table' test verified the drill-down average card center percent, table headers, and entity names on the drill-down page. The replacement 'Verify open drill-down link' test only checks navigation and page title. The 'Accessibility on weighted average card' test was also removed without replacement.

Info

  • [import-organization] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts:16 — The import type { Response } is on a separate line from import { Page, expect } from the same module. Could be merged into a single import statement.

  • [naming-convention] workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts:40 — The AGGREGATED_CARDS_METADATA object uses different key names than the parallel AGGREGATED_CARDS_METRIC_IDS and AGGREGATED_CARDS_WIDGET_TITLES objects. This is an intentional design choice for descriptiveness but adds cognitive overhead.

  • [return-type] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts:48 — The exported addAggregatedScorecardWidgets function lacks an explicit : Promise<void> return type annotation, unlike companion functions in the same file.

Previous run

Review

Findings

Medium

  • [test-integrity] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The test.afterEach block that called page.unroute("**/api/scorecard/metrics/**") and page.unroute("**/api/scorecard/aggregations/**") is removed without replacement. All tests in the outer test.describe share a single Page instance (created in beforeAll). Playwright's page.route() stacks handlers — without explicit cleanup, route handlers registered by one test.describe block's beforeAll persist into subsequent blocks. While Playwright's LIFO dispatch means later-registered handlers shadow earlier ones for the same URL, glob patterns like **/api/scorecard/aggregations/** (used by mockHomepageAggregationsPermissionDenied and mockAggregationNoDataFound) will intercept requests that no subsequent handler explicitly overrides. This changes the test isolation contract and could cause flaky failures if future tests are added to existing describe blocks without their own route setup.
    Remediation: Restore the afterEach unroute calls, or add await page.unrouteAll({ behavior: 'wait' }) in each test.beforeAll before registering new routes.

  • [naming-convention] workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts:28 — The key gitHubOpenPrsWeightedKpi uses uppercase 'H' in 'GitHub' while all other GitHub-related keys use lowercase 'h' (githubMetricId, githubOpenPrsKpi). This inconsistency propagates into scorecardResponseUtils.ts fixture names (gitHubPartiallyAggregatedResponse, gitHubWeightedPartiallyAggregatedResponse vs githubCustomAggregatedResponse, githubAggregatedResponse). The codebase convention (routes, page objects, existing fixtures) uniformly uses lowercase github as a camelCase prefix.
    Remediation: Normalize to githubOpenPrsWeightedKpi (lowercase 'h') across constant maps and fixture variable names.

Low

  • [naming-convention] workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts:40 — The keys of AGGREGATED_CARDS_METADATA use a different naming scheme from AGGREGATED_CARDS_METRIC_IDS and AGGREGATED_CARDS_WIDGET_TITLES (e.g., jiraDeprecatedMetricId vs jiraMetricId). The three parallel maps cannot be indexed with the same key, breaking the pattern from the old homepageWidgetTitles.ts where the two maps shared identical keys. Consider collapsing into a single map or aligning keys.

  • [missing-authorization] — The PR references Jira ticket RHDHBUGS-3057 but has no linked GitHub issue. The Jira ticket is not accessible via GitHub API. The PR body provides reasonable context (follow-up to merged PR RHIDP-12121: Support "StatusGrouped" and "Average" types of aggregation #2923), which serves as partial provenance.

Info

  • [naming-coherence] The rename from getThresholdsSnapshot to getStatusGroupedCardSnapshot improves clarity by matching the domain terminology. The new getAverageCardSnapshot follows the same pattern. Both are consistent with how the production code categorizes aggregation types.
Previous run (2)

Review

Findings

High

  • [logic-error] workspaces/scorecard/packages/app-legacy/e2e-tests/pages/HomePage.ts:125 — Key mismatch: AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi does not exist in the new aggregations.ts constants file. The correct key is gitHubOpenPrsWeightedKpi. At runtime, this evaluates to undefined, so the specialized else if branch (which matches the alternative ScorecardOpenPrsWeightedKpi identifier via regex) never fires. The card falls through to the generic else branch, losing the ability to match the component identifier.
    Remediation: Change AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi to AGGREGATED_CARDS_WIDGET_TITLES.gitHubOpenPrsWeightedKpi.

Low

  • [test-weakened] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts:111 — The afterEach block that called page.unroute() for metrics and aggregations routes was removed. Without cleanup, Playwright route handlers accumulate on the shared page instance. While Playwright's LIFO ordering means newer handlers take precedence (tests behave correctly), accumulated handlers are a hygiene concern that could complicate debugging.

  • [pattern-violation] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts:51AGGREGATED_CARDS_WIDGET_TITLES[instanceId] uses a dynamic string key (from Object.keys()) to index an as const object. Works at runtime but bypasses TypeScript type safety.

Info

  • [sub-agent-failure] The style-conventions and intent-coherence sub-agents could not be dispatched (sonnet/haiku models unavailable on this deployment). Lightweight orchestrator assessment: the PR is a well-scoped test refactoring aligned with its stated intent (RHDHBUGS-3057, follow-up to RHIDP-12121: Support "StatusGrouped" and "Average" types of aggregation #2923), following existing codebase patterns.
Previous run (3)

Review

Findings

Medium

  • [coverage-reduced] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The old "GitHub weighted KPI: drill-down, average card, and table" test (previously in the "Average aggregation KPI" describe block) verified that the drill-down page for the weighted average KPI correctly displays the average card center percent (51.5%), table headers, and entity names (5 entities). This test was removed entirely and no equivalent exists in the new "Configured aggregation KPI - 'average' type" describe block. The new "Verify open drill-down link" test only checks navigation and page title but does not verify drill-down card content or the entity table for the average aggregation type.
    Remediation: Add a test within the "average" type describe that navigates to the drill-down page and verifies the average card center percent, table headers, and entity names — mirroring the removed test's assertions.

  • [coverage-reduced] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The old "Accessibility on weighted average card" test ran axe accessibility checks on the weighted average homepage card. This test was removed with no replacement in the new "Configured aggregation KPI - 'average' type" describe block. Other card type describes retain their accessibility assertions (via testInfo parameter and runAccessibilityTests calls), but the average card type no longer has one.
    Remediation: Add an accessibility test within the "average" type describe that renders the weighted average card and calls runAccessibilityTests.

Low

  • [test-isolation] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The PR removes the test.afterEach hook that called page.unroute('**/api/scorecard/metrics/**') and page.unroute('**/api/scorecard/aggregations/**'). Route handlers registered by mockApiResponse (via page.route) now accumulate across tests and test.describe blocks without cleanup. While Playwright's LIFO handler ordering means the most recently registered handler takes priority, stale handlers remain and could cause subtle issues if a later test expects an unmocked route to reach the real server. Consider restoring route cleanup in an afterEach or afterAll hook, or calling page.unrouteAll().

  • [edge-case] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts:48addAggregatedScorecardWidgets iterates Object.keys(AGGREGATED_CARDS_METRIC_IDS) (typed as string[]) to index into AGGREGATED_CARDS_WIDGET_TITLES. If these two as const objects ever diverge in keys, AGGREGATED_CARDS_WIDGET_TITLES[instanceId] will silently be undefined, causing a confusing test failure rather than a compile-time error.

  • [naming-convention] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — In the "Verify status grouped drill-down link" test within the deprecated metricId describe, the variable githubOpenPrsTitle evaluates translations.metric['jira.open_issues'].title. The value is used correctly (passed to expectPageTitle with 'jira.open_issues'), but the name appears copy-pasted from a different context and could mislead future maintainers.

Previous run (4)

Review

Findings

High

  • [logic-error] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/mockHomepageAggregations.ts:77mockAggregationNoDataFound intercepts **/api/scorecard/aggregations/** which matches both data URLs (e.g., /aggregations/openPrsKpi) and metadata URLs (e.g., /aggregations/openPrsKpi/metadata). For metadata URLs, url.split('/').pop() returns 'metadata', which doesn't match any aggregation ID, so it falls through to the 404 branch. This means card titles/descriptions fail to load, producing an error UI state rather than the intended "no data found" state. The existing mockHomepageAggregationsPermissionDenied correctly handles this by checking url.includes('/metadata') and returning 200 with metadata (lines 58-64).
    Remediation: Add a metadata check at the top of the route handler, similar to mockHomepageAggregationsPermissionDenied: check url.includes('/metadata') and return the appropriate metadata response with status 200 using the existing aggregationMetadataForRequestUrl helper (which would need to be exported or the logic duplicated).

Medium

  • [test-weakened] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The top-level test.afterEach that previously unrouted both **/api/scorecard/metrics/** and **/api/scorecard/aggregations/** after every test has been removed. In the refactored code, only some describe blocks have test.afterAll with partial cleanup. Other describe blocks ('Deprecated homepage card', 'Default aggregation', 'Drill down logic', 'Unsupported aggregation type') have no route cleanup. Additionally, **/api/scorecard/metrics/** is never unrouted. Since all tests share the same page instance, stale mock routes from earlier describe blocks can leak into later tests. The wildcard page.unroute('**/api/scorecard/aggregations/**') in some afterAll blocks also removes ALL aggregation handlers, not just the ones from that block.
    Remediation: Either restore a top-level test.afterEach that cleans up all mock routes, or ensure every test.describe block that sets up routes has a corresponding test.afterAll that removes them.

  • [test-weakened] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The original 'GitHub weighted KPI: drill-down, average card, and table' test verified the full drill-down flow: drill-down card center percent (51.5%), page title (expectPageTitle), table headers (expectTableHeadersVisible), and entity names (expectEntityNamesVisible for 5 entities). This test was removed entirely. The replacement 'Verify open drill-down link' test only checks clickDrillDownLink() and expectOnPage(...) — the drill-down card rendering, table headers, and entity list assertions are lost.
    Remediation: Add back the missing assertions for the weighted KPI drill-down: verify drill-down card center percent, page title, table headers, and entity names in the 'average type' describe block.

Low

  • [test-weakened] workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts — The 'Verify entity counts' tests in the 'Deprecated homepage card' and 'Default aggregation' blocks previously called mockAllDefaultHomepageAggregationsSuccess and addAggregatedScorecardWidgets (setting up all 5 cards), verifying entity counts render correctly when all cards are present simultaneously. The refactored version uses test.beforeAll with setupHomepageAggregationCard (single card only). This changes what the test validates — multi-card interaction is no longer tested.

  • [edge-case] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts:53isAggregationDataUrl uses url.split('/').pop() which would include query parameters if present, causing match failures.

  • [naming-convention] workspaces/scorecard/packages/app-legacy/e2e-tests/utils/homepageWidgetUtils.ts:32addWidgets is exported but only used internally by setupHomepageAggregationCard within the same file. Consider removing the export.

Info

  • [design-direction] workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts — The new AGGREGATED_CARDS_METADATA constant combining id, title, and metricId into structured objects is a good architectural improvement that reduces cross-referencing and the risk of mismatched values.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

});
}

export async function mockAggregationNoDataFound(page: Page): Promise<void> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[high] logic-error

mockAggregationNoDataFound intercepts /api/scorecard/aggregations/ which matches metadata URLs. For metadata URLs, url.split('/').pop() returns 'metadata' which doesn't match any aggregation ID, falling through to the 404 branch. Card titles/descriptions fail to load, producing an error UI instead of the intended 'no data found' state. The existing mockHomepageAggregationsPermissionDenied correctly handles this by checking url.includes('/metadata').

Suggested fix: Add a metadata check at the top of the route handler: if url.includes('/metadata'), return 200 with the appropriate metadata response using the existing aggregationMetadataForRequestUrl helper.

function isAggregationDataUrl(url: string, aggregationId: string): boolean {
return (
url.includes(`/api/scorecard/aggregations/${aggregationId}`) &&
!url.includes('/metadata')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] edge-case

isAggregationDataUrl uses url.split('/').pop() which would include query parameters if present, causing match failures.

response: object;
status?: number;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] naming-convention

addWidgets is exported but only used internally by setupHomepageAggregationCard within the same file. Consider removing the export.

…get handling

Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jun 4, 2026

@dzemanov dzemanov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you @imykhno for this nice refactoring, I have only a couple of small comments, otherwise looks nice.

Can you please also confirm that all of these comments are fixed by the PR or are tracked in other issue or were fixed before?

Are we testing when some entities are reporting errors in aggregation scorecards? E.g we show x/y in the aggregation card and some rows in drill down do not show status. If not, we can implement those as part of https://redhat.atlassian.net/browse/RHIDP-14421

Comment thread workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts Outdated
Comment thread workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts Outdated
Comment thread workspaces/scorecard/packages/app-legacy/e2e-tests/constants/aggregations.ts Outdated
Comment thread workspaces/scorecard/packages/app-legacy/e2e-tests/utils/apiUtils.ts Outdated
Comment thread workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts Outdated
Comment thread workspaces/scorecard/packages/app-legacy/e2e-tests/scorecard.test.ts Outdated
Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 9, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:47 PM UTC · Completed 3:57 PM UTC
Commit: 0b54852 · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

@@ -129,11 +111,6 @@ test.describe('Scorecard Plugin Tests', () => {
await page?.context()?.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] test-weakened

The afterEach block that called page.unroute() was removed. Route handlers accumulate on the shared page instance across tests.

}

await homePage.saveChanges();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] pattern-violation

Dynamic string key from Object.keys() used to index an as-const object bypasses TypeScript type safety.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Jun 9, 2026
…avior

Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Review · Started 5:08 PM UTC
Commit: 0b54852 · View workflow run →

@imykhno

imykhno commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Comment:

Thank you @imykhno for this nice refactoring, I have only a couple of small comments, otherwise looks nice.

Can you please also confirm that all of these comments are fixed by the PR or are tracked in other issue or were fixed before?

Answers:

Screenshot 2026-05-05 at 12 18 03 Screenshot 2026-05-05 at 12 18 26
  • #2923 (comment): The await page.reload(); still exist, however was refactored.

Comment:

Are we testing when some entities are reporting errors in aggregation scorecards? E.g we show x/y in the aggregation card and some rows in drill down do not show status. If not, we can implement those as part of https://redhat.atlassian.net/browse/RHIDP-14421

Answers:

  • Yes, you are right. We hadn't tested the described behaviour. I have added the tests case Verify card shows healthy/total entity ratio when calculation errors exist to cover it. These tests were added under both the average and statusGroup aggregation type groups.

CC @dzemanov

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jun 9, 2026
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:08 PM UTC · Completed 5:19 PM UTC
Commit: 0b54852 · View workflow run →

…gation config

Signed-off-by: Ihor Mykhno <imykhno@redhat.com>
@sonarqubecloud

Copy link
Copy Markdown

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:44 AM UTC · Completed 9:56 AM UTC
Commit: 23ab1ea · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

} else if (
cardName === AGGREGATED_CARDS_WIDGET_TITLES.withOpenPrsWeightedKpi
) {
} else if (cardName === AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[high] logic-error

Property AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi does not exist on the new AGGREGATED_CARDS_WIDGET_TITLES object defined in aggregations.ts. The new object uses key gitHubOpenPrsWeightedKpi. Accessing .openPrsWeightedKpi evaluates to undefined, so the else if branch will never match and the weighted KPI card name will fall through to the generic else branch.

Suggested fix: Change AGGREGATED_CARDS_WIDGET_TITLES.openPrsWeightedKpi to AGGREGATED_CARDS_WIDGET_TITLES.gitHubOpenPrsWeightedKpi.

@@ -129,11 +114,6 @@ test.describe('Scorecard Plugin Tests', () => {
await page?.context()?.close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] test-isolation

The test.afterEach that called page.unroute() was removed. Route handlers accumulate without cleanup, making the test suite slightly fragile to reordering.

Suggested fix: Consider calling page.unroute(route) before page.route(route, ...) inside mockApiResponse, or restore the afterEach cleanup.

export const AGGREGATED_CARDS_WIDGET_TITLES = {
jiraMetricId: 'Scorecard: With deprecated metricId property (Jira)',
githubMetricId: 'Scorecard: With default aggregation config (GitHub)',
githubOpenPrsKpi: 'Scorecard: GitHub open PRs',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] naming-convention

Inconsistent casing for the GitHub prefix: githubMetricId and githubOpenPrsKpi use lowercase github, while gitHubOpenPrsWeightedKpi uses camelCase gitHub. Same inconsistency in scorecardResponseUtils.ts.

Suggested fix: Standardize to github (lowercase) prefix across all new identifiers.

@@ -462,394 +441,419 @@ test.describe('Scorecard Plugin Tests', () => {
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] coverage-reduced

The weighted KPI drill-down test and accessibility test were removed without full replacement. The new drill-down link test only verifies navigation, not drill-down card content or entity table.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Jun 10, 2026

@dzemanov dzemanov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for the changes

@dzemanov dzemanov merged commit 36cb2bc into redhat-developer:main Jun 10, 2026
92 checks passed
@imykhno imykhno deleted the scorecard/implement-e2e-tests branch June 10, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants