Skip to content

Conversation

@mirnumaan
Copy link
Contributor

@mirnumaan mirnumaan commented Nov 16, 2025

Proposed change

Resolves #2653

Summary

Add descriptive aria-label attributes to interactive elements without visible text to improve accessibility and achieve WCAG 2.1 compliance.

Fixed accessibility issues in 9 components by adding clear, descriptive aria-label attributes:

  • AnchorTitle.tsx: Added aria-label to section anchor link icon
  • Search.tsx: Added aria-label="Clear search" to clear button
  • SortBy.tsx: Added dynamic aria-label to sort order toggle button
  • ProgramActions.tsx: Added aria-label, aria-expanded, and aria-haspopup to menu button
  • Card.tsx: Added aria-label to social media icon links
  • ModuleList.tsx: Added aria-label describing each module to module badge buttons
  • ToggleableList.tsx: Added aria-label and disabled attribute to tag buttons
  • Release.tsx: Added aria-label to repository link button
  • Pagination.tsx: Added aria-label to previous, next, and page number buttons

Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Improved accessibility across multiple components by adding descriptive labels for interactive elements, enhancing support for screen readers and assistive technologies for all users.
  • Tests

    • Updated test expectations and timing configurations to support accessibility improvements and ensure consistent rendering behavior across all application pages.

Walkthrough

Added ARIA labels and a few interaction attributes to multiple frontend interactive elements; applied disabled to ToggleableList item buttons; updated unit and e2e tests to expect new accessible names and adjusted some wait/timeouts and matching strategies.

Changes

Cohort / File(s) Summary
Anchors & Repository Links
frontend/src/components/AnchorTitle.tsx, frontend/src/components/Release.tsx
Added aria-label to anchor/link elements (e.g., "Link to {title} section", View repository {release.repositoryName}).
Action Buttons & Menus
frontend/src/components/Search.tsx, frontend/src/components/SortBy.tsx, frontend/src/components/ProgramActions.tsx
Added aria-label to action buttons (e.g., "Clear search", "Sort in ascending/descending order", "Program actions menu"); added aria-expanded and aria-haspopup where applicable.
Lists, Modules & Cards
frontend/src/components/ModuleList.tsx, frontend/src/components/ToggleableList.tsx, frontend/src/components/Card.tsx
Added aria-label to module buttons, toggle items, and social links; ToggleableList buttons receive disabled={isDisabled}; module buttons labeled Module: {name} and truncated names preserve full text in title.
Pagination Controls
frontend/src/components/Pagination.tsx
Added aria-label to pagination controls: "Go to previous page", "Go to page X", "Go to next page".
Tests (unit & e2e)
frontend/__tests__/unit/components/ModuleList.test.tsx, frontend/__tests__/unit/components/Pagination.test.tsx, frontend/__tests__/unit/pages/About.test.tsx, frontend/__tests__/unit/pages/Home.test.tsx, frontend/__tests__/unit/pages/ProjectDetails.test.tsx, frontend/__tests__/e2e/pages/About.spec.ts, frontend/__tests__/e2e/pages/Users.spec.ts, frontend/__tests__/e2e/pages/Chapters.spec.ts, frontend/__tests__/e2e/pages/Contribute.spec.ts, frontend/__tests__/e2e/pages/Home.spec.ts, frontend/__tests__/e2e/pages/OrganizationDetails.spec.ts, frontend/__tests__/e2e/pages/ProjectsHealthDashboardMetrics.spec.ts
Updated assertions to match new accessible names; switched some exact matches to regex/looser matching; adjusted wait logic/timeouts for animated counters and visibility checks; added a mock flag for project health tests.
Playwright config
frontend/playwright.config.ts
Increased expect.timeout to 10000 ms for the "Mobile Safari - iPhone 13" project.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Changes are mostly consistent ARIA additions and test updates across many files.
  • Areas needing extra attention:
    • ToggleableList: verify disabled behavior aligns with existing click guards and keyboard accessibility.
    • Interpolated aria-labels for dynamic content (ensure characters/i18n safe).
    • Test timing increases (waitFor / explicit timeouts) that could affect CI flakiness.

Possibly related PRs

Suggested reviewers

  • kasya
  • arkid15r

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding aria-labels to interactive elements for WCAG 2.1 compliance, which aligns perfectly with all the component-level changes in the changeset.
Description check ✅ Passed The description is well-related to the changeset, providing a detailed summary of the specific components modified and the accessibility improvements made through aria-label additions.
Linked Issues check ✅ Passed The PR successfully addresses all objectives from issue #2653 by adding descriptive aria-label attributes to all identified components (AnchorTitle, Search, SortBy, ProgramActions, Card, ModuleList, ToggleableList, Release, Pagination) with concise, informative labels reflecting each element's action or purpose.
Out of Scope Changes check ✅ Passed Beyond the core aria-label additions, the PR includes test updates that align with the new accessible names and minor test timeout adjustments. While these test changes go slightly beyond the core accessibility objective, they are necessary adaptations to maintain test validity given the renamed/newly-labeled interactive elements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
frontend/src/components/SortBy.tsx (1)

63-82: Invert the aria-label logic to describe the action, not the state.

The aria-label currently describes the current state rather than the action the button will perform. WCAG guidelines require that button labels describe what happens when the button is activated.

When selectedOrder === 'asc', clicking the button will sort in descending order (Line 64), so the label should say "Sort in descending order", not "Sort in ascending order".

Apply this diff to fix the logic:

             aria-label={
-              selectedOrder === 'asc' ? 'Sort in ascending order' : 'Sort in descending order'
+              selectedOrder === 'asc' ? 'Sort in descending order' : 'Sort in ascending order'
             }

Note: The tooltip on Line 57 correctly describes the current state and should remain unchanged.

frontend/src/components/ProgramActions.tsx (1)

70-80: Keyboard navigation support missing – required for accessibility compliance.

The component has appropriate ARIA attributes (aria-label, aria-expanded, aria-haspopup, role="menuitem"), but lacks the keyboard interactions they imply. The button does not respond to Enter/Space keys, and the dropdown does not close on Escape. Additionally, focus management is not implemented—keyboard users cannot navigate menu items or have focus restored after the menu closes.

Required fixes:

  • Add onKeyDown handler to the button (lines 69-77) to toggle dropdown on Enter/Space
  • Add keyboard listener in useEffect (lines 52-62) to close dropdown on Escape
  • Manage focus: move focus to first menu item when dropdown opens; restore focus to button when dropdown closes
🧹 Nitpick comments (1)
frontend/src/components/ToggleableList.tsx (1)

40-48: LGTM! Consider simplifying onClick handler.

The aria-label and disabled attributes improve accessibility. The disabled attribute correctly prevents interaction when isDisabled is true.

The onClick guard at Line 43 (!isDisabled && handleButtonClick({ item })) is now redundant since the disabled attribute prevents click events. Consider simplifying:

-            onClick={() => !isDisabled && handleButtonClick({ item })}
+            onClick={() => handleButtonClick({ item })}

This is purely defensive code and not required for correctness.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2a8c86 and 3c12aa4.

📒 Files selected for processing (9)
  • frontend/src/components/AnchorTitle.tsx (1 hunks)
  • frontend/src/components/Card.tsx (1 hunks)
  • frontend/src/components/ModuleList.tsx (1 hunks)
  • frontend/src/components/Pagination.tsx (3 hunks)
  • frontend/src/components/ProgramActions.tsx (1 hunks)
  • frontend/src/components/Release.tsx (1 hunks)
  • frontend/src/components/Search.tsx (1 hunks)
  • frontend/src/components/SortBy.tsx (1 hunks)
  • frontend/src/components/ToggleableList.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.
📚 Learning: 2025-06-21T12:21:32.372Z
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.

Applied to files:

  • frontend/src/components/AnchorTitle.tsx
  • frontend/src/components/ProgramActions.tsx
  • frontend/src/components/Card.tsx
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.

Applied to files:

  • frontend/src/components/ToggleableList.tsx
  • frontend/src/components/ProgramActions.tsx
  • frontend/src/components/Card.tsx
📚 Learning: 2025-04-30T13:41:20.846Z
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.

Applied to files:

  • frontend/src/components/ProgramActions.tsx
🔇 Additional comments (7)
frontend/src/components/Search.tsx (1)

88-94: LGTM!

The aria-label="Clear search" clearly describes the button's action for screen readers, improving accessibility for users relying on assistive technologies.

frontend/src/components/Card.tsx (1)

114-127: LGTM!

The aria-label with a fallback (item.title || 'Social media link') ensures that each social media link is properly labeled for screen readers, even when the title is missing.

frontend/src/components/AnchorTitle.tsx (1)

49-56: LGTM!

The aria-label clearly describes the anchor link's purpose and destination, making the icon-only link accessible to screen readers.

frontend/src/components/ModuleList.tsx (1)

23-32: LGTM! Note: pre-existing issue with non-interactive buttons.

The aria-label addition improves accessibility by providing context about each module.

Note (pre-existing issue, not blocking): The module buttons (Lines 23-31) have no onClick handler, making them non-functional. If these are meant to be purely presentational, consider using <span> or <div> elements instead of <button> to avoid confusing keyboard and screen reader users. If they should be interactive, add appropriate click handlers.

frontend/src/components/Pagination.tsx (3)

63-71: Excellent accessibility improvement for the Previous button!

The descriptive aria-label provides clear context for screen reader users navigating the pagination controls.


83-96: Well-implemented dynamic aria-label for page buttons!

The aria-label transforms the minimal visible page number into a clear, descriptive action ("Go to page X") for assistive technologies, while the existing aria-current properly indicates the active page.


99-107: Excellent accessibility improvement for the Next button!

The descriptive aria-label provides clear context for screen reader users, maintaining consistency with the Previous button implementation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
frontend/src/components/Release.tsx (1)

72-84: Consider adding type="button" for clarity.

While not required for this PR, explicitly setting type="button" is a best practice that ensures the button won't accidentally submit a form if the component's context changes.

Apply this diff:

           <button
+            type="button"
             className="cursor-pointer overflow-hidden text-ellipsis whitespace-nowrap text-gray-600 hover:underline dark:text-gray-400"
             disabled={!release.organizationName || !release.repositoryName}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c12aa4 and 5cb3d1a.

📒 Files selected for processing (1)
  • frontend/src/components/Release.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.
🔇 Additional comments (1)
frontend/src/components/Release.tsx (1)

81-81: LGTM! Descriptive aria-label improves accessibility.

The aria-label clearly describes the button's action and includes a sensible fallback for missing repository names. This meets WCAG 2.1 requirements for accessible interactive elements.

@kasya
Copy link
Collaborator

kasya commented Nov 16, 2025

@mirnumaan hi! Please run make check-test locally and address found issues! Thanks!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cb3d1a and 61af4cb.

📒 Files selected for processing (1)
  • frontend/src/components/Release.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.

if (!org || !repo) return
router.push(`/organizations/${org}/repositories/${repo}`)
}}
aria-label={`View repository ${release.repositoryName || 'Unknown'}`}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Make aria-label conditional on button state.

The aria-label correctly uses a fallback for undefined repositoryName, but there's a mismatch when the button is disabled. The button is disabled when either organizationName or repositoryName is missing (line 74), yet the aria-label always suggests an actionable "View repository" command. This can confuse screen reader users who encounter a disabled button with a label implying it can be activated.

Consider making the aria-label reflect the button's actual state:

-              aria-label={`View repository ${release.repositoryName || 'Unknown'}`}
+              aria-label={
+                !release.organizationName || !release.repositoryName
+                  ? 'Repository information unavailable'
+                  : `View repository ${release.repositoryName}`
+              }

This ensures screen reader users understand why the button is disabled when repository information is missing.

📝 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
aria-label={`View repository ${release.repositoryName || 'Unknown'}`}
aria-label={
!release.organizationName || !release.repositoryName
? 'Repository information unavailable'
: `View repository ${release.repositoryName}`
}
🤖 Prompt for AI Agents
In frontend/src/components/Release.tsx around line 81, the aria-label always
reads "View repository ..." even when the button is disabled (disabled when
organizationName or repositoryName is missing); change the aria-label to reflect
the disabled state by conditionally rendering a non-actionable label when
disabled (for example "Repository information unavailable" or "View repository
[name]" only when organizationName and repositoryName are present), keep the
existing fallback for repositoryName when available, and ensure the same boolean
used to compute the disabled prop is reused for the aria-label check so screen
readers get an accurate status.

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

@mirnumaan thanks for working on this!
The changes look good, however you also need to update tests that we have - they are failing right now. Make sure to check locally with make check-test 👍🏼

Dishant1804 and others added 13 commits November 16, 2025 13:51
* spelling fixes and tests

* sonar and code rabbit suggestions implemented

* json chunking and suggestions implemented

* code rabbit and sonar qube suggestions

* code rabbit suggestions

* suggestions implemented

* github advance security addressed

* tests fixed

* fixed tests

* Clean up backend/test_commands.py

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
* Sync www-repopsitories (OWASP#2164)

* spelling fixes and tests

* sonar and code rabbit suggestions implemented

* json chunking and suggestions implemented

* code rabbit and sonar qube suggestions

* code rabbit suggestions

* suggestions implemented

* github advance security addressed

* tests fixed

* fixed tests

* Clean up backend/test_commands.py

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>

* Consolidate code commits

* Update cspell/custom-dict.txt

* Update docker-compose/local.yaml

* local yaml worder volume fix

* instance check

* poetry file updated

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
Co-authored-by: Arkadii Yakovets <[email protected]>
* fix slack and duplication errors

* code rabbit suggestions

* integrity error solved

* using set

* Update code

---------

Co-authored-by: Arkadii Yakovets <[email protected]>
* improvements and refactoring

* added prompt checks and tests for it
* question detection refining

* sonar qube fixes

* fix tests
* agentic rag

* spelling fixes

* code rabbit and sonar qube suggestions

* code rabbit suggestions

* refining

* fix test

* refining
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
frontend/__tests__/unit/pages/About.test.tsx (1)

297-297: Use exact accessible name matcher instead of regex for consistency with e2e tests and stricter validation.

The h2 heading's accessible name remains "Roadmap" after the aria-label addition to the anchor link (aria-labels on non-landmark elements don't affect parent heading names). The e2e test at frontend/__tests__/e2e/pages/About.spec.ts:42 expects exact match { name: 'Roadmap' }, so the unit test should do the same. The regex /Roadmap/ is unnecessarily permissive and could mask regressions if the heading's accessible name unexpectedly changes.

Update line 297 to use the exact string match:

const roadmapSection = screen.getByRole('heading', { name: 'Roadmap' }).closest('div')
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3952f04 and 4fa69bb.

📒 Files selected for processing (3)
  • frontend/__tests__/unit/components/ModuleList.test.tsx (4 hunks)
  • frontend/__tests__/unit/components/Pagination.test.tsx (3 hunks)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.
Learnt from: ahmedxgouda
Repo: OWASP/Nest PR: 1633
File: frontend/src/components/GradientRadialChart.tsx:67-116
Timestamp: 2025-06-21T12:21:32.372Z
Learning: The react-apexcharts Chart component does not support ARIA attributes like aria-label and role as direct props. To add accessibility attributes to ApexCharts in React, wrap the Chart component in a container div with the appropriate ARIA attributes.
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/unit/components/Pagination.test.tsx
  • frontend/__tests__/unit/pages/About.test.tsx
🔇 Additional comments (8)
frontend/__tests__/unit/components/ModuleList.test.tsx (3)

6-42: LGTM! Mock implementations support aria-label correctly.

The mock for @heroui/button properly passes through the aria-label attribute (lines 22, 36), which is essential for the accessibility-focused test updates. Both mocks are well-structured for isolated unit testing.


182-228: LGTM! Truncation tests correctly updated for new aria-label pattern.

The tests properly verify:

  • Buttons use the full module name in aria-label even when text is truncated (lines 190-193)
  • The title attribute is added for truncated modules (line 193, 216)
  • The title attribute is omitted for non-truncated modules (line 226)

The use of a regex pattern at line 213-215 provides appropriate flexibility for testing truncation behavior.


230-269: LGTM! Button property tests consistently updated.

The queries at lines 235 and 257 correctly use the new Module: {moduleName} aria-label pattern. The tests continue to thoroughly verify button classes, attributes, and edge cases.

frontend/__tests__/unit/components/Pagination.test.tsx (5)

44-45: LGTM: Prev/Next button ARIA labels are clear and consistent.

The updated test selectors use descriptive ARIA labels ("Go to previous page" and "Go to next page") that clearly communicate the button actions to assistive technologies. The changes are applied consistently across all test cases covering enabled, disabled, and click behavior scenarios.

Also applies to: 58-58, 64-64, 71-71, 74-74, 116-117


52-52: LGTM: Page number button labels are specific and contextual.

The test updates use the pattern "Go to page N" for all page number buttons, providing specific context about which page each button navigates to. The test on line 105 correctly verifies both the accessible name and the aria-current="page" attribute on the active page button, which is excellent for accessibility testing.

Also applies to: 77-77, 86-86, 95-95, 99-99, 105-105, 118-118, 126-126, 129-129


89-91: LGTM: Ellipses now have accessible labels.

Adding the "More pages" label to ellipses (pagination truncation indicators) is a good accessibility improvement. Screen reader users will now understand that these elements represent additional pages that aren't displayed, rather than encountering unlabeled content.


135-135: LGTM: Regex pattern correctly matches page button labels.

The regex pattern /^Go to page (1|2)$/ properly matches the new ARIA label format while using anchors to ensure exact matching. This is a clean approach for validating the presence of multiple similar elements.


1-137: All test expectations are met by the component implementation.

Verification confirms that the Pagination component (frontend/src/components/Pagination.tsx) includes all ARIA labels and attributes that the tests expect: "Go to previous page" (line 68), "Go to next page" (line 104), "Go to page" pattern (line 86), "More pages" (line 78), and aria-current attributes (line 85). The test file is correctly aligned with the component implementation.

@mirnumaan
Copy link
Contributor Author

mirnumaan commented Nov 16, 2025

Summary for my edits :

I found few more errors while editing the test file I have made changes, please let me know if you want to revert it or keep it , Thank you @kasya for assigning me the issue, looking forward to work on more issues .

Pagination.test.tsx

Changes:

  • Previous/Next button queries updated to match new aria-labels
  • Page number button queries updated to include descriptive labels

Before:

screen.getByRole('button', { name: 'Prev' })
screen.getByRole('button', { name: 'Next' })
screen.getByRole('button', { name: '1' })

After:

screen.getByRole('button', { name: 'Go to previous page' })
screen.getByRole('button', { name: 'Go to next page' })
screen.getByRole('button', { name: 'Go to page 1' })

Reason :

  • Pagination component now has descriptive aria-label attributes on all buttons for better screen reader support.

About.test.tsx

Changes:

  • Updated heading query from exact match to regex pattern

Before:

screen.getByRole('heading', { name: 'Roadmap' })

After:

screen.getByRole('heading', { name: /Roadmap/ })

Reason:

  • AnchorTitle component adds aria-labels to anchor links (e.g., "Roadmap Link to Roadmap section"), changing the heading's accessible name. Using regex makes the test more flexible.

ModuleList.test.tsx

Changes :

  • Updated module badge button queries to include "Module:" prefix:

Before

const button = screen.getByRole('button', { name: 'Test Module' })
const button = screen.getByRole('button', { name: shortModuleName })

After

const button = screen.getByRole('button', { name: 'Module: Test Module' })
const button = screen.getByRole('button', { name: Module: ${shortModuleName} })

ProjectDetails.test.tsx

Changes:

-Added feature flag mock IS_PROJECT_HEALTH_ENABLED: true

  • Changed all chart titles to regex patterns (e.g., /Issues Trend/)

Reason:

  • Health metrics weren't rendering + AnchorTitle changed heading text

Home.test.tsx

Changes:

  • Fixed setTimeout bug with proper waitFor
  • Fixed comment spelling: "millified" → "the number only"

Reason :

  • Unrelated async timing issue

Users.spec.ts

Changes:

  • { name: '2', exact: true } → { name: 'Go to page 2' }

Root Causes:

  • All changes were needed because of two accessibility improvements made:
  • Pagination component - Added descriptive aria-labels to all buttons
  • AnchorTitle component - Adds anchor links to headings, changing their accessible name from "Title" to "Title Link to Title section"

Reason :

  • Pagination button aria-labels

###Kindly refer to screenshot for test results :

Screenshot 2025-11-16 at 4 32 30 pm

@kasya

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
frontend/__tests__/unit/pages/Home.test.tsx (1)

278-289: Good improvement: setTimeout replaced with waitFor.

Replacing the blocking setTimeout with waitFor is a testing best practice—it allows the test to pass as soon as the condition is met rather than waiting the full duration. The 3-second timeout appropriately buffers the 2-second animation.

The exact: false approach works for handling the separately rendered "+", though it could theoretically match values appearing elsewhere in the DOM.

If you want to make the test more robust in the future, consider querying by test IDs or more specific selectors (e.g., within a stats container) rather than relying on partial text matches:

// Example alternative approach (for future consideration)
const statsContainer = screen.getByTestId('stats-overview') // if such container exists
for (const value of Object.values(stats)) {
  expect(within(statsContainer).getByText(millify(value), { exact: false })).toBeInTheDocument()
}
frontend/__tests__/unit/pages/ProjectDetails.test.tsx (1)

166-170: Consider more precise text matching or verify anchor links.

The regex patterns accommodate AnchorTitle's anchor link additions but are quite loose (substring matching). This reduces test precision and could match unintended text.

Consider one of these approaches:

Option 1: Use more specific queries that verify both heading and anchor link

-      expect(screen.getByText(/Issues Trend/)).toBeInTheDocument()
+      const issuesHeading = screen.getByRole('heading', { name: /Issues Trend/ })
+      expect(issuesHeading).toBeInTheDocument()
+      expect(within(issuesHeading).getByRole('link', { name: /anchor/i })).toBeInTheDocument()

Option 2: Use word boundaries in regex for stricter matching

-      expect(screen.getByText(/Issues Trend/)).toBeInTheDocument()
+      expect(screen.getByText(/\bIssues Trend\b/)).toBeInTheDocument()

Both approaches maintain test resilience while improving precision.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa69bb and 6d9e50c.

📒 Files selected for processing (4)
  • frontend/__tests__/e2e/pages/About.spec.ts (2 hunks)
  • frontend/__tests__/e2e/pages/Users.spec.ts (1 hunks)
  • frontend/__tests__/unit/pages/Home.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/ProjectDetails.test.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/e2e/pages/About.spec.ts
🧬 Code graph analysis (1)
frontend/__tests__/e2e/pages/About.spec.ts (1)
frontend/__tests__/unit/data/mockAboutData.ts (1)
  • mockAboutData (1-50)
🔇 Additional comments (4)
frontend/__tests__/unit/pages/ProjectDetails.test.tsx (1)

40-42: Mock structure is correct and follows Jest best practices.

The mock properly exports IS_PROJECT_HEALTH_ENABLED as a named export, matching the actual module at frontend/src/utils/env.client.ts. Hardcoding the value to true appropriately isolates the test from environment configuration while enabling the health metrics section for testing.

frontend/__tests__/e2e/pages/Users.spec.ts (1)

44-44: LGTM! Test selector correctly updated to match new pagination aria-label.

The selector change from a numeric button name to the descriptive "Go to page 2" aria-label aligns with the accessibility improvements in the Pagination component and maintains the same test behavior.

frontend/__tests__/e2e/pages/About.spec.ts (2)

39-42: Heading matchers correctly updated for AnchorTitle accessibility changes.

The shift from exact string matching to regex patterns accommodates the anchor link content that AnchorTitle adds to headings' accessible names. Note that these unanchored regex patterns (e.g., /Roadmap/) will match any text containing the substring, which slightly reduces test precision but is acceptable given the accessibility improvements.

Also applies to: 73-73


81-88: Counter assertions correctly match component structure; verify stat ordering aligns with test expectations.

The split counter assertions match the actual component rendering in frontend/src/app/about/page.tsx (lines 294–305), where each statistic is rendered with a label and formatted numeric value as separate elements. Using exact: false for numeric values is appropriate for formatted counters (e.g., '1.2K+', '40+').

Confirm the stat order in the test matches the component's grid rendering: Forks/Stars/Contributors/Open Issues.

@mirnumaan mirnumaan requested a review from kasya November 16, 2025 12:29
Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

@mirnumaan there are still some tests failing. Could you fix those? I also left some questions.

Comment on lines 39 to 42
await expect(page.getByRole('heading', { name: /Project Timeline/ })).toBeVisible()
await expect(page.getByRole('heading', { name: /Our Story/ })).toBeVisible()
await expect(page.getByRole('heading', { name: 'Leaders' })).toBeVisible()
await expect(page.getByRole('heading', { name: 'Roadmap' })).toBeVisible()
await expect(page.getByRole('heading', { name: /Roadmap/ })).toBeVisible()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why did you change these to be a regex? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I apologize for the confusion, I made an incorrect assumption about how the AnchorTitle component affects the accessible name of headings.

What I assumed was that when the AnchorTitle component adds an anchor link with aria-label="Link to {title} section" inside or near a heading, I thought the heading's accessible name would be affected and become something like:
"Project Timeline Link to Project Timeline section"
So I thought Playwright's getByRole('heading', { name: 'Project Timeline' }) would fail because it was looking for an exact match.

The Reason my approach/assumption was wrong because the aria-label on the anchor link only defines the accessible name for that specific link element, not for the parent heading.

Comment on lines 81 to 82
await expect(page.getByText('1.2K+', { exact: false })).toBeVisible()
await expect(page.getByText('Contributors')).toBeVisible()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also why did you split these into 2 separate checks? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw that the number+plus sign (1.2K+) and the label (Contributors) were rendered in two separate

elements, and I thought Playwright wouldn't be able to find them as a single concatenated string like '1.2K+Contributors'. However, I was likely wrong! Playwright's getByText() can typically find text across multiple sibling elements in the DOM tree, even if they're not in the same element. The text doesn't need to be in a single element for Playwright to match it. The split was unnecessary and made the tests more verbose. The original format should work fine:

await expect(page.getByText('1.2K+Contributors')).toBeVisible()

I apologize for the confusion, I was being overly cautious about the DOM structure when the original approach was correct.

@mirnumaan
Copy link
Contributor Author

Screenshot 2025-11-17 at 9 41 50 pm Screenshot 2025-11-17 at 9 42 45 pm

I am trying to fix the test but every time it is giving me different results.

@kasya

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
frontend/__tests__/e2e/pages/Chapters.spec.ts (1)

28-28: Inconsistent timeout strategy within the same test.

Only the first assertion adds an explicit timeout, while subsequent assertions on lines 29-31 don't. If the page is genuinely slow to render, consider:

  1. Using page.waitForLoadState('networkidle') or page.waitForLoadState('domcontentloaded') in the beforeEach hook instead of adding timeouts to individual assertions.
  2. Waiting for a key element to be visible before proceeding with assertions, making the first wait act as a page-ready signal.

This approach is more maintainable than scattering timeouts across individual assertions.

frontend/__tests__/e2e/pages/ProjectsHealthDashboardMetrics.spec.ts (1)

24-24: Consider consolidating the wait strategy.

Only the first data assertion has an explicit timeout. If health metrics data loads slowly, add a proper wait condition in the test setup rather than relying on the first assertion's timeout as a side-effect page-ready signal.

For example:

 test('renders health metrics data', async ({ page }) => {
   await mockDashboardCookies(page, mockHealthMetricsData, true)
   await page.goto('/projects/dashboard/metrics')
+  await page.waitForLoadState('networkidle')
   const firstMetric = mockHealthMetricsData.projectHealthMetrics[0]
-  await expect(page.getByText(firstMetric.projectName)).toBeVisible({ timeout: 10000 })
+  await expect(page.getByText(firstMetric.projectName)).toBeVisible()
frontend/__tests__/e2e/pages/Contribute.spec.ts (1)

28-28: Same timeout pattern as other test files.

This follows the same pattern: only the first assertion gets a timeout. See comments on other test files about consolidating wait strategies at the test setup level.

frontend/__tests__/e2e/pages/OrganizationDetails.spec.ts (1)

48-50: Consolidate wait strategy for milestones section.

Apply the same consolidation recommendation as other test files. If milestones load slowly, consider waiting for the section to be ready before making assertions.

frontend/__tests__/e2e/pages/Home.spec.ts (1)

98-100: Duplicate timeout pattern.

This follows the same first-assertion timeout pattern seen across multiple test files. Consider implementing a systematic wait strategy as suggested in other files rather than adding timeouts to individual assertions.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between feb30a5 and d1906a8.

📒 Files selected for processing (6)
  • frontend/__tests__/e2e/pages/Chapters.spec.ts (1 hunks)
  • frontend/__tests__/e2e/pages/Contribute.spec.ts (1 hunks)
  • frontend/__tests__/e2e/pages/Home.spec.ts (2 hunks)
  • frontend/__tests__/e2e/pages/OrganizationDetails.spec.ts (1 hunks)
  • frontend/__tests__/e2e/pages/ProjectsHealthDashboardMetrics.spec.ts (1 hunks)
  • frontend/playwright.config.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: codic-yeeshu
Repo: OWASP/Nest PR: 1444
File: frontend/src/components/NavDropDown.tsx:0-0
Timestamp: 2025-04-30T13:41:20.846Z
Learning: When implementing dropdown menus or similar interactive components, always include proper accessibility features: ARIA attributes (aria-expanded, aria-haspopup, aria-controls), keyboard navigation support (Enter, Space, Escape keys), and mechanisms to close dropdowns when clicking outside.
🔇 Additional comments (2)
frontend/playwright.config.ts (1)

18-20: The review comment's premise is incomplete—explicit timeouts are necessary for the chromium project, not redundant.

The playwright.config.ts shows that expect.timeout: 10000 is configured at the project level only for Mobile Safari, not globally or for chromium. The 7 explicit { timeout: 10000 } calls in test files are required for the chromium project to work correctly, since chromium has no timeout configured. They are only redundant for Mobile Safari tests.

The valid concern is architectural: the current mixed approach (both project-level and explicit timeouts) creates ambiguity about intent. The design should clarify whether longer timeouts are needed for all projects (move to root config) or only Mobile Safari (remove explicit assertions and document why). The current setup contradicts itself rather than being purely redundant.

frontend/__tests__/e2e/pages/Home.spec.ts (1)

51-56: <!-- [scratchpad_start]
[task investigation_complete]
[observations]

  • Home page (page.tsx) uses GraphQL query + Algolia fetch for geoLocData
  • Page loading condition: if (isLoading || !graphQLData || !geoLocData) return <LoadingSpinner />
  • Test mocks GraphQL endpoint BUT NOT Algolia endpoint
  • Algolia fetch in useEffect is fire-and-forget (async without proper test integration)
  • AnchorTitle contains aria-label only on anchor link, not heading (accessibility feature)
  • Modified components have only scroll/focus/debounce useEffects, NO async data operations
  • Test timeout only on heading, not on subsequent assertions (author, date)
  • Other similar tests (chapters, projects) have NO timeout on their headings
    [analysis]
  • Root cause: Test setup mocks GraphQL but not Algolia - geoLocData fetch is uncontrolled
  • Page blocks rendering until BOTH graphQLData AND geoLocData load
  • Algolia response timing is unpredictable in test environment, causing intermittent delays
  • aria-label changes to AnchorTitle are accessibility improvements, not performance-related
  • Modified components' useEffects are not causing the timing issue
  • Timeout added to heading suggests developer worked around issue instead of fixing root cause
  • Date assertion works eventually because all data has loaded by then
  • Review comment's assessment is CORRECT: this is trial-and-error debugging
    [pending]
  • None - verification complete
    [done]
    Root cause identified: Algolia fetch timing in test, not aria-label changes or modified component logic
    </scratchpad_end] -->

The timing issue stems from the uncontrolled Algolia data fetch, not the accessibility changes.

The test mocks the GraphQL endpoint but not the Algolia fetch that loads chapter data (geoLocData). The page's render is blocked by the condition if (isLoading || !graphQLData || !geoLocData), meaning it waits for both the mocked GraphQL data and the uncontrolled Algolia response. Once Algolia eventually responds, the page renders and all elements become visible—which is why the timeout on the heading works but isn't needed for subsequent assertions.

The aria-label addition to the anchor in AnchorTitle is an accessibility improvement that doesn't impact rendering performance. The modified components (Search.tsx, AnchorTitle.tsx, SortBy.tsx, Pagination.tsx) contain only scroll navigation, focus management, and debounce cleanup—no async operations that would cause delays.

Recommended fixes:

  • Mock the Algolia endpoint in the test setup, or adjust the loading condition to not block on geoLocData if it's not required for the "News & Opinions" section.
  • Remove the inconsistent timeout and ensure data loading is predictable in tests rather than working around timing issues.

@mirnumaan
Copy link
Contributor Author

Fixes that helped me with the test includes. One,I Increased default timeout from 5s to 10s for all Mobile Safari assertions. Second, increased some of the Individual test timeouts by adding explicit 10s timeouts in 6 problematic test files as extra insurance.

Screenshot 2025-11-18 at 12 20 39 am

@kasya

@mirnumaan mirnumaan requested a review from kasya November 17, 2025 19:44
Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

@mirnumaan thanks for working on this 👍🏼

@kasya kasya added this pull request to the merge queue Nov 19, 2025
@mirnumaan
Copy link
Contributor Author

@mirnumaan thanks for working on this 👍🏼

Thank you so much for assigning 😊. It was so much fun to fix the errors and play with it

@mirnumaan
Copy link
Contributor Author

@mirnumaan thanks for working on this 👍🏼

I want to work on another issue, please assign to me if you have any. Since everything in the issues tab have been assigned. Kindly let me know .

@kasya @arkid15r

Merged via the queue into OWASP:main with commit 57b05f3 Nov 19, 2025
26 checks passed
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.

Missing ARIA Labels on Interactive Elements

4 participants