Skip to content

fix(a11y): label Password and Profile Picture form landmarks on settings/general#14030

Open
olayinkaadelakun wants to merge 1 commit into
release-1.11.0from
LE-1746
Open

fix(a11y): label Password and Profile Picture form landmarks on settings/general#14030
olayinkaadelakun wants to merge 1 commit into
release-1.11.0from
LE-1746

Conversation

@olayinkaadelakun

@olayinkaadelakun olayinkaadelakun commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

This PR is currently pointed to Release-1.11.0, but would be moved to release-1.12.0 when created

Summary

  • PasswordFormComponent and ProfilePictureFormComponent both render bare <Form.Root> (→ ) with no accessible name, on the same page. Confirmed with axe-core: an unlabeled isn't even considered a landmark by axe (landmark-unique comes back inapplicable, not passing), so our unit tests couldn't catch this — but IBM's Equal Access scanner is stricter and flags any duplicate unlabeled forms, which is how this was found live on /settings/general.
  • Added aria-label to both forms: t("settings.passwordTitle") ("Password") and t("settings.profilePictureTitle") ("Profile Picture").
  • Added regression coverage: GeneralPage.a11y.test.tsx (new) renders the full page and asserts both forms are now discoverable via getByRole("form", { name: ... }) with distinct names, plus full-page axe scans (closed and with the Language popover open). LanguageForm.a11y.test.tsx (new) covers the Language dropdown in isolation (keyboard open/close, focus return, named options).

Test plan

  • npx jest src/pages/SettingsPage/pages/GeneralPage — 31/31 passing
  • npx biome check on changed files — clean (pre-existing noExplicitAny warnings on unrelated prop types left untouched, out of scope)
  • npx tsc --noEmit — no new errors
  • Manual QA: verify with IBM Equal Access / axe DevTools that /settings/general no longer reports "multiple forms without unique labels" (see QA test plan shared separately — needs an environment with AUTO_LOGIN=false to see the Password form)

Screenshot
Screenshot 2026-07-13 at 12 46 31 PM

Summary by CodeRabbit

  • Accessibility

    • Improved accessible labeling for the Password and Profile Picture forms.
    • Enhanced language selection with named controls, options, keyboard navigation, and selected-state announcements.
  • Tests

    • Added accessibility coverage for the General settings page and language selector.
    • Verified keyboard interactions, form labels, language selection, and absence of accessibility violations.

@olayinkaadelakun olayinkaadelakun self-assigned this Jul 13, 2026
@olayinkaadelakun olayinkaadelakun added the DO NOT MERGE Don't Merge this PR label Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The General settings forms now expose translated accessible names. New accessibility tests cover GeneralPage structure, language selection interactions, form landmarks, axe violations, and auto-login conditional rendering.

Changes

Settings accessibility

Layer / File(s) Summary
Accessible form landmark names
src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/{PasswordForm,ProfilePictureForm}/index.tsx
Password and profile-picture forms now use translated aria-label values.
Accessibility behavior validation
src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx, src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/LanguageForm/__tests__/LanguageForm.a11y.test.tsx
Tests verify page structure, form landmark names, language combobox and listbox semantics, keyboard interactions, axe results, selected language state, and auto-login rendering.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • langflow-ai/langflow#13811: Addresses related accessibility naming and language navigation changes in the General settings page.

Suggested labels: enhancement

Suggested reviewers: lucaseduoli, ramgopalsrikar, mfortman11


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error The PR adds real tests, but the autoLogin regression is ineffective: it queries the literal key "settings.passwordPlaceholder" while the UI renders translated text. Change the check to screen.queryByRole('form', { name: 'Password' }) (or equivalent) so it actually asserts the Password form is hidden when autoLogin is enabled.
Test Quality And Coverage ⚠️ Warning The autoLogin regression test is a false positive: it queries the i18n key as a placeholder, so it passes even when the password form renders. Assert the form landmark by accessible name, e.g. queryByRole('form', { name: 'Password' }), so the regression actually checks autoLogin behavior.
Test File Naming And Structure ⚠️ Warning Names/structure are fine, but the autoLogin negative test is a false positive—it queries the untranslated placeholder key, so it doesn't verify form absence. Query the labeled form by role/name (or assert absence of the actual translated placeholder) so the negative scenario is real.
✅ Passed checks (6 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Excessive Mock Usage Warning ✅ Passed PASS: The new tests mock only external hooks/portals (API, i18n, Radix, query client) while still rendering the real page and user flows; nearby tests use similar or more mocks.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main accessibility change: labeling the Password and Profile Picture form landmarks on the Settings/General page.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch LE-1746

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.

@github-actions github-actions Bot added the bug Something isn't working label Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Jul 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 (1)
src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx (1)

24-24: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove the unused handleGetProfilePictures prop from ProfilePictureFormComponentProps and the GeneralPage call site. The form fetches profile pictures directly now, so this prop is dead plumbing. src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx:152

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx`
at line 24, Remove the unused handleGetProfilePictures field from
ProfilePictureFormComponentProps and stop passing it from the GeneralPage call
site. Keep ProfilePictureForm’s direct profile-picture fetching unchanged.
🧹 Nitpick comments (1)
src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx (1)

15-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider Playwright for integration-level accessibility tests.

Per coding guidelines, frontend tests should use Playwright where appropriate and follow the project's Playwright testing patterns. The Radix Form mock (lines 15-30) replaces form primitives with plain HTML elements, and 7 total mocks are needed to render the page. A Playwright integration test would exercise real Radix behavior, real portal rendering, and real keyboard/focus interactions without these mocks, providing higher-fidelity accessibility coverage — especially for the popover and keyboard tests.

As per coding guidelines: "use Playwright where appropriate" and "Frontend tests should follow the project's Playwright testing patterns and verify behavior rather than acting as smoke tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx`
around lines 15 - 30, Replace the mocked Radix Form-based accessibility tests in
GeneralPage.a11y.test.tsx with a Playwright integration test following the
project’s existing Playwright patterns. Exercise the real GeneralPage
components, including popover rendering and keyboard/focus interactions, and
verify accessibility behavior without the seven component mocks.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx`:
- Around line 182-189: Update the autoLogin test in the
“does_not_render_the_password_form_when_autologin_is_enabled” case to query the
form landmark by its translated accessible name, using queryByRole with name
“Password,” instead of querying the untranslated placeholder key. Keep the
assertion that the password form is not rendered.

---

Outside diff comments:
In
`@src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx`:
- Line 24: Remove the unused handleGetProfilePictures field from
ProfilePictureFormComponentProps and stop passing it from the GeneralPage call
site. Keep ProfilePictureForm’s direct profile-picture fetching unchanged.

---

Nitpick comments:
In
`@src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx`:
- Around line 15-30: Replace the mocked Radix Form-based accessibility tests in
GeneralPage.a11y.test.tsx with a Playwright integration test following the
project’s existing Playwright patterns. Exercise the real GeneralPage
components, including popover rendering and keyboard/focus interactions, and
verify accessibility behavior without the seven component mocks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d068d593-fe1f-4aba-ab86-37da488c2413

📥 Commits

Reviewing files that changed from the base of the PR and between c8fa807 and 10438c0.

📒 Files selected for processing (4)
  • src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx
  • src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/LanguageForm/__tests__/LanguageForm.a11y.test.tsx
  • src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/PasswordForm/index.tsx
  • src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx

Comment on lines +182 to +189
it("does_not_render_the_password_form_when_autologin_is_enabled", () => {
useAuthStore.setState({ autoLogin: true });
renderGeneralPage();

expect(
screen.queryByPlaceholderText("settings.passwordPlaceholder"),
).not.toBeInTheDocument();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The autoLogin test is a false positive — queryByPlaceholderText uses the i18n key, not the translated value.

queryByPlaceholderText("settings.passwordPlaceholder") queries for the literal string "settings.passwordPlaceholder", but the component renders t("settings.passwordPlaceholder") which resolves to the translated value (e.g., "Password"). Other tests in this file confirm i18n returns translated values — line 161 expects name: "Password", not name: "settings.passwordTitle". Since the query never matches the rendered placeholder, queryByPlaceholderText returns null and the assertion passes regardless of whether the form is rendered.

Use queryByRole("form", { name: "Password" }) instead, which is consistent with line 161 and actually verifies the form landmark's presence.

🐛 Proposed fix
   it("does_not_render_the_password_form_when_autologin_is_enabled", () => {
     useAuthStore.setState({ autoLogin: true });
     renderGeneralPage();

     expect(
-      screen.queryByPlaceholderText("settings.passwordPlaceholder"),
+      screen.queryByRole("form", { name: "Password" }),
     ).not.toBeInTheDocument();
   });
📝 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
it("does_not_render_the_password_form_when_autologin_is_enabled", () => {
useAuthStore.setState({ autoLogin: true });
renderGeneralPage();
expect(
screen.queryByPlaceholderText("settings.passwordPlaceholder"),
).not.toBeInTheDocument();
});
it("does_not_render_the_password_form_when_autologin_is_enabled", () => {
useAuthStore.setState({ autoLogin: true });
renderGeneralPage();
expect(
screen.queryByRole("form", { name: "Password" }),
).not.toBeInTheDocument();
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/pages/SettingsPage/pages/GeneralPage/__tests__/GeneralPage.a11y.test.tsx`
around lines 182 - 189, Update the autoLogin test in the
“does_not_render_the_password_form_when_autologin_is_enabled” case to query the
form landmark by its translated accessible name, using queryByRole with name
“Password,” instead of querying the untranslated placeholder key. Keep the
assertion that the password form is not rendered.

@github-actions

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 45%
45.73% (63206/138197) 69.87% (8607/12317) 43.85% (1425/3249)

Unit Test Results

Tests Skipped Failures Errors Time
5270 0 💤 0 ❌ 0 🔥 16m 8s ⏱️

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.80%. Comparing base (ccdb7c7) to head (10438c0).
⚠️ Report is 12 commits behind head on release-1.11.0.

Files with missing lines Patch % Lines
...ages/GeneralPage/components/PasswordForm/index.tsx 0.00% 1 Missing ⚠️
...eneralPage/components/ProfilePictureForm/index.tsx 0.00% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (0.00%) is below the target coverage (40.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.11.0   #14030      +/-   ##
==================================================
- Coverage           59.99%   59.80%   -0.19%     
==================================================
  Files                2389     2337      -52     
  Lines              230242   229356     -886     
  Branches            34463    35162     +699     
==================================================
- Hits               138125   137158     -967     
- Misses              90501    90582      +81     
  Partials             1616     1616              
Flag Coverage Δ
frontend 59.15% <0.00%> (-0.30%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ages/GeneralPage/components/PasswordForm/index.tsx 12.50% <0.00%> (-0.12%) ⬇️
...eneralPage/components/ProfilePictureForm/index.tsx 29.47% <0.00%> (ø)

... and 326 files with indirect coverage changes

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

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working DO NOT MERGE Don't Merge this PR lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants