Skip to content

feat: configurable status colors get stronger non-color support - #143

Merged
johlju merged 3 commits into
viscalyx:mainfrom
johlju:f/a6-april
May 2, 2026
Merged

feat: configurable status colors get stronger non-color support#143
johlju merged 3 commits into
viscalyx:mainfrom
johlju:f/a6-april

Conversation

@johlju

@johlju johlju commented May 2, 2026

Copy link
Copy Markdown
Member

Description

Screenshots (if applicable)

Related Issues

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement (improves performance without changing functionality)
  • Dependency update (updating libraries or tools)

Testing

  • npm run check passes locally
  • All existing tests still pass
  • Manual testing completed
  • UI tested on desktop and mobile (if applicable)

Checklist

  • Documentation updated as needed

Checklist

  • Code follows the project style guidelines (Biome)
  • Tests added/updated as needed
  • Self-review of code completed
  • Comments added for complex logic
  • No hardcoded strings (use translations if i18n is added)

This change is Reviewable

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 025c0cc0-556c-4ba0-9fe3-c09ba960f856

📥 Commits

Reviewing files that changed from the base of the PR and between 124117a and 526d9aa.

📒 Files selected for processing (3)
  • components/SuggestionStepper.tsx
  • tests/unit/deviation-pill.test.tsx
  • tests/unit/suggestion-pill.test.tsx
✅ Files skipped from review due to trivial changes (2)
  • components/SuggestionStepper.tsx
  • tests/unit/suggestion-pill.test.tsx

Walkthrough

Adds WCAG contrast utilities and tests; emits theme-aware CSS vars and a .status-badge class; updates badges, steppers, and pill components to render icon+label chips and ARIA semantics (role="status", role="group", aria-current="step"); marks decorative color dots aria-hidden; and adds accessibility-focused docs and tests plus i18n keys.

Changes

Contrast utilities & tests

Layer / File(s) Summary
Core utilities
lib/color-contrast.ts
New WCAG-oriented functions: normalizeHex, hexToRgb, relativeLuminance, contrastRatio, rgb↔hsl helpers, clampForReadability, lightenForReadability, getReadableTextColors, pickReadableTextOn.
Unit tests
lib/__tests__/color-contrast.test.ts
Comprehensive Vitest coverage for parsing, luminance/contrast math, clamping/lightening behavior, readable-color selection, and fallbacks.

Badge styling & wiring

Layer / File(s) Summary
Global CSS
app/globals.css
Adds .status-badge class that consumes --sb-fg-light with a .dark override to use --sb-fg-dark.
Component usage
components/StatusBadge.tsx
Replaces direct color use with getReadableTextColors(hex), sets alpha backgroundColor and CSS vars --sb-fg-light/--sb-fg-dark, adds status-badge class.
Unit tests
tests/unit/status-badge.test.tsx
Tests label rendering, CSS var emission, contrast/clamping behavior, fallbacks, alpha-blended bg behavior, and size prop classes.

Steppers: icons, ARIA, readable slider text

Layer / File(s) Summary
Step metadata & icons
components/DeviationStepper.tsx, components/SuggestionStepper.tsx, components/StatusStepper.tsx
Refactors STEPS to include Icon: LucideIcon and renders icons inline for each step.
Accessibility wiring
components/...Stepper.tsx
Adds role="group" plus translated aria-label on wrapper and sets aria-current="step" on the active step element.
Readable slider text
components/StatusStepper.tsx, components/SuggestionStepper.tsx
Computes slider text color via pickReadableTextOn(activeColor) and applies color transitions to the active highlight.
Unit tests
tests/unit/*-stepper.test.tsx
Adds/updates tests to assert role="group", aria-label keys, single aria-current="step", icon rendering (svg[aria-hidden="true"]), and WCAG-driven slider text colors.

Pill components: status chips and role=status

Layer / File(s) Summary
Visual state modeling
components/DeviationPill.tsx, components/SuggestionPill.tsx
Derives statusChip/visualState pairing icon + translated label + classes; replaces color-only cues with icon+label chip.
Accessibility wiring
components/DeviationPill.tsx, components/SuggestionPill.tsx
Sets role="status" on root containers and applies devMarker(..., value: visualState).
Unit tests
tests/unit/deviation-pill.test.tsx, tests/unit/suggestion-pill.test.tsx
Updates/adds tests asserting role="status", icon presence (svg[aria-hidden="true"]), expected status labels, and border-color classes per state.

Requirements table & small accessibility tweaks

Layer / File(s) Summary
Decorative indicators
components/RequirementsTable.tsx
Adds aria-hidden="true" to colored indicator <span> elements in riskLevel and packageItemStatus cells.
Unit tests
tests/unit/requirements-table.test.tsx
Adds test asserting the color dot is aria-hidden="true" and reflects expected inline backgroundColor.

Docs / testing guidelines / i18n

Layer / File(s) Summary
Guidelines
.github/instructions/ui-ux.instructions.md, .github/instructions/tests.instructions.md
UI/UX instructions require non-color cues (icon + text), WCAG contrast guidance for DB-driven colors (light/dark), require role="status" for dynamic containers, mandate role="group", translated aria-label, and aria-current="step" for steppers; tests guideline adds ARIA assertion examples.
i18n
messages/en.json, messages/sv.json
Adds requirement.statusStepperAriaLabel, deviation.stepperAriaLabel, and improvementSuggestion.stepperAriaLabel translations.
Component tests
tests/unit/*
Multiple test additions/updates across components to assert accessibility attributes, icon decoration, aria-current semantics, and color-contrast outcomes.

Sequence Diagram(s)

(Skipped — changes are primarily library/util, component rendering, ARIA attributes and tests; no multi-actor sequential control flow requiring diagram.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description contains only the template structure with no actual content filled in; all sections lack implementation details, rationale, testing notes, or checked items. Complete the Description section with a summary of changes, check the appropriate Type of Change boxes, complete the Testing section, and fill in all checklists to document the implementation and verification steps.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective of the PR: enhancing configurable status colors with stronger non-color accessibility support.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@codecov

codecov Bot commented May 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.23%. Comparing base (145c7fd) to head (526d9aa).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #143      +/-   ##
==========================================
+ Coverage   57.66%   58.23%   +0.56%     
==========================================
  Files         289      290       +1     
  Lines       17472    17616     +144     
  Branches     6674     6607      -67     
==========================================
+ Hits        10076    10258     +182     
+ Misses       7286     7247      -39     
- Partials      110      111       +1     
Files with missing lines Coverage Δ
components/DeviationPill.tsx 100.00% <100.00%> (ø)
components/DeviationStepper.tsx 97.91% <100.00%> (+0.18%) ⬆️
components/RequirementsTable.tsx 76.07% <ø> (+1.29%) ⬆️
components/StatusBadge.tsx 100.00% <100.00%> (ø)
components/StatusStepper.tsx 100.00% <100.00%> (ø)
components/SuggestionPill.tsx 96.07% <100.00%> (+51.07%) ⬆️
components/SuggestionStepper.tsx 97.95% <100.00%> (+2.50%) ⬆️
lib/color-contrast.ts 100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

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

@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 (2)
components/RequirementsTable.tsx (1)

2395-2407: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

packageItemStatus color dot is missing aria-hidden="true" — identical pattern to the riskLevel fix in this PR.

The read-only variant of the packageItemStatus cell (when no onPackageItemStatusChange handler is present) renders the exact same structure — a colored dot followed by a text label — but the dot is not hidden from assistive technology. Screen readers will announce a meaningless empty element or color rectangle.

As per coding guidelines: "Mark decorative icons with aria-hidden="true""

🛡️ Proposed fix
         <span
+          aria-hidden="true"
           className="inline-block w-2.5 h-2.5 rounded-full shrink-0"
           style={{ backgroundColor: statusColor }}
         />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/RequirementsTable.tsx` around lines 2395 - 2407, The colored
status dot in the read-only rendering of packageItemStatus is missing
aria-hidden and will be announced by screen readers; update the inline dot
element (the span that sets style={{ backgroundColor: statusColor }}) used
alongside statusLabel in the packageItemStatus rendering to include
aria-hidden="true" so the decorative color circle is ignored by assistive tech;
keep the rest of the structure (statusColor, statusLabel, and the surrounding
inline-flex span) unchanged and apply this change where
onPackageItemStatusChange is not present (the read-only branch).
components/SuggestionStepper.tsx (1)

155-180: ⚠️ Potential issue | 🟠 Major

Hardcoded text-white on all three active step colors violates WCAG 1.4.3 AA.

The active slider uses className="… text-white" against step background colors with insufficient contrast:

Step Background Contrast (white) WCAG AA (4.5:1)
Draft #3b82f6 ~3.67:1 ❌ fails
Review Requested #eab308 ~1.92:1 ❌ fails
Resolved #22c55e ~2.28:1 ❌ fails

The coding guidelines explicitly state: "a yellow status would render white-on-yellow and fail 1.4.3." Use pickReadableTextOn(activeColor) from lib/color-contrast.ts to choose between #ffffff and #111827 at runtime.

🔧 Proposed fix
 import { CheckCircle2, Eye, type LucideIcon, PenLine } from 'lucide-react'
+import { pickReadableTextOn } from '@/lib/color-contrast'
 import { useTranslations } from 'next-intl'
+  const activeTextColor = pickReadableTextOn(activeColor)

   return (
     // biome-ignore ...
           <div
-            className="h-10 flex items-center justify-center text-white"
+            className="h-10 flex items-center justify-center"
             style={{
               backgroundColor: activeColor,
+              color: activeTextColor,
               clipPath: sliderClipPath(targetIndex === 0),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/SuggestionStepper.tsx` around lines 155 - 180, The active step
text is hardcoded to "text-white" which fails WCAG contrast; update
SuggestionStepper to compute the readable text color at render using
pickReadableTextOn(activeColor) (from lib/color-contrast.ts) and apply that
value to the active slider's text instead of the "text-white" class;
specifically, remove the fixed "text-white" on the div that uses activeColor and
set the span (or container) style/class to use the returned color (either
"#ffffff" or "#111827") so icons and t(STEPS[targetIndex].translationKey) have
sufficient contrast for the STEPS/targetIndex active state.
🧹 Nitpick comments (3)
tests/unit/deviation-pill.test.tsx (1)

56-64: ⚡ Quick win

Strengthen getAllByText assertions — >= 1 won't catch regressions.

getAllByText already throws on zero matches, so >= 1 provides no additional signal. Since statusApproved and statusRejected appear in two places (the header chip and the decision section), the assertion should require at least 2 occurrences. If the chip were accidentally removed the count would fall to 1, and the current guard would still pass silently.

♻️ Proposed fix
-    // statusApproved appears twice: once in the header chip, once in the decision heading
-    expect(screen.getAllByText('statusApproved').length).toBeGreaterThanOrEqual(
-      1,
-    )
+    // statusApproved appears in both the header chip and the decision heading
+    expect(screen.getAllByText('statusApproved').length).toBeGreaterThanOrEqual(2)
-    expect(screen.getAllByText('statusRejected').length).toBeGreaterThanOrEqual(
-      1,
-    )
+    expect(screen.getAllByText('statusRejected').length).toBeGreaterThanOrEqual(2)

Also applies to: 78-86

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/deviation-pill.test.tsx` around lines 56 - 64, The current test in
deviation-pill.test.tsx uses getAllByText('statusApproved').length to assert >=1
which is too weak; update the assertion for getAllByText('statusApproved') (and
the analogous getAllByText('statusRejected') later) to require two occurrences
(e.g., expect(...length).toBeGreaterThanOrEqual(2) or
expect(...length).toHaveLength(2)) because the text must appear in both the
header chip and the decision section; adjust the assertions around the calls to
getAllByText('statusApproved') and the similar block at lines 78-86 to enforce
at least 2 matches.
tests/unit/suggestion-pill.test.tsx (1)

84-90: ⚡ Quick win

Extend the step prop override tests to cover all three values.

The test only exercises step="review_requested". Since step="draft" and step="resolved" each produce different (and possibly surprising) outcomes — in particular step="resolved" on an unresolved suggestion currently renders the draft chip — adding those cases documents the actual behavior and would have caught the issue flagged in components/SuggestionPill.tsx.

🧪 Suggested additional test cases
+  it('forces draft appearance when step="draft" overrides review_requested data', () => {
+    const reviewRequested = { ...baseSuggestion, isReviewRequested: 1 }
+    const { container } = render(
+      <SuggestionPill step="draft" suggestion={reviewRequested} />,
+    )
+    expect(container.querySelector('.border-blue-200')).toBeTruthy()
+    expect(screen.getByText('stepDraft')).toBeInTheDocument()
+  })
+
+  it('renders resolved chip when step="resolved" is provided (even if not yet resolved)', () => {
+    const { container } = render(
+      <SuggestionPill step="resolved" suggestion={baseSuggestion} />,
+    )
+    // Verify the resolved chip appears, not a draft fallback
+    expect(screen.getByText('statusResolved')).toBeInTheDocument()
+    expect(container.querySelector('.border-green-200')).toBeTruthy()
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/suggestion-pill.test.tsx` around lines 84 - 90, Add two more
assertions in the unit test for SuggestionPill to exercise all three step prop
values: render SuggestionPill with step="draft", step="review_requested", and
step="resolved" (using the existing baseSuggestion and render helper) and assert
the expected DOM for each case—e.g., presence of the corresponding border class
and text node (the test already checks .border-yellow-200 and 'statusPending'
for review_requested; add equivalent expects for draft and resolved, noting that
resolved currently renders the draft chip so assert that behavior). Locate usage
of SuggestionPill and baseSuggestion in tests/unit/suggestion-pill.test.tsx and
add the two new cases to the same it block or separate it blocks.
lib/color-contrast.ts (1)

133-152: 💤 Low value

Verify the step count handles extreme color adjustments.

Both clampForReadability and lightenForReadability reuse MAX_DARKEN_STEPS = 12. With DARKEN_STEP = 0.05, the maximum lightness adjustment is 0.60 (60% of the L range). This should suffice for most DB-driven status colors, but very bright colors on white (or very dark on dark) may fall through to the fallback.

The fallback behavior is correct, but consider whether 12 steps is adequate for all real-world status colors. The test suite exercises the fallback path, which is good.

💡 Optional: Rename constant for clarity

Since this constant is used for both darkening and lightening, a more neutral name would improve clarity:

-const MAX_DARKEN_STEPS = 12
+const MAX_ADJUSTMENT_STEPS = 12

Then update references in both functions.

Also applies to: 160-179

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/color-contrast.ts` around lines 133 - 152, clampForReadability and
lightenForReadability use MAX_DARKEN_STEPS with DARKEN_STEP which limits total
lightness change to 0.60 and can let extreme colors fall back; update this by
either increasing the step count or renaming and adjusting the constant to
reflect total lightness range used by both functions (e.g., MAX_LIGHTNESS_STEPS)
and/or reducing DARKEN_STEP so the product MAX_*_STEPS * DARKEN_STEP covers the
full required range; change all references to the old constant
(MAX_DARKEN_STEPS) in both clampForReadability and lightenForReadability and run
tests to ensure the fallback path still behaves as expected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/SuggestionPill.tsx`:
- Around line 51-77: The statusChip logic incorrectly falls through to the draft
variant when a caller passes step="resolved" but isResolved is false; update the
conditional in SuggestionPill.tsx (statusChip, isResolved, effectiveStep) to
explicitly handle effectiveStep === 'resolved' before the final draft branch (or
alternatively restrict the step prop type to only 'draft' | 'review_requested');
ensure the new branch returns the intended resolved/dismissed visuals (Icon,
label, className) for the resolved step so previewing a resolved pill shows the
correct styling even when isResolved is false.

---

Outside diff comments:
In `@components/RequirementsTable.tsx`:
- Around line 2395-2407: The colored status dot in the read-only rendering of
packageItemStatus is missing aria-hidden and will be announced by screen
readers; update the inline dot element (the span that sets style={{
backgroundColor: statusColor }}) used alongside statusLabel in the
packageItemStatus rendering to include aria-hidden="true" so the decorative
color circle is ignored by assistive tech; keep the rest of the structure
(statusColor, statusLabel, and the surrounding inline-flex span) unchanged and
apply this change where onPackageItemStatusChange is not present (the read-only
branch).

In `@components/SuggestionStepper.tsx`:
- Around line 155-180: The active step text is hardcoded to "text-white" which
fails WCAG contrast; update SuggestionStepper to compute the readable text color
at render using pickReadableTextOn(activeColor) (from lib/color-contrast.ts) and
apply that value to the active slider's text instead of the "text-white" class;
specifically, remove the fixed "text-white" on the div that uses activeColor and
set the span (or container) style/class to use the returned color (either
"#ffffff" or "#111827") so icons and t(STEPS[targetIndex].translationKey) have
sufficient contrast for the STEPS/targetIndex active state.

---

Nitpick comments:
In `@lib/color-contrast.ts`:
- Around line 133-152: clampForReadability and lightenForReadability use
MAX_DARKEN_STEPS with DARKEN_STEP which limits total lightness change to 0.60
and can let extreme colors fall back; update this by either increasing the step
count or renaming and adjusting the constant to reflect total lightness range
used by both functions (e.g., MAX_LIGHTNESS_STEPS) and/or reducing DARKEN_STEP
so the product MAX_*_STEPS * DARKEN_STEP covers the full required range; change
all references to the old constant (MAX_DARKEN_STEPS) in both
clampForReadability and lightenForReadability and run tests to ensure the
fallback path still behaves as expected.

In `@tests/unit/deviation-pill.test.tsx`:
- Around line 56-64: The current test in deviation-pill.test.tsx uses
getAllByText('statusApproved').length to assert >=1 which is too weak; update
the assertion for getAllByText('statusApproved') (and the analogous
getAllByText('statusRejected') later) to require two occurrences (e.g.,
expect(...length).toBeGreaterThanOrEqual(2) or
expect(...length).toHaveLength(2)) because the text must appear in both the
header chip and the decision section; adjust the assertions around the calls to
getAllByText('statusApproved') and the similar block at lines 78-86 to enforce
at least 2 matches.

In `@tests/unit/suggestion-pill.test.tsx`:
- Around line 84-90: Add two more assertions in the unit test for SuggestionPill
to exercise all three step prop values: render SuggestionPill with step="draft",
step="review_requested", and step="resolved" (using the existing baseSuggestion
and render helper) and assert the expected DOM for each case—e.g., presence of
the corresponding border class and text node (the test already checks
.border-yellow-200 and 'statusPending' for review_requested; add equivalent
expects for draft and resolved, noting that resolved currently renders the draft
chip so assert that behavior). Locate usage of SuggestionPill and baseSuggestion
in tests/unit/suggestion-pill.test.tsx and add the two new cases to the same it
block or separate it blocks.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5fcf0f9e-05b5-4104-8a42-ac317b2428f5

📥 Commits

Reviewing files that changed from the base of the PR and between 145c7fd and 8d26b42.

📒 Files selected for processing (20)
  • .github/instructions/tests.instructions.md
  • .github/instructions/ui-ux.instructions.md
  • app/globals.css
  • components/DeviationPill.tsx
  • components/DeviationStepper.tsx
  • components/RequirementsTable.tsx
  • components/StatusBadge.tsx
  • components/StatusStepper.tsx
  • components/SuggestionPill.tsx
  • components/SuggestionStepper.tsx
  • lib/__tests__/color-contrast.test.ts
  • lib/color-contrast.ts
  • messages/en.json
  • messages/sv.json
  • tests/unit/deviation-pill.test.tsx
  • tests/unit/deviation-stepper.test.tsx
  • tests/unit/status-badge.test.tsx
  • tests/unit/status-stepper.test.tsx
  • tests/unit/suggestion-pill.test.tsx
  • tests/unit/suggestion-stepper.test.tsx

Comment thread components/SuggestionPill.tsx Outdated
@johlju

johlju commented May 2, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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.

🧹 Nitpick comments (4)
components/SuggestionStepper.tsx (1)

56-64: ⚡ Quick win

Use the standard ComponentProps interface name for props.

Please rename SuggestionStepperProps to ComponentProps and update the component signature accordingly for consistency with repo conventions.

As per coding guidelines "components/**/*.tsx: Define component props using an interface named ComponentProps".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/SuggestionStepper.tsx` around lines 56 - 64, Rename the props
interface SuggestionStepperProps to ComponentProps and update the component
signature to use ComponentProps; specifically change the interface name and the
type annotation in the SuggestionStepper function parameter (the destructured
props { currentStep, developerModeContext }: SuggestionStepperProps) to use
ComponentProps instead, and ensure any other references to
SuggestionStepperProps in this file are updated to ComponentProps for
consistency with the components/**/*.tsx convention.
tests/unit/deviation-pill.test.tsx (1)

39-40: ⚡ Quick win

Use Testing Library role queries for the status assertion.

Prefer screen.getByRole('status') here instead of container.querySelector('[role="status"]') to keep the test aligned with user-facing accessibility semantics.

As per coding guidelines, “Test ARIA roles and attributes on status and state components by asserting role ... values using screen.getByRole()”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/deviation-pill.test.tsx` around lines 39 - 40, Replace the DOM
query using container.querySelector('[role="status"]') with Testing Library's
role query — call screen.getByRole('status') in the deviation-pill.test.tsx
assertion so the test uses user-facing semantics; ensure you have the render
call that sets up screen (or import screen from '@testing-library/react') and
change the expect to assert the element returned by screen.getByRole('status').
tests/unit/suggestion-pill.test.tsx (2)

25-26: ⚡ Quick win

Add a beforeEach(() => vi.clearAllMocks()) in this describe block.

The suite currently skips mock clearing between tests; please add the standard beforeEach hook for consistency and isolation.

As per coding guidelines, “Structure tests with describe() blocks containing a beforeEach(() => vi.clearAllMocks()) hook and it() test cases.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/suggestion-pill.test.tsx` around lines 25 - 26, Add a beforeEach
hook to clear mocks in the describe('SuggestionPill') test suite: inside the
describe block (before the it() tests) add beforeEach(() => vi.clearAllMocks())
so vi.clearAllMocks() runs before each test, ensuring isolation between tests in
this suite.

34-35: ⚡ Quick win

Prefer screen.getByRole('status') over selector-based role checks.

Use a role query for this assertion instead of container.querySelector('[role="status"]') to keep the test accessibility-first and resilient.

As per coding guidelines, “Test ARIA roles and attributes on status and state components by asserting role ... values using screen.getByRole()”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/suggestion-pill.test.tsx` around lines 34 - 35, Replace the
selector-based assertion that checks for a status role
(container.querySelector('[role="status"]')) with an accessibility-first role
query using screen.getByRole('status'); update the test in
suggestion-pill.test.tsx to call screen.getByRole('status') and assert its
presence (e.g., toBeInTheDocument()), and ensure the file imports or uses the
testing-library's screen helper rather than relying on container.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@components/SuggestionStepper.tsx`:
- Around line 56-64: Rename the props interface SuggestionStepperProps to
ComponentProps and update the component signature to use ComponentProps;
specifically change the interface name and the type annotation in the
SuggestionStepper function parameter (the destructured props { currentStep,
developerModeContext }: SuggestionStepperProps) to use ComponentProps instead,
and ensure any other references to SuggestionStepperProps in this file are
updated to ComponentProps for consistency with the components/**/*.tsx
convention.

In `@tests/unit/deviation-pill.test.tsx`:
- Around line 39-40: Replace the DOM query using
container.querySelector('[role="status"]') with Testing Library's role query —
call screen.getByRole('status') in the deviation-pill.test.tsx assertion so the
test uses user-facing semantics; ensure you have the render call that sets up
screen (or import screen from '@testing-library/react') and change the expect to
assert the element returned by screen.getByRole('status').

In `@tests/unit/suggestion-pill.test.tsx`:
- Around line 25-26: Add a beforeEach hook to clear mocks in the
describe('SuggestionPill') test suite: inside the describe block (before the
it() tests) add beforeEach(() => vi.clearAllMocks()) so vi.clearAllMocks() runs
before each test, ensuring isolation between tests in this suite.
- Around line 34-35: Replace the selector-based assertion that checks for a
status role (container.querySelector('[role="status"]')) with an
accessibility-first role query using screen.getByRole('status'); update the test
in suggestion-pill.test.tsx to call screen.getByRole('status') and assert its
presence (e.g., toBeInTheDocument()), and ensure the file imports or uses the
testing-library's screen helper rather than relying on container.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b2f540f-9db0-408e-9dd6-e24427b6c2df

📥 Commits

Reviewing files that changed from the base of the PR and between 8d26b42 and 124117a.

📒 Files selected for processing (7)
  • components/RequirementsTable.tsx
  • components/SuggestionPill.tsx
  • components/SuggestionStepper.tsx
  • tests/unit/deviation-pill.test.tsx
  • tests/unit/requirements-table.test.tsx
  • tests/unit/suggestion-pill.test.tsx
  • tests/unit/suggestion-stepper.test.tsx
✅ Files skipped from review due to trivial changes (2)
  • tests/unit/requirements-table.test.tsx
  • components/RequirementsTable.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/suggestion-stepper.test.tsx

…; update tests to use screen.getByRole for status checks
@johlju

johlju commented May 2, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@johlju
johlju merged commit 112d116 into viscalyx:main May 2, 2026
9 checks passed
@johlju
johlju deleted the f/a6-april branch May 2, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant