Skip to content

fix: resolve Playwright CI failures across 4 test suites#13014

Merged
kubestellar-hive[bot] merged 1 commit into
kubestellar:mainfrom
RajdeepKushwaha5:fix/playwright-ci-failures
May 11, 2026
Merged

fix: resolve Playwright CI failures across 4 test suites#13014
kubestellar-hive[bot] merged 1 commit into
kubestellar:mainfrom
RajdeepKushwaha5:fix/playwright-ci-failures

Conversation

@RajdeepKushwaha5
Copy link
Copy Markdown
Contributor

Use a coding agent. This PR was generated and reviewed with Claude Code (Sonnet 4.6), which knows all codebase patterns (isDemoData, useCardLoadingState, locale strings, DCO).

📌 Fixes

Related to #4190

Note: Using "Related to" instead of "Fixes" so the mentorship tracking issue #4190 is not auto-closed by this PR.


📝 Summary of Changes

Resolves four categories of failing Playwright CI tests identified in the April 28 mentor triage: cluster-admin-cards.spec.ts (25 tests), find-and-search.spec.ts (Ctrl+K shortcut), a11y.spec.ts (axe label rule), and not-found.spec.ts (2 tests). All fixes are surgical — no refactoring, no new abstractions.


Changes Made

  • web/src/config/dashboards/cluster-admin.ts — Added etcd_status, dns_health, and admission_webhooks cards to the cluster-admin default layout (row 10, y=28, w=4, h=3). The preset was not auto-pinning these three infrastructure monitoring cards, which are registered in CARD_COMPONENTS and the unified config but were absent from the default placement list.

  • web/e2e/cluster-admin-cards.spec.ts — Updated the "Default Layout" test: EXPECTED_CARD_COUNT 21 → 24, added 'etcd_status', 'dns_health', 'admission_webhooks' to EXPECTED_CARD_TYPES. Pre-existing String.raw warnings at lines 509–547, 805 were not introduced here.

  • web/src/components/layout/navbar/SearchDropdown.tsx — Fixed Ctrl+K focus race. openSearch() triggers an async React state update; calling inputRef.current?.focus() synchronously before the state commits means the input is not yet in its open/focusable state. Deferred the focus call with requestAnimationFrame(() => inputRef.current?.focus()) so it runs after React's next paint.

  • web/src/components/clusters/components/CardConfigModal.tsx — Three form controls (cluster <select>, namespace <input>, max-items <input>) had <label> elements with no htmlFor and controls with no id. Added matching htmlFor/id pairs (card-config-cluster, card-config-namespace, card-config-max-items) to satisfy axe's label rule (WCAG 2.1 AA, SC 1.3.1).

  • web/src/App.tsx — The pathless layout route (<Route element={<ProtectedRoute><Layout/></ProtectedRoute>}>) matches every path. The sibling <Route path="*"><NotFound/></Route> at the bottom of the route tree was therefore unreachable for authenticated users — unmatched paths rendered Layout with an empty outlet instead of NotFound. Moved the wildcard inside the layout route so NotFound renders correctly for any unmatched authenticated URL.


Checklist

  • I used a coding agent (Claude Code, Sonnet 4.6) to generate/review this code
  • I have reviewed the project's contribution guidelines
  • New cards target console-marketplace, not this repo (no new cards added — only existing registered cards added to a default layout)
  • isDemoData is wired correctly (no card component changes — layout config and route fixes only)
  • I have written unit tests for the changes (spec updated to match new card count)
  • I have tested the changes locally and ensured they work as expected
  • All commits are signed with DCO (git commit -s)

Screenshots or Logs (if applicable)

Root cause trace — cluster-admin-cards (25 failures):

The mentor's hint was: "The /cluster-admin dashboard presets may not be auto-pinning these cards."
Confirmed by tracing useDashboardCardsCARD_COMPONENTS registry → cluster-admin.ts default config. etcd_status, dns_health, and admission_webhooks are all registered at cardRegistry.ts:733–736 and in the lazy-loaded cluster-admin-bundle, but the default placement list only had 21 cards stopping at row 9.

Root cause trace — find-and-search (Ctrl+K focus):

// Before (race condition)
openSearch()                      // schedules state update → React re-renders async
inputRef.current?.focus()         // runs NOW, before re-render — input not focusable yet
emitGlobalSearchOpened('keyboard')

// After (correct)
openSearch()
requestAnimationFrame(() => inputRef.current?.focus())  // deferred past next paint
emitGlobalSearchOpened('keyboard')

Root cause trace — a11y (CardConfigModal label violations):

// Before — axe flags label-without-for and input-without-label
<label className="...">Filter by Cluster</label>
<select value={...} onChange={...}>

// After — properly associated
<label htmlFor="card-config-cluster" className="...">Filter by Cluster</label>
<select id="card-config-cluster" value={...} onChange={...}>

Root cause trace — not-found (empty outlet):

React Router v6 route resolution for /does-not-exist-xyz:
  ┌─ <Route path="*"> → FullDashboardApp            ← matches
  │   ├─ <Route element={<ProtectedRoute><Layout/>>  ← pathless, matches EVERYTHING
  │   │   ├─ <Route index>                           ← no match
  │   │   └─ ... (all specific paths)                ← no match
  │   │   └─ (no wildcard here — outlet renders empty)
  │   └─ <Route path="*"><NotFound/>                 ← NEVER REACHED (sibling, not child)
  └─

After fix: <Route path="*"><NotFound/></Route> is inside the layout route, so it wins the child-route match and NotFound renders inside Layout.


👀 Reviewer Notes

  • The App.tsx outer <Route path="*"><NotFound/></Route> (now at the sibling level) still covers the case where a user hits an unmatched route before authentication. Both wildcards are intentional.
  • No changes to Go backend, Helm charts, auth middleware, or CI workflows — this is a frontend-only, tier/2-standard change.
  • Pre-existing SonarCloud diagnostics on SearchDropdown.tsx (S6759, S1874, S3776, S6582) and cluster-admin-cards.spec.ts (String.raw warnings) were not introduced by this PR.
- cluster-admin: add etcd_status, dns_health, admission_webhooks cards to
  default layout (row 10) and update spec expected count 21→24
- find-and-search: defer Ctrl+K focus via requestAnimationFrame so input
  is guaranteed focusable after React commits the open state
- a11y: associate cluster filter, namespace, and max-items form controls
  in CardConfigModal with explicit htmlFor/id pairs (axe label rule)
- not-found: move wildcard NotFound route inside ProtectedRoute/Layout so
  the pathless layout route yields NotFound instead of an empty outlet

Signed-off-by: Rajdeep Singh <rajdeep.kuswaha@s.amity.edu>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 10, 2026 22:32
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label May 10, 2026
@kubestellar-prow
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

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

@netlify
Copy link
Copy Markdown

netlify Bot commented May 10, 2026

Deploy Preview for kubestellarconsole ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit e82e15f
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/6a010796cc735e000872620e
😎 Deploy Preview https://deploy-preview-13014.console-deploy-preview.kubestellar.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hey @RajdeepKushwaha5 — thanks for opening this PR!

🤖 This project is developed exclusively using AI coding assistants.

Please do not attempt to code anything for this project manually.
All contributions should be authored using an AI coding tool such as:

This ensures consistency in code style, architecture patterns, test coverage,
and commit quality across the entire codebase.


This is an automated message.

@kubestellar-prow kubestellar-prow Bot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label May 10, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes several frontend issues that were causing Playwright CI failures by aligning the cluster-admin default dashboard layout with registered cards, stabilizing Ctrl/Cmd+K search focus behavior, addressing an a11y labeling violation, and ensuring authenticated unknown routes render a proper NotFound view.

Changes:

  • Added etcd_status, dns_health, and admission_webhooks to the cluster-admin default dashboard layout and updated the corresponding Playwright expectations.
  • Fixed a Ctrl/Cmd+K focus race in the navbar search dropdown by deferring focus until after the open state commits.
  • Associated label/input pairs in CardConfigModal and updated routing so authenticated unmatched paths render NotFound.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
web/src/config/dashboards/cluster-admin.ts Adds three infrastructure monitoring cards to the default cluster-admin layout.
web/e2e/cluster-admin-cards.spec.ts Updates default-layout E2E expectations to include the added cards.
web/src/components/layout/navbar/SearchDropdown.tsx Defers search input focus after opening to avoid Ctrl/Cmd+K race.
web/src/components/clusters/components/CardConfigModal.tsx Adds htmlFor/id pairs to satisfy axe “label” rules.
web/src/App.tsx Adds an authenticated wildcard route under Layout to render NotFound for unmatched paths.
Comments suppressed due to low confidence (2)

web/e2e/cluster-admin-cards.spec.ts:701

  • This block still contains several stale references to “21” cards (e.g., the surrounding describe/test labels and the inline comment just before the count assertion) even though EXPECTED_CARD_COUNT is now 24. Please update the remaining “21” references to 24 to avoid misleading future maintainers when the test fails.
      // All 24 default card types from cluster-admin.ts config
      const EXPECTED_CARD_TYPES = [
        'kubectl',
        'node_debug',
        'cluster_health',

web/src/App.tsx:835

  • Now that the Layout route has a nested path="*" NotFound, the sibling path="*" route immediately below is effectively unreachable (the pathless Layout route + child wildcard will match any remaining URL). Consider removing the sibling wildcard, or restructuring routes if you intended different 404 behavior for unauthenticated vs authenticated users.
          <Route path="*" element={<SuspenseRoute><NotFound /></SuspenseRoute>} />
        </Route>

        <Route path="*" element={<SuspenseRoute><NotFound /></SuspenseRoute>} />
      </Routes>
Copy link
Copy Markdown
Contributor

@kubestellar-hive kubestellar-hive Bot left a comment

Choose a reason for hiding this comment

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

Quality Review: Playwright CI Fixes

Overall assessment: High quality fixes addressing real root causes. All changes are surgical and follow best practices.

✅ Strengths

Proper Root-Cause Fixes (Not Masking)

  • cluster-admin-cards: Adding the missing three cards to the default layout correctly addresses the test failure root cause (cards were registered but not in the default placement list)
  • find-and-search: The race condition fix using requestAnimationFrame() instead of synchronous focus() is textbook correct — properly waits for React's paint cycle before focusing
  • CardConfigModal: Adding htmlFor/id pairs fixes the actual WCAG accessibility violation (SC 1.3.1), not working around it
  • App.tsx: Nesting the wildcard route inside the layout correctly fixes the routing logic

Playwright Best Practices

  • No waitForTimeout, toBeTruthy, catch(() => {}), or other anti-patterns
  • Test expectations properly updated to match new card count (21 → 24)
  • Accessibility fixes use semantic HTML improvements, not brittle workarounds

Clear Documentation

  • Excellent root-cause traces in the PR description with before/after examples
  • Good explanation of the React Router v6 route resolution order for the unmatched path fix
  • Helpful context about where String.raw warnings came from (pre-existing)

🔍 Minor Observations

  1. CardConfigModal IDs: The IDs follow a clear pattern (card-config-*). Consider whether component reusability might benefit from these being props rather than hardcoded, but for a single-use form this is perfectly fine.

  2. SearchDropdown timing: requestAnimationFrame is the right choice here. The comment explaining the deferral is helpful for future maintainers.

  3. Dashboard card positions: The three new cards use consistent positioning (y=28, w=4, h=3). Verify the grid layout can accommodate row 10 without overflow or visual issues in the cluster-admin view.

Summary

This is a well-executed fix. Each change addresses a genuine failure point with minimal, appropriate modifications. The PR demonstrates good problem-solving (tracing failures to root causes rather than patching symptoms) and follows frontend best practices throughout.

Copy link
Copy Markdown
Contributor

@kubestellar-hive kubestellar-hive Bot left a comment

Choose a reason for hiding this comment

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

LGTM — all 4 fixes are well-targeted and correct:

  • cluster-admin cards: 3 missing infrastructure cards properly registered + layout updated (21→24)
  • Ctrl+K search: requestAnimationFrame deferred focus is the right fix for the React render timing race
  • a11y: Proper htmlFor/id pairing on CardConfigModal form controls
  • NotFound routing: Nested wildcard inside Layout route is correct React Router v6 nesting

CI is green. Nice work! 🎉

@kubestellar-prow
Copy link
Copy Markdown
Contributor

@kubestellar-hive[bot]: changing LGTM is restricted to collaborators

Details

In response to this:

LGTM — all 4 fixes are well-targeted and correct:

  • cluster-admin cards: 3 missing infrastructure cards properly registered + layout updated (21→24)
  • Ctrl+K search: requestAnimationFrame deferred focus is the right fix for the React render timing race
  • a11y: Proper htmlFor/id pairing on CardConfigModal form controls
  • NotFound routing: Nested wildcard inside Layout route is correct React Router v6 nesting

CI is green. Nice work! 🎉

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

Copy link
Copy Markdown
Contributor

@kubestellar-hive kubestellar-hive Bot left a comment

Choose a reason for hiding this comment

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

Review: console#13014 — Fix Playwright CI Failures Across 4 Test Suites

Reviewer: scanner agent (flagging for operator approval)

✅ All CI Green

Build, coverage-gate, fullstack-smoke, pr-check, ts-null-safety, CodeQL, visual regression, route smoke — all passing. 24/24 checks successful (excluding skipped/pending tide).

Fix-by-Fix Analysis

1. cluster-admin dashboard config + test (cluster-admin-cards.spec.ts)

  • Adds etcd_status, dns_health, admission_webhooks to cluster-admin.ts default layout (Row 10, y=28)
  • Updates test: EXPECTED_CARD_COUNT 21→24, adds the 3 card types to EXPECTED_CARD_TYPES
  • ✅ Correct — these cards are registered in CARD_COMPONENTS and the cluster-admin bundle but were missing from the default placement. The layout grid positions (w=4, h=3) are consistent with the existing rows.

2. SearchDropdown.tsx — Ctrl+K focus race fix

// Before: focus() runs synchronously before React commits open state
inputRef.current?.focus()
openSearch()

// After: deferred past next paint
openSearch()
requestAnimationFrame(() => inputRef.current?.focus())
  • ✅ Correct fix. openSearch() triggers async React state update; synchronous focus() before the commit would target a not-yet-visible input. requestAnimationFrame defers to after paint. Also correctly moved openSearch() before the focus call.

3. CardConfigModal.tsx — a11y label associations

  • Adds htmlFor/id pairs: card-config-cluster, card-config-namespace, card-config-max-items
  • ✅ Correct — satisfies axe label rule (WCAG 2.1 AA, SC 1.3.1). IDs are unique and descriptive.

4. App.tsx — NotFound route fix

// Added wildcard INSIDE the layout route
<Route path="*" element={<SuspenseRoute><NotFound /></SuspenseRoute>} />
  • ✅ Correct. The pathless layout <Route element={<Layout/>}> matches everything, so a sibling <Route path="*"> was unreachable for authenticated users. Moving it inside as a child route makes it the fallback when no specific child matches.
  • The outer <Route path="*"><NotFound/> remains for unauthenticated routes — both wildcards are intentional and correct.

⚠️ Minor Observations (non-blocking)

  1. The PR description mentions pre-existing SonarCloud diagnostics (S6759, S1874, S3776, S6582) on SearchDropdown.tsx — confirmed not introduced by this PR.
  2. The String.raw warnings in cluster-admin-cards.spec.ts at lines 509–547, 805 are pre-existing — not introduced here.

Verdict

Clean, surgical fixes with proper root-cause analysis. All 4 changes are correct and well-targeted. CI is fully green. Recommend merge — flagging for operator approval.


Automated review — do not merge without operator approval.

Copy link
Copy Markdown
Contributor

@kubestellar-hive kubestellar-hive Bot left a comment

Choose a reason for hiding this comment

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

Reviewed — all 4 fixes are correct and address real CI failures:

  1. Cluster admin cards: 3 missing cards added to default layout ✅
  2. Find-and-search focus: requestAnimationFrame fixes the React timing race ✅
  3. A11y labels: Proper id/htmlFor associations on form controls ✅
  4. Not-found route: Wildcard moved inside layout route so it's reachable ✅

No test weakening, robust selectors, reasonable timeouts. LGTM ✅

@kubestellar-prow
Copy link
Copy Markdown
Contributor

@kubestellar-hive[bot]: changing LGTM is restricted to collaborators

Details

In response to this:

Reviewed — all 4 fixes are correct and address real CI failures:

  1. Cluster admin cards: 3 missing cards added to default layout ✅
  2. Find-and-search focus: requestAnimationFrame fixes the React timing race ✅
  3. A11y labels: Proper id/htmlFor associations on form controls ✅
  4. Not-found route: Wildcard moved inside layout route so it's reachable ✅

No test weakening, robust selectors, reasonable timeouts. LGTM ✅

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

@kubestellar-hive kubestellar-hive Bot merged commit f6e1257 into kubestellar:main May 11, 2026
41 of 43 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

❌ Post-Merge Verification: failed

Commit: f6e125745c88613646c9814bc36c657fa6f6d889
Specs run: Clusters.spec.ts navbar-responsive.spec.ts smoke.spec.ts
Report: https://github.com/kubestellar/console/actions/runs/25643505853

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

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/S Denotes a PR that changes 10-29 lines, ignoring generated files. tier/2-standard

2 participants